Wednesday, May 7, 2008

First small steps

So I've decided to write a WIN32 application.... To force myself to learn how the API works I am limiting myself to just the pure WIN32 API. I use no graphic toolkits. The first thing I noticed is how much easier it is to deal with messages and overriding default functions when working without C++ (object oriented aspects). The next thing was how gargantuan an effort it is to learn how the APIs work.

So I've managed to figure out how to create a window, add a menu, and use accelerator keys with relative ease. Dialogs on the other hand have been hell. I create dialogs with CreateWindowEx. The Dialog API is a bit too high level for me. You'll notice that if you create a dialog with the Dialog API you end up getting button IDs that you never created. I get the reason why - it makes sense for those who want it, but I like to have full control and understanding over my application.

The trouble: How do you use the CreateWindow API to create a regular looking dialog? This would be a dialog without a system icon in the top left, and with an X (close) in the top right? First of all this is impossible with CreateWindow. You must use CreateWindowEx. CreateWindowEx adds in a new paramter of extended styles. What was not so intuitive to me was that the new styles affect the way the window is created based upon the old parameters. The code required to create the window is:

WNDCLASSEX wc;

memset(&wc, 0, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = DefWindowProc; //or customWndProc with the default case calling DefWindowProc
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
wc.hbrBackground = GetSysColorBrush(GetSysColor(COLOR_WINDOWFRAME));
wc.lpszMenuName = NULL;
wc.lpszClassName = "CustomWndClass";
wc.hIconSm = NULL;

RegisterClassEx(&wc);

hwndCustom = CreateWindowEx(WS_EX_DLGMODALFRAME, "CustomWndClass", "Custom", WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, (HMENU)NULL, hinst, (LPVOID)NULL);

ShowWindow(hwndCustom, SW_SHOW);

CreateWindow doesn't allow you to give NULL as the wc.hIcon - or rather it allows NULL, and then promptly ignores it by giving you a default ICON. CreateWindowEx will do the same thing unless you set WS_EX_DLGMODALFRAME as part of the extended style. Once you use the WS_EX_DLGMODALFRAME and wc.hIcon is NULL you will end up with a dialog window without an icon and with an X (close) button!!

I'd like to thank Dave Miller from the post that finally unlocked this mystery for me:
http://groups.google.com/group/microsoft.public.win32.programmer.ui/browse_thread/thread/9bc4077917f5f7fa/5e84ee3431e71f44?lnk=st&q=CreateWindowEx+WS_EX_DLGMODALFRAME+DefWindowProc+%22int+main%22#5e84ee3431e71f44

That's enough for now, see you next time.

No comments: