How to use setevent to stop process handler - winapi

I'm trying to createProcess then inherit process handle to event handle
HANDLE app_event;
TCHAR* path = L"C:\\My.exe";
STARTUPINFO info;
PROCESS_INFORMATION processInfo;
ZeroMemory(&info, sizeof(info));
info.cb = sizeof(info);
ZeroMemory(&processInfo, sizeof(processInfo));
CreateProcess(path, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo);
ThreadId = processInfo.dwThreadId;
app_event = CreateEventW(nullptr, TRUE, FALSE, nullptr);
DuplicateHandle(GetCurrentProcess(), processInfo.hProcess,
GetCurrentProcess(),
&app_event,
0, FALSE,
DUPLICATE_SAME_ACCESS);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
and I'm creating thread for event
But when I call setEvent to stop process
The process don't stop and i got stuck at WaitForSingleObject
SetEvent(app_event);
WaitForSingleObject(app_thread, INFINITE);
Am I doing something wrong?
Sorry I'm new to C++.

DuplicateHandle doesn't do what you think it does. It makes a new handle to an existing object. You seem to think it can be used to turn an object of one type into an object of another type. It cannot. A process handle cannot become an event handle.
This mis-understanding is compounded by your code's lack of error checking. The Win32 API won't raise exceptions. Errors are signaled by way of the API function return values. Which you ignore, unfortunately.
What you seem to be doing is trying to terminate a process in a co-operative manner. Signal an event to indicate termination is required. Then wait for the process to stop. That only works if the other process co-operates. There's no indication that is the case for you. You certainly cannot inject a termination event into the other process.
If the other process doesn't have a documented way to be signaled for termination then the best you can do is call TerminateProcess. If you are in control of the other process then you can agree on a co-operative procedure for termination. Use a named event that both process can gain access to.
I would like to repeat my main advice one more time. Always check for errors when calling Win32 functions. There's no one single way to do that, you must read the documentation carefully for each and every function that you call.

Related

Why does WaitForSingleObject() after CreateProcess() show the AppStarting cursor?

I've written a simple launcher that looks up the actual program and then executes it. This works fine, but there is one issue: Windows displays the "pointer with hourglass" cursor for about give seconds. This does not happen if I launch the program directly.
I tried setting sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK but this did not help. I guess that's because it's my program that somehow needs to disable the cursor and the program I start does that fine (it creates a proper window etc.).
This is the relevant code from my application. I do not have any threads or any other fancy stuff (the sole purpose of the program is to launch another program and pass on the exit code to its caller in case it cares about it):
STARTUPINFO sinfo = {0};
PROCESS_INFORMATION pinfo = {0};
if (!CreateProcess(program, buf, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
Fail("Could not launch Vim");
}
if (WaitForSingleObject(pinfo.hProcess, INFINITE) == WAIT_FAILED) {
Fail("WaitForSingleObject");
}
Apparently Windows expects a Windows program to process messages and does not consider it fully started before that point, which is why it shows the appstarting cursor.
Adding the following code to process a single dummy message solved the problem:
MSG msg;
PostMessage(NULL, WM_NULL, 0, 0);
GetMessage(&msg, NULL, 0, 0);
Your program is showing the hour-glass icon because your UI thread is hanging as a result of being stalled on the WaitForSingleObject call. Remember, WaitForSingleObject does not return until after the child process exits. You could substitute the Wait call with a Sleep and get the same effect.
You have some options:
Use MsgWaitForMultipleObjects instead of WaitForSingleObject. This is the more formal way to pump messages and wait at the same time instead of the PostMessage/GetMessage thing you suggest in your own answer.
Do the Wait call on another thread. When the thread returns, it PostMessage something to your UI thread to indicate it is done.
In both of the above cases, the UI will become responsive to clicks and input events while the child process is still happening. You will need to code your UI thread to handle this as appropriate (if it's warranted).

Using event object in inter-process

I'm trying to use event object in win32 environment to synchronize two processes. Below are the simplified code of two programs.
// process1
int main()
{
HANDLE h = CreateEvent(NULL, FALSE, FALSE, TEXT("Hello"));
WaitForSingleObject(h, INFINITE);
// RunProcess(L"process2.exe", L"");
}
// process2
int main()
{
HANDLE h = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("Hello"));
SetEvent(h);
}
It's quite simple, and works well when two processes are launched independently. However it does not work when the process 1 launches process 2 as a child process (which is commented in the above code) - the SetEvent call fails. What is the reason and solution of this problem?
Your code needs to check and handle errors. Both CreateEvent and OpenEvent will return NULL if they fail, in that case you need to check the error using GetLastError.
Your calls to WaitForSingleObject and SetEvent should be checked per the MSDN docs as well.
The order in which you need to do things in the parent process is:
CreateEvent
Start child process
WaitForSingleObject.
Otherwise you will hit the problem called out by #Mark Tolonen.
It would also be best to have a timeout on your wait, to handle the case where the child process fails to start, exits unexpectedly, or hangs.
An alternative approach if you intend to use this parent/child relationship would be to allow inheritance of the event handle. Then the event does not need to be named, and nobody else can 'squat' on it in a DoS attack on your apps. You can pass the handle value to the child as a command-line parameter. You do this using the bInheritHandle field on the eventAttributes parameter to CreateEvent.
A Boolean value that specifies whether
the returned handle is inherited when
a new process is created. If this
member is TRUE, the new process
inherits the handle.
Are you sure? As written, if process1 creates process2 in the current location, it will never create process2 because it will wait forever for the event to be fired. Create process2 first, then wait for the event to be set.
You have a NULL security descriptor, which the documentation says cannot allow the handle to be inherited by children processes, specifically:
If this parameter is NULL, the handle cannot be inherited by child processes
Maybe you need to create a proper security descriptor?

CreateProcess with WaitForSingleObject performance degradation

Everyone probably knows the code to run a program and wait for it to end:
CreateProcess(...
WaitForSingleObject(Process.hProcess, INFINITE
It was used several times by myself. But recently I found that this call when it launches a program with a multimedia playback has worse performance than the same process being executed from a general file manager (Windows XP). That's ok with CPU consumption of my (parent) process, but while playing the fragment there are unexpected little stops.
I made a little change to something like:
CreateProcess ...
do {
Sleep(100);
Res = WaitForSingleObject(Process.hProcess, 10);
} while (Res == WAIT_TIMEOUT);
And it helped. Now the child process plays the fragment without problems.
So what's wrong with the first fragment and is it documented somewhere? As I see from the tests the second "wait" is more "relaxed" than the first one, but the first one doesn't eat CPU at least formally
If this code is running on a UI thread, you will cause performance problems with other processes that (directly or indirectly) send messages to your window(s), since you do not run the message loop while you are waiting for the child process. Neither Sleep() nor WaitForSingleObject() will process messages.
Windows Explorer (the file manager) will not suffer this problem because it:
Does not keep an open handle to processes it launches at the user's request (I think this is more likely, since Explorer needs neither to know when the process exits or its exit code), or
Does not wait on any open process handles it may keep from its children, and importantly
Always makes sure to run a message loop while it waits on handles. This is very important in any process that makes use of COM, which Explorer uses heavily.
Instead of calling WaitForSingleObject(), you can call MsgWaitForMultipleObjects(). If you specifiy QS_ALLINPUT for the dwWaitMask parameter, MsgWaitForMultipleObjects will return either when your event is signaled or when there is input in the thread's message queue. If MsgWaitForMultipleObjects() returned because a message is available, you can process it and resume waiting:
MSG msg;
DWORD reason = WAIT_TIMEOUT;
while (WAIT_OBJECT_0 != reason) {
reason = MsgWaitForMultipleObjects(1, &hChildProcess, FALSE, INFINITE, QS_ALLINPUT);
switch (reason) {
case WAIT_OBJECT_0:
// Your child process is finished.
break;
case (WAIT_OBJECT_0 + 1):
// A message is available in the message queue.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// Note that if your main message loop does additional processing
// (such as calling IsDialogMessage() for modeless dialogs)
// you will want to do those things here, too.
}
break;
}
}

Why does WaitForSingleObject(INVALID_HANDLE_VALUE, INFINITE) block?

Why does
HANDLE mutexHandle = INVALID_HANDLE_VALUE;
WaitForSingleObject(mutexHandle, INFINITE);
block? It does not return with an error message. Checking the handle for INVALID_HANDLE would be stupid for a mutex as I would need a mutex for accessing the mutex handle...
BTW: It does return with WAIT_FAILED if the handle was closed.
From http://blogs.msdn.com/oldnewthing/archive/2004/03/02/82639.aspx:
Fourth, you have to be particularly careful with the INVALID_HANDLE_VALUE value: By coincidence, the value INVALID_HANDLE_VALUE happens to be numerically equal to the pseudohandle returned by GetCurrentProcess(). Many kernel functions accept pseudohandles, so if if you mess up and accidentally call, say, WaitForSingleObject on a failed INVALID_HANDLE_VALUE handle, you will actually end up waiting on your own process. This wait will, of course, never complete, because a process is signalled when it exits, so you ended up waiting for yourself.

How can I update a win32 app gui while it is waiting for another program to finish?

I am currently using CreateProcess/WaitForSingleObject from within a win32 GUI app to launch a small GUI app that deals with software licensing issues. This all works fine, but it essentially hangs the "parent" app while it waits for the licensing app to finish its work. During this time, updates to the parent app do not occur and it ends up with ugly white squares if the utility app window is moved.
Also, for some strange reason, while the utility app is running, if I copy something from within that app to the clipboard, it HANGS. I haven't figured out why yet, but it only happens if I am waiting for the app to finish from within the parent app.
So I'm thinking that if I can cause the parent app to handle its events while waiting for my other app to finish, it might solve both problems.
So, is there a replacement for CreateProcess/WaitForSingleObject that also handles UI updates?
Your parent process appears to hang because the WaitForSingleObject() call blocks your thread until the handle you pass into the call is signaled.
Your child process likely hangs during the copy-to-clipboard operation because it is, as a part of that operation, sending a message either specifically to the parent process's window or to all top-level windows. The message loop in your parent process's thread is not running, because it is blocked waiting until the child process exits, so the message is never processed and the child process remains blocked.
Instead of calling WaitForSingleObject(), you can call MsgWaitForMultipleObjects(). If you specifiy QS_ALLINPUT for the dwWaitMask parameter, MsgWaitForMultipleObjects will return either when your event is signaled or when there is input in the thread's message queue. If MsgWaitForMultipleObjects() returned because a message is available, you can process it and resume waiting:
MSG msg;
DWORD reason = WAIT_TIMEOUT;
while (WAIT_OBJECT_0 != reason) {
reason = MsgWaitForMultipleObjects(1, &hChildProcess, FALSE, INFINITE, QS_ALLINPUT);
switch (reason) {
case WAIT_OBJECT_0:
// Your child process is finished.
break;
case (WAIT_OBJECT_0 + 1):
// A message is available in the message queue.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// Note that if your main message loop does additional processing
// (such as calling IsDialogMessage() for modeless dialogs)
// you will want to do those things here, too.
}
break;
}
}
You could put the WaitForSingleObject call in a loop and use a relatively small value for the dwMilliseconds parameter.
The condition to exit the loop is when the WaitForSingleObject call returns WAIT_OBJECT_0.
In the loop you have to examine the message queue to see if there are any that you must process. How you handle this is really up to you an it depends on your typical needs.
// Assuming hYourWaitHandle is the handle that you're waiting on
// and hwnd is your window's handle, msg is a MSG variable and
// result is a DWORD variable
//
// Give the process 33 ms (you can use a different value here depending on
// how responsive you wish your app to be)
while((result = WaitForSingleObject(hYourWaitHAndle, 33)) == WAIT_TIMEOUT)
{
// if after 33 ms the object's handle is not signaled..
// we examine the message queue and if ther eare any waiting..
// Note: see PeekMessage documentation for details on how to limit
// the types of messages to look for
while(PeekMessage(&msg, hwnd, 0, 0, PM_NOREMOVE))
{
// we process them..
if(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
// if you're here it means WaitForSingleObject returned WAIT_OBJECT_0, so you're done
// (but you should always check and make sure it really is WAIT_OBJECT_0)
if(result != WAIT_OBJECT_0)
{
// This should not be.. so react!
}
I suggest you can handle this as follows:
Parent application does CreateProcess, and then returns immediately instead of waiting for a response or for the utility app to finish
Because the parent applicatin has returned, it can handle other Window messages (e.g. WM_PAINT)
When the utility app finishes, it notifies the parent application (e.g. using PostMessage and RegisterWindowMessage APIs)
Parent application handles positive notification received via PostMessage
Parent application may also have a Windows timer (WM_TIMER) running, so that it knows if the utility app is killed before it send its notification
You can get a hanging problem if the app you are spawning causes a sendmessage broadcast, either explicit or implicit. This is clipped from my website:
The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (HWND_BROADCAST or HWND_TOPMOST), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.
I don't do clipboard code, but if that causes the situation above (believeable), then you'll deadlock. You can:
put the launch of the secondary application into a little thread
use a timeout and spin around a PeekMessage loop (yuck)
use the MsgWaitForMultipleObjects API.
No preference is implied by that ordering... I'm assuming you don't create the spawned application yourself, in which case you could use IPC to get around this issue, as ChrisW suggested.
You should create a thread that does only the following:
call CreateProcess() to run the other app
call WaitForSingleObject() to wait for the process to finish - since this is a background thread your app will not block
call CloseHandle() on the process handle
call PostMessage() with a notification message for your main thread
Now you only need to make sure that your main application has its GUI disabled to prevent reentrancy problems, possible by showing a modal dialog that informs the user that the other app is running and needs to be dealt with first. Make sure that the dialog can not be closed manually, and that it closes itself when it receives the posted notification message from the background thread. You can put the whole thread creation into this dialog as well, and wrap everything in a single function that creates, shows and destroys the dialog and returns the result your external application produces.

Resources