Creating invisible and modeless property sheet causes focus change? - winapi

I was investigating an issue related to losing focus and changing activation of windows. What I found was that if I create an invisible property sheet, the active/foreground window changes and so does the focus window. Here is some sample MFC code:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
After the call to pSheet->Create(), the active/foreground/focus window has changed and the application window is on top. If I use Spy++ and look at the window that is created, it turns out that a property sheet is a DIALOG window class. I am assuming it has a different WNDPROC, of course. What is interesting, is if I create an invisible modeless dialog using, it does not exhibit the problem. If I create the invisible modeless dialog, the active/foreground/focus window remains the same.
I tried setting various flags as in the code snippet, but alas they did not have any discernible effect--I still had the flashing and activation non-sense.
I could get some improvement by setting and clearing a hook (WH_CBT) before and after pSheet->Create()--and then eating the activation messages. When I do that, I don't have the horrible flashing and my application window does not come to the top. However, the focus (and caret for windows that have carets) does go away from whichever window had it before the Create().
Does anyone know a way to keep the focus and activation unchanged when creating an invisible property sheet? (At some point, the property sheet may or may not be set visible. And, if the property sheet is invisible when being destroyed, it also causes the blinking and activation changes.)
I tried using the values returned in GetUIThreadInfo() to try and restore things after the call to Create(), but it causes some flashing as well.
I just want to know how to create an invisible Property Sheet which won't cause the active, foreground, and focus window to change.

Unfortunately the underlying API function PropertySheet calls SetForegroundWindow on the main property sheet dialog after creation. There's no easy way around this - your kludge with the WH_CBT hook is probably your best option.
Edit: As suggested by #stephen in the comments on this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow.

I have been struggling with this same issue for weeks, with a similar project, where my main application launches a secondary EXE process to act as a server in an audio application (which needs to be a separate process to shield the application from plugin faults, and so it can be high priority for real-time audio processing).
My secondary EXE is a modeless CPropertySheet, for status and diagnostic display, but is intended to be launched hidden and in the background. However it was always stealing the activation from the main application on launch, regardless of what workarounds I tried (such as overriding OnWindowPosChanging).
I thought I was going to go mad, so I was very happy to find this question. The WH_CBT trick is useful, but I found while it prevented activation of the secondary EXE, it did not prevent deactivation of the main application.
But then I discovered an excellent solution, in the LockSetForegroundWindow API (available since Win2K) which I had never heard of before. Looks like it is intended for exactly this purpose, to disable the change of foreground activation and prevent peer processes from stealing it.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
It works very well to nullify the internal call to SetForegroundWindow that happens deep within the property sheet common control, and works equally well whether used in the main application before CreateProcess or in the secondary EXE. I chose the latter case, to wrap the property sheet creation:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
This minimises the scope of the intervention and keeps the fix localised to the process that is the source of the problem. I hope this will save others from wasting as much time on this tedious issue as I did.

Related

CPropertySheet app lauched with CreateProcess steals focus [duplicate]

