首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用CreateProcess()和CreatePipe()从cmd.exe读取输出

如何使用CreateProcess()和CreatePipe()从cmd.exe读取输出
EN

Stack Overflow用户
提问于 2016-03-13 19:35:54
回答 5查看 14K关注 0票数 16

如何使用CreateProcess()和CreatePipe()从cmd.exe读取输出

我一直在尝试创建一个子进程来执行cmd.exe使用命令行指定/K dir..。其目的是使用管道将命令的输出读回到父进程中。

我已经有了CreateProcess()工作,但是涉及管道的步骤给我带来了麻烦。使用管道,新的控制台窗口不会显示(与以前一样),并且父进程停滞在调用ReadFile()..。

有人知道我做错了什么吗?

代码语言:javascript
运行
复制
#include 
#include 
#include 

#define BUFFSZ 4096

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

int wmain(int argc, wchar_t* argv[]) 
{
    int result;
    wchar_t aCmd[BUFFSZ] = TEXT("/K dir"); // CMD /?
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;

    printf("Starting...\n");

    ZeroMemory(&si, sizeof(STARTUPINFO));
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

    // Create one-way pipe for child process STDOUT
    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0)) {
        printf("CreatePipe() error: %ld\n", GetLastError());
    }

    // Ensure read handle to pipe for STDOUT is not inherited
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
        printf("SetHandleInformation() error: %ld\n", GetLastError());
    }

    // Create one-way pipe for child process STDIN
    if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &sa, 0)) {
        printf("CreatePipe() error: %ld\n", GetLastError());
    }

    // Ensure write handle to pipe for STDIN is not inherited
    if (!SetHandleInformation(g_hChildStd_IN_Rd, HANDLE_FLAG_INHERIT, 0)) {
        printf("SetHandleInformation() error: %ld\n", GetLastError());
    }

    si.cb = sizeof(STARTUPINFO);
    si.hStdError = g_hChildStd_OUT_Wr;
    si.hStdOutput = g_hChildStd_OUT_Wr;
    si.hStdInput = g_hChildStd_IN_Rd;
    si.dwFlags |= STARTF_USESTDHANDLES;

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    // Pipe handles are inherited
    sa.bInheritHandle = true;

    // Creates a child process
    result = CreateProcess(
        TEXT("C:\\Windows\\System32\\cmd.exe"),     // Module
        aCmd,                                       // Command-line
        NULL,                                       // Process security attributes
        NULL,                                       // Primary thread security attributes
        true,                                       // Handles are inherited
        CREATE_NEW_CONSOLE,                         // Creation flags
        NULL,                                       // Environment (use parent)
        NULL,                                       // Current directory (use parent)
        &si,                                        // STARTUPINFO pointer
        &pi                                         // PROCESS_INFORMATION pointer
        );

    if (result) {
        printf("Child process has been created...\n");
    }
    else {
        printf("Child process could not be created\n");
    }

    bool bStatus;
    CHAR aBuf[BUFFSZ + 1];
    DWORD dwRead;
    DWORD dwWrite;
    // GetStdHandle(STD_OUTPUT_HANDLE)

    while (true) {
        bStatus = ReadFile(g_hChildStd_OUT_Rd, aBuf, sizeof(aBuf), &dwRead, NULL);
        if (!bStatus || dwRead == 0) {
            break;
        }
        aBuf[dwRead] = '\0';
        printf("%s\n", aBuf);
    }

        // Wait until child process exits
        WaitForSingleObject(pi.hProcess, INFINITE);

        // Close process and thread handles
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        printf("Stopping...\n");

        return 0;
    }
EN

回答 5

Stack Overflow用户

发布于 2019-04-17 08:26:24

伊恩·博伊德的答案是这样的:一旦你启动了你的子进程:确保关闭那些你不再需要的管道的末端。

我制作了另一个版本的CreatePipe+CreateProcess我希望更清晰的解决方案是:

