2011-12-17 25 views
2

我試圖使用CreateProcessCreatePipe從Windows中執行過程形成在Visual Studio C++/CLR應用2010的CreateProcess和CreatePipe執行過程並返回輸出作爲VC字符串++

從內我的Windows窗體應用程序我想要執行子進程(控制檯應用程序),並在Windows窗體應用程序中將輸出作爲std::stringstd::wstringSystem::String^返回。另外,我不希望新創建的子進程產生一個窗口。

控制檯應用程序是我自己創建的,所以我也可以控制它的源代碼。

我已經看到了下面的例子,但我不明白如何修改代碼來完成我想做的事:

MSDN代碼似乎寫成兩個控制檯應用程序,一個調用另一個。代碼讓我感到困惑。我只用C++工作了大約4個月,所以我仍然不瞭解所有的東西。它似乎引用了一個文本文件,我不需要這樣做。

有沒有比MSDN的200多行代碼或kgui的300多行代碼更簡單的方法?

答案here很有幫助,但過於簡單。我希望看到一個基本的源代碼示例(不涉及數百行復雜代碼將是更可取的)。我會用MFC的代碼,但我很難適應我的目的(我不使用MFC)。

以下是我從代碼項目代碼的適應性:

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窗體應用程序中嘗試從,而它編譯OK,不會引起任何錯誤,這不是」 t似乎也工作。我不知道爲什麼。

這是我如何執行上面的代碼:

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

它似乎沒有做任何事情,只是在第一次執行它給人一種很奇怪3個字符作爲輸出,然後在後續執行,沒有。

+1

你這樣做很難,不知道爲什麼。改用ProcessStartInfo :: RedirectStandardOutput屬性。 「 – 2011-12-17 22:11:01

+0

」改爲使用ProcessStartInfo :: RedirectStandardOutput屬性。「你能否詳細解釋一下你的意思?也許提供一個例子的鏈接? – Jason 2011-12-17 22:45:14

+1

複製/麪食到谷歌查詢。採取第一擊,這是一個很好的。 – 2011-12-17 23:14:15

回答

2

感謝漢斯帕桑特該讓我這個簡單明瞭的一段代碼,不正是我一直在尋找的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; 

編輯:添加編碼信息。見上面的代碼。

+0

你這樣做很難,不知道爲什麼。使用System :: Net :: NetworkInformation :: Ping類:) – 2011-12-18 07:15:15

+0

@HansPassant - 實際上,ping只是測試此代碼的一個示例。它可能是任何有輸出的東西。再次感謝您的幫助。上述確實正是需要的。 – Jason 2011-12-18 13:21:36

+0

@Jason我相信這是一個笑話,參考前面的Hans'es評論。儘管如此,你還是應該爲這段代碼添加解碼(控制檯應用程序使用'CP_OEMCP'代碼頁,這可能與爲非unicode GUI應用程序設置的'CP_ACP'不同。因爲.NET沒有提供一個準備就緒的選項,所以你必須從'kernel32.dll'中導入'GetOEMCP()'函數,然後執行以下操作:'myprocess-> StandardOutputEncoding = Encoding-> GetEncoding(GetOEMCP()) ;'。 – GSerg 2011-12-18 15:17:46

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; 
+0

嗨邁克。感謝你的快速回復。是否有可能向我展示一個代碼示例,因爲您會將它寫入上面的代碼中? – Jason 2011-12-17 22:48:05

+0

@Jason我編輯了答案以提供一些代碼示例。我不是說錯誤地使用'ReadFile()'就是你的問題;如果不是,請說出來,我們可以嘗試找出其他原因,可能無法正常工作。 – 2011-12-17 23:59:00

+0

感謝您提供該代碼。不幸的是,我仍然沒有得到該函數的輸出字符串。 Hans的建議讓我找到了一個解決方案,我會在時限到期時發佈。 – Jason 2011-12-18 03:19:20

相關問題