Globally intercept window movement

2020-06-04 09:07发布

I am having trouble getting a global system hook to work. I want to be notified whenever a window is moving, as early as possible, and change the window size. This means the CBT hook HCBT_MOVESIZE won't cut it, it only happens after the window has been moved. I want to hook the actual movement of the window, and be able to change the window size during the move.

The hooks are set from a DLL, and the callback function is within that DLL. This is what I've tried.

  • WH_CALLWNDPROC. It does alert me when a window is moved (WM_MOVING is received for windows from other applications), but I cannot change the contents of the message.
  • WH_CALLWNDPROCRET Same as WH_CALLWNDPROC.
  • CBT hook HCBT_MOVESIZE. Event happens to late.
  • WH_GETMESSAGE. Never receive WM_MOVE, WM_MOVING or WM_WINDOWPOSCHANGING. This hook would allow me to change the messages.

Update: Windows event hooks seem to allow me to capture it:

hWinEventHook = SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART,    
    EVENT_SYSTEM_MOVESIZEEND, NULL, WinEventProc, 
    0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

However, this creates a different problem: changing the size of the window using SetWindowPos() does not work (it changes size alright, but immediately changes back to its previous size), even though I use SWP_NOSENDCHANGING. Ideas?

Update 2: Subclassing seems to work, however Visual Studio crashes after each program run (so does a lot of other windows). It works well if I place breakpoints and walk through the "unsubclassing", but not when I let the program run by itself. Ideas?

I have a CBT hook (it was there from earlier), and whenever HCBT_ACTIVATE is sent for a new window, I remove any previous subclassing using SetWindowLongPtr() (this has to run on 64-bit as well), and then subclass the new window. If I put a breakpoint anywhere, and immediately resume the session when it breaks, everything works fine. However, when I do not have any breakpoints, Visual Studio crashes when the program exits.

标签: c++ winapi
2条回答
对你真心纯属浪费
2楼-- · 2020-06-04 09:40

Hm, I would've thought that HCBT_MOVESIZE is precisely what you want, given that the MSDN says this about CBT hooks:

The system calls this function before activating, creating, destroying,
minimizing, maximizing, moving, or sizing a window.

and in particular:

HCBT_MOVESIZE
    A window is about to be moved or sized.

(these quotes were taken from http://msdn.microsoft.com/en-us/library/ms644977%28VS.85%29.aspx)

...so I'd have thought that you get the HCBT_MOVESIZE call in time. The hook function which handles HCBT_MOVESIZE is also allowed to return an integer so that the system can determine whether the operation is allowed or should be prevented. Hence, given that the HCBT_MOVESIZE hook should get an option to prevent the operation, I'd say it's called before the move event occurred.

Are you really sure the hook function is called after the move event? If you do a GetWindowRect call on the particular handle within your hook function, does the returned rect equal the rectangle which is passed to the hook function?

查看更多
▲ chillily
3楼-- · 2020-06-04 09:40

Hooks are pretty heavy. You only want to use them when you absolutely have to.

That said, you could use one of the basic hooks simply as a way to get into the process. Once in the process, you could subclass the window you're interested in and handle the sizing messages in your subclass proc rather than trying to catch everything at the hook level.

Depending on what you want to do in response to the resize, you might need some interprocess communication.

查看更多
登录 后发表回答