今天還是繼續說說C#調用系統Api啟動外部程式的方法,今天要說的是CreateProcess這個Api函數,相比前兩篇文章(一、二)中所說的Api,CreateProcess參數要更複雜一些,但使用起來,要更靈活。
1.using System.Runtime.InteropServices;
2. CreateProcess中用到了幾個結構體類型,先聲明他們:
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES
{
public int nLength;
public string lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public int lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public int wShowWindow;
public int cbReserved2;
public byte lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
3. 聲明CreateProcess
[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
public static extern bool CreateProcess(
StringBuilder lpApplicationName, StringBuilder lpCommandLine,
SECURITY_ATTRIBUTES lpProcessAttributes,
SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
StringBuilder lpEnvironment,
StringBuilder lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation
);
4. 下邊這三個也是Api,作用看注釋
#region Win32 Api : WaitForSingleObject
//檢測一個系統核心對象(線程,事件,訊號)的訊號狀態,當對象執行時間超過dwMilliseconds就返回,否則就一直等待對象返回訊號
[DllImport("Kernel32.dll")]
public static extern uint WaitForSingleObject(System.IntPtr hHandle, uint dwMilliseconds);
#endregion
#region Win32 Api : CloseHandle
//關閉一個核心對象,釋放對象佔有的系統資源。其中包括檔案、檔案對應、進程、線程、安全和同步對象等
[DllImport("Kernel32.dll")]
public static extern bool CloseHandle(System.IntPtr hObject);
#endregion
#region Win32 Api : GetExitCodeProcess
//擷取一個已中止進程的結束代碼,非零表示成功,零表示失敗。
//參數hProcess,想擷取結束代碼的一個進程的控制代碼,參數lpExitCode,用於裝載進程結束代碼的一個長整數變數。
[DllImport("Kernel32.dll")]
static extern bool GetExitCodeProcess(System.IntPtr hProcess, ref uint lpExitCode);
#endregion
5. 如果樣本中argm指定的程式執行時間很長,進程會被阻塞到WaitForSingleObject行處,直到命令執行完畢或進程被中止才繼續執行後邊的語句。
string argm = "cmd.exe";
STARTUPINFO sInfo = new STARTUPINFO();
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
if (!CreateProcess(null, new StringBuilder(argm), null, null, false, 0, null, null, ref sInfo, ref pInfo))
{
throw new Exception("調用失敗");
}
uint i = 0;
WaitForSingleObject(pInfo.hProcess, int.MaxValue);
GetExitCodeProcess(pInfo.hProcess, ref i);
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);