3

I am trying to send a message to stdin of an existing process. This process writes to stdout, and therefore a command prompt is visible when the process is running.

I have looked here, but it is specific to .net. I would like to use C with the winapi.

Here is what I have tried:
I launch an exe that runs in a command prompt. When launched, the Process ID and Process Handle for the exe are captured by calling GetHandleOfProcessByExeName() (below). My understanding , through reading the MSDN page on WriteFile(), that I should be able to pass the handle of the process along with some text to the process pointed to by the handle. Say "prg.exe", is running on Windows 7. I get its process handle, then pass it along with a message to WriteToProcess().

I expect to see text appear on the command prompt, but this has not happened yet.

Relevant code:

int main(void)
{
    HANDLE h = GetHandleOfProcessByExeName("prg.exe");

    //this continually fails (returns FALSE)
    BOOL status = WriteToProcess("test message", sizeof("test message"));
    return 0;
}  

HANDLE GetHandleOfProcessByExeName(char *exe)
{
    PROCESSENTRY32 entry;
    HANDLE hProcess=0;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (stricmp(entry.szExeFile, exe) == 0)
            {  
                hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

                CloseHandle(hProcess);
            }
        }
    }

    CloseHandle(snapshot);
    return hProcess;
}

BOOL WriteToProcess(char *msg, size_t size)
{
    BOOL status = FALSE;

    status = WriteFile(gStdinWrite, msg, size, NULL, NULL);

    return status; //TRUE for success   
}

Edit to response to comments:

defined as file globals:

HANDLE gStdinRead = NULL;
HANDLE gStdinWrite = NULL;

int SystemX(char *cmd, int index)
{
    STARTUPINFO sj;
    PROCESS_INFORMATION pj;
    SECURITY_ATTRIBUTES saAttr; 
    HANDLE h = 0;
    int exit;

    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    ZeroMemory( &sj, sizeof(sj) );
    sj.cb = sizeof(sj);
    ZeroMemory( &pj, sizeof(pj) );
    //create pipe and pass read end to CreateProcess

    CreatePipe(&gStdinRead, &gStdinWrite, &saAttr, 0);
    sj.hStdInput = gStdinRead;
    sj.hStdOutput = gStdinWrite;
    if(!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &sj, &pj))
    {
        return h;
    }
    //Wait until child processes exit.
    WaitForSingleObject( pj.hProcess, IGNORE ); //ingnore signal
    //Get exit code
    GetExitCodeProcess(pj.hProcess, (LPDWORD)(&exit));

    return exit;
}
Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • No, you can't pass a process handle to `WriteFile`. You need to pass a file handle, or a pipe, or a handle to a device, etc. But not a process handle. If you want to create a process, and write to its stdin, then create a pipe and pass the read end of the pipe to `CreateProcess`. Later, write to the write end of the pipe. – David Heffernan Sep 01 '15 at 20:28
  • @DavidHeffernan - I will read up on creating and using a pipe. I have no experience with that yet. I am using CreateProcess to launch the exe, and tried using member `PROCESS_INFORMATION` struct (hProcess) also, but that is also a process handle. Thanks – ryyker Sep 01 '15 at 20:31
  • You pass in the pipe handle in the `STARTUPINFO` struct. `CreateProcess` is a pretty hard core API. Takes some work to call it. Steep learning curve. Have to read the docs a few times. Find some good examples and read those. The ones on MSDN are often lame because they use `TCHAR`. – David Heffernan Sep 01 '15 at 20:36
  • @DavidHeffernan - Yes, I have used it, and it's variations to create processes, (like a windows `system()` command) and to launch process as session 0, or as another user. I still do not feel confident, but your comment has given some direction. Thanks again. – ryyker Sep 01 '15 at 20:44
  • @DavidHeffernan - I get a general protection fault when I call `WriteToProcessStdin()` with the the pipe handles to stdin and stdout created as above. Do you see the problem? (edited post with my CreateProcess function) By the way, I only need to send a message to stdin. I don't need to read it. – ryyker Sep 01 '15 at 21:12
  • You don't do any error checking when you call `CreatePipe`. You don't set the flags in `STARTUPINFO`. You send the output of your process back in to the process stdin. I suggest that you do as I say and start from a good example. – David Heffernan Sep 01 '15 at 21:20
  • @DavidHeffernan - Okay. Thanks ( looked at ***[this one](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx)*** so far. Will look for another ). – ryyker Sep 01 '15 at 21:24
  • [Creating a Child Process with Redirected Input and Output](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499.aspx) – Remy Lebeau Sep 01 '15 at 21:28
  • That one is fine, but don't get any ideas about the wisdom of using TCHAR in 2015. Just don't. Note how two pipes are created. The parent holds the write end of the first pipe, and passes the read end to the stdin of the new process. So the parent can write into it, and have the child read. Likewise for the other pipe, the write end is used as the child's stdout, and the parent reads from the other end. Don't do what you did (a classic mistake) and connecting the stdin of the child to the stdout of the child. Everything the child writes, is pushed back into the child! Not good! – David Heffernan Sep 01 '15 at 21:29

0 Answers0