代码语言:javascript
运行
复制
int main()
{
    BOOL ok = TRUE;
    HANDLE hStdInPipeRead = NULL;
    HANDLE hStdInPipeWrite = NULL;
    HANDLE hStdOutPipeRead = NULL;
    HANDLE hStdOutPipeWrite = NULL;

    // Create two pipes.
    SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
    ok = CreatePipe(&hStdInPipeRead, &hStdInPipeWrite, &sa, 0);
    if (ok == FALSE) return -1;
    ok = CreatePipe(&hStdOutPipeRead, &hStdOutPipeWrite, &sa, 0);
    if (ok == FALSE) return -1;

    // Create the process.
    STARTUPINFO si = { };
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdError = hStdOutPipeWrite;
    si.hStdOutput = hStdOutPipeWrite;
    si.hStdInput = hStdInPipeRead;
    PROCESS_INFORMATION pi = { };
    LPCWSTR lpApplicationName = L"C:\\Windows\\System32\\cmd.exe";
    LPWSTR lpCommandLine = (LPWSTR)L"C:\\Windows\\System32\\cmd.exe /c dir";
    LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL;
    LPSECURITY_ATTRIBUTES lpThreadAttribute = NULL;
    BOOL bInheritHandles = TRUE;
    DWORD dwCreationFlags = 0;
    LPVOID lpEnvironment = NULL;
    LPCWSTR lpCurrentDirectory = NULL;
    ok = CreateProcess(
        lpApplicationName,
        lpCommandLine,
        lpProcessAttributes,
        lpThreadAttribute,
        bInheritHandles,
        dwCreationFlags,
        lpEnvironment,
        lpCurrentDirectory,
        &si,
        &pi);
    if (ok == FALSE) return -1;

    // Close pipes we do not need.
    CloseHandle(hStdOutPipeWrite);
    CloseHandle(hStdInPipeRead);

    // The main loop for reading output from the DIR command.
    char buf[1024 + 1] = { };
    DWORD dwRead = 0;
    DWORD dwAvail = 0;
    ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    while (ok == TRUE)
    {
        buf[dwRead] = '\0';
        OutputDebugStringA(buf);
        puts(buf);
        ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    }

    // Clean up and exit.
    CloseHandle(hStdOutPipeRead);
    CloseHandle(hStdInPipeWrite);
    DWORD dwExitCode = 0;
    GetExitCodeProcess(pi.hProcess, &dwExitCode);
    return dwExitCode;
}

一些注意事项:

  • 实际上并不需要StdIn的管道:

这是因为DIR命令不需要用户输入(但是,我把它留在了代码中,因为它是运行其他命令的 一个很好的模板)

所有与此相关的事情hStdInPipeRead&hStdInPipeWrite可以省略

设置si.hStdInput可以省略

  • 替换硬编码L"C:\\Windows\\System32\\cmd.exe"通过阅读COMSPEC环境变量。
  • 如果我们希望编译为非UNICODE,请将LPWSTR替换为LPTSTR。
  • 替换cmd.exe /k DIR使用cmd.exe /c DIR从什么时候开始DIR命令结束时,我们并不真正想要cmd.exe留下来。
票数 6
EN

Stack Overflow用户

发布于 2019-02-14 19:31:12

我也有同样的情况。在我使用Lib的情况下,需要执行内部exe并读取输出。下面的代码可以正常工作,没有任何问题。

