How to use WaitForSingleObject - c++

In order to try out how to program with the Win32 API, I wrote a program that creates a process.
Then I want to check if my process waits for the newly created process, close the handle and then check WaitForSingleObject again (the second process is sleeping for 700 ms)
First process:
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
void main()
{
bool ret;
bool retwait;
STARTUPINFO startupinfo;
GetStartupInfo (&startupinfo);
PROCESS_INFORMATION pro2info;
wchar_t wcsCommandLine[] = L"D:\\betriebssystemePRA1PRO2.exe";
ret = CreateProcess(NULL, wcsCommandLine, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL,
NULL, &startupinfo, &pro2info);
cout<<"hProcess: "<<pro2info.hProcess<<endl;
cout<<"dwProcessId: "<<pro2info.dwProcessId <<endl;
if (retwait= WaitForSingleObject (pro2info.hProcess, INFINITE)==true)
cout<<"waitprocess:true"<<endl; //The process is finished
else
cout<<"waitprocess:false"<<endl;
CloseHandle (pro2info.hProcess);//prozesshandle schließen, "verliert connection"
if (retwait= WaitForSingleObject (pro2info.hProcess, INFINITE)==true) //When the process has finished
cout<<"waitprocess:true"<<endl;
else
cout<<"waitprocess:false"<<endl;
//cout<<GetLastError()<<endl; //Output the last error.
ExitProcess(0);
}
Second process:
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
void main()
{
int b;
b = GetCurrentProcessId();
cout << b << endl;
cout << "Druecken Sie Enter zum Beenden" << endl;
cin.get();
//Wait until the user confirms
Sleep (700);
ExitProcess(0);
cout<<"test";
}
The first process prints false, false ; but it should print true, false.
Instead of the if-else statement, I used this:
//switch(WaitForSingleObject (pro2info.hProcess, INFINITE)){
// case WAIT_OBJECT_0: cout << "ja";
// break;
// case WAIT_FAILED:cout << "nein";
// break;
// case WAIT_TIMEOUT:
// break;
//}
// cout<<"waitprocess:true"<<endl;//prozess ist fertig
//else
// cout<<"waitprocess:false"<<endl;
And this seems to work. What did I do wrong with my if-else statement?

You really need to pay attention to the meaning for the return value of the API functions. You cannot ignore a FALSE return from CreateProcess(). WaitForSingleObject() can return several values, it returns 0 if the wait completed successfully. Which makes you print "false".

According to MSDN, WaitForSingleObject will return WAIT_OBJECT_0 if the wait wasn't aborted. If you check the documentation, the value of WAIT_OBJECT_0 happens to be 0x00000000L, which happens to be the value commonly converted to false, not true. Hence your comparison fails.
Promoting the return value of WaitForSingleObject to a bool is IMHO not a good idea given that you get several potentially illuminating non-zero return codes that indicate why the wait expired.
If you still want to keep the above code as using a boolean check, change the tests to !WaitForSingleObject(...) instead.

I think you sort of answered your question yourself. The point is that WaitForSingleObject doesn't return true or false, but WAIT_OBJECT_0 et al.
So instead of
if (retwait= WaitForSingleObject (pro2info.hProcess, INFINITE)==true)
you need
if (retwait= WaitForSingleObject (pro2info.hProcess, INFINITE)==WAIT_OBJECT_0)

Related

How can I check whether the input buffer is empty?

I'm trying to write a simple class for operating a Serial Port on Windows, using standart windows library .
I need to check whether the input buffer is empty.
So far I've tried to use SetCommEvent, using EV_RXCHAR option, however this method doesn't work. The function seems to wait for arrival of new char. If I tried to send char, sleep for a second and the apply this, the function would not return - it keeps waiting.
bool isEmpty()
{
DWORD dwEventMask = 0;
DWORD Status = 0;
if (CheckAsyncRead())
return false;
if (!SetCommMask(hPort, EV_RXCHAR)) //wait for char receival
std::cout << "Error in creating Overlapped event" << std::endl;
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (WaitCommEvent(hPort, &dwEventMask, &osReader))
{
//close event handle
return false;
}
Status = WaitForSingleObject(osReader.hEvent, 10);
//I wait for 10 ms in case the function doesn't return immediately
//Close event handle
if (Status == WAIT_OBJECT_0)
{
return false;
}
else
return true;
}
I hoped the WaitCommEvent or WaitForSingleObject would return in case any chars were present in buffer but the does not happen if there is a longer pause between receival of a character and calling of Wait function.
You can use the ClearCommError function to find out the size of the data stored in the buffer.
As a result of calling, cbInQue of the COMSTAT structure to be notified has the size of the data stored in the input buffer.
You can use ReadFile() with a handle opened with CreateFile() with the FILE_FLAG_OVERLAPPED flag. If the ReadFile() function has nothing to return, it will return a last error ERROR_IO_PENDING which means that your buffer is currently empty.

