Winapi how to hide/show a third-party program window? - c++

I'm trying to hide/show a third-party program (e.g. Discord):
#include <windows.h>
void show_hide(HWND window)
{
if (IsWindowVisible(window) == TRUE) {
ShowWindow(window, SW_HIDE);
} else {
ShowWindow(window, SW_SHOW);
}
}
BOOL CALLBACK enum_windows_cb(HWND window, const LPARAM lParam)
{
const char* target = "Discord";
char title[255];
if (GetWindowText(window, title, sizeof(title))) {
if (strcmpi(title, target) == 0) {
show_hide(window);
return FALSE;
}
}
return TRUE;
}
int main(int argc, char *argv[])
{
EnumWindows(&enum_windows_cb, 0);
return 0;
}
It's work fine, but if I hide a third-party program by click on close button, my program shows frozen window, until I press the tray icon.
Video demonstration:
https://www.youtube.com/watch?v=P-_Fi-Dew1w
I also wrote message log through microsoft spy++ https://pastebin.com/YwGt88yh
It recorded three actions: click on close button hides program, click on tray icon shows program, and my program tries to show window.
I also tried to add these functions one by one after ShowWindow:
SetForegroundWindow(window);
SendMessage(window, WM_SYSCOMMAND, SC_RESTORE, 0);
UpdateWindow(window);
RedrawWindow(window, 0, nil, RDW_INVALIDATE or RDW_ALLCHILDREN or RDW_UPDATENOW or RDW_FRAME);
SendMessage(window, WM_ACTIVATEAPP, TRUE, GetWindowThreadProcessId(window, 0));
But it did not help. What did I do wrong?
I use windows 10.

Related

C++ when pressing close: minimize to system tray and keep running

I have an app in c++ for windows, which should minimize the window of the command line when the user presses the close button. It shouldn't be in the taskbar anymore and have an icon in the system tray.
What I mean is: when user presses close button, the program should only "hide" like i described.
I can only manage to make the program have an icon in the tray while running, but can't make it stay running when x is pressed
Thanks for help!
this is my code so far:
#include <iostream>
#include <Windows.h> // needed for console window and system tray functionality
// global variables
NOTIFYICONDATA trayIcon; // structure for the tray icon
HWND hwnd = GetConsoleWindow(); // handle to the console window
// function prototypes
void minimizeToTray(); // function to minimize the console window to the system tray
int main()
{
// set up the tray icon
trayIcon.cbSize = sizeof(NOTIFYICONDATA);
trayIcon.hWnd = hwnd;
trayIcon.uID = 1;
trayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
trayIcon.hIcon = (HICON)LoadImage(NULL, "icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); // specify the icon file
trayIcon.uCallbackMessage = WM_USER + 1; // message identifier for tray icon clicks
trayIcon.uVersion = NOTIFYICON_VERSION_4;
strcpy_s(trayIcon.szTip, "Program Running");
// add the tray icon to the system tray
Shell_NotifyIcon(NIM_ADD, &trayIcon);
std::cout << "Program running..." << std::endl;
// set up a message loop to handle tray icon clicks and window messages
MSG msg;
while (true) // infinite loop
{
// check for messages
while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
{
// if the user clicks the close button, minimize the window to the tray
if (msg.message == WM_CLOSE)
{
minimizeToTray();
continue; // skip the rest of the message loop
}
// if the user clicks the tray icon, restore the window
if (msg.message == WM_USER + 1)
{
ShowWindow(hwnd, SW_RESTORE);
}
// pass the message to the default window procedure
DispatchMessage(&msg);
}
// do other tasks here
}
// remove the tray icon before exiting the program
Shell_NotifyIcon(NIM_DELETE, &trayIcon);
return 0;
}
// function to minimize the console window to the system tray
void minimizeToTray()
{
// hide the console window
ShowWindow(hwnd, SW_HIDE);
// update the tray icon
trayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
Shell_NotifyIcon(NIM_MODIFY, &trayIcon);
}
When the user "closes" the window it should just hide and not close entirely, like ms teams or discord do
After testing your code, it definitely fails. It cannot get the message WM_CLOSE. Just as Hans Passant said, you can use SetConsoleCtrlHandler() to attached to the console receive the signal.
Here is my code. It runs well.
It used ShellExecuteW() API to restart the program to implement minimization.
Setting SW_MINIMIZE, it will minimize in the task bar.
Setting SW_HIDE, it will minimize in the system tray. But it cannot be opened again.
#include <Windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <iostream>
NOTIFYICONDATA trayIcon;
HWND hwnd = GetConsoleWindow();
BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
char mesg[128];
switch (CEvent)
{
case CTRL_C_EVENT:
MessageBox(NULL,
L"CTRL+C received!", L"CEvent", MB_OK);
break;
case CTRL_BREAK_EVENT:
MessageBox(NULL,
L"CTRL+BREAK received!", L"CEvent", MB_OK);
break;
case CTRL_CLOSE_EVENT:
ShellExecuteW(NULL, L"open", L"yourexe.exe", NULL, NULL, SW_MINIMIZE);
break;
case CTRL_LOGOFF_EVENT:
MessageBox(NULL,
L"User is logging off!", L"CEvent", MB_OK);
break;
case CTRL_SHUTDOWN_EVENT:
MessageBox(NULL,
L"User is logging off!", L"CEvent", MB_OK);
break;
}
return TRUE;
}
int main()
{
trayIcon.cbSize = sizeof(NOTIFYICONDATA);
trayIcon.hWnd = hwnd;
trayIcon.uID = 1;
trayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
trayIcon.hIcon = (HICON)LoadImage(NULL, L"icon1.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
trayIcon.uCallbackMessage = WM_USER + 1;
trayIcon.uVersion = NOTIFYICON_VERSION_4;
Shell_NotifyIcon(NIM_ADD, &trayIcon);
std::cout << "Program running..." << std::endl;
MSG msg;
if (SetConsoleCtrlHandler(
(PHANDLER_ROUTINE)ConsoleHandler, TRUE) == FALSE)
{
printf("Unable to install handler!\n");
return -1;
}
while (true)
{
while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
{
if (msg.message == WM_CLOSE)
{
continue;
}
if (msg.message == WM_USER + 1)
{
ShowWindow(hwnd, SW_RESTORE);
}
DispatchMessage(&msg);
}
}
Shell_NotifyIcon(NIM_DELETE, &trayIcon);
return 0;
}

Maximize/Minimize window from another thread

I'm trying to find out the correct way to minimize/maximize a window owned by another thread. My target window can be fullscreen or not (i should be able to minimize and maximize it regardless of its state). I've tried various combinations of ShowWindow SW_MINIMIZE, SW_MAXIMIZE, SW_FORCEMINIMIZE etc... but the only result i've been able to achieve was restoring it (maximizing) when it was minimized AND fullscreen with ShowWindow(hWnd, SW_RESTORE).
Here it is the code i'm using to retrieve my handle:
#include <Windows.h>
#include <iostream>
// I'm a console application
int main(int argc, char* argv[]) {
HWND hWnd = FindWindow(TEXT("MyWindowClass"), NULL);
if(IsWindow(hWnd)) {
std::cout << "Window found!" << std::endl;
SetForegroundWindow(hWnd); // I'll give focus to my window. This is always working.
if(IsIconic(hWnd))
ShowWindow(hWnd, SW_RESTORE); // This is working only if the window is minimized while in fullscreen mode
Sleep(3000);
ShowWindow(hWnd, SW_MINIMIZE); // Not working. SW_FORCEMINIMIZE, SW_HIDE etc are not working either.
}
return 0;
}
After struggling for a whole day I've found a solution that works for both minimizing and maximizing the window regardless of its state: Post/SendMessage.
To maximize it:
PostMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
To minimize it:
PostMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
Try ShowWindow first, and then call SetForegroundWindow:
void show_and_setforeground(HWND hwnd)
{
WINDOWPLACEMENT place;
memset(&place, 0, sizeof(WINDOWPLACEMENT));
place.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hwnd, &place);
switch (place.showCmd)
{
case SW_SHOWMAXIMIZED:
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
break;
case SW_SHOWMINIMIZED:
ShowWindow(hwnd, SW_RESTORE);
break;
default:
ShowWindow(hwnd, SW_NORMAL);
break;
}
SetForegroundWindow(hwnd);
}
In addition to IsWindow(hWnd) you may want to use IsWindowVisible(hWnd) because some programs use invisible windows which are not meant to be used.
hwnd = FindWindow(TEXT("MyWindowClass"), NULL);
if (IsWindow(hwnd))
{
if(IsWindowVisible(hwnd))//optional
{
show_and_setforeground(hwnd);
...
}
}

Browse For Folder dialog window handle C++

