This is in no way meant to be a true tutorial. I haven't done any research on the subject and using my own personnal knowledge of the API to write that. I'm just writing that for my own enjoyment and perhaps inject a little bit of life in this wiki.

About the Win32 API

Win32 peculiarities

Writing Win32 applications in C/C++ is a bit different to writing "standard" C/C++ applications - a difference one will notice early is the entry function. Normal C/C++ applications start with a function called main():

int main( int argc, char* argv[] )
{
   /* whatever */
   return 0;
}

Win32 applications, on the other hand, have an entry point called WinMain():

int WINAPI WinMain( HINSTANCE thisInstance, HINSTANCE unused, LPSTR lpCommand, int nShow )
{
    /* whatever */
    return 0;
}

Besides a bunch of new parameters, one will notice the WINAPI keyword stuffed between int and WinMain. This modifier (as it is called in the Platform SDK docs) declares the calling convention of the function. In this case, it tells the compiler that WinMain uses the "standard" calling calling convention rather than the default C convention - this affects the way parameters are passed etc etc. To make a long story short, if you forget the WINAPI modifier, you'll probably get a error during linking.

Here's a short description of the parameters:

Win32 API and handles

The Win32 API sure is a weird beast. You first have to understand that every basic objects (brush, pen, windows, thread, etc.) are accessed through something called an 'handle'. A handle is probably a kind of pointer used by the system to find the data associated to the object in the system memory. I know this is a simplistic definition and if someone is willing to dig for more accurate information, they are free to change it.

Hence, when you call the CreateWindow API functions, you'll get a handle to the window that you'll use with other API functions like ShowWindow, CloseWindow, DestroyWindow, etc. There are thousands of API functions in the Win32 API. All of them are documented on MSDN.

Windows

You also need to know that the term 'window' refer to all types of controls: buttons, labels, windows, toolbars, which may or may not be displayed on the screen. You can view a window as an instance of a class to which you send messages. Messages are the basis of the communication between a program and it's windows.

To create a window, you need to inform CreateWindow of the class of the window you want to create. Win32 has a set of predefined classes you can use: BUTTON, STATIC, EDITBOX (?), etc. But you can also register your own classes. RegisterClass requires a WndProc procedure to be passed as a parameter. The WndProc (it can have another name) receives all the messages sent to windows of the associated class.

Here how a WndProc look like (excerpt from 1 lousy program of mine):

LRESULT CALLBACK gui_wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
CREATESTRUCT * lpcs;
RECT rect;

        GetClientRect(hWnd, &rect);

        switch (msg) {
                
                /* snip */

                case WM_COMMAND:
                        if ((HWND)lParam == hWnd_Button_Connect && lpfn_Handler_Connect != NULL)
                                (* lpfn_Handler_Connect)();

                        if ((HWND)lParam == hWnd_Button_Listen && lpfn_Handler_Listen != NULL)
                                (* lpfn_Handler_Listen)();

                        if ((HWND)lParam == hWnd_Button_Chargen && lpfn_Handler_Chargen != NULL)
                                (* lpfn_Handler_Chargen)();

                        if ((HWND)lParam == hWnd_Button_Send && lpfn_Handler_Chargen != NULL)
                                (* lpfn_Handler_Send)();

                        break;
        
                case WM_CREATE:
                        
                        /* lotsa bullshit removed */

                        break;

                case WM_DESTROY:
                        for (i = 0; i < nStore_Index; i++)
                                DestroyWindow(hWnd_Store[i]);

                        PostQuitMessage(0);
                        break;

                default:
                        return DefWindowProc(hWnd, msg, wParam, lParam);
        }

        return (LRESULT) NULL;
}

Each case handles a particular message sent by the program, other programs, or the Windows system itself in response to actions from users.

WM_COMMAND is the message received when the user presses on buttons, menu items and such. It's the basic of most interactions with the program.

WM_CREATE is received just after the window has been created. It's usually used (by me at least) to create child windows on the main window (buttons, menu, etc.). You don't need to see this yet so that's why I removed that part of the code from the example.

WM_DESTROY is received while the window is being removed from the system. At this point, you should quickly free all resources allocated by the program. It's a point of no-return since the function PostQuitMessage is used to post the return value of the program. That function never returns to the caller.

The second simplest Win32 application

Usually, the classic simplest Win32 application is a call to the MessageBox function. Since this is a site of hobbyist programmer, I think I can jump this one.

The simplest not-really-that-trivial-but-still-trivial program you can make is an empty window with 'Hello World' in it.

The usual steps are:

  1. Register a new window class for your application.
  2. Create the window.
  3. Show the window using ShowWindow

  4. Update the window using UpdateWindow (I know it sound stupid but I tend to forgot those 2 and end up displaying an invisible window)

  5. In the WndProc, handle the WM_PAINT message and use the TextOut function to display the wanted text on the screen.

That's all for today kids! See you tomorrow (or maybe never)

*silly little childish music*

Win32ApiProgramming (last edited 2008-07-09 05:48:11 by localhost)