July 27th, 2003, 03:17 AM
Win32 GUI Programing
Win32 GUI Programming
Sequel to Win32 Getting Down and Dirty
This time we will cover the GUI in Win32. GUI - Graphical User Interface. The user interacts with the Application. Common GUI objects such as Menus, Buttons, Combo Box, List Box and the Edit control provide input from the user. Other such GUI objects such as the Status bar and Progress bar provide output to the user.
We will now take an example of a button. Buttons and other GUI objects are children to a parent window. Because of this we will need to create a window using the CreateWindow() function, and then add our button.
Create the parent window::
We use CreateWindow() or the newer CreateWindowEx functions to create the window. CreateWindow requires a window class. There are predefined classes but we will define our own by filling in a WNDCLASS data structure. Remember this goes inside WinMain()
wc.style = 0; // This is a class style, we will ignore this for now
wc.lpfnWndProc = WndProc; // See below
wc.cbClsExtra = 0; // Extra stuff we will ignore for now
wc.cbWndExtra = 0;
wc.hInstance = hInst; // Handle to ourself, this we got from WinMain
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Standard icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Standard arrow
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Color of our window
wc.lpszClassName = "Class1"; // Name of our class, give to CreateWindow
wc.lpszMenuName = NULL; // Our app will not use a menu
That's a mouth full, it's not important to understand it all right now. There are a few key things to note. WndProc is the name of a function we create, every time our window receives a message, the message is sent to our window procedure. Our window procedure handles all messages. The user clicks a button, window is closed, minimized, maximized, resized or moved. These all send a message to our window procedure.
hIcon is a handle to the icon to use for our window. IDI_APPLICATION is pre defined by windows.h and Windows takes care of this. IDC_ARROW same thing, pre-defined. You can however make your own icon and cursor, we will describe that in another tutorial.
lpszClassName is a long pointer to a zero terminated string, what a mouth full. Ok it's just a string. We need this later to pass to Createwindow so it knows what class to use.
We now have a WNDCLASS structure filled, we need to register our class using RegisterClass()
It requires a pointer to a WNDCLASS structure, so the & (address-of) operator provides this. We registered our class now we create the window:
HWND hWnd; // Handle to our window
hWnd = CreateWindow("Class1", // Remember this?
"Title", // Goes in the title bar
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // styles for window
0,0,300,300, // x,y position of window + width and height
NULL, NULL, hInst, NULL);
The best way to understand the function arguments is to look them up. We are the parent we supplied NULL as the parent handle. No menu, so again NULL. Do you remember me saying HINSTANCE is used frequently, well here is one of those times.
Now you remember lpfnWndProc = WndProc from our class, this is the brain of our window, any time a button is pushed the window is resized or any user activity, a message is posted to the message quote. We need to make a message loop, the heart that will pump the messages to our WndProc. To do that we use GetMessage() TranslateMessage() and DispatchMessage() functions in a while loop. This retrieves any messages in the message quote and dispatches them to the appropriate window procedure.
MSG Msg; // Another predefined data structure gets filled by GetMessage
while(GetMessage(&Msg, NULL, 0, 0) > 0)
Now we need a WndProc. This is the brain to our window. It's a callback function. We will define callback in a later tutorial.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hwnd, msg, wParam, lParam);
WM_CLOSE is a Windows Message hence WM that gets sent to the window procedure whenever the user clicks the x to close the window. For all messages we don't explicitly handle ourselves we let DefWindowProc take care of.
When the window is created a message WM_CREATE is sent to our procedure. We are going to handle this message and use it as an opportunity to create a button. The pre-defined class name "Button" gives us a button so all we do is call CreateWindow, except this time with a few changes.
HWND hButton; // A button is actually a window
hButton = CreateWindow("Button", "My Button", // Button predefined class
WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, // always child
15, 15, // x and y position within parent of button
200, 25, // 200 width 25 height
hwnd, // parent window handle from WndProc arguments
NULL, GetModuleHandle(NULL), NULL);
We use the pre-defined class Button. All GUI objects are children of their parent thus the style WS_CHILD. The Button Style hence BS is a push button, and we want it to be visible. This time we did provide a handle to our parent, hwnd. It came from WndProc's hwnd argument.
Last time we had hInst provided to us in WinMain, this time our WndProc don't know this value, so we use the function GetModuleHandle to get a handle to ourself.
Now you should have a Window with a button inside. The button don't do anything but does push down. Notice one thing however, the font used on the button. This is not the standard font. There is a reason for this to be discussed in a later tutorial.
It's important to note, we don't explicitly destroy our button, only when the parent is closed, all children are automatically killed. If this did not happen we would have a resource leak.
Remember I'm not covering each new function in detail. You need to look them up in the win32.hlp file. Or on msdn http://msdn.microsoft.com
Windows programming overview: http://www.antionline.com/showthrea...5419#post645419
Win32 Under the hood:
Win32 Getting Down and Dirty
Check also mathgirl32's Win32 API Programming C++
And also www.winprog.org a nice FAQ and tutorial found there.