2 using System.Diagnostics;
\r
3 using System.Runtime.InteropServices;
\r
5 namespace NaGet.InteropServices
\r
8 /// Win32 API の<code>CreateProcess</code>を直に叩くためのクラス。
\r
11 /// .NETのProcess.Startは、<code>CreateProcess(NULL, cmdLine, ...)</code>
\r
12 /// のように第一引数が<code>NULL</code>に相当する呼び出しが、
\r
13 /// *厳密な意味*でできない。厳密な意味で、
\r
14 /// これと同じ呼び出しを実現する必要があるときに使われる。
\r
16 public class CreateProcessCaller : IDisposable
\r
21 [StructLayout(LayoutKind.Sequential)]
\r
22 internal struct SECURITY_ATTRIBUTES
\r
25 public IntPtr lpSecurityDescriptor;
\r
26 public int bInheritHandle;
\r
30 [StructLayout(LayoutKind.Sequential)]
\r
31 internal struct PROCESS_INFORMATION
\r
33 public IntPtr hProcess;
\r
34 public IntPtr hThread;
\r
35 public int dwProcessId;
\r
36 public int dwThreadId;
\r
39 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
\r
50 Int32 dwXCountChars;
\r
51 Int32 dwYCountChars;
\r
52 Int32 dwFillAttribute;
\r
62 [DllImport("kernel32.dll", CharSet= CharSet.Auto, SetLastError=true)]
\r
63 static extern bool CreateProcess(string lpApplicationName,
\r
64 string lpCommandLine,
\r
65 /* ref SECURITY_ATTRIBUTES lpProcessAttributes, */
\r
66 IntPtr lpProcessAttributes,
\r
67 /* ref SECURITY_ATTRIBUTES lpThreadAttributes, */
\r
68 IntPtr lpThreadAttributes,
\r
69 bool bInheritHandles,
\r
70 uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
\r
71 [In] ref STARTUPINFO lpStartupInfo,
\r
72 out PROCESS_INFORMATION lpProcessInformation);
\r
74 [DllImport("kernel32", SetLastError=true, ExactSpelling=true)]
\r
75 static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);
\r
77 [DllImport("kernel32.dll", SetLastError=true)]
\r
78 [return: MarshalAs(UnmanagedType.Bool)]
\r
79 static extern bool CloseHandle(IntPtr hObject);
\r
81 [DllImport("kernel32.dll", SetLastError = true)]
\r
82 [return: MarshalAs(UnmanagedType.Bool)]
\r
83 static extern bool GetExitCodeProcess(IntPtr hProcess, out int lpExitCode);
\r
88 PROCESS_INFORMATION pi;
\r
93 /// <param name="procInfo">プロセス起動情報。
\r
94 /// なお、<code>procInfo.UseShellExecute</code>は必ずfalseでなければならない</param>
\r
95 public CreateProcessCaller(ProcessStartInfo procInfo)
\r
97 if (procInfo.UseShellExecute) {
\r
98 throw new ArgumentException("UseShellExecute must be false");
\r
100 si.cb = Marshal.SizeOf(si);
\r
102 string lpFileName = (string.IsNullOrEmpty(procInfo.FileName))? null : procInfo.FileName;
\r
104 uint dwCreationFlags = 0x0020; // NORMAL_PRIORITY_CLASS
\r
105 if (procInfo.CreateNoWindow) dwCreationFlags |= 0x08000000; // CREATE_NO_WINDOW
\r
106 string lpCurrentDirectory = (System.IO.Directory.Exists(procInfo.WorkingDirectory))? procInfo.WorkingDirectory : null;
\r
108 bool retValue = CreateProcess(lpFileName, procInfo.Arguments,
\r
109 IntPtr.Zero, IntPtr.Zero,
\r
110 false, dwCreationFlags,
\r
111 IntPtr.Zero, lpCurrentDirectory, ref si, out pi);
\r
113 throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
\r
115 CloseHandle(pi.hThread);
\r
119 /// 関連付けられたプロセスが終了するまで、最大指定したミリ秒間待機。
\r
121 /// <param name="timeout">最大待機時間(ミリ秒単位)</param>
\r
122 /// <returns>終了コード</returns>
\r
123 public uint WaitForExit(uint timeout)
\r
125 return WaitForSingleObject(pi.hProcess, timeout);
\r
129 /// 関連付けられたプロセスが終了するまで無期限に待機。
\r
131 /// <returns>終了コード</returns>
\r
132 public uint WaitForExit()
\r
134 // return WaitForExit(INFINITE)
\r
135 return WaitForExit(0xFFFFFFFF);
\r
141 public int ExitCode {
\r
144 if (! GetExitCodeProcess(pi.hProcess, out lpExitCode) ) {
\r
145 throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
\r
154 public void Dispose()
\r
156 CloseHandle(pi.hProcess);
\r