fork() and exec() Two Child Processes

I am calling fork() twice to create two child processes. I want child process A to do an exec() call and child process B to also do an exec() call. The problem I am having with the given code is that after the first exec() from child process A, the next fork() does not seem to occur and the program exits. I think that it has to do with how exec() overlays the parent process. What I want to accomplish is to call exec() from each of the child processes created by fork().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
int main() {
pid_t cpid_a, cpid_b;
cpid_a = fork();
if(cpid_a < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
cpid_b = fork();
if(cpid_b < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_b == 0) { // code for child process B
execlp("/bin/ls", "ls", NULL);
}
}
else { // code for parent process
while(wait(NULL) != -1);
}
return 0;
}
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
If this calls succeeds, the following statement, and nothing that follows will ever be executed. That's how exec() works. The immediately-following fork() never occurs. That's simply how exec() works. If exec() succeeds, it never returns. The replacement process gets executed in its place.
You even added the 100% correct comment, above: "code for child process A". Everything inside the if() statement is "code for child process A", and gets executed when fork() returns 0.
You also correctly stated that you want the parent process to fork a second process. Well, you need to have that code obviously get executed by the parent process, and not the child process:
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
exit(1);
} else {
cpid_b = fork();
// The rest of the code.
Now, the parent process goes ahead and fork() a second time, proceeded on the rest of your plan.
P.S. The exit() is just for a good measure. The only time exec() returns is when exec() fails to execute the given process. Highly unlikely, in the case of /bin/ls; if it's missing you have bigger problems to worry about. Still, that's the technically correct thing to do, since continuing execution at that point will result in complete chaos. Again, if /bin/ls is missing that's going to be the least of the problems, but this can also happen if, say, the system ran out of memory and can't execute it for that reason; in which case there's no need to add fuel to the fire; but rather have the process die anyway.

RegisterWaitForSingleObjectEx() & several SetEvent()

I find a tricky behavior of multiple SetEvents with RegisterWaitForSingleObjectEx().
#include <windows.h>
#include <iostream>
using namespace System;
using namespace System::Drawing;
using namespace System::Threading;
VOID CALLBACK Callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
String^ string = gcnew String("");
Monitor::Enter(string->GetType());
//wait for 2 seconds
for(int i=1; i<=2;i++) {
Sleep(1000);
cout << i << " seconds \n";
}
Monitor::Exit(string->GetType());
}
void main()
{
HANDLE eventhandle = CreateEvent(
NULL, // default security attributes
FALSE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
//register the callback for the event
RegisterWaitForSingleObjectEx(eventhandle, Callback, nullptr, -1, WT_EXECUTELONGFUNCTION);
BOOL bEvented[3];
bEvented[0] = SetEvent(eventhandle);
//Sleep(10);
bEvented[1] = SetEvent(eventhandle);
//Sleep(10);
bEvented[2] = SetEvent(eventhandle);
cout << "event0 = " << bEvented[0] << ", event1 = " << bEvented[1] << ", event2 = " << bEvented[2] << " \n";
}
I set the Event 3 times. So, I expect the callback to be called 3 times (please correct me if I am wrong).
But I get only 2 callbacks.
If I uncomment the lines //Sleep(10); , I get 3 callbacks.
What is happening here?
I am using Win7 64bit
UPDATE:
Can you please give an example about how to achieve this using semaphore?
Actual scenario:
I have a third-party library where I have to register a HANDLE to get notified about the occurrence of an event. Most of the times, I am able to get the notification (signalling on the HANDLE). Sometimes, I am not getting the correct "number of signalling", as expected.
I am passing the HANDLE created using CreateEvent() and registered a callback for the HANDLE using RegisterWaitForSingleObjectEx().
I suspect that this race condition is the reason for the behavior.
How to overcome this?
SetEvent on an event that's already signalled is a no-op. You have a race condition between the main thread that calls SetEvent, and the worker thread that waits on it (and resets it automatically when the wait is satisfied).
Most likely, you manage to call SetEvent twice while the worker is still running the first callback.

Mutex behavior on Windows

I've the following code...
On one machine it throws ERROR_ACCESS_DENIED and on other it throws ERROR_ALREADY_EXISTS (Handle is not NULL). I'd like to understand why two different behaviors. On both the machines user is a domain user part of local system administrators group. I tried running three instances simultaneously.
#include <windows.h>
#include<iostream>
using namespace std;
void * _hMutex = NULL;
void createMyMutex()
{
_hMutex = CreateMutex(
NULL, // default security attributes
false, // initially not owned
L"LockTest"); // named mutex
if (_hMutex == NULL)
{
cout<< GetLastError()<< " Error creating mutex handle"<<endl;
Exit(0);
}
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
cout<< GetLastError()<< " Mutex already created" <<endl;
}
}
void Lock()
{
cout<<"Acquiring Lock..."<< endl;
if(_hMutex != NULL)
WaitForSingleObject(_hMutex, INFINITE);
cout<< "Acquired Lock." <<endl;
}
void Unlock()
{
cout<< "Releasing Lock..." <<endl;
if(_hMutex != NULL)
ReleaseMutex(_hMutex);
}
int main(int argc, char* argv[])
{
cout<<"Creating lock"<<endl;
createMyMutex();
cout<<"Lock create success"<<endl;
cout<<"Taking lock"<<endl;
Lock();
cout<<"Got the lock"<<endl;
cout<<"Waiting for 20 seconds"<<endl;
Sleep(20000);
cout<<"Wait over"<<endl;
cout<<"Releasing lock"<<endl;
Unlock();
cout<<"Lock released successfully"<<endl;
cout<<"exiting the program"<<endl;
return 0;
}
From MSDN:
If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.
So try using OpenMutex instead with just the SYNCHRONIZE access right.
Also note that the Windows type BOOL is different from the C++ type bool. So you should use the corresponding values TRUE and FALSE when calling Windows API functions that take BOOL, not true and false.
I guess you're getting the ERROR_ALREADY_EXISTS when calling createMyMutex(); and the ERROR_ACCESS_DENIED when calling Lock();. I's suggest to choose an object name in the global namespace. So you better use something like
CreateMutex( NULL, FALSE, "Global\\LockTest" );
See Object Namespaces on MSDN for details.

Close handle to a mutex in another process

I want to close a handle to a mutex located in another process, so I can run more than one instance of the application.
I already know this can be done, see Process Explorer. Example: Windows Minesweeper (Windows 7) uses a mutex to only allow one game, so I thought I would use it as an example since it's pre-installed with Windows and therefore easier for you guys to guide me.
The mutex that I need to close is \Sessions\1\BaseNamedObjects\Oberon_Minesweeper_Singleton, which I found using Process Explorer.
After closing this mutex I was able to launch two games of Minesweeper, but I want to do this in my program using C++.
After some searching I have found that I might need the API DuplicateHandle. So far I haven't been able to close the handle on this mutex.
Here is my code so far:
#include <Windows.h>
#include <iostream>
using namespace std;
void printerror(LPSTR location){
printf("Error: %s_%d", location, GetLastError());
cin.get();
}
int main(){
DWORD pid = 0;
HWND hMineWnd = FindWindow("Minesweeper", "Minesveiper");
GetWindowThreadProcessId(hMineWnd, &pid);
HANDLE hProc =OpenProcess(PROCESS_DUP_HANDLE, 0, pid);
if(hProc == NULL){
printerror("1");
return 1;
}
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, "Oberon_Minesweeper_Singleton");
if(hMutex == NULL){
printerror("2");
return 2;
}
if(DuplicateHandle(hProc, hMutex, NULL, 0, 0, FALSE, DUPLICATE_CLOSE_SOURCE) == 0){
printerror("3");
return 3;
}
if(CloseHandle(hMutex) == 0){
printerror("4");
return 4;
}
return 0;
}
This code returns 0, but the mutex is still there, and I am not able to launch more games of Minesweeper. I think some of my parameters to DuplicateHandle are wrong.
The second argument to DuplicateHandle expects "an open object handle that is valid in the context of the source process", however I believe the handle you're passing in would only be valid within the current process (OpenMutex creates a new handle to an existing mutex object). You'll likely need to determine what the mutex's handle is in the remote process, and use that value when calling DuplicateHandle.