CreateProcess和CreatePipe用于执行进程并在VC ++中将输出作为字符串返回

时间:2011-12-17 21:19:17

标签: c++ visual-c++ createprocess

我正在尝试使用CreateProcessCreatePipe从Visual Studio 2010中的Windows窗体C ++ / CLR应用程序中执行进程。

在我的Windows窗体应用程序中,我想执行子进程(控制台应用程序)并在我的Windows窗体应用程序中将输出作为std::stringstd::wstringSystem::String^返回。另外,我不希望新创建的子进程生成一个窗口。

控制台应用程序是我自己创建的,所以我也可以控制它的来源。

我看过以下示例,但我不明白如何修改代码以完成我想要做的事情:

MSDN代码似乎写成两个控制台应用程序,一个调用另一个。代码让我很困惑。我只在C ++工作了大约4个月,所以我仍然不明白一切。它似乎引用了一个文本文件,我不需要这样做。

有没有比MSDN的200多行代码或kgui的300多行代码更简单的方法呢?

答案here很有帮助,但过于简单化。我希望看到一个基本的源代码示例(一个不涉及数百行复杂代码的代码将是更可取的)。我会使用MFC代码,但我很难适应我的目的(我没有使用MFC)。

以下是我对Code Project代码的改编:

string ExecuteExternalFile(string csExeName, string csArguments)
{
  string csExecute;
  csExecute=csExeName + " " + csArguments;

  SECURITY_ATTRIBUTES secattr; 
  ZeroMemory(&secattr,sizeof(secattr));
  secattr.nLength = sizeof(secattr);
  secattr.bInheritHandle = TRUE;

  HANDLE rPipe, wPipe;

  //Create pipes to write and read data

  CreatePipe(&rPipe,&wPipe,&secattr,0);
  //

  STARTUPINFO sInfo; 
  ZeroMemory(&sInfo,sizeof(sInfo));
  PROCESS_INFORMATION pInfo; 
  ZeroMemory(&pInfo,sizeof(pInfo));
  sInfo.cb=sizeof(sInfo);
  sInfo.dwFlags=STARTF_USESTDHANDLES;
  sInfo.hStdInput=NULL; 
  sInfo.hStdOutput=wPipe; 
  sInfo.hStdError=wPipe;

  //Create the process here.

  CreateProcess(0,(LPWSTR)csExecute.c_str(),0,0,TRUE,NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&sInfo,&pInfo);
  CloseHandle(wPipe);

  //now read the output pipe here.

  char buf[100];
  DWORD reDword; 
  string m_csOutput,csTemp;
  BOOL res;
  do
  {
                  res=::ReadFile(rPipe,buf,100,&reDword,0);
                  csTemp=buf;
                  m_csOutput+=csTemp;
  }while(res);
  return m_csOutput;
}

我尝试在我的Windows窗体应用程序中使用它,虽然它编译好并且不会导致任何错误,但它似乎也不起作用。我不明白为什么。

这就是我执行上述代码的方式:

std::string ping = ExecuteExternalFile("ping.exe", "127.0.0.1");

它似乎没有做任何事情,除了在第一次执行时它给出一个非常奇怪的3个字符作为输出,然后在后续执行中,没有。

2 个答案:

答案 0 :(得分:3)

您没有正确使用::ReadFile()功能。

在此处阅读:http://msdn.microsoft.com/en-us/library/ms891445.aspx

基本上,如果函数没有返回TRUE,你想要失败并且你想要保持循环,直到它产生零reDword。

另外,::ReadFile()不会为您终止您的数据,因此您必须自己完成,例如:buf[reDword] = '\0';(确保您的buf早有101个字符这样做。)

修改 因为我被要求提供一些示例代码,这里是,虽然我没有经历实际编译它以确保它工作的麻烦,所以请注意语法错误,并且通常认为它只是作为粗略的指针应该做的方向:

#define BUFFER_SIZE 100
string csoutput;
for( ;; )
{
    char buf[BUFFER_SIZE+1];
    DWORD redword; 
    if( !::ReadFile(rPipe,buf,BUFFER_SIZE,&redword,0) )
    {
        DWORD error = ::GetLastError();
        //throw new Exception( "Error " + error ); //or something similar
    }
    if( redword == 0 )
        break;
    buf[redword] = '\0';
    string cstemp = buf;
    csoutput += cstemp;
}
return csoutput;

答案 1 :(得分:3)

感谢Hans Passant的lead让我接受了这个简单而简单的代码,完全符合我的要求。

/// this namespace call is necessary for the rest of the code to work
using namespace System::Diagnostics;
using namespace System::Text;/// added for encoding

Process^ myprocess = gcnew Process;
Encoding^ Encoding;/// added for encoding
Encoding->GetEncoding(GetOEMCP());/// added for encoding

myprocess->StartInfo->FileName = "ping.exe";
myprocess->StartInfo->Arguments = "127.0.0.1";
myprocess->StartInfo->UseShellExecute = false;

/// added the next line to keep a new window from opening
myprocess->StartInfo->CreateNoWindow = true;

myprocess->StartInfo->RedirectStandardOutput = true;
myprocess->StartInfo->StandardOutputEncoding = Encoding;/// added for encoding
myprocess->Start();

String^ output = gcnew String( myprocess->StandardOutput->ReadToEnd() );

myprocess->WaitForExit();

/// OutputBox is the name of a Windows Forms text box in my app.
OutputBox->Text = output;

编辑:添加了编码信息。见上面的代码。