Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DeferWindowPos weird behaviour

Tags:

c++

winapi

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.

like image 217
sashoalm Avatar asked Apr 11 '11 15:04

sashoalm


2 Answers

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.

like image 87
adzm Avatar answered Nov 11 '22 10:11

adzm


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?

like image 41
AJG85 Avatar answered Nov 11 '22 09:11

AJG85