SetParent: Window reacts slow when getting focus - c++

I have a problem with the SetParent function of the Windows API. I'm using it to inject one of my windows into the Window of an external application (like Notepad). My Window contains an EditWindow as Child Window and a few buttons, nothing more. I use something like this:
long style = GetWindowLong(hwnd, GWL_STYLE);
style |= WS_CHILD;
style &= ~WS_POPUP;
SetWindowLong(hwnd, GWL_STYLE, style);
SetParent(hwnd, newParent);
This works, however if I click from outside of the external application into the textbox, it takes several seconds until it gets the focus. In the meantime nothing happens, even with Spy++ I can't catch any messages within this delay.
The strange thing is also that this only seems to happen with my specific application (its some very old and special measurement software), with notepad for example the delay does not happen.
So, here is my question: What could potentialy cause this problem? Are there cases where SetParent could cause such a behaviour?
Greets,
cpp_beginner

Related

Pin window to desktop / Glue window to desktop / "Always-on-bottom" window

I'm working on a basic desktop app in C++ / Win32.
My goal right now is to create a basic "sticky note" app that would be pinned / glued to the desktop, i.e always in front of the desktop but always behind of any other application.
Really a personal project there, just to fight my bad memory and have my tasks/notes always visible on the desktop so I couldn't miss them when starting the computer & so on.
The behaviour I'm aiming for would be similar to Stardock Fences ("kind of" because I'm not going to store any desktop icon in there, but you hopefully get the idea)
I started with the sample code from the Get Started with Win32 and C++ docs to have the most basic Win32 minimal window setup.
What I got so far :
I managed to keep my window on bottom of every other app and in front of the desktop by calling SetWindowPos in the window procedure (WindowProc), when handling the event WM_SETFOCUS (I first tried with the event WM_WINDOWPOSCHANGING as suggested in this answer but this resulted in an annoying flickering when dragging the window).
case WM_SETFOCUS:
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
The problem : my window stays in front of the desktop, except when I click on the "Show Desktop" button in the taskbar (or hit the Windows + D shortcut). As I often use this shortcut myself, I'd like my window to stay over the desktop no matter what.
A not-satisfying-enough-but-still-something I managed to do is to bring back my window in front of the desktop when clicking on any other window after hitting Windows + D (this mostly makes sense with multiple monitors, as opening a random app on the first one for example, will toggle back my own app in front of the desktop on another screen).
I could do this using this time the event WM_SIZE and calling ShowWindow then SetWindowPos, still in the WindowProc
case WM_SIZE:
ShowWindow(hwnd, SW_SHOWNORMAL);
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
Not ideal though, as I'd really want my app to always remain in front of the desktop and "survive" to the Show Desktop action.
What I tried :
I checked out those answers but couldn't figure out how to achieve what I want.
How to make 'always-on-bottom'-window
Window “on desktop” : Note on this one, I tried the trick with SetParent like this in the wWinMain
HWND desktop = FindWindow(L"ProgMan", L"Program Manager");
if (desktop == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
SetParent(hwnd, desktop);
However, my app isn't visible at all anymore with this, even though the FindWindow didn't return NULL but an actual handle.
Make aplication always on Bottom (pinned to desktop, behind all other apps) in C++/WinAPI [duplicate]
Disable Minimize, Maximize, Close buttons in Win32 I tried those to "intercept" the Show Desktop event but it seems this event doesn't get fired with the Show Desktop action.
Did I miss something ?
As #JonathanPotter pointed out, when hitting Windows + D or the Show Desktop button, the event WM_WINDOWPOSCHANGING gets fired, and the window gets moved to -32 000, -32 000 (its size also gets changed)
NOTE : a window without the style WS_MINIMIZEBOX seems not receiving WINDOWPOSCHANGING event when hitting Windows + D. Thus, no -32 000 coordinates detection in that case... Also noticed the same issue when using the ex style WS_EX_TOOLWINDOW (as this one gets rid of the minimize box, even if you set the style flag WS_MINIMIZEBOX).
Didn't find a solution for that case, so I'm sticking to an overlapped window.
To prevent this movement, just set the flags SWP_NOMOVE and SWP_NOSIZE on the WINDOWPOS structure passed in the lParam
So as a final result, to achieve the wanted behaviour (i.e always behind every other window but always in front of the desktop), the only needed code to add to the doc's sample is the following, placed in the window procedure WindowProc's switch statement :
EDIT : the best place to force the Z order with HWND_BOTTOM thus ensuring the window is always on bottom is also in the WM_WINDOWPOSCHANGING event. Indeed, calling SetWindowPos to force it in the WM_SIZE event when dragging the window over, as I was doing previously, causes some flickering on the window when resizing it, whereas no flickering occurs when setting directly the hwndInsertAfter property of the WINDOWPOS structure in WM_WINDOWPOSCHANGING.
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pos = (WINDOWPOS*)lParam;
// Show desktop (Windows + D) results in the window moved to -32000, -32000 and size changed
if (pos->x == -32000) {
// Set the flags to prevent this and "survive" to the desktop toggle
pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
}
// Also force the z order to ensure the window is always on bottom
pos->hwndInsertAfter = HWND_BOTTOM;
return 0;
}
I had the same problem and found a solution via using "autohotkey". autohotkey is a powerful free scripting language for automation in windows that you can download from here. Below scripts are an instance of making sticky notes always on top when you execute it inside a .ahk file (you can copy these codes to a simple notepad and then change .txt to .ahk if you already had installed autohotkey on your computer). by right clicking on .ahk file, you can also see option of Compiling .ahk into .exe which enables you to share it with your other friends too:
#SingleInstance Force
GroupAdd, ontop, Sticky Notes ; you can replace sticky note by any application,
; if you know the name of that application window
; (and its ahk_class for more specific cases).
; for example you can replace "Sticky Notes"
; with "Calculator" to make calculator stay always
; on top.
Loop {
WinWait, ahk_group ontop
WinSet, AlwaysOnTop, On
SoundBeep, 1500
WinWaitClose
SoundBeep, 1000
}
(main codes are credit of mikeyww)

