{"id":36023,"date":"2005-03-30T07:04:00","date_gmt":"2005-03-30T07:04:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/03\/30\/the-dialog-manager-part-2-creating-the-frame-window\/"},"modified":"2005-03-30T07:04:00","modified_gmt":"2005-03-30T07:04:00","slug":"the-dialog-manager-part-2-creating-the-frame-window","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050330-00\/?p=36023","title":{"rendered":"The dialog manager, part 2: Creating the frame window"},"content":{"rendered":"<p>The dialog template describes what the dialog box should look like,\nso the dialog manager walks the template and follows the\ninstructions therein.  It&#8217;s pretty straightforward; there isn&#8217;t\nmuch room for decision-making. You just do what the template says.<\/p>\n<p>\nFor simplicity, I&#8217;m going to assume that the dialog template\nis an\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/DialogBoxes\/DialogBoxReference\/DialogBoxStructures\/DLGTEMPLATEEX.asp\">\nextended dialog template<\/a>.  This is a superset of the\nclassic\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/DialogBoxes\/DialogBoxReference\/DialogBoxStructures\/DLGTEMPLATE.asp\">\nDLGTEMPLATE<\/a>, so there is no loss of generality.<\/p>\n<p>\nFurthermore, I will skip over some of the esoterica\n(like the\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/DialogBoxes\/DialogBoxReference\/DialogBoxMessages\/WM_ENTERIDLE.asp\">\nWM_ENTERIDLE<\/a> message)\nbecause that would just\nbe distracting from the main point.\n<\/p>\n<p>\n<strong>I am also going to ignore error-checking for the same reason<\/strong>.\n<\/p>\n<p>\nFinally, I&#8217;m going to assume you already understand the structure of\nthe various dialog templates and ignore the parsing issues.\n(If you&#8217;ve forgotten, you can go back and re-read my series from\nlast June.\nMost important are parts\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/06\/21\/161375.aspx\">2<\/a>\nand\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/06\/21\/163596.aspx\">4<\/a>,\nand the\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/06\/24\/164737.aspx\">summary table<\/a>\nis a handy quick-reference.)\n<\/p>\n<p>Okay, here we go.\n<\/p>\n<p>\nThe first order of business is to study the dialog styles and\ntranslate the <code>DS_*<\/code> styles into <code>WS_*<\/code> and\n<code>WS_EX_*<\/code> styles.\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" STYLE=\"border: 0pt;border-collapse: collapse\">\n<tr>\n<th>Dialog style<\/th>\n<th>Window style<\/th>\n<th>Extended window style<\/th>\n<\/tr>\n<tr>\n<td VALIGN=\"top\"><code>DS_MODALFRAME<\/code><\/td>\n<td>&nbsp;<\/td>\n<td VALIGN=\"top\">add <code>WS_EX_DLGMODALFRAME<\/code><br \/>\n        add <code>WS_EX_WINDOWEDGE<\/code><\/td>\n<\/tr>\n<tr>\n<td VALIGN=\"top\"><code><code>DS_CONTEXTHELP<\/code><\/code><\/td>\n<td>&nbsp;<\/td>\n<td VALIGN=\"top\">add <code>WS_EX_CONTEXTHELP<\/code><\/td>\n<\/tr>\n<tr>\n<td VALIGN=\"top\"><code>DS_CONTROL<\/code><\/td>\n<td VALIGN=\"top\">remove <code>WS_CAPTION<\/code><br \/>\n        remove <code>WS_SYSMENU<\/code><\/td>\n<td VALIGN=\"top\">add <code>WS_EX_CONTROLPARENT<\/code><\/td>\n<\/tr>\n<\/table>\n<p>\n<b>Question<\/b>: Why does the <code>DS_CONTROL<\/code> style remove the\n<code>WS_CAPTION<\/code> and <code>WS_SYSMENU<\/code> styles?\n<\/p>\n<p>\n<b>Answer<\/b>: To make it easier for people to convert an\nexisting dialog into a <code>DS_CONTROL<\/code> sub-dialog\nby simply adding a single style flag.\n<\/p>\n<p>\nIf the template includes a menu, the menu is loaded from\nthe instance handle passed as part of the creation parameters.\n<\/p>\n<pre>\n  hmenu = LoadMenu(hinst, &lt;resource identifier in template&gt;);\n<\/pre>\n<p>\nThis is a common theme in dialog creation:  The instance handle\nyou pass to the dialog creation function is used for all resource-related\nactivities during dialog creation.\n<\/p>\n<p>\nThe algorithm for getting the dialog font goes like this:\n<\/p>\n<pre>\n  if (DS_SETFONT) {\n    use font specified in template\n  } else if (DS_FIXEDSYS) {\n    use GetStockFont(SYSTEM_FIXED_FONT);\n  } else {\n    use GetStockFont(SYSTEM_FONT);\n  }\n<\/pre>\n<p>\nNotice that <code>DS_SETFONT<\/code> takes priority over\n<code>DS_FIXEDFONT<\/code>.\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/07\/368423.aspx\">\nWe saw the reason for this a few weeks ago<\/a>.\n<\/p>\n<p>\nOnce the dialog manager has the font, it is measured so\nthat its dimensions can be used to convert\ndialog units (DLUs) to pixels.\nEverything in dialog box layout is done in DLUs.\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/windowing\/dialogboxes\/dialogboxreference\/dialogboxfunctions\/mapdialogrect.asp\">\nHere&#8217;s a reminder if you&#8217;ve forgotten the formula that converts\nDLUs to pixels<\/a>.  In explicit terms:\n<\/p>\n<pre>\n\/\/ 4 xdlu = 1 average character width\n\/\/ 8 ydlu = 1 average character height\n#define XDLU2Pix(xdlu) MulDiv(xdlu, AveCharWidth, 4)\n#define YDLU2Pix(ydlu) MulDiv(ydlu, AveCharHeight, 8)\n<\/pre>\n<p>\nThe dialog box size come from the template.\n<\/p>\n<pre>\ncxDlg = XDLU2Pix(DialogTemplate.cx);\ncyDlg = YDLU2Pix(DialogTemplate.cy);\n<\/pre>\n<p>\nThe dialog size in the template is the size of the\n<em>client area<\/em>, so we need to add in the nonclient\narea too.\n<\/p>\n<pre>\n  RECT rcAdjust = { 0, 0, cxDlg, cyDlg };\n  AdjustWindowRectEx(&amp;rcAdjust, dwStyle, hmenu != NULL, dwExStyle);\n  int cxDlg = rcAdjust.right - rcAdjust.left;\n  int cyDlg = rcAdjust.bottom - rcAdjust.top;\n<\/pre>\n<p>\nHow do I know that it&#8217;s the client area instead of the full\nwindow including nonclient area?  Because if it were the\nfull window rectangle, then it would be impossible to design\na dialog!\nThe template designer doesn&#8217;t know what nonclient\nmetrics the end-user&#8217;s system will be set to and therefore\ncannot take it into account at design time.\n<\/p>\n<p>\n(This is a special case of a more general rule:\nIf you&#8217;re not sure whether something is true, ask yourself,\n&#8220;What would the world be like if it were true?&#8221;\nIf you find a logical consequence\nthat is obviously wrong, then you have\njust proven [by contradiction]\nthat the thing you&#8217;re considering is indeed not true.\nThis is an important logical\nprinciple that I will come back to again\nand again.\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/15\/372995.aspx\">\nIn fact, you saw it just a few days ago<\/a>.\n)\n<\/p>\n<p>\nAssuming the <code>DS_ABSALIGN<\/code> style is not set,\nthe coordinates given in the dialog template are\nrelative to the dialog&#8217;s parent.\n<\/p>\n<pre>\n  POINT pt = { XDLU2Pix(DialogTemplate.x),\n               YDLU2Pix(DialogTemplate.y) };\n  ClientToScreen(hwndParent, &amp;pt);\n<\/pre>\n<p>\nBut what if the caller passed <code>hwndParent = NULL<\/code>?\nIn that case, the dialog position is relative to the upper left\ncorner of the primary monitor.\nBut <strong>don&#8217;t do this<\/strong>.\n<\/p>\n<ul>\n<li>On a multiple-monitor system, it puts the dialog box on\n    the primary monitor, even if your program is running on\n    a secondary monitor.<\/p>\n<li>The user may have docked their taskbar at the top or left\n    edge of the screen, which will cover your dialog.<\/p>\n<li>Even on a single-monitor system, your program might be running\n    in the lower-right corner of the screen.  Putting your dialog\n    at the upper left corner doesn&#8217;t create a meaningful connection\n    between the two.<\/p>\n<li>If two copies of your program are running, their dialog boxes\n    will cover each other precisely.\n    <a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/03\/14\/395271.aspx\">\n    We saw the dangers of this in a previous entry<\/a>.\n<\/ul>\n<p>\nMoral of the story: Always pass a <code>hwndParent<\/code> window\nso that the dialog appears in a meaningful location relative to\nthe rest of your program.\n(And\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/24\/79212.aspx\">\ndon&#8217;t just grab <code>GetDesktopWindow<\/code> either<\/a>!)\n<\/p>\n<p>\nOkay, we are now all ready to create the dialog:\nWe have its class, its font, its menu, its size\nand position&#8230;\n<\/p>\n<p>\nOh wait, we have to deal with that subtlety\nof dialog box creation discussed earlier:\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/03\/11\/87941.aspx\">\nThe dialog box is always created initially hidden<\/a>.\n<\/p>\n<pre>\n  BOOL fWasVisible = dwStyle &amp; WS_VISIBLE;\n  dwStyle &amp;= ~WS_VISIBLE;\n<\/pre>\n<p><p>\nThe dialog class and title come from the template.\nPretty much everyone just uses the default dialog class,\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/11\/13\/55662.aspx\">\nalthough I explained in an earlier article how\nyou might use a custom dialog class<\/a>.\n<\/p>\n<p>Okay, now we have the information necessary to create the window.\n<\/p>\n<pre>\n HWND hdlg = CreateWindowEx(dwExStyle, pszClass,\n      pszCaption, dwStyle &amp; 0xFFFF0000, pt.x, pt.y,\n      cxDlg, cyDlg, hwndParent, hmenu, hinst, NULL);\n<\/pre>\n<p>\nNotice that we filter\nout all the low style bits (per-class) since we already\ntranslated the <code>DS_*<\/code> styles into &#8220;real&#8221; styles.\n<\/p>\n<p>\nThis is why your dialog procedure doesn&#8217;t get\nthe window creation messages like <code>WM_CREATE<\/code>.\nAt the time the frame is created, the dialog procedure\nhasn&#8217;t yet entered the picture.\nOnly after the frame is created can the dialog manager\nattach the dialog procedure.\n<\/p>\n<pre>\n \/\/ Set the dialog procedure\n SetWindowLongPtr(hdlg, DWLP_DLGPROC, (LPARAM)lpDlgProc);\n<\/pre>\n<p>\nThe dialog manager does some more fiddling at\nthis point, based on the dialog template styles.\nThe template may have asked for a window context help ID.\nAnd if the template did not specify window styles that\npermit resizing, maximizing or minimizing, the associated\nmenu items are removed from the dialog box&#8217;s system menu.\n<\/p>\n<p>\nAnd it sets the font.<\/p>\n<pre>\n  SetWindowFont(hdlg, hf, FALSE);\n<\/pre>\n<p>\nThis is why the first message your dialog procedure\nreceives happens to be <code>WM_SETFONT<\/code>: It is the first\nmessage sent after the <code>DWLP_DLGPROC<\/code> has been set.\nOf course, this\nbehavior can change in the future; you shouldn&#8217;t\nrely on message ordering.\n<\/p>\n<p>\nOkay, the dialog frame is now open for business.\nNext up: Creating the controls.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The dialog template describes what the dialog box should look like, so the dialog manager walks the template and follows the instructions therein. It&#8217;s pretty straightforward; there isn&#8217;t much room for decision-making. You just do what the template says. For simplicity, I&#8217;m going to assume that the dialog template is an extended dialog template. This [&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-36023","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The dialog template describes what the dialog box should look like, so the dialog manager walks the template and follows the instructions therein. It&#8217;s pretty straightforward; there isn&#8217;t much room for decision-making. You just do what the template says. For simplicity, I&#8217;m going to assume that the dialog template is an extended dialog template. This [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36023","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=36023"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36023\/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=36023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=36023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=36023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}