Combining CreateProcess and AllowSetForegroundWindow on WIN32 - c++

I have an application that is essentially a "helper" application that wraps another app.
The app that the user interacts with is a process that is created by the "helper" app like so:
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
memset(&processInfo, 0, sizeof(processInfo));
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.cb = sizeof(startupInfo);
int retval = CreateProcess(cmd, cmdLine, NULL, NULL, false,
CREATE_NO_WINDOW, NULL, NULL, &startupInfo,
&processInfo);
This process is an executable that I do not have the source code to and cannot make changes to.
The "helper" application does a few things based mainly on network traffic from the other app. At one point I want to display a file browse dialog from the helper app based on something the user does in the started UI process.
When I show the file dialog from the helper app, it's shown behind the UI of the process that was created, which isn't ideal. I tried calling SetForegroundWindow() from the helper app but it fails the criteria specified for SetForegroundWindow in the MSDN docs ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539%28v=vs.85%29.aspx ), namely:
The process is not the foreground process.
The process was not started by the foreground process.
(even though the process created the foreground process).
Is there a way to call CreateProcess() with a flag or setting that works like calling AllowSetForegroundWindow() from that process? Or a flag that can be used to make Windows think the started process is "the same" as the process that started it for purposes of SetForegroundWindow permissions?
Or is there another way I can show the dialog generated by the helper app on top of the created process' dialogs?

The only solution I could think of off the top of my head would be to do remote thread injection into the child process, and then have your injected thread call AllowSetForegroundWindow with the appropriate parameters to allow the parent process to steal foreground-ness back.
I have not tested this though.

Related

CTRL_BREAK_EVENT to a GUI application will compromise parent process

I created a console application with code beneath.
Those code will just start a child process of the explorer.exe then send a CTRL_BREAK_EVENT to it which is expected to be a NO-OP since the child explorer process is not a console application. Then using TerminateProcess to kill the child process which had no effect either but it's ok too.
The problem is, after those steps, the whole console event system for this parent process is broken - I cannot shutdown this console application by clicking X on the console window nor by pressing CTRL-C.
#include <Windows.h>
#include <iostream>
int main() {
const LPWSTR exe = const_cast<LPTSTR>(TEXT("C:\\Windows\\explorer.exe"));
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
CreateProcess(exe,
exe,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&si,
&pi);
Sleep(1000);
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pi.dwProcessId);
Sleep(1000);
TerminateProcess(pi.hProcess, 0);
Sleep(1000);
while (true) {
Sleep(1000);
std::cout << "Hello World!\n";
}
}
I do this because I'm making an application hosting platform that people can upload and run applications on a private cloud. We don't know what kinds of EXEs users will upload. If user uploads a console application that relying on CTRL_BREAK_EVENT for a graceful exit, we want to make it possible, so we try CTRL_BREAK_EVENT first. If the program doesn't shutdown in time after a while (for example a GUI program) we will kill it, just like the code above did. We don't want it to break the whole console control event system if we do this on a GUI application since we rely on it to manage lifecycles other services which run as children processes.
By the way, if we created the process with creation flag "DETACHED_PROCESS", the breaking of console control event system will break too even the EXE is a console application.
Any idea to workaround this?
Many thanks!
This is a workaround to prevent this issue from occuring which I use currently in our production, for anyone who is facing the same issue.
Use QueryFullProcessImageName to find the PE image file path of the child process.
Find the subsystem of this PE image. https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
If the subsystem is GUI, don't use GenerateConsoleCtrlEvent on it.
If you are not familiar with PE format and don't want to read the doc, just do this:
Read at 0x3c as UINT16 of the PE file to find the offset of PE header.
Read UINT8 at PE_HEADER + 0x18 + 0x44, and 0x02 means a GUI application.
I would like to not mark this as an answer since I'm hoping some more elegant way.

How to start an application as a child of a newly created explorer process?

I'm working on an application that resembles a kiosk. After the application starts, it creates a new desktop with limited capabilities. Using a key combo I can move back and forth between desktops. In order to inform the user about the desktop it's currently using, or any other information I've created an application, which is displaying balloon messages is System Tray area.
In the newly created desktop, I start an explorer.exe using CreateProcess function, and providing the new desktop thru a STARTUPINFO structure, and I'm returning a handle for the process in a PROCESS_INFORMATION structure.
Using the same technique I'm trying to start the icon tray application in the new desktop , providing the new desktop in the STARTUPINFO structure. The trouble is that, according to the task manager, the application is running, but the tray icon is not displayed.
My intuition says that in the new desktop, the icon is not shown because it's not a child of the new explorer.exe process, the procexp application from live.systernals is showing these two processes, on the same level in a tree representation.
Is there a way to provide an argument to CreateProcess, maybe the explorer process handle, so that the icon tray application starts as a child of this process?
L.E.: Here is the code that I use to create start the explorer.exe and the icon tray processes:
STARTUPINFO sInfoNT; /// startupinfo for the explorer.exe
PROCESS_INFORMATION pInfoNT; /// process infromation for the explorer.exe
ZeroMemory(&sInfoNT, sizeof(sInfoNT));
sInfoNT.lpDesktop = L"threadDesktop"; /// setting the desktop for the process
pInfoNT = startProcess(sInfoNT, L"C:\\Windows\\explorer.exe"); /// starting the process
if (!pInfoNT.hProcess)
LOG(ERROR) << "Unable to start the new explorer process";
else
LOG(INFO) << "Started the new explorer process";
STARTUPINFO sInfoTITD; /// doing the same thing for the tray icon application
PROCESS_INFORMATION pInfoTITD;
ZeroMemory(&sInfoTITD, sizeof(sInfoTITD));
sInfoTITD.lpDesktop = L"threadDesktop";
pInfoTITD = startProcess(sInfoTITD, L"DesktopTrayIcon.exe");
if (!pInfoTITD.hProcess)
LOG(ERROR) << "Unable to start the tray icon for the new desktop";
else
LOG(INFO) << "Started the tray icon for the new desktop";
And this is the startProcess function:
PROCESS_INFORMATION KioskLauncher::startProcess(STARTUPINFO startUpInfo, LPCTSTR lpApplicationName)
{
PROCESS_INFORMATION processInformation;
ZeroMemory(&processInformation, sizeof(processInformation));
if (!CreateProcess(lpApplicationName, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startUpInfo, &processInformation))
MessageBox(0, L"Unable to start the process!\nThe path is broken!", L"Path Error!", MB_ICONERROR);
return processInformation;
}
If your really want to make the new Process a child of that other process, you have to use code injection. A search for CreateRemoteThread will give you plenty of reading material. The biggest problem is, that your process has to be the same bit-ness as the target. There are 3 ALTERNATIVE ways of using it:
Dll injection (standard)
Inject actual shellcode: Assembler code that will resolve all dependencies itself. (Will not work with EMET enabled)
Copy a block of code from your application and fix the imports (Tricky)

