OSDN Git Service

AppliStation-*,とりあえずの実装 of 「インストール先フォルダ」のところで実行ファイルを直接 実行できるように
[applistation/AppliStation.git] / na-get-lib / NaGet.InteropServices / CreateProcessCaller.cs
1 using System;\r
2 using System.Diagnostics;\r
3 using System.Runtime.InteropServices;\r
4 \r
5 namespace NaGet.InteropServices\r
6 {\r
7         /// <summary>\r
8         /// Win32 API の<code>CreateProcess</code>を直に叩くためのクラス。\r
9         /// </summary>\r
10         /// <remarks>\r
11         /// .NETのProcess.Startは、<code>CreateProcess(NULL, cmdLine, ...)</code>\r
12         /// のように第一引数が<code>NULL</code>に相当する呼び出しが、\r
13         /// *厳密な意味*でできない。厳密な意味で、\r
14         /// これと同じ呼び出しを実現する必要があるときに使われる。\r
15         /// </remarks>\r
16         public class CreateProcessCaller : IDisposable\r
17         {\r
18                 #region Win32API\r
19                 \r
20                 /*\r
21                 [StructLayout(LayoutKind.Sequential)]\r
22                 internal struct SECURITY_ATTRIBUTES\r
23                 {\r
24                     public int nLength;\r
25                     public IntPtr lpSecurityDescriptor;\r
26                     public int bInheritHandle;\r
27                 }\r
28                 */\r
29                 \r
30                 [StructLayout(LayoutKind.Sequential)]\r
31                 internal struct PROCESS_INFORMATION\r
32                 {\r
33                         public IntPtr hProcess;\r
34                         public IntPtr hThread;\r
35                         public int dwProcessId;\r
36                         public int dwThreadId;\r
37                 }\r
38                 \r
39                 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]\r
40                 struct STARTUPINFO\r
41                 {\r
42                         public Int32 cb;\r
43                         string lpReserved;\r
44                         string lpDesktop;\r
45                         string lpTitle;\r
46                         Int32 dwX;\r
47                         Int32 dwY;\r
48                         Int32 dwXSize;\r
49                         Int32 dwYSize;\r
50                         Int32 dwXCountChars;\r
51                         Int32 dwYCountChars;\r
52                         Int32 dwFillAttribute;\r
53                         Int32 dwFlags;\r
54                         Int16 wShowWindow;\r
55                         Int16 cbReserved2;\r
56                         IntPtr lpReserved2;\r
57                         IntPtr hStdInput;\r
58                         IntPtr hStdOutput;\r
59                         IntPtr hStdError;\r
60                 }\r
61                 \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
73                 \r
74                 [DllImport("kernel32", SetLastError=true, ExactSpelling=true)]\r
75                 static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);\r
76                 \r
77                 [DllImport("kernel32.dll", SetLastError=true)]\r
78                 [return: MarshalAs(UnmanagedType.Bool)]\r
79                 static extern bool CloseHandle(IntPtr hObject);\r
80                 \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
84                 \r
85                 #endregion\r
86                 \r
87                 STARTUPINFO si;\r
88                 PROCESS_INFORMATION pi;\r
89                 \r
90                 /// <summary>\r
91                 /// プロセスを生成する\r
92                 /// </summary>\r
93                 /// <param name="procInfo">プロセス起動情報。\r
94                 /// なお、<code>procInfo.UseShellExecute</code>は必ずfalseでなければならない</param>\r
95                 public CreateProcessCaller(ProcessStartInfo procInfo)\r
96                 {\r
97                         if (procInfo.UseShellExecute) {\r
98                                 throw new ArgumentException("UseShellExecute must be false");\r
99                         }\r
100                         si.cb = Marshal.SizeOf(si);\r
101                         \r
102                         string lpFileName = (string.IsNullOrEmpty(procInfo.FileName))? null : procInfo.FileName;\r
103                         \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
107                         \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
112                         if (! retValue) {\r
113                                 throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());\r
114                         }\r
115                         CloseHandle(pi.hThread);\r
116                 }\r
117                 \r
118                 /// <summary>\r
119                 /// 関連付けられたプロセスが終了するまで、最大指定したミリ秒間待機。 \r
120                 /// </summary>\r
121                 /// <param name="timeout">最大待機時間(ミリ秒単位)</param>\r
122                 /// <returns>終了コード</returns>\r
123                 public uint WaitForExit(uint timeout)\r
124                 {\r
125                         return WaitForSingleObject(pi.hProcess, timeout);\r
126                 }\r
127                 \r
128                 /// <summary>\r
129                 /// 関連付けられたプロセスが終了するまで無期限に待機。\r
130                 /// </summary>\r
131                 /// <returns>終了コード</returns>\r
132                 public uint WaitForExit()\r
133                 {\r
134                         // return WaitForExit(INFINITE)\r
135                         return WaitForExit(0xFFFFFFFF);\r
136                 }\r
137                 \r
138                 /// <summary>\r
139                 /// 終了コード\r
140                 /// </summary>\r
141                 public int ExitCode {\r
142                         get {\r
143                                 int lpExitCode;\r
144                                 if (! GetExitCodeProcess(pi.hProcess, out lpExitCode) ) {\r
145                                         throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());\r
146                                 }\r
147                                 return lpExitCode;\r
148                         }\r
149                 }\r
150                 \r
151                 /// <summary>\r
152                 /// プロセスのハンドルを開放する\r
153                 /// </summary>\r
154                 public void Dispose()\r
155                 {\r
156                         CloseHandle(pi.hProcess);\r
157                 }\r
158                 \r
159         }\r
160 }\r