Date: | November 13, 2003 / year-entry #128 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20031113-00/?p=41843 |
Comments: | 4 |
Summary: | The other method of using a window-procedure-like dialog box is to change the rules of the game. Normally, the window procedure for a dialog box is the DefDlgProc function, which calls the dialog procedure and then takes action if the dialog procedure indicated that it desired the default action to take place. The dialog procedure... |
The other method of using a window-procedure-like dialog box is
to change the rules of the game.
Normally, the window procedure for a dialog box is
the
The dialog procedure is subservient to
We do this by making the window procedure be our own function
which decides whether or not it wants the default action to happen.
If so, it calls Here's the flow diagram: Message delivered -> WLWndProc -> your WLDlgProc decide what to do want to do the default action -> DefDlgProc -> dummy dialog procedure <- always returns FALSE DefDlgProc does default action <- returns result of default behavior you do other stuff (perhaps modify default behavior after it occurred) <- returns result <- returns result To do this, we need to register a custom dialog class. You always wondered what that was for: Now you know. BOOL InitApp(void) { WNDCLASS wc; wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; wc.lpfnWndProc = WLWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(WLDLGPROC); wc.hInstance = g_hinst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("WLDialog"); if (!RegisterClass(&wc)) return FALSE; return TRUE; } This creates a new window class called "WLDialog" which we will use as our custom dialog class. When you create a custom dialog class, you must set the cbWndExtra to DLGWINDOWEXTRA bytes, plus any additional bytes you wish to use for yourself. We need to store an extra WLDLGPROC, so we add that in. To use our custom dialog procedure, the dialog template must use the "CLASS" keyword to specify the custom dialog class: 1 DIALOGEX DISCARDABLE 0, 0, 200,200 STYLE DS_SHELLFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CLASS "WLDialog" CAPTION "sample" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Bye", IDCANCEL, 7,4,50,14, WS_TABSTOP END
This is exactly the same as a regular dialog box template, except
that there is a "CLASS" entry which specifies that this dialog box
should use our new class. Paralleling the typedef LRESULT (CALLBACK* WLDLGPROC)(HWND, UINT, WPARAM, LPARAM); struct WLDIALOGINFO { WLDLGPROC wldp; LPARAM lParam; }; INT_PTR WLDialogBoxParam(HINSTANCE hinst, LPCTSTR pszTemplate, HWND hwndParent, WLDLGPROC wldp, LPARAM lParam) { WLDIALOGINFO wldi = { wldp, lParam }; return DialogBoxParam(hinst, pszTemplate, hwndParent, WLDlgProc, (LPARAM)&wldi); } This packages up the WndProc-Like dialog procedure and its reference data so we can recover it in our window procedure: LRESULT CALLBACK WLWndProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { if (uiMsg == WM_INITDIALOG) { WLDIALOGINFO *pwldi = (WLDIALOGINFO*)lParam; SetWindowLongPtr(hdlg, DLGWINDOWEXTRA, (LONG_PTR)pwldi->wldp); lParam = pwldi->lParam; } WLDLGPROC wldp = (WLDLGPROC)GetWindowLongPtr(hdlg, DLGWINDOWEXTRA); if (wldp) { return wldp(hdlg, uiMsg, wParam, lParam); } else { return DefDlgProc(hdlg, uiMsg, wParam, lParam); } }
This is the window procedure for the custom dialog. When the
The last piece of the puzzle is the dialog procedure we actually hand to the dialog manager: INT_PTR CALLBACK WLDlgProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { return FALSE; } All it says is, "Do the default thing." Okay so let's write yet another version of our sample program, using this new architecture: LRESULT CALLBACK SampleWLDialogProc( HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { case WM_INITDIALOG: break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: MessageBox(hdlg, TEXT("Bye"), TEXT("Title"), MB_OK); EndDialog(hdlg, 1); break; } break; case WM_SETCURSOR: if (LOWORD(lParam) == HTCAPTION) { SetCursor(LoadCursor(NULL, IDC_SIZEALL)); return TRUE; } break; } return DefDlgProc(hdlg, uiMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nShowCmd) { InitApp(); WLDialogBoxParam(hinst, MAKEINTRESOURCE(1), NULL, SampleWLDialogProc, 0); return 0; }
In this style of WndProc-Like dialog, we just write our
dialog procedure as if it were a window procedure,
calling So now I've developed two quite different ways you can write WndProc-Like dialog procedures. You may not like either one of them, so go ahead and write a third way if you prefer. But at least I hope you learned a little more about how Windows works. |
Comments (4)
Comments are closed. |
Thanks for the insight Raymond. I think I prefer this method somewhat (seems more intuitive to me). It’s nice to know someone’s listening :)
Thank you!
After hours of digging I finally found some really useful info about DIALOG templates in rc files and about custom window classes. I needed all that for my dialog application.
Your article helped me a lot, thanks!
PingBack from http://www.shugye.com/2007/11/why-do-we-even-have-the-defwindowproc-function-%e4%b8%ba%e4%bb%80%e4%b9%88%e6%88%91%e4%bb%ac%e9%9c%80%e8%a6%81defwindowproc-%e5%87%bd%e6%95%b0-48.html
It's important to know that you need to call InitCommonControlsEx function with INITCOMMONCONTROLSEX