{"id":109554,"date":"2024-03-20T07:00:00","date_gmt":"2024-03-20T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109554"},"modified":"2024-03-20T07:25:10","modified_gmt":"2024-03-20T14:25:10","slug":"20240320-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240320-00\/?p=109554","title":{"rendered":"Using the <CODE>Display&shy;Information<\/CODE> class from a desktop Win32 application, part 1"},"content":{"rendered":"<p>For UWP apps, the Windows Runtime <code>Display\u00adInformation<\/code> class provides information about the display that the app is running one. In particular, the <code>Orientation<\/code> property tells you whether the screen is running in landscape, portrait, landscape-flipped, or portrait-flipped orientation.<\/p>\n<p>For Win32 desktop apps, you can obtain a <code>Display\u00adInformation<\/code> object corresponding to a window handle or a display monitor with the assistance of the <code>IDisplay\u00adInformation\u00adStatics\u00adInterop<\/code> interface. This interface follows <a title=\"How do I show the sharing pane from a Win32 desktop application?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170315-00\/?p=95735\"> the usual pattern for interop interfaces<\/a>: Query for the interface from the class activation factory and then use the desired <code>Get\u00adFor\u00ad...<\/code> method.<\/p>\n<p>Let&#8217;s try that in our <a title=\"The scratch program\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20030723-00\/?p=43073\"> scratch program<\/a>.<\/p>\n<pre>#include &lt;windows.graphics.display.interop.h&gt;\r\n#include &lt;winrt\/Windows.Graphics.Display.h&gt;\r\n\r\nnamespace winrt\r\n{\r\n    using namespace winrt::Windows::Graphics::Display;\r\n}\r\n\r\nwinrt::DisplayInformation g_info{ nullptr };\r\n\r\nBOOL\r\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs) <span style=\"border: solid 1px currentcolor;\">try<\/span>\r\n{\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">winrt::check_hresult(                                        <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    winrt::get_activation_factory&lt;winrt::DisplayInformation, <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">        ::IDisplayInformationStaticsInterop&gt;()-&gt;GetForWindow(<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    hwnd, winrt::guid_of&lt;decltype(g_info)&gt;(),                <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">    winrt::put_abi(g_info)));                                <\/span>\r\n    return TRUE;\r\n}\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\">catch (...)      <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    return FALSE;<\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">}                <\/span>\r\n<\/pre>\n<p>We are following the principle of <a title=\"Before you try to do something, make sure you can do nothing\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230725-00\/?p=108482\"> starting by doing nothing<\/a>: Our first step is simply to create the <code>Display\u00adInformation<\/code>. We don&#8217;t do anything with it.<\/p>\n<p>Our <code>OnCreate<\/code> can be simplified by <a title=\"Using Windows Runtime interop methods from C++\/WinRT: Some helper functions\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210806-00\/?p=105529\"> taking advantage of the <code>capture_interop<\/code> helper<\/a>.<\/p>\n<pre>BOOL\r\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs) noexcept\r\n{\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">g_info = wil::capture_interop&lt;winrt::DisplayInformation&gt;     <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">    (&amp;IDisplayInformationStaticsInterop::GetForWindow, hwnd);<\/span>\r\n\r\n    return TRUE;\r\n}\r\ncatch (...)\r\n{\r\n    return FALSE;\r\n}\r\n<\/pre>\n<p>And when the window is destroyed, we clean up the <code>Display\u00adInformation<\/code>.<\/p>\n<pre>void\r\nOnDestroy(HWND hwnd)\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">g_info = nullptr;<\/span>\r\n    PostQuitMessage(0);\r\n}\r\n<\/pre>\n<p>If we run this program, we get a &#8220;not implemented&#8221; exception when we call <code>Get\u00adFor\u00adWindow()<\/code>. Phew, good thing we didn&#8217;t get in too deep. We added only a few lines of code, so it&#8217;s easy to narrow in on the lines that are the source of the problem. And if it turns out that the entire undertaking is not implemented, well, we saved ourselves a lot of trouble: It took us only a few lines of code to discover this.<\/p>\n<p>If you watch the debugger, you see a helpful message:<\/p>\n<pre style=\"white-space: pre-wrap;\">onecoreuap\\<wbr \/>windows\\<wbr \/>wgi\\<wbr \/>winrt\\<wbr \/>display\\<wbr \/>displayinformation.cpp(101)\\<wbr \/>Windows.Graphics.dll!<wbr \/>00007FFFAB1BC87B: (caller: 00007FFFAB1BB741) ReturnHr(2) tid(6f04) 80004001 Not implemented\r\n    Msg:[A DispatcherQueue is required for DisplayInformation created from an HWND] \r\n<\/pre>\n<p>Aha, so the problem is that we need the thread to have a dispatcher queue. We&#8217;ll take up the story next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A little interop music.<\/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-109554","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A little interop music.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109554","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=109554"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109554\/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=109554"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109554"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}