我正在尝试使用CreateProcess
和CreatePipe
从Visual Studio 2010中的Windows窗体C ++ / CLR应用程序中执行进程。
在我的Windows窗体应用程序中,我想执行子进程(控制台应用程序)并在我的Windows窗体应用程序中将输出作为std::string
,std::wstring
或System::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个字符作为输出,然后在后续执行中,没有。
答案 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;
编辑:添加了编码信息。见上面的代码。