How to terminate a program started with ShellExecute - c++

In MFC, I am using this code
ShellExecute(NULL, _T("open"), _T(EXTERNAL_APP), params,
_T(EXTERNAL_PATH), SW_HIDE);
to start an external program which runs in the background.
However when my app is terminated , this program is still running, as can be verified by inspecting the Windows Task Manager pane.
So my question is, how can I make the external program stop when my app stops ?

Try ShellExecuteEx instead, which can return a HANDLE hProcess of the newly-started process.
When/if you have a HANDLE hProcess then I expect you can pass it as a parameter it to the TerminateProcess function: which you would call (to terminate the child process) before your application stops.

Related

Creating a command interpreter process and writing to it

I have been trying to create a cmd.exe from a c++-program and then being able to execute commands from the program inside the cmd.exe, so I can view the results of the operation in the cmd.exe. CreateProcessA() is the function I used:
_STARTUPINFOA CMD_StartupInfo = {};
CMD_StartupInfo.cb = sizeof(_STARTUPINFOA);
_PROCESS_INFORMATION CMD_ProcessInfo = {};
CreateProcessA("C:\\Windows\\System32\\cmd.exe",
0,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&CMD_StartupInfo,
&CMD_ProcessInfo);
The cmd.exe opened and it looked to be working. Then I thought I'd use PostMessage() to pass WM_KEYDOWN messages to the cmd.exe to execute a command. For this function I needed a window handle and it turns out that the process of getting a window handle from a process/thread ID which is obtained from the CreateProcessA() is f***ing complicated. You have to loop through all active windows with EnumWindows() that requires a callback function which needs to check whether or not the process ID of the current window is the same as the process ID of the process I created.
I did that and it turned out that none of the windows the function iterated over were my window.
So I presume that means that the thread of this process which I created has no windows but I can see a beautiful-looking cmd.exe right there. What is going on? Is this not considered a window? If not, how do I pass messages to the cmd.exe and if yes, how do I get the window handle?
Any help is appreciated (also ideas to do the entire cmd-thing differently).

Executing external exe in a child window (C++, win32)

I have written a simple win32 program say abc.exe.
I have added a button in it, clicking on which an external exe say xyz.exe should start.
But the original program i.e. abc.exe should be inaccessible while xyz.exe is running. (Same as in the case of message box where the parent window remains inactive unless message box is closed)
How can Ido it ?
It would be great if you could post an example code.
You can use WaitForSingleObject (IIRC) to wait for the new process to terminate. You can make your window not visible (e.g. via ShowWindow) before waiting. Check successful launch first.
When the button is pressed, create the 'xyz.exe' process using CreateProcess function and save the new process' handle (hProcess in the PROCESS_INFORMATION struct you passed in CreateProcess).
Then you can disable the 'abc.exe' window by calling EnableWindow with bEnable set to FALSE.
In the window procedure of 'abc.exe', where the WM_PAINT message is handled add a check to see if the 'xyz.exe' process is still running. You can do this by using GetExitCodeProcess function with the handle you saved earlier and checking if the return value is STILL_ACTIVE. If the 'xyz.exe' process is no longer active, you can then enable the 'abc.exe' window using EnableWindow again.

Hide console window in remote process

I have a windows application which invokes CreateProcess and then it exits. The process being invoked displays console and GUI windows at startup. I would like to hide the console window of the child process right when it starts.
More info:
Process is NOT started with DETACHED_PROCESS flag.
If injecting code with FreeConsole() to the remote process is the only way (I'm looking for a better one), is it not going to cause trouble with over-sensitive anti-viruses?
You can use the CREATE_NO_WINDOW flag to start a console application without a console window. It's not the same as it being hidden, but it sounds like it's what you want.

Have a user close a process' allocated console without exiting the process?

Using the Win32 API in Visual C++, I want to create a program under the Windows subsystem that allocates a console with AllocConsole and writes to it with WriteConsole. However, if the user closes the console, the process should keep running in the background. As it stands, I can't get that to happen. When X is pressed on the console title bar, the process exits.
Is there any particular way of doing this?
Thanks in advance!
The key is to respond to the Console Control Event that is raised when the user attempts to close the console. You can then call FreeConsole to detach your program from the console, and let the console be destroyed. That should keep your program running.
Additional info:
If the process is terminated when the HandlerRoutine exits, then my suggestion didn't work as expected. If that's the case, then you might have a problem. You can try hooking the SC_CLOSE system message, and do the FreeConsole there before passing the message on. That might work, although I don't know what it'll do if the user presses Ctrl+C or Ctrl+Break.
The problem is that the control handler exits the process. It might be that calling FreeConsole in the HandlerRoutine is too late.

Win32 windowless application - wait for program exit

I have a windowless application whose only purpose is to install a 32 bit hook DLL file and wait until the parent program (a 64-bit program) exits. The 64-bit program is written in C#, and the windowless application is written in C++. I originally had this GetMessage loop which held the program open:
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
I was closing the C++ application using the Process.Kill method in C#, but I found out that that isn't allowing the C++ application to close cleanly. Also, if the C# application crashed, the C++ application would stay open forever. I made the C++ application check to see if the C# application is still running, using this loop:
while(true)
{
if(PeekMessage(&msg, NULL, 0, 0, true))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(!isMainProgramRunning())
break;
Sleep(1000);
}
For some reason the Sleep causes problems. The hooks installed by the DLL file are WH_CBT and WH_KEYBOARD. Whenever I press a key while the C++ application is running with this loop, the keys just get eaten up. Removing the Sleep makes it work fine, but, as expected, it uses 100% CPU, which I don't want. I tried removing the message loop altogether and instead using WaitForSingleObject with an infinite timeout on a thread which would end when isMainProgramRunning returned false. This basically locks up the whole computer.
I don't really understand why GetMessage, which, as far as I saw, never returned, but suspended the main thread indefinitely, didn't cause these problems yet WaitForSingleObject causes every application to freeze when I click on it. How can I get the C++ application to stay open until the C# application closes?
Edit:
Since it's been pointed out to me that sleeping in a message pump is bad, let me ask this: Is there a way to specify a timeout on the message waiting, so the program isn't waiting indefinitely for a message, but rather, will wait about 250 ms, timeout, let me run the isMainProgramRunning method, then wait some more?
Edit2:
I tried using MsgWaitForMultipleObjects, although in a somewhat different way than Leo suggested. This is the loop I used:
while(MsgWaitForMultipleObjects (0, NULL, true, 250, QS_ALLPOSTMESSAGE) != WAIT_FAILED)
{
if(PeekMessage(&msg, NULL, 0, 0, true))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(!isMainProgramRunning())
break;
}
Again I had the same problem with the Sleep. I also tried suspending the main thread and having the other thread resume it. Same problem. What is it that GetMessage does that allows it to wait without causing these problems? Maybe this should be the subject of another post, but why is it that when the C++ application installing the hooks sleeps or is suspended, all processing in the hooks seems to suspend as well?
Edit3:
Here is the DLL method that the C++ application calls to install the hooks:
extern "C" __declspec(dllexport) void install()
{
cbtHook = SetWindowsHookEx(WH_CBT, hookWindowEvents, hinst, NULL);
if(cbtHook == NULL)
MessageBox(NULL, "Unable to install CBT hook", "Error!", MB_OK);
keyHook = SetWindowsHookEx(WH_KEYBOARD, LowLevelKeyboardProc, hinst, NULL);
if(keyHook == NULL)
MessageBox(NULL, "Unable to install key hook", "Error!", MB_OK);
}
You have two separate problems:
How to make the windowless C++ program exit automatically if the C# program exits (e.g. crashes).
In the C++ program, open a handle to the C# program. Since the C# program runs the C++ program, have the C# program pass its own PID as an argument; the C++ program can then open a handle to that process using OpenProcess.
Then use MsgWaitForMultipleObjects in your message loop. If the C# program exits the handle you have to it will be signalled and you will wake up. (You can also use WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0 to check if the process is signalled or not, e.g. to verify why you were woken up, although the MsgWaitForMultipleObjects result will tell you that as well.)
You should close the process handle as you are exiting (although the OS will do it for you when you exit, it's good practice in case you re-use this code in a different context). Note that the handle outlives the process it represents, and that is why you can wait on it.
How to make the C# program instruct the C++ program to exit.
You may not need this if you get #1 working, but you could just have the C# program post a message to the C++ one if you want.
Do NOT use PostQuitMessage and do NOT post or send WM_QUIT across threads or processes.
Instead, post some other message that the two apps agree on (e.g. WM_APP+1) using PostThreadMessage.
You can create a named event and use:
MsgWaitForMultipleObjects
in your message loop.
The C# application only have to open and raise this event to tell your application to exit.
It's kind of minimal interprocess communication.
You should exit the process by posting a WM_QUIT message to it and handling it correctly, as specified in this article (Modality), by Raymond Chen. Don't sleep inside a loop without handling messages - it's wrong. Your app should either be handling a message or waiting for new messages.
GetMessage never returns is because you don't have a window created!
To use a message-queue you have to have some GUI. You Can for instance create a hidden window.