代码语言:javascript
运行
复制
void executeCMDInNewProcessAndReadOutput(LPSTR lpCommandLine)
    {
        STARTUPINFO si;
        SECURITY_ATTRIBUTES sa;
        PROCESS_INFORMATION pi;
        HANDLE g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr, g_hChildStd_OUT_Rd, g_hChildStd_IN_Wr;  //pipe handles
        char buf[1024];           //i/o buffer

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

        if (CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &sa, 0))   //create stdin pipe
        {
            if (CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0))  //create stdout pipe
            {

                //set startupinfo for the spawned process
                /*The dwFlags member tells CreateProcess how to make the process.
                STARTF_USESTDHANDLES: validates the hStd* members.
                STARTF_USESHOWWINDOW: validates the wShowWindow member*/
                GetStartupInfo(&si);

                si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
                si.wShowWindow = SW_HIDE;
                //set the new handles for the child process
                si.hStdOutput = g_hChildStd_OUT_Wr;
                si.hStdError = g_hChildStd_OUT_Wr;
                si.hStdInput = g_hChildStd_IN_Rd;

                //spawn the child process
                if (CreateProcess(NULL, lpCommandLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
                    NULL, NULL, &si, &pi))
                {
                    unsigned long bread;   //bytes read
                    unsigned long avail;   //bytes available
                    memset(buf, 0, sizeof(buf));

                    for (;;)
                    {
                        PeekNamedPipe(g_hChildStd_OUT_Rd, buf, 1023, &bread, &avail, NULL);
                        //check to see if there is any data to read from stdout
                        if (bread != 0)
                        {
                            if (ReadFile(g_hChildStd_OUT_Rd, buf, 1023, &bread, NULL))
                            {
                                break;
                            }
                        }
                    }

                    //clean up all handles
                    CloseHandle(pi.hThread);
                    CloseHandle(pi.hProcess);
                    CloseHandle(g_hChildStd_IN_Rd);
                    CloseHandle(g_hChildStd_OUT_Wr);
                    CloseHandle(g_hChildStd_OUT_Rd);
                    CloseHandle(g_hChildStd_IN_Wr);
                }
                else
                {
                    CloseHandle(g_hChildStd_IN_Rd);
                    CloseHandle(g_hChildStd_OUT_Wr);
                    CloseHandle(g_hChildStd_OUT_Rd);
                    CloseHandle(g_hChildStd_IN_Wr);
                }
            }
            else
            {
                CloseHandle(g_hChildStd_IN_Rd);
                CloseHandle(g_hChildStd_IN_Wr);
            }
        }
    }
票数 2
EN

Stack Overflow用户

发布于 2016-03-13 21:08:07

下面是一个线程的例子(取自一个更大的程序),它可以完成你想要做的事情。它为stdout创建管道,为它创建的进程创建stderr管道,然后进入一个循环,读取这些管道,直到程序结束。

