{"id":41843,"date":"2003-11-13T03:29:00","date_gmt":"2003-11-13T03:29:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2003\/11\/13\/another-different-type-of-dialog-procedure\/"},"modified":"2003-11-13T03:29:00","modified_gmt":"2003-11-13T03:29:00","slug":"another-different-type-of-dialog-procedure","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20031113-00\/?p=41843","title":{"rendered":"Another different type of dialog procedure"},"content":{"rendered":"<p>\nThe other method of using a window-procedure-like dialog box is\nto change the rules of the game.\nNormally, the window procedure for a dialog box is\nthe <code>DefDlgProc<\/code> function, which calls the dialog\nprocedure and then takes action if the dialog procedure indicated\nthat it desired the default action to take place.\n<\/p>\n<p>\nThe dialog procedure is subservient to <code>DefDlgProc<\/code>,\nproviding advice when requested.\nThe kernel of the idea for this technique is to &#8220;turn the tables&#8221;.\nMake <code>DefDlgProc<\/code> be the one who gives advice and you\nbe the one that asks for the advice when you want it.\n<\/p>\n<p>\nWe do this by making the window procedure be our own function\nwhich decides whether or not it wants the default action to happen.\nIf so, it calls <code>DefDlgProc<\/code> to do it, after giving\nthe dialog a dummy dialog procedure that always says &#8220;Just do the\ndefault&#8221;.\n<\/p>\n<p>\nHere&#8217;s the flow diagram:\n<\/p>\n<pre>\nMessage delivered\n-&gt; WLWndProc\n   -&gt; your WLDlgProc\n      decide what to do\n      want to do the default action\n      -&gt; DefDlgProc\n         -&gt; dummy dialog procedure\n         &lt;- always returns FALSE\n         DefDlgProc does default action\n      &lt;- returns result of default behavior\n      you do other stuff (perhaps modify\n      default behavior after it occurred)\n   &lt;- returns result\n&lt;- returns result\n<\/pre>\n<p>\nTo do this, we need to register a custom dialog class.\nYou always wondered what that was for: Now you know.\n<\/p>\n<pre>\nBOOL\nInitApp(void)\n{\n  WNDCLASS wc;\n  wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;\n  wc.lpfnWndProc = WLWndProc;\n  wc.cbClsExtra = 0;\n  wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(WLDLGPROC);\n  wc.hInstance = g_hinst;\n  wc.hIcon = NULL;\n  wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n  wc.hbrBackground = NULL;\n  wc.lpszMenuName = NULL;\n  wc.lpszClassName = TEXT(\"WLDialog\");\n  if (!RegisterClass(&amp;wc)) return FALSE;\n  return TRUE;\n}\n<\/pre>\n<p>\nThis creates a new window class called &#8220;WLDialog&#8221; which we will use\nas our custom dialog class. When you create a custom dialog class, you\nmust set the cbWndExtra to DLGWINDOWEXTRA bytes, plus any additional\nbytes you wish to use for yourself.  We need to store an extra\nWLDLGPROC, so we add that in.\n<\/p>\n<p>\nTo use our custom dialog procedure, the dialog template must use the\n&#8220;CLASS&#8221; keyword to specify the custom dialog class:<\/p>\n<pre>\n1 DIALOGEX DISCARDABLE  0, 0, 200,200\nSTYLE DS_SHELLFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU\nCLASS \"WLDialog\"\nCAPTION \"sample\"\nFONT 8, \"MS Shell Dlg\"\nBEGIN\n    DEFPUSHBUTTON \"&amp;Bye\", IDCANCEL, 7,4,50,14, WS_TABSTOP\nEND\n<\/pre>\n<p>\nThis is exactly the same as a regular dialog box template, except\nthat there is a &#8220;CLASS&#8221; entry which specifies that this dialog box\nshould use our new class.  Paralleling the <code>DialogBoxParam<\/code>\nfunction we have our own:\n<\/p>\n<pre>\ntypedef LRESULT (CALLBACK* WLDLGPROC)(HWND, UINT, WPARAM, LPARAM);\nstruct WLDIALOGINFO {\n  WLDLGPROC wldp;\n  LPARAM lParam;\n};\nINT_PTR\nWLDialogBoxParam(HINSTANCE hinst, LPCTSTR pszTemplate,\n  HWND hwndParent, WLDLGPROC wldp, LPARAM lParam)\n{\n  WLDIALOGINFO wldi = { wldp, lParam };\n  return DialogBoxParam(hinst, pszTemplate,\n           hwndParent, WLDlgProc, (LPARAM)&amp;wldi);\n}\n<\/pre>\n<p>\nThis packages up the WndProc-Like dialog procedure and its reference\ndata so we can recover it in our window procedure:\n<\/p>\n<pre>\nLRESULT CALLBACK\nWLWndProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)\n{\n  if (uiMsg == WM_INITDIALOG) {\n    WLDIALOGINFO *pwldi = (WLDIALOGINFO*)lParam;\n    SetWindowLongPtr(hdlg, DLGWINDOWEXTRA, (LONG_PTR)pwldi-&gt;wldp);\n    lParam = pwldi-&gt;lParam;\n  }\n  WLDLGPROC wldp = (WLDLGPROC)GetWindowLongPtr(hdlg, DLGWINDOWEXTRA);\n  if (wldp) {\n    return wldp(hdlg, uiMsg, wParam, lParam);\n  } else {\n    return DefDlgProc(hdlg, uiMsg, wParam, lParam);\n  }\n}\n<\/pre>\n<p>\nThis is the window procedure for the custom dialog.  When the\n<code>WM_INITDIALOG<\/code> message comes in, we recover the original\nparameters to <code>WLDialogBoxParam<\/code>.\nThe <code>WLDLGPROC<\/code> we save in the extra bytes we reserved,\nand the original <code>LPARAM<\/code> becomes the <code>lParam<\/code>\nthat we pass to the <code>WLDLGPROC<\/code>.  Then for each message\nthat comes in, we pass the message and its parameters directly to\nthe <code>WLDLGPROC<\/code> and return the value directly.\nNo <code>DWLP_MSGRESULT<\/code> necessary.\n<\/p>\n<p>\nThe last piece of the puzzle is the dialog procedure we actually hand\nto the dialog manager:\n<\/p>\n<pre>\nINT_PTR CALLBACK\nWLDlgProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)\n{\n  return FALSE;\n}\n<\/pre>\n<p>\nAll it says is, &#8220;Do the default thing.&#8221;\n<\/p>\n<p>\nOkay so let&#8217;s write yet another version of our sample program,\nusing this new architecture:\n<\/p>\n<pre>\nLRESULT CALLBACK SampleWLDialogProc(\nHWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)\n{\n  switch (uiMsg) {\n  case WM_INITDIALOG:\n    break;\n  case WM_COMMAND:\n    switch (GET_WM_COMMAND_ID(wParam, lParam)) {\n    case IDCANCEL:\n      MessageBox(hdlg, TEXT(\"Bye\"), TEXT(\"Title\"), MB_OK);\n      EndDialog(hdlg, 1);\n      break;\n    }\n    break;\n  case WM_SETCURSOR:\n    if (LOWORD(lParam) == HTCAPTION) {\n      SetCursor(LoadCursor(NULL, IDC_SIZEALL));\n      return TRUE;\n    }\n    break;\n  }\n  return DefDlgProc(hdlg, uiMsg, wParam, lParam);\n}\nint WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,\n                   LPSTR lpCmdLine, int nShowCmd)\n{\n  InitApp();\n  WLDialogBoxParam(hinst, MAKEINTRESOURCE(1),\n            NULL, SampleWLDialogProc, 0);\n  return 0;\n}\n<\/pre>\n<p>\nIn this style of WndProc-Like dialog, we just write our\ndialog procedure as if it were a window procedure,\ncalling <code>DefDlgProc()<\/code> to perform default behavior.\nAnd to get this new behavior, we use <code>WLDialogBoxParam<\/code>\ninstead of <code>DialogBoxParam<\/cODE>\n<\/p>\n<p>\nSo now I've developed two quite different\nways you can write WndProc-Like dialog procedures.\nYou may not like either one of them, so go ahead and write a third\nway if you prefer.  But at least I hope you\nlearned a little more about how Windows works.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-41843","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>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 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41843","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=41843"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41843\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=41843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=41843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=41843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}