I was investigating an issue related to losing focus and changing activation of windows. What I found was that if I create an invisible property sheet, the active/foreground window changes and so does the focus window. Here is some sample MFC code:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
After the call to pSheet->Create(), the active/foreground/focus window has changed and the application window is on top. If I use Spy++ and look at the window that is created, it turns out that a property sheet is a DIALOG window class. I am assuming it has a different WNDPROC, of course. What is interesting, is if I create an invisible modeless dialog using, it does not exhibit the problem. If I create the invisible modeless dialog, the active/foreground/focus window remains the same.
I tried setting various flags as in the code snippet, but alas they did not have any discernible effect--I still had the flashing and activation non-sense.
I could get some improvement by setting and clearing a hook (WH_CBT) before and after pSheet->Create()--and then eating the activation messages. When I do that, I don't have the horrible flashing and my application window does not come to the top. However, the focus (and caret for windows that have carets) does go away from whichever window had it before the Create().
Does anyone know a way to keep the focus and activation unchanged when creating an invisible property sheet? (At some point, the property sheet may or may not be set visible. And, if the property sheet is invisible when being destroyed, it also causes the blinking and activation changes.)
I tried using the values returned in GetUIThreadInfo() to try and restore things after the call to Create(), but it causes some flashing as well.
I just want to know how to create an invisible Property Sheet which won't cause the active, foreground, and focus window to change.
Unfortunately the underlying API function PropertySheet calls SetForegroundWindow on the main property sheet dialog after creation. There's no easy way around this - your kludge with the WH_CBT hook is probably your best option.
Edit: As suggested by #stephen in the comments on this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow.
I have been struggling with this same issue for weeks, with a similar project, where my main application launches a secondary EXE process to act as a server in an audio application (which needs to be a separate process to shield the application from plugin faults, and so it can be high priority for real-time audio processing).
My secondary EXE is a modeless CPropertySheet, for status and diagnostic display, but is intended to be launched hidden and in the background. However it was always stealing the activation from the main application on launch, regardless of what workarounds I tried (such as overriding OnWindowPosChanging).
I thought I was going to go mad, so I was very happy to find this question. The WH_CBT trick is useful, but I found while it prevented activation of the secondary EXE, it did not prevent deactivation of the main application.
But then I discovered an excellent solution, in the LockSetForegroundWindow API (available since Win2K) which I had never heard of before. Looks like it is intended for exactly this purpose, to disable the change of foreground activation and prevent peer processes from stealing it.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
It works very well to nullify the internal call to SetForegroundWindow that happens deep within the property sheet common control, and works equally well whether used in the main application before CreateProcess or in the secondary EXE. I chose the latter case, to wrap the property sheet creation:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
This minimises the scope of the intervention and keeps the fix localised to the process that is the source of the problem. I hope this will save others from wasting as much time on this tedious issue as I did.

On Windows, should my child window get a WM_WINDOWPOSCHANGED when its z-order changes relative to one of its siblings?

I am trying to insert a custom widget into the Internet Explorer 8 url bar, next to the stop and reload buttons. This is just a personal productivity enhancer for myself.
The "window model" for this part of the IE frame is an "address bar root" window that owns the windows which comprise the IE8 url bar: an edit box, a combo control, and the stop and reload buttons.
From another process, I create a new WS_CHILD window (with a custom class name) that is parented by IE's address bar root window, thus making it a sibling of the edit box and stop/reload. I call SetWindowPos with an hwndInsertAfter of HWND_TOP to make sure it appears "above" (i.e. "in") the urlbar. This works nicely, and I see my window painted initially inside the IE urlbar.
However, when I activate the IE window, the urlbar edit control jumps back in front of my window. I know this is happening because I still see my window painted behind the urlbar, and because when I print ->GetTopWindow() to the debug console on a timer, it becomes the HWND of the urlbar edit control.
If I update my message loop to call SetWindowPos with HWND_TOP on WM_PAINT, things are better -- now when I activate the IE window and move it around, my control properly stays planted above the edit control in the urlbar. However, as soon as I switch between IE tabs, which updates the text of IE's urlbar Edit control, my control shift backs behind the Edit control. (Note: This also happens when I maximize or restore the window.)
So my questions are:
1) Is it likely that IE is intentionally putting its urlbar edit control back on top of the z-order every time you click on a tab in IE, or is there a gap in my understanding of how Windows painting and z-ordering works? My understanding is that once you specify z-ordering of child windows (which are not manipulable by the end-user), that ordering should remain until programmatically changed. So even though IE is repainting its Edit control upon tab selection whereas I am not repainting or otherwise acting upon my window, my window should stil remain firmly on top.
2) Given that the z-order of my window is apparently changing, shouldn't it receive a WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED? If it did, I could at least respond to that event and keep myself on top of the Edit control. But even though I can see my window painting behind the urlbar Edit control when I click on a tab, and even though my debug window output confirms that the address bar root's GetTopWindow() becomes the HWND of the Edit control when I click on a tab, and even though I see WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED being sent to the Edit control with an hwndInsertAfter of HWND_TOP when I click on a tab, my own window receives no messages whatsoever that would allow me to keep the z-order constant. This seems wrong to me, and addressing it would force me to run in IE's process and hook all messages sent to its Edit control just to have an event to respond to :(
Thank you for your help!
It's quite likely that IE is juggling the Z-order of the controls when you change tabs. In IE9, the URL bar and the tabs have a common parent. When you select a new tab, it activates the URL bar (and activation usually brings the window to the top of its local Z order).
No. You get WM_WINDOWPOSCHANGED when a SetWindowPos function acts on your window. If some of the siblings have their z-orders changed, you don't get a message. Nobody called SetWindowPos on your window. You can see this by writing a test program that juggles the z-order of some child windows.
This makes sense because there might be an arbitrary number of sibling windows, and it could be an unbounded amount of overhead to notify all of them. It also would be nearly impossible to come up with a consistent set of rules for delivering these messages to all the siblings given that some of the siblings could react by further shuffling the z-order. Do the siblings that haven't yet received the first notification now have two pending notifications? Do they get posted or dispatched immediately? What if the queue grows and grows until it overflows?
This is different from WM_KILLFOCUS/WM_SETFOCUS notifications in that it affects, at most, two windows. That puts a reasonable bound on the number of notifications. Even if there's a runaway infinite loop because the losing control tries to steal the focus back, the queue won't overflow because there's only one SetFocus call for each WM_KILLFOCUS delivered.
Also, it's reasonable that windows might need to react to a loss of focus. It's much less likely that window C needs to know that B is now on top of A instead of the other way around, so why design the system to send a jillion unnecessary messages?
Hacking the UI of apps you don't control and that don't have well-defined APIs for doing the types of things you want to do is anywhere from hard to impossible, and it's always fragile. Groups that put out toolbars and browser customizations employee more people than you might expect, and they spend much of their day probing with Spy++ and experimenting. It is by nature hacking.