代码语言:javascript
运行
复制
DWORD WINAPI ThreadProc(LPVOID lpParameter)
   {
#define EVENT_NAME "Global\\RunnerEvt"

   HANDLE hev;
   SECURITY_ATTRIBUTES psa;
   InitSAPtr(&psa);
   DWORD waitRc;
   DWORD bytesRead;
   int manual_triggered = 1;

   hev = CreateEvent(&psa, FALSE, FALSE, EVENT_NAME);

   // Create pipes we'll read

      for(;;)
      {

      if (manual_triggered)
         {
         waitRc = WAIT_OBJECT_0;
         manual_triggered = 0;
         }
      else
         {
         waitRc = WaitForSingleObject(hev, 500);
         }

      if (waitRc == WAIT_OBJECT_0)
         {
         `logprint`f(LOG_DBG, "Received command to run process\n");

         CreateChildOutFile();

         stdOutEvt = CreateEvent(&psa, TRUE, FALSE, 0);
         stdOutOvl.hEvent = stdOutEvt;

         stdErrEvt = CreateEvent(&psa, TRUE, FALSE, 0);
         stdErrOvl.hEvent = stdErrEvt;

         gStdOutReadHand =  CreateNamedPipe(STD_OUT_PIPE_NAME, PIPE_ACCESS_DUPLEX + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE + PIPE_READMODE_BYTE,
            PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &psa);
         if (gStdOutReadHand == INVALID_HANDLE_VALUE)
            {
            log(LOG_DBG, "Error %d on create STDOUT pipe\n", GetLastError());
            }

         gStdErrReadHand =  CreateNamedPipe(STD_ERR_PIPE_NAME, PIPE_ACCESS_DUPLEX + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE + PIPE_READMODE_BYTE,
            PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &psa);
         if (gStdErrReadHand == INVALID_HANDLE_VALUE)
            {
            log(LOG_DBG, "Error %d on create STDERR pipe\n", GetLastError());
            }

         runProcess();

         log(LOG_DBG, "After runProcess, new PID is %d/%x\n", piProcInfo.dwProcessId, piProcInfo.dwProcessId);

         if (piProcInfo.dwProcessId == 0)
            {
            log(LOG_DBG, "runProcess failed, closing child STDIN/STDERR\n");
            closeChildPipes();

#define FAIL_MSG "Child process failed to start\n"
            writeChildOutFile(FAIL_MSG, strlen(FAIL_MSG) );

            CloseHandle(hChildOut);
            }
         else
            {
            log(LOG_DBG, "Child process created, setting up for redir/restart/termination\n");

            issueRead(gStdOutReadHand, &stdOutOvl, stdOutBuff, &stdOutBytesAvail);
            //log(LOG_DBG, "After read set on STDOUT\n");

            issueRead(gStdErrReadHand, &stdErrOvl, stdErrBuff, &stdErrBytesAvail);
            //log(LOG_DBG, "After read set on STDERR\n");

            HANDLE harr[4];

            for(;;)
               {
               harr[0] = hev;
               harr[1] = piProcInfo.hProcess;
               harr[2] = stdOutEvt;
               harr[3] = stdErrEvt;

               DWORD waitRc2 = WaitForMultipleObjects(4, harr, FALSE, 500);

               #if 0
               if (waitRc2 == -1)
                  {
                  log(LOG_DBG, "Wait error %d\n", GetLastError());
                  Sleep(500);
                  }

               log(LOG_DBG, "waitRc2 %d\n", waitRc2);
               #endif


               if ((waitRc2 - WAIT_OBJECT_0) == 0)
                  {
                  log(LOG_DBG, "Woke up because another trigger command was received\n");
                  #define NEW_CMD_MSG "Child process is being terminated because new trigger received\n"

                  writeChildOutFile(NEW_CMD_MSG, strlen(NEW_CMD_MSG));

                  terminateChild();
                  CloseHandle(hChildOut);
                  manual_triggered = 1;
                  break;
                  }
               else if ((waitRc2 - WAIT_OBJECT_0) == 1)
                  {
                  //log(LOG_DBG, "Woke up because child has terminated\n");
                  closeChildPipes();
                  #define NORM_MSG "Normal child process termination\n"
                  writeChildOutFile(NORM_MSG, strlen(NORM_MSG));
                  CloseHandle(hChildOut);
                  break;
                  }
               else if ((waitRc2 - WAIT_OBJECT_0) == 2)
                  {
                  //log(LOG_DBG, "Woke up because child has stdout\n");
                  if (GetOverlappedResult(gStdOutReadHand, &stdOutOvl, &bytesRead, TRUE))
                     {
                     writeChildOutFile(stdOutBuff, bytesRead);
                     ResetEvent(stdOutEvt);
                     issueRead(gStdOutReadHand, &stdOutOvl, stdOutBuff, &stdOutBytesAvail);
                     }

                  }
               else if ((waitRc2 - WAIT_OBJECT_0) == 3)
                  {
                  //log(LOG_DBG, "Woke up because child has stderr\n");

                  if (GetOverlappedResult(gStdErrReadHand, &stdErrOvl, &bytesRead, TRUE))
                     {
                     writeChildOutFile(stdErrBuff, bytesRead);
                     ResetEvent(stdErrEvt);
                     issueRead(gStdErrReadHand, &stdErrOvl, stdErrBuff, &stdErrBytesAvail);
                     }
                  }
               else
                  {
                  if (gShuttingDown)
                     {
                     log(LOG_DBG, "Woke with active child and service is terminating\n");

#define SHUTDOWN_MSG "Child process is being terminated because the service is shutting down\n"

                     writeChildOutFile(SHUTDOWN_MSG, strlen(SHUTDOWN_MSG));
                     terminateChild();
                     CloseHandle(hChildOut);
                     break;
                     }
                  }

               if (gShuttingDown)
                  {
                  break;
                  }

               }
            }
         }
      else if (gShuttingDown)
         {
         break;
         }

      CloseHandle(gStdOutReadHand);
      CloseHandle(gStdErrReadHand);

      }

   return 0;
   }

