Restore a minimized window of another application (C++ WinAPI) - c++

I'm working on a C++ program that which launches a .NET Winforms application.
If the app is already running, I want to restore the window instead. I grab the .NET app's window handle and use SetForegroundWindow() to bring to to the front.
This works except when the application is minimized.
I've tried combinations of the following:
ShowWindow(windowHandle, SW_SHOW);
ShowWindow(windowHandle, SW_RESTORE);
and
SendMessage(windowHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
However, when this code is executed, the event becomes stuck. In the tray I see ".NET-BroadcastEventWindow.2.0.0.0.378734a.0" come up as a second window in the tray along with my .NET app, and the app is never restored properly.
This only happens when I try to send a SW/SC_RESTORE or SHOW event. SetForegroundWindow() has no issues.
Has anyone else seen this problem before?

I've had similar problems in the past that I've solved using Get/SetWindowPlacement():
// Ensure that the given window is not minimized.
// If it is minimized, restore it to its normal state.
void EnsureNotMinimized(HWND hWnd)
{
WINDOWPLACEMENT placement;
placement.length = sizeof(placement);
if(!GetWindowPlacement(hWnd, &placement))
return;
BOOL minimized = (placement.showCmd & SW_SHOWMINIMIZED) != 0;
if(!minimized)
return;
placement.showCmd = SW_SHOWNORMAL;
SetWindowPlacement(hWnd, &placement);
}
However, I've only used this for windows that belong to my own application. I don't know if security would allow it to be used on outsiders.

Related

What's the correct way to bring a window to the front

I've been trying multiple ways of bringing a window into focus and on top of other windows.
I've tried SetForegroundWindow(), BringWindowToTop(), SetActiveWindow(). None of these work consistently.
How can I simply make it so that a window that I want to be in focus, becomes on top of all other windows and is focused? Why is this so difficult?
SetForegroundWindow() is the correct way to change the foreground window, but the thread that calls SetForegroundWindow() has to meet certain criteria for it to "work". If it does not meet the criteria, the window's taskbar button is flashed instead. This is by design. This is to protect the user from applications stealing focus and you should respect that.
See also:
Foreground activation permission is like love: You can’t steal it, it has to be given to you
What if two programs did this?
Your process needs to satisfy a few conditions for it to be able to set the foreground window.
This is to prevent applications from stealing focus - which is a very bad user experience.
Imagine you're writing an email, and halfway through it your application decides now would be a good time to push a window into foreground. As you're typing suddenly the focused window would instantly change and your keypresses would now be sent to your program instead of the mail program. Not only could this cause all sorts of havoc (the keys you pressed are now sent to your program, so hotkeys might get triggered, dialogs dismissed, etc...) - but it would also be a really frustrating experience for the user (especially for less technically-inclined people).
That is the reason why SetForegroundWindow() & similar functions sometimes won't push your window to the foreground, but still report success. Your window will still flash in the task bar though, so users know that something happened in your application.
SetForegroundWindow
The exact list of conditions that need to be met for SetForegroundWindow() to work are detailed in the documentation:
The system restricts which processes can set the foreground window.
A process can set the foreground window only if one of the following conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
An application cannot force a window to the foreground while the user is working with another window ¹. Instead, Windows flashes the taskbar button of the window to notify the user.
1 this is what prevents the mail program example detailed above from happening.
A process that fulfills these criteria can also "share" its permission to set the foreground window with another process by calling AllowSetForegroundWindow()
SetActiveWindow
SetActiveWindow() only works if the targeted window is attached to your message queue and one of your application windows is currently the foreground window.
Activates a window. The window must be attached to the calling thread's message queue.
The window will be brought into the foreground (top of Z-Order) if its application is in the foreground when the system activates the window.
BringWindowToTop
BringWindowToTop() is a convenience function for SetWindowPos(), which again has the same restrictions:
If an application is not in the foreground, and should be in the foreground, it must call the SetForegroundWindow function.
To use SetWindowPos to bring a window to the top, the process that owns the window must have SetForegroundWindow permission.
Using UI Automation
Since you mentioned that you need this functionality for an accessibility tool, here's how you could accomplish this using UI Automation:
This example uses bare-bones COM for simplicity, but if you want you can of course use e.g. wil for a more C++-like API.
#include <uiautomation.h>
bool MoveWindowToForeground(IUIAutomation* pAutomation, HWND hWnd) {
// retrieve an ui automation handle for a given window
IUIAutomationElement* element = nullptr;
HRESULT result = pAutomation->ElementFromHandle(hWnd, &element);
if (FAILED(result))
return false;
// move the window into the foreground
result = element->SetFocus();
// cleanup
element->Release();
return SUCCEEDED(result);
}
int main()
{
// initialize COM, only needs to be done once per thread
CoInitialize(nullptr);
// create the UI automation object
IUIAutomation* pAutomation = nullptr;
HRESULT result = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<LPVOID*>(&pAutomation));
if (FAILED(result))
return 1;
// move the given window into the foreground
HWND hWnd = FindWindowW(nullptr, L"Calculator");
MoveWindowToForeground(pAutomation, hWnd);
// cleanup
pAutomation->Release();
CoUninitialize();
return 0;
}

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)