Big problems with MFC/WinAPI

I need to create a SDI form with a formview that has two tabs, which encapsulate multiple dialogs as the tab content. But the form has to have a colored background.
And things like these makes me hate programming.
First, I tried CTabControl, via resource editor, tried different things, but the undocumented behavior and the quirks with no answers led me into a roadblock.
After many hours of searching, I found that there is a control called property sheet, which is actually what I need.
Some more searching later, I found that property sheet can even be actually embedded onto CFormView like so: http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591
And that the dialog classes derived from CPropertyPage can be directly added as pages via AddPage method of CPropertySheet.
Great! Not quite so... Some of the controls didn't worked, and were not created, ran into weird asserts. Turns out the DS_CONTROL style was missing from the dialogs. Found it completely accidentaly on Link, no word about that on MSDN!!!! Property page must have: DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP, and can have: DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN styles! Not any other, which are created by default with resource editor. Sweet, super hidden information for software developers!
The quote in comments on that page: "OMG. That's where that behavior came from...
It turns out that the PlaySound API relied on that behavior when playing sounds on 64bit machines." by Larry Osterman, who as I understand works for Microsoft for 20 years, got me laughing out loud.
Anyway, fixed that, the dialog-controls(CPropertyPages) are created as expected now, and that part looks something remotely promising, but the next part with color is dead end again!
Normally you override WM_CTLCOLOR, check for control ID or hwnd and supply the necessary brush to set the color you need. Not quite so with CPropertySheet, the whole top row stays gray! For CTabCtrl it somehow works, for CPropertySheet it doesn't.
Why? Seems that the CPropertySheet is kinda embedded inside CTabControl or something, because if I override WM_ERASEBKGND, only the internal part changes the color.
Now it seems that there is a GetTabControl() method in the CPropertySheet, that returns the actual CTabCtrl* of the CPropertySheet. But since it's constructed internally, I can't find how to override it's WM_CTLCOLOR message processing.
There seems to be a way to subclass the windowproc, but after multiple tries I can't find any good source on how to do it. SubclassWindow doc on MSDN says: "The window must not already be attached to an MFC object when this function is called."?! What's that?
I tried creating a custom CCustomTabCtrl class based on CTabCtrl via MFC wizard, created an instance of it, called SubclassWindow from one of the CCustomPropertySheet handlers to override the internal CTabCtrl, but nothing works, mystical crashes deep inside MFC.
Tried setting WindowLong with GCL_HBRBACKGROUND for the internal CTabCtrl, nothing changed.
And worst of all, I can't find any sort of useful documentation or tutorials on the topic.
Most I can find is how to ownerdraw the tab control, but this is seriously wrong on so many ways, I want a standard control behavior minus background color, I don't want to support different color schemes, windows versions, IAccesible interfaces and all this stuff, and none of the ownerdraw samples I've seen can get even 10% of all the standard control behavior right. I have no illusion that I will create something better, I wont with the resources at hand.
I stumbled upon this thread, and I can't agree with the author more: http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6 owner draw controls are undocumented PITA, that are impossible to do right, and there is NULL information on MSDN to help.
So is there anything I have missed or haven't tried yet? How to change the top strip background color of the CPropertySheet? Anyone?
Your only option is to ownerdraw the tab control. It's not that hard. Well, it is frustrating because MFC doesn't tell you how to make the necessary Win32 calls.
In your CPropertySheet-derived class, overwrite OnInitDialog() and add:
GetTabControl()->ModifyStyle(0,TCS_OWNERDRAWFIXED);
This puts your CPropertySheet-derived class in charge of drawing the tab control. Add a handler for WM_DRAWITEM (OnDrawItem) and change backgroundColor and textColor to match whatever colors you wanted. Code for OnDrawItem follows:
void CPropSht::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (ODT_TAB != lpDrawItemStruct->CtlType)
{
CPropertySheet::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
// prepare to draw the tab control
COLORREF backgroundColor = RGB(0,255,0);
COLORREF textColor = RGB(0,0,255);
CTabCtrl *c_Tab = GetTabControl();
// Get the current tab item text.
TCHAR buffer[256] = {0};
TC_ITEM tcItem;
tcItem.pszText = buffer;
tcItem.cchTextMax = 256;
tcItem.mask = TCIF_TEXT;
if (!c_Tab->GetItem(c_Tab->GetCurSel(), &tcItem )) return;
// draw it
CDC aDC;
aDC.Attach(lpDrawItemStruct->hDC);
int nSavedDC = aDC.SaveDC();
CBrush newBrush;
newBrush.CreateSolidBrush(backgroundColor);
aDC.SelectObject(&newBrush);
aDC.FillRect(&lpDrawItemStruct->rcItem, &newBrush);
aDC.SetBkMode(TRANSPARENT);
aDC.SetTextColor(textColor);
aDC.DrawText(tcItem.pszText, &lpDrawItemStruct->rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
aDC.RestoreDC(nSavedDC);
aDC.Detach();
}
Thank you for this solution but...
The above solution works well with one tab, but when you have multiple tabs it seems rename the wrong tabs. I needed to change the if statement for GetItem to:
if (!c_Tab->GetItem(lpDrawItemStruct->itemID, &tcItem )) return;
Needed lpDrawItemStruct->itemID to get the tabs named correctly

How to Get the Active ChildWindow of an application?

I have this problem. I have an handler to the mainWindow of a certain application, and I want to simulate a keypress on that application...
I'm using sendMessage/postMessage api calls to do this. The reason why I don't use the .Net SendKeys function or the keybd_event of the win32 api, is that they simulate the keypress at a global level. In my case, I may have the application minimized and still want the keypress to be simulated.
The problem with sendMessage and postMessage is that you must pass the handler of the exact childwindow where you want the key to be pressed. For example, in notepad, if I send the key to the mainWindow, nothing happens, I have to send the key to the child window that basically consists of the white canvas where you can write.
With msPaint for example, if a user creates a new document, and opens a textbox in that drawing, and I want to simulate a keypress there, I have to get the childwindow of the childwindow of the mainwindow for it to works.
So I found a way that seemed to work for every situation, basically, I used getWindow with the parameter GW_CHILD, to get the child-window with the highest z-value. Then I do it again for the child window and continue doing it until a certain childWindow has no more childWindows..
And it seemed to work and I was very happy!
However... I found cases where this does not work. Firefox is one of them. Firefox has the mainWindow, and then has a childWindow that's pretty much the same as the mainWindow and then it has another childWindow which is the website area, ie, the area under the address bar and menus. If I am on www.google.com for example, and I want to simulate a keypress in the focused search box, it works, cause getting the child-window of the child-window gives me the correct childWindow. However, if the user clicks on the address bar for example, nothing changes in the way the getWindow works. It will still eventually get the childwindow that's under the address bar, doing nothing, instead of simulating the keypress on the address bar.
The thing is that I haven't found a way of getting the active child window of a certain application. I can only use the GetWindow method to get the child window of a certain window and do it until I find a child window with no childs. However, as you've seen in the firefox case, the active window is actually the parent of the child window that I get in the end.
I've tried other api calls like getTopWindow but I had no luck..
Anyone can put some light on this issue?
Thanks!
If the application violates the windowing rules of windows, you'll need an exception.
In Mozilla, it's like this (IIRC):
There's this 'god' window of the class MozillaUIWindowClass and with the "- Mozilla Firefox" string in its window text.
If you know the position of the address bar you can use the following function:
And provide it with the HWND of the 'god' window and the position of the address bar.
HWND ChildWindowFromPoint(HWND, POINT);
There is probably a better solution, I came up with this since I needed to automate mouse, which is position based.
For more information you might need to consult the sources of particular software, or spend whole day in Spy+. :>
You can use GetGUIThreadInfo to get info about the UI of a particular process.
If you have the main window you can call GetWindowThreadProcessId to obtain the process thread id. Then you can call GetGUIThreadInfo to get info about the active/focused windows, etc.
I also have to point that some applications only have one window and all its controls are windowsless (like Windows Live Messenger).

Win32 window Owner vs window Parent?

In Win32 programming, what is the difference between a window's parent and a window's owner? I thought I had it figured out, then I came across this code:
SetWindowLong(handle, GWL_HWNDPARENT, foo);
This actually sets the window's owner, not the parent - despite the GWL_HWNDPARENT being used. Are the terms parent/owner interchangeable, or is there actually a difference?
Ownership is a relationship between two top level windows while Parent is a relationship between a top level and a WS_CHILD, or a WS_CHILD and another WS_CHILD.
The parent of a button is the form it is on, while a message box is owned by the form that showed it.
Read this article from Microsoft Win32 Window Hierarchy and Styles to get a much clearer understanding of Ownership, Parenting, ZOrder, SetWindowLong, GetWindow and all the other nasty bits of the Win32 api for creating window relationships.
EDIT: Looks like Microsoft took down that content, here is another reasonable summary of Ownership / Parenting.
Owner is the Window* responsible for a control or dialog (for example, responsible for creating/destroying the window).
Parent is the next-senior window* to a control or dialog in the window chain, but isn't actually responsible for it (doesn't necessarily care about its lifecycle, etc). A window's parent can also be its owner.
*Window vs window: Window is an actual window displayed on the screen; window is any object with a HWND (includes buttons, panels, etc).
Chen's blog post is the one to read. The key point for me is that the WS_CHILD style must be used on the child window. You can attempt to create a child window and pass the parent handle in to CreateWindow( ), but if you don't have the WS_CHILD style set the two windows will have the owner relationship, not the parent/child relationship.
It's super easy: the code is wrong. End of story right here.
Yes, some windows may happen to react favorably to such a call - someone not knowing any better may have implemented support for it. Quoth documentation (and it's old documentation) - You must not call SetWindowLong with the GWL_HWNDPARENT index to change the parent of a child window. Instead, use the SetParent function.
So, all there's to it: you came upon buggy code, change it to SetParent or refactor to do something else, and keep going?

Resources