I try to get Handle ID of opened applications (windows).
I run Window detective program, (like spy++) to verify that I get proper values.
For testing I try to get only one Handle Id pointed by red arrow (see the image):
So I have program that gives me process id and thread Id but not 1st Child Handle ID.
In my case I took calc.exe, but actually I need to do that for all exe applications:
readWindow.c
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#include <tchar.h>
#include <psapi.h>
HMODULE getModulePid(DWORD processID, char* searchStr){ // gets the module by the module name from an explicit process
HANDLE hProcess;
HMODULE hMods[1024];
TCHAR szModName[MAX_PATH];
DWORD cbNeeded;
if(hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ))
{
if(EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
unsigned int k;
for(k = 0; k < (cbNeeded / sizeof(HMODULE)); ++k )
{
if (GetModuleFileNameEx(hProcess, hMods[k], szModName, sizeof(szModName)/sizeof(TCHAR)))
{
//printf( "fess pid: %u modname: %s\n", processID, szModName );
if(strstr(szModName, searchStr))
{
printf( "pid: %u modname: %s\n", processID, szModName );
CloseHandle( hProcess );
return hMods[k];
}
}
}//for
}
}
CloseHandle( hProcess );
return NULL;
}
HMODULE getModule(char* searchStr){ // gets the module by the modul name from all processes
DWORD aProcesses[1024], cbNeeded, cProcesses;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) return NULL;
cProcesses = cbNeeded / sizeof(DWORD);
HMODULE hmodule;
unsigned int i;
for (i = 0; i < cProcesses; ++i )
{
if(hmodule = getModulePid(aProcesses[i], searchStr))
{
return hmodule;
}
}
return NULL;
}
HMODULE getModuleHwnd(HWND hwnd){ // gets the module from a window
DWORD pid;
DWORD tid = GetWindowThreadProcessId(hwnd, &pid ); // !!??!!
printf( "hwnd tid: %u\n", tid );
printf( "hwnd pid: %u\n", pid );
return getModulePid(pid, ".exe");
}
HMODULE hModuleT;
char* searchStrT;
BOOL CALLBACK shownWindow(HWND hwnd, LPARAM lParam){ // EnumWindows callback
if(hModuleT) return TRUE;
char pcWinTitle[256];
if(GetWindow(hwnd, GW_OWNER)) return TRUE; // whats that?
GetWindowText(hwnd, pcWinTitle, 1024);
if(strstr(pcWinTitle, searchStrT)){
printf( "wndtitle: %s\n", pcWinTitle);
hModuleT = getModuleHwnd(hwnd);
}
return TRUE;
}
HMODULE getModuleByWndTitle(char* searchStr){ // gets the module from a window title
searchStrT = searchStr;
EnumWindows(shownWindow, 0);
return hModuleT;
}
int main()
{
//EnumWindows(EnumWindowsProc, 0);
printf("find by name ... \n");
getModule("calc.exe");
printf("\nfind by title ... \n");
getModuleByWndTitle("Calculator");
printf("Done");
return 0;
}
Run from minGW:
$ gcc -L/local/lib -I/local/include -o readWindow readWindow.c -lpsapi
Output:
find by title ...
wndtitle: Calculator
hwnd tid: 33364
hwnd pid: 25440
Done
How can I get the Handle from Process?
I'm sure it should be some 1-2 rows of code.
DWORD dwValue .....
printf("The value in hexa: 0X%.8X(%d).\n", dwValue);
it should be 0x007B137C
From Spy++ I need this value, red arrow:
It was pretty easy but for me tricky a bit.
I just need to print pointer HWND hwnd with %p.
So I added to my code:
char szBuff[512];
sprintf(szBuff, "%p", hwnd);
printf( "Found .... hWnd: %s\n", szBuff);
And got what I need:
Found .... hWnd: 007B137C
[EDIT]
Working code example:
readWindow.c
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#include <tchar.h>
#include <psapi.h>
HMODULE getModulePid(DWORD processID, char* searchStr){ // gets the module by the module name from an explicit process
HANDLE hProcess;
HMODULE hMods[1024];
TCHAR szModName[MAX_PATH];
DWORD cbNeeded;
if(hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ))
{
if(EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
unsigned int k;
for(k = 0; k < (cbNeeded / sizeof(HMODULE)); ++k )
{
if (GetModuleFileNameEx(hProcess, hMods[k], szModName, sizeof(szModName)/sizeof(TCHAR)))
{
//printf( "fess pid: %u modname: %s\n", processID, szModName );
if(strstr(szModName, searchStr))
{
printf( "pid: %u modname: %s\n", processID, szModName );
CloseHandle( hProcess );
return hMods[k];
}
}
}//for
}
}
CloseHandle( hProcess );
return NULL;
}
HMODULE getModule(char* searchStr){ // gets the module by the modul name from all processes
DWORD aProcesses[1024], cbNeeded, cProcesses;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) return NULL;
cProcesses = cbNeeded / sizeof(DWORD);
HMODULE hmodule;
unsigned int i;
for (i = 0; i < cProcesses; ++i )
{
if(hmodule = getModulePid(aProcesses[i], searchStr))
{
return hmodule;
}
}
return NULL;
}
HMODULE getModuleHwnd(HWND hwnd){ // gets the module from a window
DWORD pid;
DWORD tid = GetWindowThreadProcessId(hwnd, &pid ); // !!??!!
printf( "hwnd tid: %u\n", tid );
printf( "hwnd pid: %u\n", pid );
return getModulePid(pid, ".exe");
}
HMODULE hModuleT;
char* searchStrT;
BOOL CALLBACK shownWindow(HWND hwnd, LPARAM lParam){ // EnumWindows callback
if(hModuleT) return TRUE;
char pcWinTitle[256];
if(GetWindow(hwnd, GW_OWNER)) return TRUE; // whats that?
GetWindowText(hwnd, pcWinTitle, 1024);
if(strstr(pcWinTitle, searchStrT))
{
printf( "wndtitle: %s\n", pcWinTitle);
hModuleT = getModuleHwnd(hwnd);
char szBuff[512];
sprintf(szBuff, "%p", hwnd);
printf( "Found .... hWnd: %s\n", szBuff);
}
return TRUE;
}
HMODULE getModuleByWndTitle(char* searchStr){ // gets the module from a window title
searchStrT = searchStr;
EnumWindows(shownWindow, 0);
return hModuleT;
}
int main()
{
//EnumWindows(EnumWindowsProc, 0);
printf("find by name ... \n");
getModule("calc.exe");
printf("\nfind by title ... \n");
getModuleByWndTitle("Calculator");
printf("Done");
return 0;
}
Related
I'm using the EnumProcesses function to get all process IDs on the system. Then I iterate over each process ID and pass it to OpenProcess to get a process handle, which I then pass to GetProcessImageFileNameA to get the process name.
Here's a code snippet:
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>
DWORD GetProcessName(DWORD processID, TCHAR lpFileName, DWORD nSize)
{
HANDLE hProcess;
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
processID
);
if ( !hProcess )
return NULL;
// Write process name to buffer
if ( pLength = GetProcessImageFileNameA(hProcess, lpFileName, nSize) )
{
CloseHandle(hProcess);
return pLength;
}
CloseHandle(hProcess);
}
int main(void)
{
DWORD processIDs[PROC_ID_SIZE], cbNeeded, cProcess;
unsigned int i;
// Get process IDs
if ( !EnumProcesses(processIDs, sizeof(processIDs), &cbNeeded) )
return 1;
// Get process ID count
cProcess = cbNeeded / sizeof(DWORD);
printf("Number of Processes: %u | Size of Process Array: %d\n", cProcess, (int)sizeof(processIDs));
// Get the process name of each process
for (i = 0; i < cProcess; i++)
{
if ( processIDs[i] != 0 )
{
// The access violation is happening here
TCHAR processName[MAX_PATH];
GetProcessName(processIDs[i], processName, sizeof(processName));
printf("Process name: %s\n", (char*)processName);
}
}
return 0;
}
It compiles fine, but I get this runtime error:
Exception thrown at 0x00007FF985433338 (KernelBase.dll) in QuickSave.exe: 0xC0000005: Access violation writing location 0x000000000000F8D0.
I have a suspicion it's because I'm declaring processName from outside of the function's scope. When I create another function and declare processName within that function's scope, it works. I'm not entirely sure why.
DWORD PrintProcessName(DWORD processID)
{
HANDLE hProcess;
TCHAR processName[MAX_PATH];
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
processID
);
if (!hProcess)
return NULL;
// Write process name to buffer and print it
if ( pLength = GetProcessImageFileNameA(hProcess, processName, sizeof(processName)) )
{
printf("Process name: %s\n", (char*)processName);
return pLength;
}
CloseHandle(hProcess);
}
I'm still learning C so I'm probably making a newbie mistake, but hopefully someone can help me make sense of what's going on here.
I have fixed your code. The main errors was bad declaration of GetProcessName, wrong size passed for processName size, incorrect printf format specification, function doesn't always return a value, missing error checks.
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>
#define PROC_ID_SIZE 1000
DWORD GetProcessName(DWORD processID, TCHAR *lpFileName, DWORD nSize)
{
HANDLE hProcess;
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION,
FALSE,
processID
);
if (!hProcess)
return 0;
// Write process name to buffer
pLength = GetProcessImageFileNameW(hProcess, lpFileName, nSize);
CloseHandle(hProcess);
return pLength;
}
int main(void)
{
DWORD processIDs[PROC_ID_SIZE], cbNeeded, cProcess;
unsigned int i;
// Get process IDs
if (!EnumProcesses(processIDs, sizeof(processIDs), &cbNeeded))
return 1;
// Get process ID count
cProcess = cbNeeded / sizeof(DWORD);
printf("Number of Processes: %u | Size of Process Array: %d\n", cProcess, (int)sizeof(processIDs));
// Get the process name of each process
for (i = 0; i < cProcess; i++)
{
if (processIDs[i] != 0)
{
// The access violation is happening here
TCHAR processName[MAX_PATH];
if (GetProcessName(processIDs[i], processName, sizeof(processName)/sizeof(processName[0])))
printf("Process name: %ls\n", processName);
}
}
return 0;
}
I'm trying to get handles of windows. Then I was trying to get associated process id for every handle. But somehow, I'm magically get process_id out of nowhere. Please guide me here.
If I try to initialize process_id using GetWindowThreadProcessId() function, I encounter a runtime error.
However, if I comment out that part of code and let process_id print in both printf() functions, the programs runs successfully, displays data and exits cleanly. It should be garbage value here.
#include <stdio.h>
#include <windows.h>
WNDENUMPROC DisplayData(HWND str, LPARAM p) {
LPDWORD process_id;
DWORD P_ID;
printf("PID :: %x\n", process_id);
//this is where error occurs
//P_ID = GetWindowThreadProcessId(str, process_id);
printf("Found: %x, P_ID: %x\n", str, process_id);
return TRUE;
}
int main() {
EnumWindows( (WNDENUMPROC) DisplayData, 1);
return 0;
}
#include <stdio.h>
#include <windows.h>
LPDWORD target = (LPDWORD) 0; // Replace 0 with PID of the task from taskmgr.
HWND target_handle = NULL; // stores the handle of the target process
WNDENUMPROC DisplayData(HWND str, LPARAM p) {
LPDWORD thread_id;
DWORD process_id;
char title[30];
GetWindowTextA(str, (LPSTR) &title, 29);
process_id = GetWindowThreadProcessId(str, (PDWORD) &thread_id);
if( thread_id == target & IsWindowVisible(str) ) {
// Target thread with associated handle
// printf("Handle Addr: %lu, Thread ID: %lu, Process ID: %lu, Title: %s\n", str, thread_id, process_id, title );
target_handle = str;
}
return TRUE;
}
int main() {
EnumWindows( (WNDENUMPROC) DisplayData, 1);
ShowWindow(target_handle, SW_HIDE);
Sleep(1000);
ShowWindow(target_handle, SW_SHOW);
return 0;
}
The Thread ID shown by this code is the one that is displayed in Task Manager as PID. target_handle variable contains handle address after the execution of EnumWindows() function, just as required.
I'm new to Win32 programming.
I'm trying to pass a HANDLE obtained using CreateFile() to a function in a DLL.
But upon trying to read bytes, dwBytesRead says 0.
Am I allowed to pass HANDLEs to DLL entries? I read here [Writing DLLs] that resources of the caller do not belong to callee, and hence I should not call CloseHandle() or things like free() for malloc() in caller.
Is my understanding correct? Kindly point me in the right direction. Here's the code:
main.c
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFFERSIZE 5
int __declspec( dllimport ) hello( HANDLE );
void __cdecl _tmain(int argc, TCHAR *argv[])
{
HANDLE hFile;
printf("\n");
if( argc != 2 )
{
printf("Usage Error: Incorrect number of arguments\n\n");
_tprintf(TEXT("Usage:\n\t%s <text_file_name>\n"), argv[0]);
return;
}
hFile = CreateFile(argv[1], // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("Terminal failure: unable to open file \"%s\" for read.\n"), argv[1]);
return;
}
printf( "Entered main, calling DLL.\n" );
hello(hFile);
printf( "Back in main, exiting.\n" );
CloseHandle(hFile);
}
hello.c
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFFERSIZE 5
DWORD g_BytesTransferred = 0;
VOID CALLBACK FileIOCompletionRoutine(
__in DWORD dwErrorCode,
__in DWORD dwNumberOfBytesTransfered,
__in LPOVERLAPPED lpOverlapped )
{
_tprintf(TEXT("Error code:\t%x\n"), dwErrorCode);
_tprintf(TEXT("Number of bytes:\t%x\n"), dwNumberOfBytesTransfered);
g_BytesTransferred = dwNumberOfBytesTransfered;
}
int __declspec( dllexport ) hello( HANDLE hFile )
{
DWORD dwBytesRead = 0;
char ReadBuffer[BUFFERSIZE] = {0};
OVERLAPPED ol = {0};
if( FALSE == ReadFileEx(hFile, ReadBuffer, BUFFERSIZE-1, &ol, FileIOCompletionRoutine) )
{
DWORD lastError = GetLastError();
printf("Terminal failure: Unable to read from file.\n GetLastError=%08x\n", lastError);
return lastError;
}
dwBytesRead = g_BytesTransferred;
if (dwBytesRead > 0 && dwBytesRead <= BUFFERSIZE-1)
{
ReadBuffer[dwBytesRead]='\0';
printf("Data read from file (%d bytes): \n", dwBytesRead);
printf("%s\n", ReadBuffer);
}
else if (dwBytesRead == 0)
{
printf("No data read from file \n");
}
else
{
printf("\n ** Unexpected value for dwBytesRead ** \n");
}
printf( "Hello from a DLL!\n" );
return( 0 );
}
You are missing the SleepEx(5000, TRUE) call from the example.
You are using async-io, in which case you will receive a callback when the read occurs. If you don't wait for the callback you may get 0 bytes read depending on when the callback is triggered.
So I am trying to create a folder structure after a registry key. This is what I did so far
#include "stdafx.h"
#include "windows.h"
#define MAX_KEY_LENGTH 200
#define MAX_VALUE_NAME 16383
DWORD retCode;
void RecursiveQueryKey(HKEY hKey)
{
HKEY nextKey;
WCHAR achKey[MAX_KEY_LENGTH];
DWORD cbName;
DWORD retCode = NULL;
DWORD i=0;
while(retCode !=ERROR_NO_MORE_ITEMS)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i,achKey,&cbName,NULL,NULL,NULL,NULL);
if (retCode == ERROR_SUCCESS)
{
wprintf(L"(%d) %s\n", i+1, achKey);
WCHAR path[MAX_KEY_LENGTH];
wchar_t *wcsncat(wchar_t *path, const wchar_t *achKey, size_t n);
if(CreateDirectoryEx(TEXT("D:\\csso\\"),achKey, NULL) != 0){
wprintf(L"Directory created in D:\\csso\\%s\n", achKey);
} else {
printf("Directory failed with the error:");
}
wprintf(L"%d\n", GetLastError());
if(RegOpenKeyEx(hKey, achKey, 0, KEY_READ | KEY_WOW64_64KEY, &nextKey) == ERROR_SUCCESS)
{
RecursiveQueryKey(nextKey);
}
}
i++;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Apple Inc."), 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS)
{
printf("RegOpenKeyEx() is OK!\n");
RecursiveQueryKey(hKey);
}
else
printf("RegOpenKeyEx() failed!\n");
RegCloseKey(hKey);
}
I'm pretty new at this, but when I first run the program it says that directory's have all been created but they are not, when I run it again I get error 183 (Already Existent).
I'm really not sure what is the problem here.
OK so I figured it out, the problem came from my inability to create a path, apparently it was pretty simple, here is my final code, maybe it will help someone out.
#include "stdafx.h"
#include "windows.h"
#include "tchar.h"
#include <iostream>
#define KEY_LENGHT 255
#define MAX_VALUE_NAME 16000
#define DEFAULT_KEY L"Apple Inc."
WCHAR path[1024] = L"D:\\csso\\" DEFAULT_KEY;
void Query(HKEY key, WCHAR *path) {
HKEY next;
WCHAR name[KEY_LENGHT];
DWORD lpcname;
DWORD returncode = NULL;
DWORD i = 0;
WCHAR xpath[1024];
while(returncode != ERROR_NO_MORE_ITEMS) {
lpcname = KEY_LENGHT;
returncode =
RegEnumKeyEx(key, i, name, &lpcname, NULL, NULL, NULL, NULL);
if (returncode ==ERROR_SUCCESS) {
wcscpy(xpath, path);
wcscat(xpath, L"\\");
wcscat(xpath, name);
if(CreateDirectory(xpath, NULL)) {
wprintf(L"Creat Folder %s\n", xpath);
} else {
printf("Folder nu a putut fi creat! \n");
wprintf(L"%d\n", GetLastError());
}
DWORD verif =
RegOpenKeyEx(key, name, 0, KEY_READ | KEY_WOW64_64KEY, &next);
if(verif == ERROR_SUCCESS) {
Query(next, xpath);
}
i++;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key;
DWORD verif =
RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\" DEFAULT_KEY), 0, KEY_READ | KEY_WOW64_64KEY, &key);
if(verif == ERROR_SUCCESS) {
printf("RegOpenKeyEx SUCCESS! \n");
if(!CreateDirectory(_T("D:\\csso\\" DEFAULT_KEY), NULL)) {
printf("Folder nu a putut fi creat! \n");
} else {
Query(key, path);
}
} else {
printf("RegOpenKeyEx FAIL! \n");
wprintf(L"%d\n", GetLastError);
}
RegCloseKey(key);
}
Cheers and best of luck to you guys.
I'm using libuv. I've read http://nikhilm.github.com/uvbook/processes.html and still cannot work out how to capture the stdout of a child process so that it is available in the parent (but not in place of the parent's stdin).
My code is currently:
#include <stdio.h>
#include <stdlib.h>
#include "../../libuv/include/uv.h"
uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
uv_pipe_t apipe;
void on_child_exit(uv_process_t *req, int exit_status, int term_signal) {
fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal);
uv_close((uv_handle_t*) req, NULL);
}
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) {
printf("alloc_buffer called\n");
uv_buf_t buf;
buf.base = malloc(len);
buf.len = len;
return buf;
}
void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
printf("read %li bytes from the child process\n", nread);
}
int main(int argc, char *argv[]) {
printf("spawn_test\n");
loop = uv_default_loop();
char* args[3];
args[0] = "dummy";
args[1] = NULL;
args[2] = NULL;
uv_pipe_init(loop, &apipe, 0);
uv_pipe_open(&apipe, 0);
options.stdio_count = 3;
uv_stdio_container_t child_stdio[3];
child_stdio[0].flags = UV_IGNORE;
child_stdio[1].flags = UV_INHERIT_STREAM;
child_stdio[1].data.stream = (uv_stream_t *) &apipe;
child_stdio[2].flags = UV_IGNORE;
options.stdio = child_stdio;
options.exit_cb = on_child_exit;
options.file = args[0];
options.args = args;
uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe);
if (uv_spawn(loop, &child_req, options)) {
fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
return 1;
}
return uv_run(loop, UV_RUN_DEFAULT);
}
dummy.c:
#include <unistd.h>
#include <stdio.h>
int main() {
printf("child starting\n");
sleep(1);
printf("child running\n");
sleep(2);
printf("child ending\n");
return 0;
}
I have the nagging feeling that I do not quite understand the point of libuv's pipes yet.
I've found the solution:
I had the wrong flags, they should have been UV_CREATE_PIPE | UV_READABLE_PIPE not UV_INHERIT_STREAM.
I needed to call uv_read_start after uv_spawn. I assume that there's no chance of data loss, as uv_run has not yet been called.
The above two fixes showed all the output from dummy to arriving at once, rather than in three lumps (as it does on the command line). An fflush in dummy.c fixed this.
spawn_test:
#include <stdio.h>
#include <stdlib.h>
#include "../../libuv/include/uv.h"
uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
uv_pipe_t apipe;
void on_child_exit(uv_process_t *req, int exit_status, int term_signal) {
fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal);
uv_close((uv_handle_t*) req, NULL);
}
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) {
printf("alloc_buffer called, requesting a %lu byte buffer\n");
uv_buf_t buf;
buf.base = malloc(len);
buf.len = len;
return buf;
}
void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
printf("read %li bytes in a %lu byte buffer\n", nread, buf.len);
if (nread + 1 > buf.len) return;
buf.base[nread] = '\0'; // turn it into a cstring
printf("read: |%s|", buf.base);
}
int main(int argc, char *argv[]) {
printf("spawn_test\n");
loop = uv_default_loop();
char* args[3];
args[0] = "dummy";
args[1] = NULL;
args[2] = NULL;
uv_pipe_init(loop, &apipe, 0);
uv_pipe_open(&apipe, 0);
options.stdio_count = 3;
uv_stdio_container_t child_stdio[3];
child_stdio[0].flags = UV_IGNORE;
child_stdio[1].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
child_stdio[1].data.stream = (uv_stream_t *) &apipe;
child_stdio[2].flags = UV_IGNORE;
options.stdio = child_stdio;
options.exit_cb = on_child_exit;
options.file = args[0];
options.args = args;
if (uv_spawn(loop, &child_req, options)) {
fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
return 1;
}
uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe);
return uv_run(loop, UV_RUN_DEFAULT);
}
dummy.c:
#include <unistd.h>
#include <stdio.h>
int main() {
printf("child starting\n");
fflush(stdout);
sleep(1);
printf("child running\n");
fflush(stdout);
sleep(2);
printf("child ending\n");
fflush(stdout);
return 0;
}
See how they do it in the libuv unit test libuv/test/test-stdio-over-pipes.c:
Don't call uv_pipe_open
Flags for child's stdin: UV_CREATE_PIPE | UV_READABLE_PIPE
Flags for child's stdout and stderr: UV_CREATE_PIPE | UV_WRITABLE_PIPE
There is also an issue on Windows, where uv_spawn might return zero even though it encountered an error, and in those cases, you need to check process.spawn_error, which only exists on Windows.