2016-05-30 73 views
1

TL; DR用於Windows的可執行包裝的CreateProcess用法?

CreateProcess(?, ?, ?, ...)爲:

  • 通電流過程PARAMS(即"batchfile" %*
  • 正確連接stdin和stdout
  • 創建旗幟?

我有以下問題:

  • 我需要啓動一個給定的第三方可執行文件與自定義環境和自定義參數。 (兩個半固定)
  • 我不能用一個批處理文件,因爲(再次,第三方)側調用模塊直接調用CreateProcess
  • 我需要通過傳遞

因此,任何額外的paramers ,我想要做的就是創建一個非常簡單的可執行啓動程序會像一個批處理文件,相當於:

set PATH=... 
set WHATEVER=... 
...\3rd-pty-tool.exe -switch1 -switch2 %* 
exit /B %ERRORLEVEL% 

而且,我不想惹any bat2exe converter東西 - 太醜陋當我有任何Visual Studio唉。

運行的另一個executable via CreateProcess is trivial原則

STARTUPINFO info={sizeof(info)}; 
PROCESS_INFORMATION processInfo; 
if (CreateProcess(?, ?, ?, ?, ?, ?, ?, ?, &info, &processInfo)) 
{ 
    WaitForSingleObject(processInfo.hProcess, INFINITE); 
    CloseHandle(processInfo.hProcess); 
    CloseHandle(processInfo.hThread); 
} 

通過_putenv等建立子進程的環境。也很容易。然而

什麼是不平凡的我是什麼傳授給CreateProcess

BOOL WINAPI CreateProcess(
    _In_opt_ LPCTSTR    lpApplicationName, 
    _Inout_opt_ LPTSTR    lpCommandLine, 
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 
    _In_  BOOL     bInheritHandles, 
    _In_  DWORD     dwCreationFlags, 
    _In_opt_ LPVOID    lpEnvironment, 
    _In_opt_ LPCTSTR    lpCurrentDirectory, 
    _In_  LPSTARTUPINFO   lpStartupInfo, 
    _Out_  LPPROCESS_INFORMATION lpProcessInformation 
); 
  • 如何我在%*相當於當前Win32進程得到什麼?
  • 只通過lpApplicationName,只有lpCommandLine或兩者兼而有之?
  • 如何處理繼承和創建標誌?
  • 如何正確地轉發/返回stdin和stdout?

不是欺騙:CreateProcess to execute Windows command

+1

我不知道'%*'的意思,但是您可能正在尋找[GetCommandLine](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx) –

+0

另外感興趣的是:[使用重定向輸入和輸出創建子進程](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499.aspx) –

+0

@Igor'%*'如同在批處理文件。感謝,這個重定向文章是一個很好的。 –

回答

1

應該是相當簡單。

BOOL WINAPI CreateProcess(
    _In_opt_ LPCTSTR    lpApplicationName, 
    _Inout_opt_ LPTSTR    lpCommandLine, 
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 
    _In_  BOOL     bInheritHandles, 
    _In_  DWORD     dwCreationFlags, 
    _In_opt_ LPVOID    lpEnvironment, 
    _In_opt_ LPCTSTR    lpCurrentDirectory, 
    _In_  LPSTARTUPINFO   lpStartupInfo, 
    _Out_  LPPROCESS_INFORMATION lpProcessInformation 
); 

讓我們按順序。

  • lpApplicationName - 如果您有要運行的可執行文件的完整路徑,請將其放在此處。這可以確保獲得您期望的可執行文件,即使PATH上有另一個具有相同名稱的可執行文件。

  • lpCommandLine - 第一個元素是可執行文件的名稱。如果你已經指定lpApplicationName這不需要完全限定,或者甚至是可執行文件的實際名稱,但它確實需要存在。這必須是一個可寫的緩衝區,它不能是一個常量字符串。

如果你的額外的參數可以走在命令行的年底,這很容易:

wchar_t buffer[1024]; 
wcscpy_s(buffer, _countof(buffer), GetCommandLine()); 
wcscat_s(buffer, _countof(buffer), L" -switch1 -switch2"); 

否則,你需要解析命令行找到合適的地方插入參數,像這樣:

while (*lpCmdLine == L' ') lpCmdLine++; 
while (ch = *lpCmdLine) 
{ 
    if (ch == L'"') for (lpCmdLine++; ch = *lpCmdLine; lpCmdLine++) if (ch == L'"') break; 
    if (ch == L' ') break; 
    lpCmdLine++; 
} 
while (*lpCmdLine == L' ') lpCmdLine++; 
  • lpProcessAttributeslpThreadAttributes - NULL

  • bInheritHandles - TRUE,因爲您希望孩子繼承標準手柄。

  • dwCreationFlags - 您的場景中無需使用,因此0

  • lpEnvironment - NULL要通過當前環境。在某些情況下,您希望顯式構建新環境或環境的修改副本,但是因爲您的過程僅用於啓動不必要的子項。

  • lpCurrentDirectory - NULL繼承您的當前目錄。

  • lpStartupInfo - 請撥GetStartupInfo填寫與當前流程相同的設置,或者將其保留爲空,就像您發佈的代碼中一樣。

  • lpProcessInformation - 這是一個輸出參數,如代碼中所示使用。在你的場景中,如果一個應用程序正在爲另一個應用程序站立,那麼可能需要保留該進程的句柄並使用它來等待子進程在退出之前退出。 (如果你知道,如果你離開你的孩子做之前,你的父母不會感到困惑,這是沒有必要的。)

你並不需要從保證做什麼特別的標準手柄,除了即設置了bInheritHandles。默認情況下,孩子與父母保持相同的標準手柄。

+0

謝謝哈利。非常好的總結!*其實*,我目前的測試應用程序設置'bInhertHandles:= FALSE',它*仍然*工作。這兩個二進制文件都是「控制檯可執行文件」。在這種情況下似乎不需要處理繼承。一旦我有了,我打算舉出完整的例子。 –

+1

是的,我決定不要討論這個問題,作爲一個不必要的複雜因素。在Windows 7和更早版本中,如果標準句柄仍指向原始控制檯句柄,則不需要句柄繼承。這是因爲它們不是真正的內核句柄,它們是「僞手柄」。 –

+1

我不*認爲*如果標準句柄已被重定向到文件或管道,但它沒有句柄繼承將工作,但我沒有檢查。另外,如果我理解正確,在新版本的Windows控制檯句柄*是*真正的內核句柄。 Windows可能會特殊處理這兩種情況,但爲了確保最大的兼容性,我建議在這種情況下繼續使用繼承。 (對於更復雜的場景,可以選擇指定哪些句柄被繼承,這可能是一般情況下的最佳選擇。) –

相關問題