MFC - Strange access violation while sending WM_IDLEUPDATECMDUI message

I'm currently revising the code on an old MFC application, which I updated to be compiled with Visual Studio 2017. This application contains several MDI frames.
However there is a strange access violation happening randomly when I close these frames, which I cannot figure out, in the main form following function:
BOOL PSS_App::OnIdle(LONG count)
{
if (!count)
if (m_pMainWnd)
{
// look for any top-level windows owned by this class. NOTE handlers are used to
// avoid generation of too many temporary CWnds
for (HWND hWnd = ::GetWindow(m_pMainWnd->m_hWnd, GW_HWNDFIRST); hWnd; hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT))
if (::GetParent(hWnd) == m_pMainWnd->m_hWnd)
{
// if owned window is active, move the activation to the application window
if (GetActiveWindow() == hWnd && !::GetCapture())
m_pMainWnd->SetActiveWindow();
// update the buttons for the top-level window
::SendMessage(hWnd, WM_IDLEUPDATECMDUI, WPARAM(TRUE), 0L);
}
}
return CWinApp::OnIdle(count);
}
The issue happens when the ::SendMessage(hWnd, WM_IDLEUPDATECMDUI, WPARAM(TRUE), 0L); function is called. I tried to get the hWnd class name using the following code:
char lpClassName[256];
::GetClassName(hWnd, lpClassName, 256);
I get tooltips_class32 as result, but I don't know which class it refers to. If I try to modify the code in the following manner:
// update the buttons for the top-level window
if (std::strcmp(lpClassName, "tooltips_class32") != 0)
::SendMessage(hWnd, WM_IDLEUPDATECMDUI, WPARAM(TRUE), 0L);
The issue no longer happen in this function, and I can close my child MDI frames without problems, however another access violation happens randomly when the main form looses the focus (e.g when I click outside the app).
Can someone explain me what is happening here, or at least provide me info about what may happen? What the tooltips_class32 is exactly, and which kind of class may inherits it in MFC? Or is an ActiveX related control?
NOTE I don't know if that may have a link, but the main application inherits from CWinApp, which inherits from CWinThread. The application isn't using the multi-threading, except for the splash screen. However the issue remains the same even if I completely deactivate the splash screen code.
NOTE also that the application is a huge application containing around 30 attached DLLs. I cannot run it in Debug for now, because another strange access violation happens in one of the modules when it is loaded, which happen in Debug but never in Release. So the application is currently running in release.

IsIconic() always return false and OpenIcon() never open the window

