{"id":14613,"date":"2010-03-15T07:00:00","date_gmt":"2010-03-15T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/03\/15\/a-window-can-have-a-parent-or-an-owner-but-not-both\/"},"modified":"2021-04-19T09:08:56","modified_gmt":"2021-04-19T16:08:56","slug":"20100315-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100315-00\/?p=14613","title":{"rendered":"A window can have a parent or an owner but not both"},"content":{"rendered":"<p>Commenter MontagFTB had a problem which, upon investigation, allegedly was caused by a subtle &#8220;fact&#8221;: &#8220;<a href=\"http:\/\/web.archive.org\/web\/20100130070610\/http:\/\/blogs.msdn.com\/oldnewthing\/pages\/407234.aspx#925651\">The parent specified in <code>CreateWindowEx<\/code> is both the parent of the window and the owner of the window<\/a>, but when you call <code>SetParent<\/code> it only sets the parent of the window, not the owner.&#8221; MontagFTB then concluded that some messages were sent to the parent and others were sent to the owner.<\/p>\n<p>This is a faulty diagnosis. We&#8217;ll look at the correct diagnosis next time, but today&#8217;s topic is parents and owners. Actually, parent and owner windows were already covered by my 2005 PDC talk, <i>Five Things Every Win32 Programmer Should Know<\/i>, so for most of you, today&#8217;s topic is a review. (And I included the topic in the talk specifically so I wouldn&#8217;t have to blog about it, but obviously that plan didn&#8217;t work out.)<\/p>\n<p>A window can be created as a child window (<code>WS_CHILD<\/code> set) or a top-level window (<code>WS_CHILD<\/code> not set). A child window has a parent, which you specify when you call <code>CreateWindowEx<\/code>, and which you can change by calling <code>SetParent<\/code>. A top-level window, on the other hand, has no parent. Its parent is <code>NULL<\/code>.<\/p>\n<p>Ownership is a concept that relates top-level windows. A top-level window can optionally have an owner, which is also specified when you call <code>CreateWindowEx<\/code>, and which you can change by a complicated mechanism described in my talk.<\/p>\n<p>Note that changing a window&#8217;s parent or owner is not a normal operation. You usually create a window with a specific parent or owner and leave it that way for the lifetime of the window.<\/p>\n<p>Now, a window can have a parent, or it can have an owner, or it can have neither, but it can never have both.<\/p>\n<p>What would it mean for a window to have both a parent and an owner? Well, in order to have a parent, the window must itself be a child. But in order to have an owner, the window must be top-level. And top-level windows and child windows are mutually exclusive (and collectively exhaustive), because you either have the <code>WS_CHILD<\/code> style (which makes you a child) or you don&#8217;t (which makes you top-level). Since people like tables so much, here&#8217;s a table:<\/p>\n<table border=\"1\">\n<tbody>\n<tr>\n<th>\u00a0<\/th>\n<th>Child window<\/th>\n<th>Top-level window<\/th>\n<\/tr>\n<tr>\n<th>The Parent window is&#8230;<\/th>\n<td>non-<code>NULL<\/code><\/td>\n<td><code>NULL<\/code><\/td>\n<\/tr>\n<tr>\n<th>The Owner window is&#8230;<\/th>\n<td>N\/A<\/td>\n<td><code>NULL<\/code> or non-<code>NULL<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The box for &#8220;The Owner window of a Child window&#8230;&#8221; is marked N\/A because the question is meaningless. Ownership is a relationship among top-level windows.<\/p>\n<p>By analogy, consider the people at a school for children. They can be separated into two groups, students and teachers. (We&#8217;ll treat non-teaching staff as teachers with no students.)<\/p>\n<p>Each student is assigned to a teacher. Each teacher might or might not have another teacher as a mentor. Several students can be assigned the same teacher, but every student must be assigned to some teacher. Similarly, several teachers might have the same mentor, but some teachers won&#8217;t have a mentor at all, and some mentors might themselves have mentors.<\/p>\n<p>It&#8217;s impossible for a person to have both a teacher and a mentor, because having a teacher applies only to students, and having a mentor applies only to teachers. Teachers don&#8217;t attend classes (they <i>lead<\/i> the classes) so they don&#8217;t have a teacher. But they might have mentors. Asking for a student&#8217;s mentor is a meaningless question because students don&#8217;t have mentors; teachers do.<\/p>\n<p>Since a window cannot have both a parent and an owner, the <code>CreateWindowEx<\/code> function takes a single <code>HWND<\/code> parameter which is either the parent or owner of the window being created, depending on what type of window you&#8217;re creating. If you&#8217;re creating a child window, then the parameter represents the parent window; if you&#8217;re creating a top-level window, then the parameter represents the owner window.<\/p>\n<p>A similar overloading of parameters happens with the <code>HMENU<\/code>: If you&#8217;re creating a child window, then the parameter represents the child window identifier; if you&#8217;re creating a top-level window, then the parameter represents the window menu. Because only top-level windows can have menus, and only child windows can have child window identifiers.<\/p>\n<p>If this parameter overloading bothers you, you can write your own helper functions:<\/p>\n<pre>HWND CreateChildWindowEx(\r\n    DWORD dwExStyle,\r\n    LPCTSTR lpClassName,\r\n    LPCTSTR lpWindowName,\r\n    DWORD dwStyle,\r\n    int x,\r\n    int y,\r\n    int nWidth,\r\n    int nHeight,\r\n    HWND hWndParent,\r\n    UINT_PTR id,\r\n    HINSTANCE hInstance,\r\n    LPVOID lpParam\r\n)\r\n{\r\n \/\/ A child window must have the WS_CHILD style\r\n if (!(dwStyle &amp; WS_CHILD)) {\r\n  SetLastError(ERROR_INVALID_PARAMETER);\r\n  return NULL;\r\n }\r\n return CreateWindowEx(\r\n    dwExStyle,\r\n    lpClassName,\r\n    lpWindowName,\r\n    dwStyle,\r\n    x,\r\n    y,\r\n    nWidth,\r\n    nHeight,\r\n    hWndParent,\r\n    reinterpret_cast&lt;HMENU&gt;(id),\r\n    hInstance,\r\n    lpParam);\r\n}\r\n\r\nHWND CreateTopLevelWindowEx(\r\n    DWORD dwExStyle,\r\n    LPCTSTR lpClassName,\r\n    LPCTSTR lpWindowName,\r\n    DWORD dwStyle,\r\n    int x,\r\n    int y,\r\n    int nWidth,\r\n    int nHeight,\r\n    HWND hWndOwner,\r\n    HMENU hMenu,\r\n    HINSTANCE hInstance,\r\n    LPVOID lpParam\r\n)\r\n{\r\n \/\/ A top-level window must not have the WS_CHILD style\r\n if (dwStyle &amp; WS_CHILD) {\r\n  SetLastError(ERROR_INVALID_PARAMETER);\r\n  return NULL;\r\n }\r\n return CreateWindowEx(\r\n    dwExStyle,\r\n    lpClassName,\r\n    lpWindowName,\r\n    dwStyle,\r\n    x,\r\n    y,\r\n    nWidth,\r\n    nHeight,\r\n    hWndOwner,\r\n    hMenu,\r\n    hInstance,\r\n    lpParam);\r\n}\r\n<\/pre>\n<p>There&#8217;s more to parent windows and owner windows than what I&#8217;ve written here; I refer you to my talk (or other documentation) for more details.<\/p>\n<p>Next time, <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100316-00\/?p=14593\"> we&#8217;ll look at what MontagFTB is really seeing<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the five things every Win32 programmer should know.<\/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-14613","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>One of the five things every Win32 programmer should know.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14613","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=14613"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14613\/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=14613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=14613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=14613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}