{"id":109558,"date":"2024-03-21T07:00:00","date_gmt":"2024-03-21T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109558"},"modified":"2024-03-21T08:45:36","modified_gmt":"2024-03-21T15:45:36","slug":"20240321-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240321-00\/?p=109558","title":{"rendered":"Using the <CODE>Display&shy;Information<\/CODE> class from a desktop Win32 application, part 2"},"content":{"rendered":"<p>Last time, we <a title=\"Using the DisplayInformation class from a desktop Win32 application, part 1\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240320-00\/?p=109554\"> tried to create a <code>Display\u00adInformation<\/code> from an <code>HWND<\/code><\/a>, but it failed with the message &#8220;A DispatcherQueue is required for DisplayInformation created from an HWND.&#8221;<\/p>\n<p>So I guess we need to make sure the thread has a <code>Dispatcher\u00adQueue<\/code>.<\/p>\n<pre><span style=\"border: solid 1px currentcolor;\">#include &lt;DispatcherQueue.h&gt;<\/span>\r\n#include &lt;windows.graphics.display.interop.h&gt;\r\n#include &lt;winrt\/Windows.Graphics.Display.h&gt;\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\">#include &lt;winrt\/Windows.Foundation.h&gt;<\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">#include &lt;winrt\/Windows.System.h&gt;    <\/span>\r\n\r\nnamespace winrt\r\n{\r\n    using namespace winrt::Windows::Graphics::Display;\r\n    <span style=\"border: solid 1px currentcolor;\">using namespace winrt::Windows::System;<\/span>\r\n}\r\n\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\">namespace ABI                            <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    using namespace ABI::Windows::System;<\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">}                                        <\/span>\r\n<span style=\"border: solid 1px currentcolor;\">winrt::DispatcherQueueController g_controller{ nullptr };<\/span>\r\nwinrt::DisplayInformation g_info{ nullptr };\r\n\r\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs) noexcept\r\n{\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">DispatcherQueueOptions options{                              <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    sizeof(options), DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE };<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">winrt::check_hresult(                                        <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    CreateDispatcherQueueController(options,                 <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">        reinterpret_cast&lt;ABI::IDispatcherQueueController**&gt;( <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">            controller.put())));                             <\/span>\r\n\r\n    g_info = wil::capture_interop&lt;winrt::DisplayInformation&gt;\r\n        (&amp;IDisplayInformationStaticsInterop::GetForWindow, hwnd);\r\n\r\n    return TRUE;\r\n}\r\ncatch (...)\r\n{\r\n    return FALSE;\r\n}\r\n\r\n<span style=\"border: solid 1px currentcolor;\">winrt::fire_and_forget<\/span>\r\nOnDestroy(HWND hwnd)\r\n{\r\n    g_info = nullptr;\r\n    <span style=\"border: solid 1px currentcolor;\">co_await g_controller.ShutdownQueueAsync();<\/span>\r\n    PostQuitMessage(0);\r\n}\r\n<\/pre>\n<p>We use <code>Create\u00adDispatcher\u00adQueue\u00adController<\/code> to attach a dispatcher queue to our existing message pump. There is a bit of a hassle with the second parameter because we are mixing the C++\/WinRT and Win32 ABI versions of the <code>IDispatcher\u00adQueue\u00adController<\/code> interfaces. (<a title=\"The various ways of moving between C++\/WinRT and classic COM\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210830-00\/?p=105617\">Previous discussion<\/a>.) And since we created the dispatcher queue controller, we also have to <a title=\"Gotcha: Don't forget to shut down your dispatcher queues\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240222-11\/?p=109434\"> shut down the dispatcher queue when we&#8217;re done<\/a>, which we take care of in <code>OnDestroy()<\/code>.<\/p>\n<p>Hooray, this code now successfully creates a <code>Dispatcher\u00adQueue\u00adController<\/code> that manages a <code>Dispatcher\u00adQueue<\/code>\u00a0on the current thread, and that removes the obstacle that was preventing <code>Get\u00adFor\u00adWindow<\/code> from succeeding.<\/p>\n<p>Now we can hook up the event and start reading the orientation.<\/p>\n<pre>OnCreate(HWND hwnd, LPCREATESTRUCT lpcs) noexcept\r\n{\r\n    DispatcherQueueOptions options{\r\n        sizeof(options), DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE };\r\n    winrt::check_hresult(\r\n        CreateDispatcherQueueController(options,\r\n            reinterpret_cast&lt;ABI::IDispatcherQueueController**&gt;(\r\n                controller.put())));\r\n\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">g_info.OrientationChanged([hwnd](auto&amp;&amp;, auto&amp;&amp;)              <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    {                                                         <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">        InvalidateRect(hwnd, nullptr, TRUE);                  <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">    });                                                       <\/span>\r\n\r\n    g_info = wil::capture_interop&lt;winrt::DisplayInformation&gt;\r\n        (&amp;IDisplayInformationStaticsInterop::GetForWindow, hwnd);\r\n\r\n    return TRUE;\r\n}\r\ncatch (...)\r\n{\r\n    return FALSE;\r\n}\r\n\r\nvoid\r\nPaintContent(HWND hwnd, PAINTSTRUCT* pps) <span style=\"border: solid 1px currentcolor;\">noexcept<\/span>\r\n{\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">PCWSTR message;                                   <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">switch (g_info.CurrentOrientation()) {            <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">case winrt::DisplayOrientations::Landscape:       <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    message = L\"Landscape\"; break;                <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">case winrt::DisplayOrientations::Portrait:        <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    message = L\"Portrait\"; break;                 <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">case winrt::DisplayOrientations::LandscapeFlipped:<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    message = L\"LandscapeFlipped\"; break;         <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">case winrt::DisplayOrientations::PortraitFlipped: <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    message = L\"PortraitFlipped\"; break;          <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">default:                                          <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    message = L\"Unknown\"; break;                  <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">}                                                 <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">TextOut(pps-&gt;hdc, 0, 0, message,                  <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">    static_cast&lt;int&gt;(wcslen(message)));           <\/span>\r\n}<\/pre>\n<p>After creating the <code>Display\u00adInformation<\/code>, we register for the orientation change event and force a repaint when that happens.<\/p>\n<p>Our paint handler simply prints the current orientation of the monitor that the window is on.<\/p>\n<p>I won&#8217;t bother demonstrating it here, but you can also use <code>Get\u00adFor\u00adMonitor<\/code> to get a <code>Display\u00adInformation<\/code> for a specific monitor.<\/p>\n<pre>\u00a0<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Completing the prerequisites.<\/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-109558","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Completing the prerequisites.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109558","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=109558"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109558\/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=109558"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109558"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109558"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}