Saturday, May 10, 2008

Dialog with its own accelerator

I learned when I started writing this application that the way the message system works is by creating a window and having a loop poll for messages:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MSG msg;
BOOL bRet;
HMENU hMenu;

hMenu = createMenu();
hwndCustom = CreateWindow("customWndClass", "Merge & Compare", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, hMenu, hinst, (LPVOID)NULL);
haccel = createAccel();
ShowWindow(hwndMain, SW_SHOW);

while((bRet = GetMessage(&msg, NULL, 0, 0 )) != 0)
{
if(bRet == -1)
{
}
else
{
if(!TranslateAccelerator(hwndMain, haccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

DestroyAcceleratorTable(haccel);
return msg.wParam;
}

The question was how do I create a new dialog with a different accelerator table. I guess I could've hacked the TranslateAccelerator call to use a different HACCEL when the dialog was active, but that felt really hacky. The way I chose was to create a new message loop after the dialog creation, and use the PostQuitMessage on the dialog's loop to go back to my main message loop:
My main window wndProc:
static LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_COMMAND:
if(HIWORD(wParam) == 0)
{
if(LOWORD(wParam) == exitID)
{
PostQuitMessage(0);
return 0;
}
}
//menu or accelerator message
if(HIWORD(wParam) == 0 || HIWORD(wParam) == 1)
{
if(LOWORD(wParam) == openFilesID)
{
OpenDialog();
return 0;
}
}

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}

void OpenDialog()
{
HWND hwnd;
MSG msg;
BOOL bRet;
HACCEL haccel;

hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME, "customDialogWndClass", "Dialog", WS_SYSMENU, 0, 0, 0, 0, hwndCustom, (HMENU)NULL, hinst, (LPVOID)NULL);
ShowWindow(hwnd, SW_SHOW);

haccel = createAccel();

while((bRet = GetMessage(&msg, NULL, 0, 0 )) != 0)
{
if(bRet == -1)
{
}
else
{
if(!TranslateAccelerator(hwnd, haccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}

This gives you a cleaner implementation for a separate message loop and accelerator table. The PostQuitMessage allows you to end the dialog's message loop smoothly.

No comments: