How to use mutexs and processes? - c++

I have the "philosophers problem" to do, I need to use mutex as the lock (sticks) and five different proccesses to represent the philosofers, But I faced a few problems.
I dont know if the mutexes need to be in the file where I creates the proccesses and send them to the .exe that feed each philosofer with the given sticks, or in the .exe file where I feed the philosofers like I did with the switch case condition.
I dont know how do I send the parameters (philosofer number / mutexes) or more then one parameter to the main function in the .exe file.
UPDATED MY CODE!!
this is the main I run and create processes:
#include <iostream>
#include <windows.h>
HANDLE stick1;
HANDLE stick2;
HANDLE stick3;
HANDLE stick4;
HANDLE stick5;
int main()
{
stick1 = CreateMutexA(NULL, FALSE, "stick1");
stick1 = CreateMutexA(NULL, FALSE, "stick2");
stick1 = CreateMutexA(NULL, FALSE, "stick3");
stick1 = CreateMutexA(NULL, FALSE, "stick4");
stick1 = CreateMutexA(NULL, FALSE, "stick5");
LPSTR cmdArgs1 = const_cast <char*>("mutex.exe 1");
LPSTR cmdArgs2 = const_cast <char*>("mutex.exe 2");
LPSTR cmdArgs3 = const_cast <char*>("mutex.exe 3");
LPSTR cmdArgs4 = const_cast <char*>("mutex.exe 4");
LPSTR cmdArgs5 = const_cast <char*>("mutex.exe 5");
STARTUPINFOA si1;
STARTUPINFOA si2;
STARTUPINFOA si3;
STARTUPINFOA si4;
STARTUPINFOA si5;
PROCESS_INFORMATION pi1;
PROCESS_INFORMATION pi2;
PROCESS_INFORMATION pi3;
PROCESS_INFORMATION pi4;
PROCESS_INFORMATION pi5;
ZeroMemory(&si1, sizeof(si1));
si1.cb = sizeof(si1);
ZeroMemory(&pi1, sizeof(pi1));
ZeroMemory(&si2, sizeof(si2));
si2.cb = sizeof(si2);
ZeroMemory(&pi2, sizeof(pi2));
ZeroMemory(&si3, sizeof(si3));
si3.cb = sizeof(si3);
ZeroMemory(&pi3, sizeof(pi3));
ZeroMemory(&si4, sizeof(si4));
si4.cb = sizeof(si4);
ZeroMemory(&pi4, sizeof(pi4));
ZeroMemory(&si5, sizeof(si5));
si5.cb = sizeof(si5);
ZeroMemory(&pi5, sizeof(pi5));
BOOL p1 = CreateProcessA(NULL, cmdArgs1, NULL, NULL, FALSE, 0, NULL, NULL, &si1, &pi1);
BOOL p2 = CreateProcessA(NULL, cmdArgs2, NULL, NULL, FALSE, 0, NULL, NULL, &si2, &pi2);
BOOL p3 = CreateProcessA(NULL, cmdArgs3, NULL, NULL, FALSE, 0, NULL, NULL, &si3, &pi3);
BOOL p4 = CreateProcessA(NULL, cmdArgs4, NULL, NULL, FALSE, 0, NULL, NULL, &si4, &pi4);
BOOL p5 = CreateProcessA(NULL, cmdArgs5, NULL, NULL, FALSE, 0, NULL, NULL, &si5, &pi5);
if (p1 && p2 && p3 && p4 && p5)
{
WaitForSingleObject(pi1.hProcess, INFINITE);
WaitForSingleObject(pi2.hProcess, INFINITE);
WaitForSingleObject(pi3.hProcess, INFINITE);
WaitForSingleObject(pi4.hProcess, INFINITE);
WaitForSingleObject(pi5.hProcess, INFINITE);
CloseHandle(pi1.hProcess);
CloseHandle(pi1.hThread);
CloseHandle(pi2.hProcess);
CloseHandle(pi2.hThread);
CloseHandle(pi3.hProcess);
CloseHandle(pi3.hThread);
CloseHandle(pi4.hProcess);
CloseHandle(pi4.hThread);
CloseHandle(pi5.hProcess);
CloseHandle(pi5.hThread);
}
}
and this is the .exe file:
#include <iostream>
#include <windows.h>
#include <chrono>
#define TIMES_TO_EAT 1000000
#pragma warning(disable : 4996)
int main(int argc, char* argv[])
{
HANDLE rightStick;
HANDLE leftStick;
int i = 0;
char id = argv[1][0]; // supposed to be the number of the philosofer
char rightS[] = "stick";
char leftS[] = "stick";
char leftStickCalc = (char)((int)id - 1);
if (id == '1')
{
leftStickCalc = '5';
}
strncat(rightS, &id, 1);
strncat(leftS, &leftStickCalc, 1);
auto start = std::chrono::system_clock::now();
while (i < TIMES_TO_EAT)
{
rightStick = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, LPSTR(rightS));
if (rightStick != NULL)
{
leftStick = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, LPSTR(leftS));
if (leftStick != NULL)
{
i++;
ReleaseMutex(rightStick);
ReleaseMutex(leftStick);
if (i == TIMES_TO_EAT)
{
CloseHandle(rightStick);
CloseHandle(leftStick);
}
}
else
{
ReleaseMutex(rightStick);
}
}
}
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> time = end - start;
printf("philosopher %c finished eat %d times in %.2f seconds\n", id, i, time.count());
system("PAUSE");
return 0;
}

Related

WriteFile and ReadFile on child process's stdio (using overlapped named pipe)

I want to read asynchronously from a child process's stdin, so I create an IOCP loop that listens for when ReadFile() is done. But ReadFile() is never done, it always returns ERROR_IO_PENDING, and WriteFile() always returns ERROR_IO_PENDING.
Node.js can asynchronously read from a child process:
const child_process = require("child_process")
var p = child_process.spawn("gcc")
p.stdout.on('data', data=>console.log(String(data)))
p.stderr.on('data', data=>console.log(String(data)))
How to do this in the Win32 API?
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <wchar.h>
#pragma comment (lib, "User32.lib")
static HANDLE iocp = INVALID_HANDLE_VALUE;
typedef struct PROCESS {
OVERLAPPED ol;
HANDLE hProcess,
stdin_read, stdin_write,
stdout_read, stdout_write,
stderr_read, stderr_write;
char buf[100];
} PROCESS, *PPROCESS, *LPROCESS;
DWORD WINAPI Worker(LPVOID param);
BOOL create_pipe(HANDLE* pserver_pipe, HANDLE* pclient_pipe, PROCESS* p) {
static __int64 counter=0;
HANDLE server_pipe, client_pipe;
int err;
WCHAR name[64];
for (;;) {
swprintf(name, sizeof(name), L"\\\\?\\pipe\\child\\%Id.%p", counter, p);
server_pipe = CreateNamedPipeW(
name,
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
65536,
65536,
0,
NULL);
if (server_pipe != INVALID_HANDLE_VALUE)
break;
err = GetLastError();
if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
return FALSE;
}
counter++;
}
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = 1;
client_pipe = CreateFileW(name,
GENERIC_READ|WRITE_DAC,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (client_pipe==INVALID_HANDLE_VALUE){
return FALSE;
}
if (CreateIoCompletionPort(client_pipe, iocp, (ULONG_PTR)p, 0)==NULL){
return FALSE;
}
if (CreateIoCompletionPort(server_pipe, iocp, (ULONG_PTR)p, 0)==NULL){
return FALSE;
}
*pclient_pipe = client_pipe;
*pserver_pipe = server_pipe;
return TRUE;
}
int wmain()
{
iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
assert(iocp);
PROCESS child_process{};
assert(create_pipe(&child_process.stdout_write, &child_process.stdout_read, &child_process));
assert(create_pipe(&child_process.stderr_write, &child_process.stderr_read, &child_process));
assert(create_pipe(&child_process.stdin_write, &child_process.stdin_read, &child_process));
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL);
assert(hThread);
WCHAR szCmdline[]=L"cmd";
PROCESS_INFORMATION piProcInfo{};
STARTUPINFOW siStartInfo{.cb = sizeof(STARTUPINFO),
.dwFlags=STARTF_USESTDHANDLES,
.hStdInput=child_process.stdin_read,
.hStdOutput=child_process.stdout_write,
.hStdError=child_process.stderr_write};
assert(CreateProcessW(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo));
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
// CloseHandle(child_process.stdout_write);
// CloseHandle(child_process.stdin_read);
ReadFile(child_process.stdout_read, child_process.buf, sizeof(child_process.buf), NULL, &child_process.ol);
int err = GetLastError();
if (err!=ERROR_IO_PENDING){
printf("Error in ReadFile %d\n", err);
}else{
puts("ReadFile is pending...\n");
}
char buf[100];
DWORD dwIn;
for(;;){
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buf, sizeof buf, &dwIn, NULL);
if (dwIn<=0)
break;
WriteFile(child_process.stdin_write, buf, dwIn, NULL, &child_process.ol);
err = GetLastError();
if (err!=ERROR_IO_PENDING){
printf("Error in WriteFile %d\n", err);
}else{
puts("WriteFile is pending...\n");
}
}
PostQueuedCompletionStatus(iocp, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(iocp);
}
DWORD WINAPI Worker(LPVOID param) {
DWORD dwIoSize = 0;
LPOVERLAPPED ol;
PROCESS* ctx;
for(;;){
BOOL bSuccess = GetQueuedCompletionStatus((HANDLE)param, &dwIoSize,
(PDWORD_PTR)&ctx,
&ol,
INFINITE);
if (ctx == NULL) {
printf("ctx is NULL, maybe you call PostQueuedCompletionStatus? err=%d\n", GetLastError());
break;
}
if (bSuccess==FALSE || dwIoSize == 0) {
printf("GetQueuedCompletionStatus does not success(maybe EOF reached?) err=%d\n", GetLastError());
break;
}
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ctx->buf, dwIoSize, NULL, NULL);
ReadFile(ctx->stdout_read, ctx->buf, sizeof(ctx->buf), NULL, &ctx->ol);
}
return 0;
}
After search on Github, it's quite easy.
Create a Named Pipe for current process(read), and create a File for child process(write).
Github links:
https://github.com/parasol-framework/parasol/blob/c5ad64188c7496e3ff54eb75fd03c9e3124fe08b/src/core/microsoft/processes.c
https://github.com/dinamsky/malware-botnets/blob/4cd142d10f971cb93c334b6f48c12c85bcc8f63a/Phatbot-stoney/Phatbot-stoney/cmdshell.cpp
https://github.com/grimjoey/jlstudio/blob/e5d2d81f0a94d2020f2e912e43a487d9cb6f7c33/src/jls/process.cpp
https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_ESP32-S2_SDK/blob/7d75213674b4572f90c68162ad6fe9b16dae65ad/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c
https://github.com/LeonColt/skripsi/blob/141af593ec65cd7adaedf7a90fc4cd7cde5cc602/Maschinen/RedirectIOChildProcess.cpp
redirect stdout and stderr
#include <windows.h>
#include <assert.h>
#include <stdio.h>
struct Stdio;
typedef void (*Callback)(struct Stdio* self, DWORD len);
struct Stdio {
OVERLAPPED ol;
HANDLE pipe;
BYTE buf[100];
Callback callback;
};
typedef struct CTX {
struct Stdio Stdout, Stderr, Stdin;
} CTX, *LCTX, *LPCTX;
HANDLE Hstdout=INVALID_HANDLE_VALUE;
HANDLE Hstderr=INVALID_HANDLE_VALUE;
DWORD WINAPI Worker(LPVOID iocp){
struct Stdio *stdio;
OVERLAPPED *ol;
DWORD dwIoSize;
for(;;){
if (!GetQueuedCompletionStatus(iocp, &dwIoSize, (PDWORD_PTR)&stdio, &ol, INFINITE) || dwIoSize==0 || ol==NULL || stdio==NULL){
switch (GetLastError()){
case ERROR_BROKEN_PIPE:
puts("the process has been exited, exit thread...");
break;
default:
printf("error = %d, exit thread\n", GetLastError());
}
break;
}
stdio->callback(stdio, dwIoSize);
}
return 0;
}
void OnStdoutRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstdout, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStderrRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstderr, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
int wmain(){
assert(Hstdout = GetStdHandle(STD_OUTPUT_HANDLE));
assert(Hstderr = GetStdHandle(STD_ERROR_HANDLE));
HANDLE Pstdout, Pstderr; // child process's
CTX ctx{.Stdout=Stdio{.callback=OnStdoutRead}, .Stderr=Stdio{.callback=OnStderrRead}};
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL); // Worker thread
SECURITY_ATTRIBUTES sa{.nLength=sizeof(SECURITY_ATTRIBUTES), .bInheritHandle=TRUE};
const WCHAR* pipe_name1 = L"\\\\.\\Pipe\\child-1";
assert((ctx.Stdout.pipe = CreateNamedPipeW(
pipe_name1,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert(INVALID_HANDLE_VALUE != (Pstdout = CreateFileW(
pipe_name1,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL)));
const WCHAR *pipe_name2 = L"\\\\.\\Pipe\\child-2";
assert((ctx.Stderr.pipe = CreateNamedPipeW(
pipe_name2,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((Pstderr = CreateFileW(
pipe_name2,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
STARTUPINFOW si{.cb = sizeof(si),
.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW,
.wShowWindow = SW_HIDE,
.hStdInput = GetStdHandle(STD_INPUT_HANDLE), // use current stdin
.hStdOutput = Pstdout,
.hStdError = Pstderr};
WCHAR cmd[] = L"powershell"; // or cmd, py, bash...
PROCESS_INFORMATION pInfo{};
assert(CreateProcessW(
NULL, cmd, NULL, NULL,
TRUE, 0, NULL, NULL,
&si, &pInfo));
assert(CloseHandle(Pstdout)); // we don't need this
assert(CloseHandle(Pstderr)); // we don't need this
assert(CreateIoCompletionPort(ctx.Stdout.pipe, iocp, (ULONG_PTR)&ctx.Stdout, 0));
assert(CreateIoCompletionPort(ctx.Stderr.pipe, iocp, (ULONG_PTR)&ctx.Stderr, 0));
ReadFile(ctx.Stdout.pipe, ctx.Stdout.buf, sizeof(ctx.Stdout.buf), NULL, &ctx.Stdout.ol);
ReadFile(ctx.Stderr.pipe, ctx.Stdout.buf, sizeof(ctx.Stderr.buf), NULL, &ctx.Stderr.ol);
WaitForSingleObject(pInfo.hProcess, INFINITE); // wait for process exit
PostQueuedCompletionStatus(iocp, 0, 0, NULL); // tell IOCP Worker exit
WaitForSingleObject(hThread, INFINITE); // wait for thread exit
assert(CloseHandle(hThread));
assert(CloseHandle(ctx.Stderr.pipe));
assert(CloseHandle(ctx.Stdout.pipe));
assert(CloseHandle(pInfo.hProcess));
assert(CloseHandle(iocp));
assert(CloseHandle(Hstderr));
puts("exit main function..."); // !!important: before close stdout
assert(CloseHandle(Hstdout));
}
Redirect stdin, stdout, stderr
#include <windows.h>
#include <assert.h>
#include <stdio.h>
static HANDLE Hstdout, Hstderr, Hstdin, HstopEvent;
struct Stdio;
typedef void (*Callback)(struct Stdio* self, DWORD len);
struct Stdio {
OVERLAPPED ol;
HANDLE pipe;
BYTE buf[100];
Callback callback;
};
typedef struct CTX {
struct Stdio Stdout, Stderr, Stdin;
} CTX, *LCTX, *LPCTX;
DWORD WINAPI Worker(LPVOID iocp){
struct Stdio *stdio;
OVERLAPPED *ol;
DWORD dwIoSize;
for(;;){
if (!GetQueuedCompletionStatus(iocp, &dwIoSize, (PDWORD_PTR)&stdio, &ol, INFINITE) || dwIoSize==0 || ol==NULL || stdio==NULL){
switch (GetLastError()){
case ERROR_BROKEN_PIPE:
SetEvent(HstopEvent);
puts("the process has been exited, exit thread...");
break;
default:
printf("error = %d, exit thread\n", GetLastError());
}
break;
}
stdio->callback(stdio, dwIoSize);
}
return 0;
}
void OnStdoutRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstdout, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStderrRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstderr, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStdinWriteComplete(struct Stdio *self, DWORD len){
printf("[%u bytes write to stdin]\n", len);
}
int wmain(){
assert((Hstdout = GetStdHandle(STD_OUTPUT_HANDLE))!=INVALID_HANDLE_VALUE);
assert((Hstderr = GetStdHandle(STD_ERROR_HANDLE))!=INVALID_HANDLE_VALUE);
assert((Hstdin = GetStdHandle(STD_INPUT_HANDLE))!=INVALID_HANDLE_VALUE);
assert((HstopEvent=CreateEventW(NULL, FALSE, FALSE, NULL))!=INVALID_HANDLE_VALUE);
CTX ctx{.Stdout=Stdio{.callback=OnStdoutRead}, .Stderr=Stdio{.callback=OnStderrRead}, .Stdin=Stdio{.callback=OnStdinWriteComplete}};
STARTUPINFOW si{.cb = sizeof(si), .dwFlags = STARTF_USESTDHANDLES};
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL); // Worker thread
SECURITY_ATTRIBUTES sa{.nLength=sizeof(SECURITY_ATTRIBUTES), .bInheritHandle=TRUE};
const WCHAR* pipe_name1 = L"\\\\.\\Pipe\\child-1";
assert((ctx.Stdout.pipe = CreateNamedPipeW(
pipe_name1,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdOutput = CreateFileW(
pipe_name1,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
const WCHAR *pipe_name2 = L"\\\\.\\Pipe\\child-2";
assert((ctx.Stderr.pipe = CreateNamedPipeW(
pipe_name2,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdError = CreateFileW(
pipe_name2,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
const WCHAR *pipe_name3 = L"\\\\.\\Pipe\\child-3";
assert((ctx.Stdin.pipe = CreateNamedPipeW(
pipe_name3,
PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdInput = CreateFileW(
pipe_name3,
GENERIC_READ,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
WCHAR cmd[] = L"powershell"; // or cmd, py, bash...
PROCESS_INFORMATION pInfo{};
assert(CreateProcessW(
NULL, cmd, NULL, NULL,
TRUE, 0, NULL, NULL,
&si, &pInfo));
assert(CloseHandle(si.hStdError)); // we don't need this
assert(CloseHandle(si.hStdInput)); // we don't need this
assert(CloseHandle(si.hStdOutput)); // we don't need this
assert(CreateIoCompletionPort(ctx.Stdout.pipe, iocp, (ULONG_PTR)&ctx.Stdout, 0));
assert(CreateIoCompletionPort(ctx.Stderr.pipe, iocp, (ULONG_PTR)&ctx.Stderr, 0));
ReadFile(ctx.Stdout.pipe, ctx.Stdout.buf, sizeof(ctx.Stdout.buf), NULL, &ctx.Stdout.ol);
ReadFile(ctx.Stderr.pipe, ctx.Stdout.buf, sizeof(ctx.Stderr.buf), NULL, &ctx.Stderr.ol);
DWORD dwIoSize;
for(;;){
CHAR buf[100];
ReadConsoleA(Hstdin, buf, sizeof(buf), &dwIoSize, NULL);
if (WaitForSingleObject(HstopEvent, 0)==WAIT_OBJECT_0)
break;
WriteFile(ctx.Stdin.pipe, buf, dwIoSize, NULL, &ctx.Stdin.ol);
if (WaitForSingleObject(HstopEvent, 0)==WAIT_OBJECT_0)
break;
}
PostQueuedCompletionStatus(iocp, 0, 0, NULL); // tell IOCP Worker exit
WaitForSingleObject(hThread, INFINITE); // wait for thread exit
assert(CloseHandle(hThread));
assert(CloseHandle(ctx.Stderr.pipe));
assert(CloseHandle(ctx.Stdout.pipe));
assert(CloseHandle(pInfo.hProcess));
assert(CloseHandle(iocp));
assert(CloseHandle(Hstderr));
assert(CloseHandle(HstopEvent));
puts("exit main function..."); // !!important: before close stdout
assert(CloseHandle(Hstdout));
}

CreateProcessA fails for some programs

Found the below snippet here on SO:
https://stackoverflow.com/a/35658917/9265719.
It executes a command without creating a window. CreateProcessA() returns TRUE for cmd.exe but for any program in C:\Program Files(x86)\Windows Kits\10\Debuggers\x64\ it returns FALSE and GetLastError() returns 2 (ERROR_PATH_NOT_FOUND).
Why is it failing to create a process for programs in this directory?
#include <iostream>
#include <windows.h>
//
// Execute a command and get the results. (Only standard output)
//
std::string ExecCmd(
char cmd[] // [in] command to execute
)
{
std::string strResult;
HANDLE hPipeRead, hPipeWrite;
SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
saAttr.bInheritHandle = TRUE; // Pipe handles are inherited by child process.
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe to get results from child's stdout.
if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0))
return strResult;
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdOutput = hPipeWrite;
si.hStdError = hPipeWrite;
si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing.
// Requires STARTF_USESHOWWINDOW in dwFlags.
PROCESS_INFORMATION pi = { 0 };
BOOL fSuccess = ::CreateProcessA(NULL, cmd, NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
if (!fSuccess)
{
DWORD dw = GetLastError();
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
return strResult;
}
bool bProcessEnded = false;
for (; !bProcessEnded;)
{
// Give some timeslice (50 ms), so we won't waste 100% CPU.
bProcessEnded = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0;
// Even if process exited - we continue reading, if
// there is some data available over pipe.
for (;;)
{
char buf[1024];
DWORD dwRead = 0;
DWORD dwAvail = 0;
if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
break;
if (!dwAvail) // No data available, return
break;
if (!::ReadFile(hPipeRead, buf, min(sizeof(buf) - 1, dwAvail), &dwRead, NULL) || !dwRead)
// Error, the child process might ended
break;
buf[dwRead] = 0;
strResult += buf;
}
} //for
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return strResult;
} //ExecCmd
int main()
{
//char cmd[1000] = R"("C:\WINDOWS\system32\cmd.exe")";
char cmd[1000] = R"("C:\Program Files(x86)\Windows Kits\10\Debuggers\x64\cdb.exe")";
std::string op = ExecCmd(cmd);
std::cout << op.c_str();
}
You are missing a space in the path, between "Program Files" and "(x86)". Should be:
char cmd[1000] = R"("C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe")";

::SendMessage(apphwnd, WM_GETTEXTLENGTH, 0, 0) return 0

I use ::CreateProcess to create a subprocess, and use ::EnumWindows(&EnumWindowsProc, processInfo.dwThreadId) to get the subprocess's window handle, assign this handle to a global variable apphwnd, then I use length = ::SendMessage(apphwnd, WM_GETTEXTLENGTH, 0, 0); but the length is sometimes is zero.
Why is my subprocess's window handle valid but the windowText sometimes has no value? When can I operate on the window handle correctly after CreateProcess is done?
Here is EnumWindowsProc code :
HWND apphwnd;
int CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param)
{
CString str;
DWORD pID;
DWORD TpID = GetWindowThreadProcessId(hwnd, &pID);//get process id
std::string hwndProcessName = GetProcessNameByHandle(hwnd);
if (TpID == (DWORD)param)
{
apphwnd = hwnd;//hwnd is the window handle
return false;
}
return true;
}
Here is my StartProcess function code:
PROCESS_INFORMATION StartProcess(LPCTSTR program, LPCTSTR args, int sleepTime = 500, STARTUPINFO *pstartupInfo = NULL, DWORD dwCreationFlags = 0, bool isWaitInput = false)
{
HANDLE hProcess = NULL;
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
::ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
if(::CreateProcess(program, (LPTSTR)args,
NULL, // process security
NULL, // thread security
FALSE, // no inheritance
dwCreationFlags, // no startup flags
NULL, // no special environment
NULL, // default startup directory
&startupInfo,
&processInfo))
{
Sleep(500);
if (true)
{
WaitForInputIdle(processInfo.hProcess, INFINITE);
}
apphwnd = NULL;
hProcess = processInfo.hProcess;
while(true)
{
::EnumWindows(&EnumWindowsProc, processInfo.dwThreadId);//Iterate all windows
if (apphwnd)
{
break;
}
}
} /* success */
return processInfo;
}
Here is what Spy++ shows:

How do I set semaphores properly with my two processes program?

How can I properly make the 2nd process wait for the 1st process to write the coefficients to a file?
My task is to synchronize 2 processes using semaphores. The 1st process reads the data, writes to the file, then the 2nd process reads this data and finds the solution, which then writes to the file, and then the 1st process reads this solution from the file and outputs the solution to the console.
/Here is the parent file:/
#include "stdafx.h"
const char* FIRST_SEMAPHORE = "Semaphore1";
const char* SECOND_SEMAPHORE = "Semaphore2";
const char* FIRST_PROCESS = "Lab2_first.exe";
const char* SECOND_PROCESS = "Lab2_second.exe";
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO sInfo;
PROCESS_INFORMATION pInfo;
CreateSemaphore(NULL, 0, 1, (LPCWSTR) FIRST_SEMAPHORE);
CreateSemaphore(NULL, 0, 1, (LPCWSTR) SECOND_SEMAPHORE);
GetStartupInfo(&sInfo);
if(!CreateProcess(ConvertLPCSTRToLPWSTR(SECOND_PROCESS), NULL, NULL,
NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo))
{
printf("Second process failed: %d\n", GetLastError());
}
if(!CreateProcess(ConvertLPCSTRToLPWSTR(FIRST_PROCESS), NULL, NULL,
NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo))
{
printf("First process failed: %d\n", GetLastError());
}
return 0;
}
/Here is process 1 (Lab2_first):/
#include "stdafx.h"
#include "windows.h"
const char* FIRST_SEMAPHORE = "Semaphore1";
const char* SECOND_SEMAPHORE = "Semaphore2";
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE semaphore1, semaphore2;
semaphore1 = OpenSemaphore(EVENT_ALL_ACCESS, TRUE,
ConvertLPCSTRToLPWSTR(FIRST_SEMAPHORE));
semaphore2 = OpenSemaphore(EVENT_ALL_ACCESS, TRUE,
ConvertLPCSTRToLPWSTR(SECOND_SEMAPHORE));
Equation equation;
printf("Enter coefficients: ");
scanf("%d %d %d", &equation.a, &equation.b, &equation.c);
HANDLE file = CreateFile(ConvertLPCSTRToLPWSTR("equation"),
GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
DWORD number = sizeof(equation);
LPDWORD numberOfBytesWritten = &number;
WriteFile(file, &equation, sizeof(equation), numberOfBytesWritten,
NULL);
printf("1: write to file");
ReleaseSemaphore(semaphore1, 1, NULL);
WaitForSingleObject(semaphore2, INFINITE);
ReadFile(file, &equation, sizeof(equation), numberOfBytesWritten,
NULL);
if(equation.hasSolution)
{
printf("Solution");
} else {
printf("No solution");
}
char data[10];
scanf("%s", data);
return 0;
}
/Here is the 2nd process (Lab2_second):/
#include "stdafx.h"
#include "windows.h"
const char* FIRST_SEMAPHORE = "Semaphore1";
const char* SECOND_SEMAPHORE = "Semaphore2";
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE semaphore1, semaphore2;
semaphore1 = OpenSemaphore(EVENT_ALL_ACCESS, TRUE, `enter code
here`ConvertLPCSTRToLPWSTR(FIRST_SEMAPHORE));
semaphore2 = OpenSemaphore(EVENT_ALL_ACCESS, TRUE,
ConvertLPCSTRToLPWSTR(SECOND_SEMAPHORE));
WaitForSingleObject(semaphore1, INFINITE);
printf("2: read from file");
HANDLE file = CreateFile(ConvertLPCSTRToLPWSTR("equation"),
GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
Equation equation;
DWORD number = sizeof(equation);
LPDWORD numberOfBytesWritten = &number;
ReadFile(file, &equation, sizeof(equation), numberOfBytesWritten,
NULL);
// todo
equation.hasSolution = FALSE;
WriteFile(file, &equation, sizeof(equation), numberOfBytesWritten,
NULL);
ReleaseSemaphore(semaphore2, 1, NULL);
return 0;
}
The question is: why when the parent starts, the 2nd process does not wait until the 1st release semaphore1 (that is, the 2nd process does not react to WaitForSingleObject (semaphore1, INFINITE)) and reads from the file from the very start (this is clear during startup: the 2nd process immediately displays "2: read from file"), but there is nothing there. How can I properly make the 2nd process wait for the 1st process to write the coefficients to a file?

C++ CreateProcess 'telnet' is not recognized

When I pass the ipconfig command to the process, it stores the correct results in files.
char cmd[] = "C:\\windows\\system32\\cmd.exe /c ipconfig";
SaveResult("ipconfig1.txt", NULL, cmd);
char appName[] = "C:\\windows\\system32\\cmd.exe";
char cmd2[] = "/c ipconfig";
SaveResult("ipconfig2.txt", appName, cmd2);
But when i pass wuauclt or telnet
char cmd1[] = "C:\\windows\\system32\\cmd.exe /c telnet";
SaveResult("telnet1.txt", NULL, cmd1);
char appName3[] = "C:\\windows\\system32\\cmd.exe";
char cmd3[] = "/c telnet";
SaveResult("telnet2.txt", appName3, cmd3);
char cmd4[] = "C:\\windows\\system32\\cmd.exe /c wuauclt";
SaveResult("wuauclt1.txt", NULL, cmd4);
char appName5[] = "C:\\windows\\system32\\cmd.exe";
char cmd5[] = "/c wuauclt";
SaveResult("wuauclt2.txt", appName5, cmd5);
I get
'wuauclt' is not recognized as an internal or external command,
operable program or batch file.
'telnet' is not recognized as an internal or external command,
operable program or batch file.
How to fix this problem and why it happens? Do it possible to launch through cmd.exe telnet or wuauclt?
Also on this PC wuauclt and telnet in common console opened from start working like expected.
#include "stdafx.h"
#include "windows.h"
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
void SaveResult(const char *fileName, const char *appName, const char *commandLine)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE h = CreateFile(convertCharArrayToLPCWSTR(fileName),
FILE_APPEND_DATA,
FILE_SHARE_WRITE | FILE_SHARE_READ,
&sa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL ret = FALSE;
DWORD flags = CREATE_NO_WINDOW;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = NULL;
si.hStdError = h;
si.hStdOutput = h;
ret = CreateProcess(appName==NULL ? NULL : convertCharArrayToLPCWSTR(appName), commandLine == NULL ? NULL : convertCharArrayToLPCWSTR(commandLine), NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
if (ret)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(h);
}
}
int main()
{
char cmd[] = "C:\\windows\\system32\\cmd.exe /c ipconfig";
SaveResult("ipconfig1.txt", NULL, cmd);
char appName[] = "C:\\windows\\system32\\cmd.exe";
char cmd2[] = "/c ipconfig";
SaveResult("ipconfig2.txt", appName, cmd2);
char cmd1[] = "C:\\windows\\system32\\cmd.exe /c telnet";
SaveResult("telnet1.txt", NULL, cmd1);
char appName3[] = "C:\\windows\\system32\\cmd.exe";
char cmd3[] = "/c telnet";
SaveResult("telnet2.txt", appName3, cmd3);
char cmd4[] = "C:\\windows\\system32\\cmd.exe /c wuauclt";
SaveResult("wuauclt1.txt", NULL, cmd4);
char appName5[] = "C:\\windows\\system32\\cmd.exe";
char cmd5[] = "/c wuauclt";
SaveResult("wuauclt2.txt", appName5, cmd5);
return -1;
}
If you type in ipconfig in console window, the process will show IP information and exit.
On the other hand, if you type in telnet in console window, the process will show a prompt and waits for a response. The process does not finished automatically.
When you run this command with CreateProcess, CreateProcess will return immediately, but the process is not finished. Then you try to close the file handle which is still being used by telnet.
You can use WaitForSingleObject to wait until the process is complete. In the case of telnet the process doesn't complete. The example below demonstrates this problem.
For CreateProcess, supply the whole command line as the second parameter. Make sure the character buffer is writable, and freed at the end.
Side note, it is recommended to use wide character string for a Unicode program. It's fine to promote ANSI to UTF16, but not much is gained in this case. You can also use CreateProcessA along with STARTUPINFOA si = { sizeof(si) }; which accept ANSI character.
void SaveResult(const wchar_t *fileName, const wchar_t *commandLine)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE h = CreateFile(fileName, FILE_WRITE_DATA, FILE_SHARE_WRITE | FILE_SHARE_READ,
&sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(h == INVALID_HANDLE_VALUE)
return;
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { sizeof(si) };
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = NULL;
si.hStdError = h;
si.hStdOutput = h;
wchar_t *writable_cmdline = _wcsdup(commandLine);
BOOL success = CreateProcess(NULL, writable_cmdline,
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
bool finished = false;
//wait for 1 second
for(int i = 0; i < 10; i++)
{
if(WaitForSingleObject(pi.hProcess, 100) <= 0)
{
finished = true;
break;
}
}
if(success)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
CloseHandle(h);
free(writable_cmdline);
if(!finished)
printf("Process didn't finish\n");
}
int main()
{
SaveResult(L"telnet.txt", L"C:\\windows\\system32\\cmd.exe /c telnet");
SaveResult(L"ipconfig.txt", L"C:\\windows\\system32\\cmd.exe /c ipconfig");
return 0;
}