Newly created desktop doesn't receive keyboard events

I have created a small program which launches itself in a new desktop.
HDESK hDesktop = ::CreateDesktop(strDesktopName.c_str(),
NULL, // Reserved
NULL, // Reserved
0, // DF_ALLOWOTHERACCOUNTHOOK
GENERIC_ALL,
NULL); // lpSecurity
::SetThreadDesktop(hDesktop);
Later on, started another application on that desktop using the following lines:
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
si.lpDesktop = &strDesktop[0];
if (FALSE == ::CreateProcess(pathModuleName.file_string().c_str(), L"abc def", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
return false;
DWORD dwWaitRes = ::WaitForSingleObject(pi.hProcess, INFINITE);
pathModuleName is a self location obtained by GetModuleFileName(NULL).
The newly created application obtains a HWND to another window and sends window messages using the following commands:
// bring window to front
::SetForegroundWindow(hwnd);
// set focus so keyboard inputs will be caught
::SetFocus(hwnd);
::keybd_event(VK_MENU, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
...
So basically application A on desktop DEFAULT is starting application B on desktop X, which obtains an HWND to another application C started on the same desktop X.
My problem is that keyboard events coming from application B on desktop X are not being triggered in application C. Only if I use SwitchDesktop(B), then events are triggered and code is executed properly.
What am I missing?
You are trying to simulate user input on a desktop that is not active on the physical console (screen, mouse, keyboard), which is not likely to work, and why SwitchDesktop() makes it work. According to the documentation:
SwitchDesktop function
Makes the specified desktop visible and activates it. This enables the desktop to receive input from the user.
keybd_event(), mouse_event(), SendInput(), they all simply generate and store input messages into the same input queue that the physical mouse/keyboard post their messages to. The input system does not know the difference between user input and synthesized input when dispatching the input messages to applications.
Raymond Chen touched on that in his blog:
How do I simulate input without SendInput?
SendInput operates at the bottom level of the input stack. It is just a backdoor into the same input mechanism that the keyboard and mouse drivers use to tell the window manager that the user has generated input. The SendInput function doesn't know what will happen to the input. That is handled by much higher levels of the window manager, like the components which hit-test mouse input to see which window the message should initially be delivered to.
He also posted a nice little diagram in another blog article showing where SendInput() sits in relation to the input queue:
When something gets added to a queue, it takes time for it to come out the front of the queue

how to show console app window hidden by createprocess function

I have a GUI in c++. The GUI used to start another independent console based application using CreateProcess method. I am hiding these console apps by passing CREATE_NO_WINDOW flag in CreateProcess. Now I want to make it visible again. How do I do that?
Instead of using the CREATE_NO_WINDOW flag, use the wShowWindow member of the STARTUPINFO struct instead. Set it to SW_HIDE initially (and set the dwFlags member to STARTF_USESHOWWINDOW), then you can use ShowWindow() to show/hide the console window when needed. To find the window that belongs to the new process, use EnumWindows() and GetWindowThreadProcessId() to find the window whose process/thread IDs match the IDs that CreateProcess() returns in the PROCESS_INFORMATION struct.
You had one shot at getting the window created and you passed it up. Thats right but you can show or hide gui, after createProcess method.
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.lpTitle ="my_process_console";
CreateProcess(null,"my.exe",null,null,false,CREATE_NEW__CONSOLE,null,null,&si,&pi);
I created process.Now I use find method and then I can show GUI.
HWND console_name =FindWindow(null,"my_process_console");
if(console_name){
ShowWindow(console_name,SW_SHOW);
}

How to launch console application using CreateProcess with Minimized main window

I have a native c++ windows application that is launching two child processes using the following code -
if (!CreateProcess(NULL, // No module name (use command line)
cmdLine, // szCmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
false, // Set handle inheritance to FALSE
CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS // Process Create Flags
NULL, // Use parent's environment block
NULL, // workingDir, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
with all parameters in STARTUPINFO block 0. This code works fine in launching the processes. However, I need to be able to launch the windows c++ console applications with their windows minimized.
If I add CREATE_NO_WINDOW to the Process Create Flags, I can launch the processes without any windows. This will be unacceptable.
In my research, there does not appear to be a way force a console application to open in a minimized mode. Is this correct?
Yes, I know that I could minimize the child application windows from within their own process, however, the other programmers on the team prefer not to do this.
You need to specify in the STARTUPINFO structure that you want your console window to be initially minimized:
ZeroMemory(&si);
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MINIMIZE;