How to get the handle HWND of the dialog which user open when clicking on a button.
I'm using Spy++ to find the window class and tittle, but it says that no such window is found. And how then to get the handle of that dialog in C++ using Win API ?
I hope that I will be able to do that using simple functions as FindWindow, GetParent, any WIN APi function. I do not like to inject something or load DLL. Thanks
UPDATE:
the folder browser dialog is opened by other program. I want to get it's handle from different program , my program. Thanks.
The closest to want i need is for now the function WindowFromPoint
Accessibility will let you capture window creation events from other processes without DLL injection. You can modify the example to accommodate for the browsing window specifically. Here's an example I made previously to test that is based on the one from the article. Modify it however you wish:
#include <iostream>
#include <windows.h>
void CALLBACK proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG obj, LONG child, DWORD thr, DWORD time) {
if (hwnd && obj == OBJID_WINDOW && child == CHILDID_SELF) {
switch (event) {
case EVENT_OBJECT_CREATE: {
std::cout << "Window created!\n";
break;
}
case EVENT_OBJECT_DESTROY: {
std::cout << "Window destroyed!\n";
break;
}
}
}
}
int main() {
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, nullptr, proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (hook) {
UnhookWinEvent(hook);
}
}

C++ Win 32 API: Problem With Passing window SW_HIDE

I am attempting to hide a 3rd part window on bootup of our computers. I am using the following code.
#include<windows.h>
#include <stdio.h>
int main() {
char windowName[500];
HWND window = FindWindow("WindowClassAsReportedByWindowSpy++", NULL);
//GetWindowText(window, windowName, 63);
ShowWindow(firefox,SW_HIDE);
getchar();
return 0;
}
The only problem is the window will not hide. Any ideas on why this isn't working /how I could accomplish this differently.
Most likely your program calls FindWindow before the target window is created, and so doesn't find it.
You'll need to sleep and retry the find.
You probably want to do sanity checks to make sure FindWindow is not returning NULL. Even better, call FindWindow in a loop until it doesn't return NULL.
#include <windows.h>
#include <stdio.h>
static const wchar_t g_cszFirefoxClass[] = L"firefox";
int __cdecl wmain(__in int argc, __in_ecount_z_opt(argc) wchar_t* _wargv[], __in_z_opt __wenviron[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(_wargv);
UNREFERENCED_PARAMETER(__wenviron);
HWND hWnd;
do {
hWnd = FindWindow(g_cszFirefoxClass, NULL);
Sleep(100);
} while (hWnd == NULL);
wprintf(L"[-] Firefox found! [HWND = 0x%X]\n", hWnd);
if (ShowWindow(hWnd, SW_HIDE))
{
wprintf(L"[-] Successfully hid Firefox window!\n");
return EXIT_SUCCESS;
}
else
{
fwprintf(stderr, L"[x] Failed to hide Firefox window..\n");
return EXIT_FAILURE;
}
}

How to correctly pop a modeless dialog from console using MFC

I need to create a console application that has a main() function and pop a modeless dialog, so the console can still work in parallel to the modeless dialog (do other work, like communicating with the modeless dialog).
Whatever i tried, i could only pop a modal dialog. (where the console is in hold till the modal dialog close itself).
When switching to modeless dialog using Create() and ShowWindow() the dialog is displayed without its controls and it freeze / block (you can see the hourglass cursor).
1) I tried to pop the modeless dialog from the main() function:
void main()
{
AfxWinInit(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW);
TestGUI * gui;
gui = new TestGUI();
gui->Create(TestGUI::IDD);
gui->ShowWindow(SW_SHOW);
// just to see if the modeless dialog responses
Sleep(10000);
}
2) I tried to pop the modeless dialog from the InitInstance() of a CWinApp derived class:
extern int AFXAPI AfxWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow);
class MyApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{
gui = new TestGUI();
gui->Create(TestGUI::IDD);
gui->ShowWindow(SW_SHOW);
return TRUE;
}
private:
TestGUI * gui;
};
MyApp my_app;
void main()
{
AfxWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW);
// just to see if the modeless dialog responses
Sleep(10000);
}
In all cases the modeless dialog freeze.
I believe this is a one line solution.
Please help.
TNX,Vertilka
Following code snippet solves the problem:
#include "stdafx.h"
#include "TestGUI.h"
DWORD WINAPI ModelessThreadFunc(LPVOID)
{
TestGUI gui;
gui.Create(TestGUI::IDD);
gui.ShowWindow(SW_SHOW);
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, L"CloseModelessDialog");
MSG msg;
while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
{
while(::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
// event cleanup
CloseHandle(hEvent);
return 0;
}
void main()
{
// initialize MFC
AfxWinInit(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW);
// create thread for the modeless dialog
CreateThread(NULL, 0, ModelessThreadFunc, NULL, 0, NULL);
// wait for the modeless dialog to close itself
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, L"CloseModelessDialog");
while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
{
// do other job
}
// event cleanup
CloseHandle(hEvent);
}
Also look at the following link: microsoft newsgroups