Platform: Windows 7 64bit.
First of, the Windows API IsIconic() always return false. Doesn't matter if the window is maximized, normal or minimized (where IsIconic() should return true).
The window belongs to another process and has been retrieved with enumWindows()
Here is a small excerpt from my test code.
TCHAR WndCaption[100];
TCHAR NewCaption[] = TEXT("My Window handle is valid");
BOOL res;
GetWindowText(MyHWND,WndCaption,100);
SetWindowText(MyHWND,NewCaption);
// This always return 0, no matter what state the window is in.
res = IsIconic(MyHWND);
if(res) {
...
}
I know the window handle is valid because I can get and set the window's caption text. The Is Iconic() function however always return 0 (false) even when the window has been minimized.
But if we change the IsIconic() to IsWindowVisible() it reports correctly false when the window is minimized and true when it is maximized or normal.
TCHAR WndCaption[100];
TCHAR NewCaption[] = TEXT("My Window handle is valid");
BOOL res;
GetWindowText(MyHWND,WndCaption,100);
SetWindowText(MyHWND,NewCaption);
// This works correctly.
res = IsWindowVisible(MyHWND);
if(!res) {
// This always fail
OpenIcon(MyHWND);
}
So now when I can detect the window being minimized I want to restore it. IsIconic's counterpart OpenIcon() does nothing. It returns true, telling that the operation was successful, but the window is still minimized. In fact, it always return true no matter what state the window is in.
So lets try the old fashion way.
TCHAR WndCaption[100];
TCHAR NewCaption[] = TEXT("My Window handle is valid");
BOOL res;
GetWindowText(MyHWND,WndCaption,100);
SetWindowText(MyHWND,NewCaption);
// Only works if the window wasn't minimized by clicking the minimize button
res = ShowWindow(MyHWND,SW_MINIMIZE);
res = ShowWindow(MyHWND,SW_NORMAL);
res = ShowWindow(MyHWND,SW_MAXIMIZE);
If the window is in the normal or maximized state it will first minimize it, restores it back again and then maximize it. But if I run the program when the window has been minimized by clicking the minimize button, nothing happens. It doesn't restore it or maximize it.
It feels like the window becomes unresponsive if I minimize it by clicking the minimize button.
After hours of searching I have only found posts with similar problems but no solutions.
Can some one please help me to figure out how to restore a window (owned by another process) after it has been minimized by the minimize button.
Without knowing anything about the external app in question, my guess is that the window you are manipulating is not the actual window being minimized to the Taskbar, which would account for why IsIconic() is always false but IsWindowVisible() varies.
It is not uncommon, especially in legacy apps written before Vista, or apps using older versions of frameworks like Borland's VCL before they were updated to support Vista, to have a top-level hidden window that owns other windows in the same app, especially the main window. One reason (amongst others) is to group multiple windows on the same Taskbar button, before Microsoft created APIs to control that.
In such an app, when the "main" window is "minimized", the app would intercept that action, hide the "main" window, and minimize the owner window instead. When the "main" window is "restored", the app would restore the owner window and then show the "main" window.
Try checking if GetWindow(MyHWND, GW_OWNER) returns an HWND and if so then check what IsIconic() says about it.
Vista made some dramatic changes to how apps interact with the Taskbar and Alt+Tab dialog. Some coding techniques and assumptions that had been true and working fine since Win95 no longer worked correctly in Vista onwards. Some apps and frameworks adapted to the changes, some did not.
Had similar issue in Windows 7 Pro. 32-bit.
IsIconic() function is from user32.dll.
IsIconic function correctly working once copied below files to current folder.
user32.dll, advapi32.dll, gdi32.dll, kernel32.dll, ntdll.dll
Note:
These dependencies can be find usnig DEPENDS.EXE in VC 6.0 ++. Also these files copied from Windows 7 64-bit pc (IsIconic is working fine in this pc).
May be windows update is not installed on Windows 7 32-bit pc.

How do I force my app to come to the front and take focus?

I'm working on an application that happens to be the bootstrap for an installer that I'm also working on. The application makes a few MSI calls to get information that I need for putting together the wizard that is my application's main window, which causes a progress window to open while the info is being gathered and then go away once that's done. Then the wizard is set up and launched. My problem is that the wizard (derived from CPropertySheet) does not want to come to the front and be the active application without me adding in some calls to do so.
I've solved the problem of bringing it to the front with the following code in my OnInitDialog() method:
SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // force window to top
SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // lose the topmost status that the previous line gave us
My problem is that I still haven't figured out how to make the window self-activate (i.e., make itself be the one that has the focus). SetFocus() won't work in this context. I need something that will force the window to the top of the Z-order and activate it, preferably in as few calls as possible.
My guess is that the progress window opened at the beginning by the MSI calls is causing the main window to screw up, but I have no way to prevent that window from appearing. Also, it wouldn't make sense to hide it, because it lets the user know what's going on before the main window arrives.
Andrew isn't completely correct. Windows does try really hard to stop you from stealing focus, but it is possible using the folowing method.
Attach to the thread of the window that currently has focus.
Bring your window into focus.
Detach from the thread.
And the code for that would go something like this:
DWORD dwCurrentThread = GetCurrentThreadId();
DWORD dwFGThread = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
AttachThreadInput(dwCurrentThread, dwFGThread, TRUE);
// Possible actions you may wan to bring the window into focus.
SetForegroundWindow(hwnd);
SetCapture(hwnd);
SetFocus(hwnd);
SetActiveWindow(hwnd);
EnableWindow(hwnd, TRUE);
AttachThreadInput(dwCurrentThread, dwFGThread, FALSE);
You may or may not need to have to run your program with administrative privileges for this to work, but I've used this code personally and it has go the job done.
You can't steal focus. Period.
See this Old New Thing article:
https://blogs.msdn.microsoft.com/oldnewthing/20090220-00/?p=19083
doesn't ShowWindow(youwindow,SW_SHOWNORMAL) work?
-don
You will find that BringWindowToTop or SetForegroundWindow have requirements that must be met before the window will actually be forced to the front over all other windows (applications). If these aren't met, Windows will only flash the application's icon in the taskbar. This article presents a way around that but as 1800 INFORMATION points out, it is not recommended. I guess you'll just have to accept it.
There ARE good reasons for an app to 'steal' focus. My application is a server loading many driver DLLs. Another application, connecting to the server, has a button that sends a message to the server to show detail information in one of those DLLs (owned by the server, not the client app) for convenience. Unfortunately, this popped open window is usually buried under multiple windows.