DeferWindowPos weird behaviour - c++

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?

Related

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.

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..

Globally intercept window movement

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.

OnKillFocus() override in MFC triggering at odd times

I need to know when my Window goes out of input focus, so I overloaded the OnKillFocus() method of the CWnd.
However it doesn't invoke this method when I focus another application (alt+tab), or even minimize the window. But it DOES invoke the method when I restore it from being minimized. Are these the intended times for it to trigger this method?
I think you'll need a CWnd::OnActivateApp() handler if you need to be sure of being notified when your application is switched out.
OnKillFocus() is normally only used consistently for controls that have a concept of gaining the focus - buttons, edit boxes, list boxes, etc. Normally CWnd does not accept the focus, so you can't rely on that - I'm surprised you get it at all.
In addition to WM_ACTIVATEAPP mentioned above, there's also WM_ACTIVATE when switching between windows within the same application you might want to trap.

DLL plugin that creates a parented window doesn't handle messages correctly

I'm creating a plugin framework, where my application loads a series of plugin DLL's, then creates a new window and pass this new window's handle to the plugin. The plugin can, then, use this handle to create their own GUI.
Everything seems to be working very well. The only problem is that when I press TAB on a plugin widget (An editbox, for example), it doen't jump to another widget. I figured out that some Windows messages are passed, and some others aren't. The WM_KEYDOWN is passed for other keys, because I can type on the editbox, but this message doesn't handle TAB key.
Hope somebody has a hint.
I'm using Borland VCL with CBuilder, but I think I could use any framework under WIN32 to create these plugins, since they never know how their parent windows were created.
It's very complex matter indeed.
When you hit TAB focus jumps to another control only when these controls belong to a Modal Dialog Box. In fact there are some buttons like ESC, LEFT, RIGHT, DOWN, UP, TAB which modal dialog message function treats in a special way. If you want these keys to behave in similar way with modeless dialog box or any other window you should change you message processing function and use IsDialogMessage inside. You'll find more information about IsDialogMessage function in MSDN also to better understand this stuff you may check as well Dialog Boxes section.
And, as was mentioned before, you should set WS_TABSTOP and WS_GROUP styles when needed.
Good luck!
I believe you'll have to take the following steps:
Subclass your edit controls (and other controls as needed).
Capture the WM_KEYDOWN message in your edit control's WndProc.
Check to see if the shift key is currently held down (using GetKeyState or similar).
Call GetWindow, passing in a handle to your edit control and either GW_HWNDPREV or GW_HWNDNEXT depending on whether shift is held down. This will give you the handle to the window that should receive focus.
Call SetFocus and pass in the window handle you got in step 4.
Make sure you handle the case where your edit controls are multiline, as you might want to have a real tab character appear instead of moving to the next control.
Hope that helps!
I believe you suffer from having a different instance of the VCL in each of your dlls and exes. Classes from the dll are not the same as the ones from your exe, even if they are called the same. Also global variables (Application, Screen) are not shared between them. Neither is the memory since they both have their own memory manager.
The solution is to have the dlls and the exe share the VCL library and the memory manager. I am not a BCB developer, but a Delphi developer. In Delphi we would just use the rtl and the vcl as runtime packages. Maybe you could do the BCB equivalent.
A DLL has its own TApplication object.
to provide uniform key handling. when the DLL Loads.
assign the DLL::TApplication to the EXE::TApplication
Be sure to do the reverse on exit.
--
Michael