void writeChildOutFile(char *msg, int len)
   {
   DWORD bytesWritten;
   WriteFile(hChildOut, msg, len, &bytesWritten, 0);
   }


void terminateChild(void)
   {
   if (piProcInfo.dwProcessId != 0)
      {
      TerminateProcess(piProcInfo.hProcess, -1);
      CloseHandle(piProcInfo.hThread);
      CloseHandle(piProcInfo.hProcess);
      closeChildPipes();
      }
   }

void closeChildPipes(void)
   {
   CloseHandle(g_hChildStd_OUT_Wr);
   CloseHandle(g_hChildStd_ERR_Wr);
   }

void runProcess(void)
   {
   SECURITY_ATTRIBUTES saAttr;

   // Set the bInheritHandle flag so pipe handles are inherited.
   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
   saAttr.bInheritHandle = TRUE;
   saAttr.lpSecurityDescriptor = NULL;

   // Create a pipe for the child process's STDOUT.
   TCHAR szCmdline[]=TEXT("cmd.exe /C C:\\temp\\RunnerService.bat");
   STARTUPINFO siStartInfo;
   BOOL bSuccess = FALSE;

// Set up members of the PROCESS_INFORMATION structure.

   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

   g_hChildStd_OUT_Wr = CreateFile (STD_OUT_PIPE_NAME,
                FILE_WRITE_DATA,
                0,
                &saAttr,
                OPEN_EXISTING,
                0,
                NULL);

   if (g_hChildStd_OUT_Wr == INVALID_HANDLE_VALUE)
      {
      log(LOG_DBG, "Error creating child proc stdout file %d\n", GetLastError());
      }


   g_hChildStd_ERR_Wr = CreateFile (STD_ERR_PIPE_NAME,
                FILE_WRITE_DATA,
                0,
                &saAttr,
                OPEN_EXISTING,
                0,
                NULL);

   if (g_hChildStd_ERR_Wr == INVALID_HANDLE_VALUE)
      {
      log(LOG_DBG, "Error creating child proc stderr file %d\n", GetLastError());
      }


// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.

   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO);
   siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
   siStartInfo.hStdError = g_hChildStd_ERR_Wr;
   siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

// Create the child process.

   bSuccess = CreateProcess(NULL,
      szCmdline,     // command line
      NULL,          // process security attributes
      NULL,          // primary thread security attributes
      TRUE,          // handles are inherited
      0,             // creation flags
      NULL,          // use parent's environment
      NULL,          // use parent's current directory
      &siStartInfo,  // STARTUPINFO pointer
      &piProcInfo);  // receives PROCESS_INFORMATION

   }


void CreateChildOutFile(void)
   {
   SYSTEMTIME st;
   SECURITY_ATTRIBUTES sa;
   char fName[_MAX_PATH];

   InitSAPtr(&sa);

   GetLocalTime(&st);

   sprintf(fName, "C:\\TEMP\\runsvcchild_%02d_%02d_%02d_%04d.out", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);

   hChildOut = CreateFile(fName, GENERIC_WRITE, FILE_SHARE_READ, &sa,  CREATE_ALWAYS,  FILE_ATTRIBUTE_NORMAL, 0);
   }

void issueRead(HANDLE hFile, OVERLAPPED *overLapped, char *buf, DWORD *dwRead)
   {
   //log(LOG_DBG, "Start of issueRead, hfile %08x, ovl is %08x\n", hFile, overLapped);
   BOOL brc = ReadFile(hFile, buf, 4096, dwRead, overLapped);
   if (!brc)
      {
      DWORD dwle = GetLastError();
      if (dwle != ERROR_IO_PENDING)
         {
         log(LOG_DBG, "Error %d on ReadFile\n", dwle);
         }
      }
   else
      {
      // log(LOG_DBG, "Read issued\n");
      }
   }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35969730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档