2

How can I disable the snap feature of Windows 7 for my application (progmatically)? Or is there any way to detect if the application has been snapped, and specifically call an API function to unsnap it?

Calling SetWindowPos() or ShowWindow() does not unsnap it correctly *(SW_MAXIMIZE does). Calling SetWindowPos() actually causes strange behavior in future calls to SetWindowPos() and MoveWindow(). The same inconsistencies do not apply to a window that is maximized.

  • 2
    Microsoft chose not to expose an API for Aero Snap. – Jonathan Potter Oct 29 '13 at 19:27
  • Yeah, that seems to be the case. It's unfortunate in that a snapped window must be unsnapped to go fullscreen for OpenGL. I just spotted this bug today. Maximizing the window first unsnaps it. – Keyboard Chimp Oct 29 '13 at 21:07
  • @JonathanPotter If Microsoft doesn't expose an API, **we should find a hack for it.** First of possible solution is in my answer but there is second solution without transient modification of Window Styles: write own code for `WM_SYSCOMMAND:SC_MOVE` and `WM_SYSCOMMAND:SC_SIZE`. Second solution will work identically in future and other systems. – 18C Sep 10 '17 at 01:42

2 Answers2

0

I figured out a way to unsnap, by calling ShowWindow() with SW_MAXIMIZE. This is odd since no other values unsnap with this call, even though the window can be moved away, it is still anchored to the side of the screen. Maximizing it fixes the problem, whereafter I can move the window where it needs to be.

0
#define WM_RESTOREORIGINALSTYLE WM_USER+... /* your first free USER message */

case WM_SYSCOMMAND:
{
   if(wParam==(SC_MOVE|2)) wParam=SC_SIZE|9;
   if((wParam&0xFFE0)==SC_SIZE && (wParam&0x000F)) // handles MOVE and SIZE in one "if"
   {
      long int oldStyle=GetWindowLongW(hwnd,GWL_STYLE);
      PostMessageW(hwnd,WM_RESTOREORIGINALSTYLE,GWL_STYLE,oldStyle);
      SetWindowLongW(hwnd,GWL_STYLE,oldStyle &0xFEFEFFFF); // disable WS_MAXIMIZE and WS_MAXIMIZEBOX
      DefWindowProcW(hwnd,WM_SYSCOMMAND,wParam,lParam);
      return 0;
   }
   return DefWindowProcW(hwnd,WM_SYSCOMMAND,wParam,lParam);
}
case WM_RESTOREORIGINALSTYLE:
{
   if((long int)wParam==GWL_STYLE)
      SetWindowLongW(hwnd,GWL_STYLE,lParam);
   return 0;
}

The PostMessage will be processed in subsequent message loop - it means ASAP after entering into move-size loop. If you use own drawing method of frame, please do not forget to redraw your frame correctly on WM_STYLECHANGED message, internally store oldStyle in your class. Why it works? Windows check snap condition at start of move/size action. If WS_MAXIMIZE and WS_MAXIMIZEBOX are disabled at start, the snap behaviour is disabled.

The SC_SIZE|9 is equivalent of SC_MOVE|2 without blocking redrawing for half a second.

If you don't want to enable dragging maximized windows if they are fully maximized, check state of SC_MOVE item in system menu and if it is enabled, directly return 0 in WM_SYSCOMMAND.

Verified on Windows 8.1.

18C
  • 2,014
  • 10
  • 16
  • 1
    You really shouldn't use ["magic numbers"](https://en.wikipedia.org/wiki/Magic_number_(programming)) in your code, it makes it harder to understand what is going on. `SC_MOVE|2` is also known as `SC_DRAGMOVE`. `SC_SIZE|9` is as-yet unnamed. See [this list](https://stackoverflow.com/a/763273/65863). `0xFEFEFFFF` can be written as `~(WS_MAXIMIZE | WS_MAXIMIZEBOX)` – Remy Lebeau Jun 19 '21 at 00:47