which window is on top on the other

I have 2 windows and I want to know which window is on the top of the other?
I tried to test using GetWindowLong and comparing the results but no chance.
LONG wndState1 = ::GetWindowLong(handler1, GWL_EXSTYLE);
LONG wndState2 = ::GetWindowLong(handler2, GWL_EXSTYLE);
both results is equal to 256.
Edited: In the picture below I have the dialog of notepad++ is on top of the FileZilla, How do I Get That by Code.
Is there a trick for that ?
THank you
GetWindowLong is used to retrieve style information for a particular window.
In order to get the top-most window, use
HWND WINAPI GetForegroundWindow(void);
You will still need to know the window handles (HWND) for the processes you're interested in so that you can find out which process owns the foreground window.
Note that this API can only return the window that the user is interacting with (or has interacted with most recently).
UPDATE:
I agree with Remy that there isn't any API to do that. The only way I can think of to actually do that is to install a global hook and intercept certain messages (e.g. WM_ACTIVATE, WM_SETFOCUS and so on). Since you will also retrieve the timestamps for the messages, it should be simple to infer which window is on top of any other window. This will require you to write a dll but this is relatively simple to do. I can't guarantee this will work either though I think it will (I've written a global hook but never used it to find out the z-order of windows)

Why is my edit control ignoring the applied visual styles?

I have a window with several controls on it, but only the edit control is ignoring the visual styles. I've tried to track down the cause but have had no luck so far. Here is what it looks like:
As seen, the button and the listbox controls have the proper visual style. The edit control, however, does not. I had the proper style applied once a few days ago after changing a bunch of code unrelated to it so I know it's possible.
Things to note:
I have tried calls to InitCommonControls and InitCommonControlsEx with no success.
I have the WS_EX_CLIENTEDGE applied to the edit control and have always had that extended style turned on, even when it was working prior.
I have included as much code as I can to help track down this issue.
From my TextBox class (which inherits Component):
protected:
virtual void OnRegistering(CreationParameters& createParams)
{
// this is passed in as the lpClassName parameter in
// CreateWindowEx() and the lpszClassName parameter in WNDCLASSEX
createParams.BaseClassName = WC_EDIT;
// passed as the dwStyle parameter in CreateWindowEx()
createParams.WindowStyles |= ES_AUTOHSCROLL | ES_AUTOVSCROLL;
// passed as the dwExStyle parameter in CreateWindowEx()
createParams.WindowExStyles |= WS_EX_CLIENTEDGE;
}
Would an issue with handling the WM_CTLCOLOREDIT or WM_ERASEBKGND messages have anything to do with this? Or an issue with handling fonts? Or something else? Because I am 100% out of ideas at this point.
The issue was that the HBRUSH I was using to color the edit control was, somehow, inexplicably never initialized and was NULL. Since I know other people were having issues with this, here is my solution.
The problem manifested itself when WM_CTLCOLOREDIT arrived in the message queue. If an improper/incorrect HBRUSH is returned when that message arrives, the edit control reverts back to old visual styles. Since my HBRUSH was NULL, the old visual style was applied to the edit control.

Various issues using SetParent to embed window into external process [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Embedding HWND into external process using SetParent
I'm trying to embed a window from my process into the window of an external process using the SetParent function and have encountered a few problems that I'm hoping someone can help me out with. First off, here is an outline of what I am currently doing to embed my window into the application:
WND myWindow; //Handle to my application window
HWND externalWindow; //Handle to external application window
SetParent(myWindow,externalWindow);
//Remove WS_POPUP style and add WS_CHILD style
DWORD style = GetWindowLong(myWindow,GWL_STYLE);
style = style & ~(WS_POPUP);
style = style | WS_CHILD;
SetWindowLong(myWindow,GWL_STYLE,style);
This code works and my window appears in the other application, but introduces the following issues:
When my window gains input focus, the main application window of the external process loses focus (i.e. title bar changes color).
Keyboard shortcut commands of the main application do not work while my window has focus.
Does anybody know workarounds for these issues? I would like my window to be treated as just another child window of the main application.
Thanks.
When my window gains input focus, the main application window of the external process loses focus (i.e. title bar changes color).
You need to use AttachThreadInput to attach your process's thread to the input queue of the host process. In addition to synchronizing message processing across all attached threads, this causes them to share focus, asynchronous key state, activation, and other input-related properties.
Keyboard shortcut commands of the main application do not work while my window has focus.
When your window has keyboard focus, the thread that owns your window receives all keyboard messages from the system. If you need the main window's UI thread to handle accelerators, you must somehow route keyboard input to that thread for preprocessing. How you do this depends largely on the UI technologies you are using for your applications and how you need accelerators to be processed.
Building a user interface that spans multiple threads in different processes is difficult and there are many pitfalls.

Managing Window Z-Order Like Photoshop CS

So I've got an application whose window behavior I would like to behave more like Photoshop CS. In Photoshop CS, the document windows always stay behind the tool windows, but are still top level windows. For MDI child windows, since the document window is actually a child, you can't move it outside of the main window. In CS, though, you can move your image to a different monitor fine, which is a big advantage over docked applications like Visual Studio, and over regular MDI applications.
Anyway, here's my research so far. I've tried to intercept the WM_MOUSEACTIVATE message, and use the DeferWindowPos commands to do my own ordering of the window, and then return MA_NOACTIVATEANDEAT, but that causes the window to not be activated properly, and I believe there are other commands that "activate" a window without calling WM_MOUSEACTIVATE (like SetFocus() I think), so that method probably won't work anyway.
I believe Windows' procedure for "activating" a window is
1. notify the unactivated window with the WM_NCACTIVATE and WM_ACTIVATE messages
2. move the window to the top of the z-order (sending WM_POSCHANGING, WM_POSCHANGED and repaint messages)
3. notify the newly activated window with WM_NCACTIVATE and WM_ACTIVATE messages.
It seems the cleanest way to do it would be to intercept the first WM_ACTIVATE message, and somehow notify Windows that you're going to override their way of doing the z-ordering, and then use the DeferWindowPos commands, but I can't figure out how to do it that way. It seems once Windows sends the WM_ACTIVATE message, it's already going to do the reordering its own way, so any DeferWindowPos commands I use are overridden.
Right now I've got a basic implementation quasy-working that makes the tool windows topmost when the app is activated, but then makes them non-topmost when it's not, but it's very quirky (it sometimes gets on top of other windows like the task manager, whereas Photoshop CS doesn't do that, so I think Photoshop somehow does it differently) and it just seems like there would be a more intuitive way of doing it.
Anyway, does anyone know how Photoshop CS does it, or a better way than using topmost?
I havn't seen anything remarkable about Photoshop CS that requries anything close to this level of hacking that can't instead be done simply by specifying the correct owner window relationships when creating windows. i.e. any window that must be shown above some other window specifies that window as its owner when being created - if you have multiple document windows, each one gets its own set of owned child windows that you can dynamically show and hide as the document window gains and looses activation.
You can try handle WM_WINDOWPOSCHANGING event to prevent overlaping another windows (with pseudo-topmost flag). So you are avoiding all problems with setting/clearing TopMost flag.
public class BaseForm : Form
{
public virtual int TopMostLevel
{
get { return 0; }
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumThreadWindows(uint dwThreadId, Win32Callback lpEnumFunc, IntPtr lParam);
/// <summary>
/// Get process window handles sorted by z order from top to bottom.
/// </summary>
public static IEnumerable<IntPtr> GetWindowsSortedByZOrder()
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadWindows(GetCurrentThreadId(),
(hWnd, lparam) =>
{
handles.Add(hWnd);
return true;
}, IntPtr.Zero);
return handles;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WindowsMessages.WM_WINDOWPOSCHANGING)
{
//Looking for Window at the bottom of Z-order, but with TopMostLevel > this.TopMostLevel
foreach (IntPtr handle in GetWindowsSortedByZOrder().Reverse())
{
var window = FromHandle(handle) as BaseForm;
if (window != null && this.TopMostLevel < window.TopMostLevel)
{
//changing hwndInsertAfter field in WindowPos structure
if (IntPtr.Size == 4)
{
Marshal.WriteInt32(m.LParam, IntPtr.Size, window.Handle.ToInt32());
}
else if (IntPtr.Size == 8)
{
Marshal.WriteInt64(m.LParam, IntPtr.Size, window.Handle.ToInt64());
}
break;
}
}
}
base.WndProc(ref m);
}
}
public class FormWithLevel1 : BaseForm
{
public override int TopMostLevel
{
get { return 1; }
}
}
So, FormWithLevel1 will be always over any BaseForm. You can add any number of Z-order Levels. Windows on the same level behave as usual, but will be always under Windows with level Current+1 and over Windows with level Current-1.
Not being familiar to Photoshop CS it is bit hard to know exactly what look and feel you are trying to achieve.
But I would have thought if you created a modeless dialog window as you tool window and you made sure it had the WS_POPUP style then the resulting tool window would not be clipped to the main parent window and Windows would automatically manage the z-Order making sure that the tool window stayed on top of the parent window.
And as the tool window dialog is modeless it would not interfere with the main window.
Managing Window Z-Order Like Photoshop CS
You should create the toolwindow with the image as the parent so that windows manage the zorder. There is no need to set WS_POPUP or WS_EX_TOOLWINDOW. Those flags only control the rendering of the window.
Call CreateWindowEx with the hwnd of the image window as the parent.
In reply to Chris and Emmanuel, the problem with using the owner window feature is that a window can only be owned by one other window, and you can't change who owns a window. So if tool windows A and B always need to be on top of document windows C and D, then when doc window C is active, I want it to own windows A and B so that A and B will always be on top of it. But when I activate doc window D, I would have to change ownership of tool windows A and B to D, or else they will go behind window D (since they're owned by window C). However, Windows doesn't allow you to change ownership of a window, so that option isn't available.
For now I've got it working with the topmost feature, but it is a hack at best. I do get some consolation in the fact that GIMP has tried themselves to emulate Photoshop with their version 2.6, but even their implementation occasionally acts quirky, which leads me to believe that their implementation was a hack as well.
Have you tried to make the tool windows topmost when the main window receives focus, and non-topmost when it loses focus? It sounds like you've already started to look at this sort of solution... but much more elaborate.
As a note, it seems to be quite well documented that tool windows exhibit unexpected behavior when it comes to z-ordering. I haven't found anything on MSDN to confirm it, but it could be that Windows manages them specially.
I would imagine they've, since they're not using .NET, rolled their own windowing code over the many years of its existence and it is now, like Amazon's original OBIDOS, so custom to their product that off-the-shelf (aka .NET's MDI support) just aren't going to come close.
I don't like answering without a real answer, but likely you'd have to spend a lot of time and effort to get something similar if Photoshop-like is truly your goal. Is it worth your time? Just remember many programmers over many years and versions have come together to get Photoshop's simple-seeming windowing behavior to work just right and to feel natural to you.
It looks like you're already having to delve pretty deep into Win32 API functions and values to even glimpse at a "solution" and that should be your first red flag. Is it eventually possible? Probably. But depending on your needs and your time and a lot of other factors only you could decide, it may not be practical.