{"id":44944,"date":"2015-05-04T07:00:00","date_gmt":"2015-05-04T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2015\/05\/04\/creating-a-window-that-can-be-resized-in-only-one-direction\/"},"modified":"2019-03-13T12:15:13","modified_gmt":"2019-03-13T19:15:13","slug":"20150504-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150504-00\/?p=44944","title":{"rendered":"Creating a window that can be resized in only one direction"},"content":{"rendered":"<p>Today&#8217;s Little Program shows a window that can be resized in only <a HREF=\"http:\/\/www.onedirectionmusic.com\/\">one direction<\/a>, let&#8217;s say vertically but not horizontally. <\/p>\n<p>Start with the scratch program and make these changes: <\/p>\n<pre>\nUINT OnNcHitTest(HWND hwnd, int x, int y)\n{\n UINT ht = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);\n switch (ht) {\n case HTBOTTOMLEFT:  ht = HTBOTTOM; break;\n case HTBOTTOMRIGHT: ht = HTBOTTOM; break;\n case HTTOPLEFT:     ht = HTTOP;    break;\n case HTTOPRIGHT:    ht = HTTOP;    break;\n case HTLEFT:        ht = HTBORDER; break;\n case HTRIGHT:       ht = HTBORDER; break;\n }\n return ht;\n}\n\nHANDLE_MSG(hwnd, WM_NCHITTEST, OnNcHitTest);\n<\/pre>\n<p>We accomplish this by removing horizontal resize behavior from the left and right edges and corners. For the corners, we remove the horizontal resizing, but leave the vertical resizing. For the edges, we remove resizing entirely by reporting that the left and right edges should act like an inert border. <\/p>\n<p>Wait, we&#8217;re not done yet. This handles resizing by grabbing the edges with the mouse, but it doesn&#8217;t stop the user from hitting <kbd>Alt<\/kbd>+<kbd>Space<\/kbd>, followed by <kbd>S<\/kbd> (for Size), and then hitting the left or right arrow keys. <\/p>\n<p>For that, we need to handle <code>WM_GET&shy;MIN&shy;MAX&shy;INFO<\/code>. <\/p>\n<pre>\nvoid OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpmmi)\n{\n RECT rc = { 0, 0, 500, 0 };\n AdjustWindowRectEx(&amp;rc, GetWindowStyle(hwnd), FALSE,\n                    GetWindowExStyle(hwnd));\n\n \/\/ Adjust the width\n lpmmi-&gt;ptMaxSize.x =\n lpmmi-&gt;ptMinTrackSize.x =\n lpmmi-&gt;ptMaxTrackSize.x = rc.right - rc.left;\n}\n\nHANDLE_MSG(hwnd, WM_GETMINMAXINFO, OnGetMinMaxInfo);\n<\/pre>\n<p>This works out great, except for the case of being <!-- backref: How does the window manager adjust ptMaxSize and ptMaxPosition for multiple monitors? -->maximized onto a secondary monitor<\/a>, because we run into the mixed case of being small than the monitor in the horizontal direction, but larger than the monitor in the vertical direction. <\/p>\n<pre>\nvoid OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpmmi)\n{\n RECT rc = { 0, 0, 500, 0 };\n AdjustWindowRectEx(&amp;rc, GetWindowStyle(hwnd), FALSE,\n                    GetWindowExStyle(hwnd));\n\n \/\/ Adjust the width\n lpmmi-&gt;ptMaxSize.x =\n lpmmi-&gt;ptMinTrackSize.x =\n lpmmi-&gt;ptMaxTrackSize.x = rc.right - rc.left;\n\n <font COLOR=\"blue\">\/\/ Adjust the height\n MONITORINFO mi = { sizeof(mi) };\n GetMonitorInfo(MonitorFromWindow(hwnd,\n                    MONITOR_DEFAULTTOPRIMARY), &amp;mi);\n lpmmi-&gt;ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top\n                    - lpmmi-&gt;ptMaxPosition.y + rc.bottom;<\/font>\n}\n<\/pre>\n<p>The math here is a little tricky. We want the window height to be the height of the work area of the window monitor, plus some extra goop in order to <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2015\/03\/04\/10597470.aspx\">let the borders hang over the edge<\/a>. <\/p>\n<p>The first two terms are easy to explain: <code>mi.rcWork.bottom - mi.rcWork.top<\/code> is the height of the work area. <\/p>\n<p>Next, we want to add the height consumed by the borders that hang off the top of the monitor. Fortunately, the window manager told us exactly how much the window is going to hang off the top of the monitor: It&#8217;s in <code>lpmmi-&gt;ptMaxPosition.y<\/code>, but as a negative value since it is a coordinate that is off the top of the screen. We therefore have to negate it before adding it in. <\/p>\n<p>Finally, we add the borders that hang off the bottom of the work area. <\/p>\n<p>Yes, handling this mixed case (where the window is partly constrained and partly unconstrained) is annoying. Sorry. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Overriding WM_NCHITTEST.<\/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-44944","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Overriding WM_NCHITTEST.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44944","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=44944"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44944\/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=44944"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=44944"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=44944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}