{"id":106192,"date":"2022-01-24T07:00:00","date_gmt":"2022-01-24T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106192"},"modified":"2022-01-24T06:27:51","modified_gmt":"2022-01-24T14:27:51","slug":"20220124-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220124-00\/?p=106192","title":{"rendered":"The MainWindowHandle property is just a guess based on heuristics"},"content":{"rendered":"<p>A customer had a program written in Windows Forms that wanted the following behavior:<\/p>\n<ul>\n<li>When the user minimizes the app, it hides the window.<\/li>\n<li>When the user relaunches the app, the second instance finds the existing (hidden) window and makes it visible again.<\/li>\n<\/ul>\n<p>They got the &#8220;Hide when minimized&#8221; part working, but were not having success with the &#8220;Find the existing window and make it visible again.&#8221; Here&#8217;s their code:<\/p>\n<pre>Private Sub RestoreHiddenInstance\r\n    For Each process As Process In Process.GetProcesses()\r\n        If process.ProcessName.StartsWith(\"Contoso\") Then\r\n            If proceess.StartTime &lt;&gt; Process.GetCurrentProcess.StartTime Then\r\n                ShowWindow(process.MainWindowHandle, SW_RESTORE)\r\n                ShowWindow(process.MainWindowHandle, SW_SHOW)\r\n                ShowWindow(process.MainWindowHandle, SW_SHOWDEFAULT)\r\n                SetForegroundWindow(process.MainWindowHandle)\r\n            End If\r\n        End If\r\n    Next\r\nEnd Sub\r\n<\/pre>\n<p>They didn&#8217;t provide any debugging details about what &#8220;didn&#8217;t work.&#8221; All they said was that it &#8220;didn&#8217;t work.&#8221;<\/p>\n<p>We noted some time ago that <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180511-00\/?p=98735\"> the <code>Main\u00adWindow\u00adHandle<\/code> property is just a guess based on heuristics<\/a>. There is no formal definition of a &#8220;main window&#8221; for a process. It&#8217;s a synthetic property driven by enumerating all the top-level of the windows that belong to the process and trying to guess which one is the main one.<\/p>\n<p>And if you <a href=\"https:\/\/referencesource.microsoft.com\/#System\/services\/monitoring\/system\/diagnosticts\/ProcessManager.cs,49\"> go to the reference source<\/a>, you&#8217;ll see how the BCL decides whether a window is the main window:<\/p>\n<pre>bool IsMainWindow(IntPtr handle)\r\n{\r\n    if (NativeMethods.GetWindow(new HandleRef(this, handle),\r\n                                NativeMethods.GW_OWNER) != (IntPtr)0 ||\r\n        !NativeMethods.IsWindowVisible(new Handleref(this, handle)))\r\n        return false;\r\n\r\n    return true;\r\n}\r\n<\/pre>\n<p>According to the BCL heuristics, any unowned visible window is a candidate for being the &#8220;main&#8221; window.<\/p>\n<p>Since the Contoso program hid all of its windows, there are no &#8220;main&#8221; windows as far as the <code>Main\u00adWindow\u00adHandle<\/code> property is concerned. The <code>process.<wbr \/>Main\u00adWindow\u00adHandle<\/code> property is <code>null<\/code>, and naturally that means that the code doesn&#8217;t actually do anything with the main window of the previous instance.<\/p>\n<p>You need to move away from the heuristic-based window-detection and design something more deterministic. Here are some ideas.<\/p>\n<ul>\n<li>Give the main window a unique class name like <code>Contoso_<wbr \/>Main\u00adWindow<\/code>. Enumerate the top-level windows owned by the previous instance and look for one that has the correct class name. (This solution won&#8217;t work for this particular customer because the class name for Windows Forms windows cannot be customized.)<\/li>\n<li>Register a custom message like <code>Is\u00adContoso\u00adMain\u00adWindow<\/code>. Have your main window respond <code>TRUE<\/code> to that message, and have the second instance send this message to each candidate, and see which one returns <code>TRUE<\/code>.<\/li>\n<li>Create a named shared memory block and put the window handle in it.<\/li>\n<li>Find some other shared data storage that you can use to hold the window handle.<\/li>\n<\/ul>\n<p>This list is far from exhaustive, but gives you an idea of the sort of thinking you need to engage in.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you really need to find your main window, you&#8217;ll have to come up with something more determinstic.<\/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-106192","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If you really need to find your main window, you&#8217;ll have to come up with something more determinstic.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106192","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=106192"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106192\/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=106192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}