Globally intercept window movement - c++

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.

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?

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.

Related

When is a Paint msg being invoked on a CCmdUI::Enable() call?

I'm trying to debug this problem in a library where a set of controls are not being updated to be disabled. I've drilled down to a point where I've hit a black box. A mfc120ud.dll!CCmdUI::DoUpdate() call will then call CCmdUI::Enable(). It'll then go through a bunch of calls one through ntdll.dll and 4 through user32.dll for which I have no source for and then sometimes stick its head our coming back to mfc123ud.dll or sometimes not.
I don't know why the WM_PAINT message gets invoked sometimes. Does anyone know?
Your call stack shows the reason.
CCmdUI::DoUodate finally calls CCmdUI::Enable.
Look into the CCmdUI::Enable code of the MFC. There are cases that WM_NEXTDLGCTL is called or EnableWindow. WM_NEXTDLGCTL may cause a focus change. It depends how the controls will handle this message. It is possible that they directly call UpdateWindow or RedrawWindow to reflect changes to the UI, instead of just calling Invalidate(Rec). There may be a control inside your ribbon that receives the WM_PAINT message.
The call to EnableMenuItem should be safe and I am sure that it doesn't cause a WM_PAINT call.

Hooking window creation; hooks not being triggered

Essentially I'm inside a process' memory via an injected DLL and I want to stop window creation. I've tried hooking the following:
CreateWindowExW
CreateDialogParamW
DialogBoxParamW
Unfortunately, the creation of the window I want to destroy is not triggering any of my hooks. There are several IE controls within the aforementioned window and the CreateWindowExW calls are being hit for them; but not the actual window I want. It's a simple popup box, and does show up in Spy++/Window Hack so I'm certain it's an actual window.
Any ideas?
You need to try all the possible variations of the functions you are trying to hook CreateWindowExA, CreateWindowW, CreateWindowA, etc. They aren't necessarily just wrappers around the main *W one.

DeferWindowPos weird behaviour

This happens with all ActiveX controls. If I reposition an ActiveX control with DeferWindowPos
HDWP hdwp = BeginDeferWindowPos(1);
DeferWindowPos(hdwp, m_pActiveX->GetSafeHwnd(), NULL, left, top, width, height, SWP_NOZORDER);
EndDeferWindowPos(hdwp);
it goes there but then moves/resizes to its old rectangle once you click anywhere inside the control. If I use MoveWindow instead
m_pActiveX->MoveWindow(left, top, width, height);
this doesn't happen.
It doesn't happen with any other type of control, only with ActiveX controls, but it happens with all of them. I made a test to confirm this, creating a new ActiveX control project and didn't make any changes, and the problem was still there.
You never got an appropriate answer. I'll try to help out a bit here.
The issue is that MFC hides a lot of the trickiness with hosting an ActiveX control within it's framework. Specifically, if you step into the MoveWindow call, it is not simply a wrapper around the Win32 MoveWindow function. It calls into the OLE Control Container support classes. This basically says, if we have a control site interface, then call COleControlSite::MoveWindow, otherwise call the standard Win32 MoveWindow. The same occurs with several other window functions handled by CWnd etc. For example COleControlSite::SetWindowPos handles hiding/showing the control, then calls COleControlSite::MoveWindow to move it, and then finally calls ::SetWindowPos (with the move/show flags masked out) to handle the rest.
Once within COleControlSite::MoveWindow, you will notice it does several things: it calls SetExtent, updates it's internal m_rect member, and then calls SetObjectRects.
Bypassing these for ActiveX controls using the Win32 API directly (eg via DeferWindowPos) causes some of these crucial steps to be missed. Depending on how your code is layed out, usually you can handle this yourself.
What is this ActiveX control?
Apart from that consider that DeferWindowPos is meant for positioning multiple windows at the same time. The concept being you enter the begin statement, change a bunch of window positions for a new layout, then end to actually move and apply the new positions and sizes.
If you aren't updating multiple windows consider using SetWindowPos instead.
Consider also that you may be getting a message to move, resize, or change the windows position while you are deferring. To prevent this if that is what is happening pass the SWP_NOSENDCHANGING flag in each call to DeferWindowPos so that it is not sent or handle the message and clear all the bits in the WINDOWPOS struct received to prevent unwanted changes.
It is also possible for this call to fail ... are you checking the return value?

When does setting topmost on a window fail to work?

I have a C++ app where I need to create topmost windows. Sometimes it works, but quite often it fails. In one part of the app, I create a background thread to display a topmost information window. After the user closes the window the thread goes away. The first time the app creates the thread and displays the window, the window is topmost. However, all subsequent threads fail to set topmost on their window. I have tried both creating the window with the WS_EX_TOPMOST style and by calling SetWindowPos after the window is created. Neither of these methods works. I looked and was unable to find any references to anyone having a problem where the window could not be set to topmost.
In one test that I ran, I called SetWindowPos and after it returned I checked the window's style and it was not set to topmost even though SetWindowPos returned success. I have also used Spy++ to check the window's style and it confirms that the style is not set.
One way SetWindowPos will silently fail to set WS_EX_TOPMOST is when the process doesn't have permission to SetForegroundWindow at the time window is created or SetWindowPos is called. Which is arguably one of the times you want the window topmost (and arguably one of the times you should not be allowed to).
Rumors are MS closed that loophole since Vista.
The restriction is understandable -- you don't want topmost windows from random processes stealing focus when they have no business too.
A workaround for a reasonable use case when one process indirectly launches a helper process (like would be a case of install initiated in parent process then helper process launched from msiexec) and helper then wants to be topmost or even grab input is to use AllowSetForegroundWindow.
You need to have the right to focus to be able to relinquish it, obviously.
I had a similar problem using Borland C++ Builder. I got this to work by setting the FormStyle to fsStayOnTop after the window was created and displayed. I think that the trick is to do this only after the window is fully displayed.
*visibleForm = new TForm3(Form3);
(*visibleForm)->FormStyle = fsStayOnTop;
SetWindowPos(_hYourWindow, HWND_TOPMOST, 0, 0, 0, 0,
SWP_ASYNCWINDOWPOS|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOMOVE);
Should work!
No idea if the problem I had was the same as yours, but at least it had the same symptoms. Solved it by moving the this->TopMost = true from InitializeComponent to the Form_Load instead.
Why don't you just use SetForegroundWindow(). There's a lot less to go wrong..

WINAPI: Look at messages from other process

I'm quite new to the Windows API and would like to know how to peek at messages another process receives. As an example, I would like to get the HWND of, say, notepad and peek at all messages that are sent to this window. I code in C/C++.
Thank you
You can use SetWindowsHookEx function, with WH_CALLWNDPROC or some other type of hook, and here is an example.
The WH_CBT can give you great opportunities because you can get a HCBT_CREATEWND code from it and it's sent to you right before a window is created, thus giving you a possibility to provide your own window proc instead of the real one and then be able to get all messages possible with it.
Remember though, greater possibilities also mean greater responsibility. Say you "subclassed" some window, providing your window proc, if your application that set a hook exits, next thing you'll see is the application, whose messages you were peeking at, crashes if you didn't put the address of the original window proc back to where it belongs. The benefit of this kind of hooking is the ability to wait for a certain window (say with a certain window class, or name) to be created and get into that process before any window you're interested in would even be created.
You want to look into SetWindowsHookEx
You are looking for Windows Hooks .
http://msdn.microsoft.com/en-us/library/ms997537.aspx
You can trap SendMessage in the target process using CallWndProc hook procedure.