A Simple WindowExample: simple_window ![]() Sometimes people come on IRC and ask "How do I make a window?"...Well it's not entirely that simple I'm afraid. It's not difficult once you know what you're doing but there are quite a few things you need to do to get a window to show up; And they're more than can be simply explained over a chat room, or a quick note. I always liked to do things first and learn them later...so here is the code to a simple window which will be explained shortly. MODULE simple_window; FROM WIN32 IMPORT HWND,UINT,WPARAM,LPARAM,LRESULT,HBRUSH; FROM WINUSER IMPORT WM_CLOSE,WM_DESTROY, IDI_APPLICATION,IDC_ARROW,COLOR_WINDOW, WS_EX_CLIENTEDGE,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, WNDCLASS,MSG, DestroyWindow,PostQuitMessage,DefWindowProc, RegisterClass,CreateWindowEx, ShowWindow,UpdateWindow, GetMessage,TranslateMessage,DispatchMessage, LoadCursor,LoadIcon, MessageBox,MB_ICONEXCLAMATION,MB_OK; FROM WINX IMPORT Instance,CmdShow; FROM SYSTEM IMPORT CAST,ADR,FUNC; CONST g_szClassName = "myWindowClass"; (* Step 4: the Window Procedure *) PROCEDURE WndProc(hwnd : HWND; msg : UINT; wParam : WPARAM; lParam : LPARAM): LRESULT [EXPORT, OSCall]; BEGIN CASE msg OF | WM_CLOSE : FUNC DestroyWindow(hwnd); | WM_DESTROY : PostQuitMessage(0); ELSE RETURN DefWindowProc(hwnd, msg, wParam, lParam); END; RETURN 0; END WndProc; VAR wc : WNDCLASS; hwnd : HWND; Msg : MSG; BEGIN (* Step 1: Registering the Window Class *) wc.style := 0; wc.lpfnWndProc := WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := Instance; wc.hIcon := LoadIcon(NIL, IDI_APPLICATION^); wc.hCursor := LoadCursor(NIL, IDC_ARROW^); wc.hbrBackground := CAST(HBRUSH, COLOR_WINDOW+1); wc.lpszMenuName := NIL; wc.lpszClassName := ADR(g_szClassName); IF RegisterClass(wc)=0 THEN FUNC MessageBox(NIL, "Window Class registration failed!", "Error!", MB_ICONEXCLAMATION BOR MB_OK); RETURN ; END; (* Step 2: Creating the Window *) hwnd := CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "The title of my window",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NIL, NIL, Instance, NIL); IF hwnd = NIL THEN FUNC MessageBox(NIL, "Window Creation failed!", "Error!", MB_ICONEXCLAMATION BOR MB_OK); RETURN ; END; FUNC ShowWindow(hwnd, CmdShow); FUNC UpdateWindow(hwnd); (* Step 3: The Message Loop *) WHILE GetMessage( Msg, NIL, 0, 0) DO FUNC TranslateMessage(Msg); FUNC DispatchMessage(Msg); END; END simple_window. For most part this is the simplest windows program you can write that actually creates a functional window, a mere 70 or so lines. If you got the first example to compile then this one should work with no problems. Import sectionWhen writing Windows applications, we will import lots of procedures, varables and type definitions from the different Windows libraries, in Modula-2 available as different modules. Here are the Windows modules we will use the most:
Step 1: Registering the Window ClassA Window Class stores information about a type of window, including it's Window Procedure which controls the window, the small and large icons for the window, and the background color. This way, you can register a class once, and create as many windows as you want from it, without having to specify all those attributes over and over. Most of the attributes you set in the window class can be changed on a per-window basis if desired. A Window Class has NOTHING to do with C++ classes. CONST g_szClassName = "myWindowClass"; The constant above stores the name of our window class, we will use it shortly to register our window class with the system. VAR wc : WNDCLASS; wc.style := 0; wc.lpfnWndProc := WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := Instance; wc.hIcon := LoadIcon(NIL, IDI_APPLICATION^); wc.hCursor := LoadCursor(NIL, IDC_ARROW^); wc.hbrBackground := CAST(HBRUSH, COLOR_WINDOW+1); wc.lpszMenuName := NIL; wc.lpszClassName := ADR(g_szClassName); IF RegisterClass(wc)=0 THEN FUNC MessageBox(NIL, "Window Class registration failed!", "Error!", MB_ICONEXCLAMATION BOR MB_OK); RETURN ; END;
This is the code we use to register our window class.
We fill out the members of a The members of the struct affect the window class as follows:
Don't worry if that doesn't make much sense to you yet, the various parts that count will be explained more later. Another thing to remember is to not try and remember this stuff. I rarely (never) memorize structs, or function parameters, this is a waste of effort and, more importantly, time. If you know the functions you need to call then it is a matter of seconds to look up the exact parameters in your help files. If you don't have help files, get them. You are lost without. Eventually you will come to know the parameters to the functions you use most.
We then call Step 2: Creating the Window
Once the class is registered, we can create a window with it. You should look
up the parameters for VAR hwnd : HWND; hwnd := CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "The title of my window",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NIL, NIL, Instance, NIL);
The first parameter (
Next we have the class name (
The parameter we have as
The next four parameters (
Next ( Variable Instance: In Windows programs written in C, a procedure named WinMain() is the entry point for the program. This WinMain() procedure receives the following parameters from then environment when the program starts execution:
Since in a Modula-2 program the entry point is at the BEGIN begin statement of the program module, there must be another way to receive these parameters. This is handled in the WINX module, from we can import these important variables (Intance, CmdShow, CmdLine).
Number one cause of people not knowing what the heck is wrong with their programs is probably
that they didn't check the return values of their calls to see if they failed or not.
IF hwnd = NIL THEN FUNC MessageBox(NIL, "Window Creation failed!", "Error!", MB_ICONEXCLAMATION BOR MB_OK); RETURN ; END;
After we've created the window and checked to make sure we have a valid handle
we show the window, using the last parameter in FUNC ShowWindow(hwnd, CmdShow); FUNC UpdateWindow(hwnd);
The Step 3: The Message LoopThis is the heart of the whole program, pretty much everything that your program does passes through this point of control. WHILE GetMessage( Msg, NIL, 0, 0) DO FUNC TranslateMessage(Msg); FUNC DispatchMessage(Msg); END;
Step 4: the Window ProcedureIf the message loop is the heart of the program, the window procedure is the brain. This is where all the messages that are sent to our window get processed.PROCEDURE WndProc(hwnd : HWND; msg : UINT; wParam : WPARAM; lParam : LPARAM): LRESULT [EXPORT, OSCall]; BEGIN CASE msg OF | WM_CLOSE : FUNC DestroyWindow(hwnd); | WM_DESTROY : PostQuitMessage(0); ELSE RETURN DefWindowProc(hwnd, msg, wParam, lParam); END; RETURN 0; END WndProc;
The window procedure is called for each message, the
When we call Step 5: There is no Step 5Phew. Well that's it! If I haven't explained stuff clearly enough yet, just hang in there and hopefully things will become more clear as we get into more usefull programs.
Copyright © 1998-2011, Brook Miles. All rights reserved. Adapted for Modula-2 by Frank Schoonjans, with permission. |