Process.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. //
  2. // System.Diagnostics.Process.cs
  3. //
  4. // Authors:
  5. // Dick Porter ([email protected])
  6. // Andreas Nahr ([email protected])
  7. // Gonzalo Paniagua Javier ([email protected])
  8. //
  9. // (C) 2002 Ximian, Inc.
  10. // (C) 2003 Andreas Nahr
  11. // (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
  12. //
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining
  15. // a copy of this software and associated documentation files (the
  16. // "Software"), to deal in the Software without restriction, including
  17. // without limitation the rights to use, copy, modify, merge, publish,
  18. // distribute, sublicense, and/or sell copies of the Software, and to
  19. // permit persons to whom the Software is furnished to do so, subject to
  20. // the following conditions:
  21. //
  22. // The above copyright notice and this permission notice shall be
  23. // included in all copies or substantial portions of the Software.
  24. //
  25. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. //
  33. using System.IO;
  34. using System.Text;
  35. using System.Collections;
  36. using System.ComponentModel;
  37. using System.ComponentModel.Design;
  38. using System.Runtime.CompilerServices;
  39. using System.Runtime.InteropServices;
  40. using System.Runtime.Remoting.Messaging;
  41. using System.Security.Permissions;
  42. using System.Collections.Generic;
  43. using System.Collections.ObjectModel;
  44. using System.Security;
  45. using System.Threading;
  46. using Microsoft.Win32;
  47. using Microsoft.Win32.SafeHandles;
  48. namespace System.Diagnostics
  49. {
  50. public partial class Process : Component
  51. {
  52. [StructLayout(LayoutKind.Sequential)]
  53. private struct ProcInfo
  54. {
  55. public IntPtr process_handle;
  56. /* If thread_handle is ever needed for
  57. * something, take out the CloseHandle() in
  58. * the Start_internal icall in
  59. * mono/metadata/process.c
  60. */
  61. public int pid; // Contains -GetLastError () on failure.
  62. public string[] envVariables;
  63. public string UserName;
  64. public string Domain;
  65. public IntPtr Password;
  66. public bool LoadUserProfile;
  67. };
  68. string process_name;
  69. static ProcessModule current_main_module;
  70. /* Private constructor called from other methods */
  71. private Process (SafeProcessHandle handle, int id) {
  72. SetProcessHandle (handle);
  73. SetProcessId (id);
  74. }
  75. [MonoTODO]
  76. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  77. [MonitoringDescription ("Base process priority.")]
  78. public int BasePriority {
  79. get { return 0; }
  80. }
  81. [MonoTODO]
  82. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  83. [MonitoringDescription ("Handles for this process.")]
  84. public int HandleCount {
  85. get {
  86. return(0);
  87. }
  88. }
  89. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  90. [MonitoringDescription ("The main module of the process.")]
  91. public ProcessModule MainModule {
  92. get {
  93. /* Optimize Process.GetCurrentProcess ().MainModule */
  94. if (processId == NativeMethods.GetCurrentProcessId ()) {
  95. if (current_main_module == null)
  96. current_main_module = this.Modules [0];
  97. return current_main_module;
  98. } else {
  99. return this.Modules [0];
  100. }
  101. }
  102. }
  103. [MonoTODO]
  104. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  105. [MonitoringDescription ("The handle of the main window of the process.")]
  106. public IntPtr MainWindowHandle {
  107. get {
  108. return((IntPtr)0);
  109. }
  110. }
  111. [MonoTODO]
  112. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  113. [MonitoringDescription ("The title of the main window of the process.")]
  114. public string MainWindowTitle {
  115. get {
  116. return("null");
  117. }
  118. }
  119. private static void AppendArguments (StringBuilder stringBuilder, Collection<string> argumentList)
  120. {
  121. if (argumentList.Count > 0) {
  122. foreach (string argument in argumentList) {
  123. PasteArguments.AppendArgument (stringBuilder, argument);
  124. }
  125. }
  126. }
  127. /* Returns the list of process modules. The main module is
  128. * element 0.
  129. */
  130. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  131. private extern ProcessModule[] GetModules_internal(IntPtr handle);
  132. ProcessModule[] GetModules_internal (SafeProcessHandle handle)
  133. {
  134. bool release = false;
  135. try {
  136. handle.DangerousAddRef (ref release);
  137. return GetModules_internal (handle.DangerousGetHandle ());
  138. } finally {
  139. if (release)
  140. handle.DangerousRelease ();
  141. }
  142. }
  143. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  144. [MonitoringDescription ("The modules that are loaded as part of this process.")]
  145. public ProcessModuleCollection Modules {
  146. get {
  147. if (modules == null) {
  148. SafeProcessHandle handle = null;
  149. try {
  150. handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
  151. modules = new ProcessModuleCollection (GetModules_internal (handle));
  152. } finally {
  153. ReleaseProcessHandle (handle);
  154. }
  155. }
  156. return modules;
  157. }
  158. }
  159. /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
  160. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  161. private extern static long GetProcessData (int pid, int data_type, out int error);
  162. [MonoTODO]
  163. [Obsolete ("Use NonpagedSystemMemorySize64")]
  164. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  165. [MonitoringDescription ("The number of bytes that are not pageable.")]
  166. public int NonpagedSystemMemorySize {
  167. get {
  168. return(0);
  169. }
  170. }
  171. [Obsolete ("Use PagedMemorySize64")]
  172. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  173. [MonitoringDescription ("The number of bytes that are paged.")]
  174. public int PagedMemorySize {
  175. get {
  176. return(int)PagedMemorySize64;
  177. }
  178. }
  179. [Obsolete ("Use PagedSystemMemorySize64")]
  180. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  181. [MonitoringDescription ("The amount of paged system memory in bytes.")]
  182. public int PagedSystemMemorySize {
  183. get {
  184. return(int)PagedMemorySize64;
  185. }
  186. }
  187. [MonoTODO]
  188. [Obsolete ("Use PeakPagedMemorySize64")]
  189. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  190. [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
  191. public int PeakPagedMemorySize {
  192. get {
  193. return(0);
  194. }
  195. }
  196. [Obsolete ("Use PeakVirtualMemorySize64")]
  197. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  198. [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
  199. public int PeakVirtualMemorySize {
  200. get {
  201. int error;
  202. return (int)GetProcessData (processId, 8, out error);
  203. }
  204. }
  205. [Obsolete ("Use PeakWorkingSet64")]
  206. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  207. [MonitoringDescription ("The maximum amount of system memory used by this process.")]
  208. public int PeakWorkingSet {
  209. get {
  210. int error;
  211. return (int)GetProcessData (processId, 5, out error);
  212. }
  213. }
  214. [MonoTODO]
  215. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  216. [MonitoringDescription ("The number of bytes that are not pageable.")]
  217. [ComVisible (false)]
  218. public long NonpagedSystemMemorySize64 {
  219. get {
  220. return(0);
  221. }
  222. }
  223. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  224. [MonitoringDescription ("The number of bytes that are paged.")]
  225. [ComVisible (false)]
  226. public long PagedMemorySize64 {
  227. get {
  228. int error;
  229. return GetProcessData (processId, 12, out error);
  230. }
  231. }
  232. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  233. [MonitoringDescription ("The amount of paged system memory in bytes.")]
  234. [ComVisible (false)]
  235. public long PagedSystemMemorySize64 {
  236. get {
  237. return PagedMemorySize64;
  238. }
  239. }
  240. [MonoTODO]
  241. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  242. [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
  243. [ComVisible (false)]
  244. public long PeakPagedMemorySize64 {
  245. get {
  246. return(0);
  247. }
  248. }
  249. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  250. [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
  251. [ComVisible (false)]
  252. public long PeakVirtualMemorySize64 {
  253. get {
  254. int error;
  255. return GetProcessData (processId, 8, out error);
  256. }
  257. }
  258. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  259. [MonitoringDescription ("The maximum amount of system memory used by this process.")]
  260. [ComVisible (false)]
  261. public long PeakWorkingSet64 {
  262. get {
  263. int error;
  264. return GetProcessData (processId, 5, out error);
  265. }
  266. }
  267. [MonoTODO]
  268. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  269. [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
  270. public bool PriorityBoostEnabled {
  271. get {
  272. return(false);
  273. }
  274. set {
  275. }
  276. }
  277. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  278. [MonitoringDescription ("The amount of memory exclusively used by this process.")]
  279. [Obsolete ("Use PrivateMemorySize64")]
  280. public int PrivateMemorySize {
  281. get {
  282. int error;
  283. return (int)GetProcessData (processId, 6, out error);
  284. }
  285. }
  286. [MonoNotSupported ("")]
  287. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  288. [MonitoringDescription ("The session ID for this process.")]
  289. public int SessionId {
  290. get { return 0; }
  291. }
  292. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  293. private extern static string ProcessName_internal(IntPtr handle);
  294. static string ProcessName_internal(SafeProcessHandle handle)
  295. {
  296. bool release = false;
  297. try {
  298. handle.DangerousAddRef (ref release);
  299. return ProcessName_internal (handle.DangerousGetHandle ());
  300. } finally {
  301. if (release)
  302. handle.DangerousRelease ();
  303. }
  304. }
  305. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  306. [MonitoringDescription ("The name of this process.")]
  307. public string ProcessName {
  308. get {
  309. if (process_name == null) {
  310. SafeProcessHandle handle = null;
  311. try {
  312. handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
  313. process_name = ProcessName_internal (handle);
  314. /* If process_name is _still_ null, assume the process has exited or is inaccessible */
  315. if (process_name == null)
  316. throw new InvalidOperationException ("Process has exited or is inaccessible, so the requested information is not available.");
  317. /* Strip the suffix (if it exists) simplistically instead of removing
  318. * any trailing \.???, so we dont get stupid results on sane systems */
  319. if(process_name.EndsWith(".exe") || process_name.EndsWith(".bat") || process_name.EndsWith(".com"))
  320. process_name = process_name.Substring (0, process_name.Length - 4);
  321. } finally {
  322. ReleaseProcessHandle (handle);
  323. }
  324. }
  325. return process_name;
  326. }
  327. }
  328. [MonoTODO]
  329. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  330. [MonitoringDescription ("Allowed processor that can be used by this process.")]
  331. public IntPtr ProcessorAffinity {
  332. get {
  333. return((IntPtr)0);
  334. }
  335. set {
  336. }
  337. }
  338. [MonoTODO]
  339. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  340. [MonitoringDescription ("Is this process responsive.")]
  341. public bool Responding {
  342. get {
  343. return(false);
  344. }
  345. }
  346. #if !MONO_FEATURE_PROCESS_START
  347. [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
  348. public ProcessStartInfo StartInfo {
  349. get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
  350. set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
  351. }
  352. [Obsolete ("Process.StandardError is not supported on the current platform.", true)]
  353. public StreamReader StandardError {
  354. get { throw new PlatformNotSupportedException ("Process.StandardError is not supported on the current platform."); }
  355. }
  356. [Obsolete ("Process.StandardInput is not supported on the current platform.", true)]
  357. public StreamWriter StandardInput {
  358. get { throw new PlatformNotSupportedException ("Process.StandardInput is not supported on the current platform."); }
  359. }
  360. [Obsolete ("Process.StandardOutput is not supported on the current platform.", true)]
  361. public StreamReader StandardOutput {
  362. get { throw new PlatformNotSupportedException ("Process.StandardOutput is not supported on the current platform."); }
  363. }
  364. #endif // !MONO_FEATURE_PROCESS_START
  365. [MonoTODO]
  366. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  367. [MonitoringDescription ("The number of threads of this process.")]
  368. public ProcessThreadCollection Threads {
  369. get {
  370. if (threads == null) {
  371. int error;
  372. // This'll return a correctly-sized array of empty ProcessThreads for now.
  373. threads = new ProcessThreadCollection(new ProcessThread [GetProcessData (processId, 0, out error)]);
  374. }
  375. return threads;
  376. }
  377. }
  378. [Obsolete ("Use VirtualMemorySize64")]
  379. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  380. [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
  381. public int VirtualMemorySize {
  382. get {
  383. int error;
  384. return (int)GetProcessData (processId, 7, out error);
  385. }
  386. }
  387. [Obsolete ("Use WorkingSet64")]
  388. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  389. [MonitoringDescription ("The amount of physical memory currently used for this process.")]
  390. public int WorkingSet {
  391. get {
  392. int error;
  393. return (int)GetProcessData (processId, 4, out error);
  394. }
  395. }
  396. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  397. [MonitoringDescription ("The amount of memory exclusively used by this process.")]
  398. [ComVisible (false)]
  399. public long PrivateMemorySize64 {
  400. get {
  401. int error;
  402. return GetProcessData (processId, 6, out error);
  403. }
  404. }
  405. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  406. [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
  407. [ComVisible (false)]
  408. public long VirtualMemorySize64 {
  409. get {
  410. int error;
  411. return GetProcessData (processId, 7, out error);
  412. }
  413. }
  414. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  415. [MonitoringDescription ("The amount of physical memory currently used for this process.")]
  416. [ComVisible (false)]
  417. public long WorkingSet64 {
  418. get {
  419. int error;
  420. return GetProcessData (processId, 4, out error);
  421. }
  422. }
  423. public bool CloseMainWindow ()
  424. {
  425. SafeProcessHandle handle = null;
  426. try {
  427. handle = GetProcessHandle (NativeMethods.PROCESS_TERMINATE);
  428. return NativeMethods.TerminateProcess(handle, -2);
  429. } finally {
  430. ReleaseProcessHandle(handle);
  431. }
  432. }
  433. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  434. private extern static IntPtr GetProcess_internal(int pid);
  435. [MonoTODO ("There is no support for retrieving process information from a remote machine")]
  436. public static Process GetProcessById(int processId, string machineName) {
  437. if (machineName == null)
  438. throw new ArgumentNullException ("machineName");
  439. if (!IsLocalMachine (machineName))
  440. throw new NotImplementedException ();
  441. IntPtr proc = GetProcess_internal(processId);
  442. if (proc == IntPtr.Zero)
  443. throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
  444. /* The handle returned by GetProcess_internal is owned by its caller, so we must pass true to SafeProcessHandle */
  445. return (new Process (new SafeProcessHandle (proc, true), processId));
  446. }
  447. public static Process[] GetProcessesByName(string processName, string machineName)
  448. {
  449. if (machineName == null)
  450. throw new ArgumentNullException ("machineName");
  451. if (!IsLocalMachine (machineName))
  452. throw new NotImplementedException ();
  453. Process[] processes = GetProcesses ();
  454. if (processes.Length == 0)
  455. return processes;
  456. int size = 0;
  457. for (int i = 0; i < processes.Length; i++) {
  458. var process = processes[i];
  459. try {
  460. if (String.Compare (processName, process.ProcessName, true) == 0)
  461. processes [size++] = process;
  462. else
  463. process.Dispose();
  464. } catch (SystemException) {
  465. /* The process might exit between GetProcesses_internal and GetProcessById */
  466. }
  467. }
  468. Array.Resize<Process> (ref processes, size);
  469. return processes;
  470. }
  471. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  472. private extern static int[] GetProcesses_internal();
  473. [MonoTODO ("There is no support for retrieving process information from a remote machine")]
  474. public static Process[] GetProcesses(string machineName) {
  475. if (machineName == null)
  476. throw new ArgumentNullException ("machineName");
  477. if (!IsLocalMachine (machineName))
  478. throw new NotImplementedException ();
  479. int [] pids = GetProcesses_internal ();
  480. if (pids == null)
  481. return new Process [0];
  482. var proclist = new List<Process> (pids.Length);
  483. for (int i = 0; i < pids.Length; i++) {
  484. try {
  485. proclist.Add (GetProcessById (pids [i]));
  486. } catch (SystemException) {
  487. /* The process might exit
  488. * between
  489. * GetProcesses_internal and
  490. * GetProcessById
  491. */
  492. }
  493. }
  494. return proclist.ToArray ();
  495. }
  496. private static bool IsLocalMachine (string machineName)
  497. {
  498. if (machineName == "." || machineName.Length == 0)
  499. return true;
  500. return (string.Compare (machineName, Environment.MachineName, true) == 0);
  501. }
  502. #if MONO_FEATURE_PROCESS_START
  503. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  504. private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo, ref ProcInfo procInfo);
  505. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  506. private extern static bool CreateProcess_internal(ProcessStartInfo startInfo, IntPtr stdin, IntPtr stdout, IntPtr stderr, ref ProcInfo procInfo);
  507. bool StartWithShellExecuteEx (ProcessStartInfo startInfo)
  508. {
  509. if (this.disposed)
  510. throw new ObjectDisposedException (GetType ().Name);
  511. if (!String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null))
  512. throw new InvalidOperationException(SR.GetString(SR.CantStartAsUser));
  513. if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
  514. throw new InvalidOperationException(SR.GetString(SR.CantRedirectStreams));
  515. if (startInfo.StandardErrorEncoding != null)
  516. throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
  517. if (startInfo.StandardOutputEncoding != null)
  518. throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
  519. // can't set env vars with ShellExecuteEx...
  520. if (startInfo.environmentVariables != null)
  521. throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
  522. ProcInfo procInfo = new ProcInfo();
  523. bool ret;
  524. FillUserInfo (startInfo, ref procInfo);
  525. try {
  526. ret = ShellExecuteEx_internal (startInfo, ref procInfo);
  527. } finally {
  528. if (procInfo.Password != IntPtr.Zero)
  529. Marshal.ZeroFreeBSTR (procInfo.Password);
  530. procInfo.Password = IntPtr.Zero;
  531. }
  532. if (!ret) {
  533. throw new Win32Exception (-procInfo.pid);
  534. }
  535. SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
  536. SetProcessId (procInfo.pid);
  537. return ret;
  538. }
  539. //
  540. // Creates a pipe with read and write descriptors
  541. //
  542. static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
  543. {
  544. MonoIOError error;
  545. //
  546. // Creates read/write pipe from parent -> child perspective
  547. // a child process uses same descriptors after fork. That's
  548. // 4 descriptors in total where only 2. One in child, one in parent
  549. // should be active and the other 2 closed. Which ones depends on
  550. // comunication direction
  551. //
  552. // parent --------> child (parent can write, child can read)
  553. //
  554. // read: closed read: used
  555. // write: used write: closed
  556. //
  557. //
  558. // parent <-------- child (parent can read, child can write)
  559. //
  560. // read: used read: closed
  561. // write: closed write: used
  562. //
  563. // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
  564. //
  565. if (!MonoIO.CreatePipe (out read, out write, out error))
  566. throw MonoIO.GetException (error);
  567. if (IsWindows) {
  568. const int DUPLICATE_SAME_ACCESS = 0x00000002;
  569. var tmp = writeDirection ? write : read;
  570. if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
  571. throw MonoIO.GetException (error);
  572. if (writeDirection) {
  573. if (!MonoIO.Close (write, out error))
  574. throw MonoIO.GetException (error);
  575. write = tmp;
  576. } else {
  577. if (!MonoIO.Close (read, out error))
  578. throw MonoIO.GetException (error);
  579. read = tmp;
  580. }
  581. }
  582. }
  583. static bool IsWindows
  584. {
  585. get
  586. {
  587. PlatformID platform = Environment.OSVersion.Platform;
  588. if (platform == PlatformID.Win32S ||
  589. platform == PlatformID.Win32Windows ||
  590. platform == PlatformID.Win32NT ||
  591. platform == PlatformID.WinCE) {
  592. return true;
  593. }
  594. return false;
  595. }
  596. }
  597. bool StartWithCreateProcess (ProcessStartInfo startInfo)
  598. {
  599. if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
  600. throw new InvalidOperationException (SR.GetString(SR.StandardOutputEncodingNotAllowed));
  601. if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
  602. throw new InvalidOperationException (SR.GetString(SR.StandardErrorEncodingNotAllowed));
  603. if (this.disposed)
  604. throw new ObjectDisposedException (GetType ().Name);
  605. var procInfo = new ProcInfo ();
  606. if (startInfo.HaveEnvVars) {
  607. List<string> envVariables = new List<string> ();
  608. foreach (DictionaryEntry de in startInfo.EnvironmentVariables) {
  609. if (de.Value == null)
  610. continue;
  611. envVariables.Add (string.Concat (
  612. (string) de.Key,
  613. "=",
  614. (string) de.Value));
  615. }
  616. procInfo.envVariables = envVariables.ToArray ();
  617. }
  618. MonoIOError error;
  619. IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
  620. IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
  621. IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
  622. try {
  623. if (startInfo.RedirectStandardInput) {
  624. CreatePipe (out stdin_read, out stdin_write, true);
  625. } else {
  626. stdin_read = MonoIO.ConsoleInput;
  627. stdin_write = IntPtr.Zero;
  628. }
  629. if (startInfo.RedirectStandardOutput) {
  630. CreatePipe (out stdout_read, out stdout_write, false);
  631. } else {
  632. stdout_read = IntPtr.Zero;
  633. stdout_write = MonoIO.ConsoleOutput;
  634. }
  635. if (startInfo.RedirectStandardError) {
  636. CreatePipe (out stderr_read, out stderr_write, false);
  637. } else {
  638. stderr_read = IntPtr.Zero;
  639. stderr_write = MonoIO.ConsoleError;
  640. }
  641. FillUserInfo (startInfo, ref procInfo);
  642. //
  643. // FIXME: For redirected pipes we need to send descriptors of
  644. // stdin_write, stdout_read, stderr_read to child process and
  645. // close them there (fork makes exact copy of parent's descriptors)
  646. //
  647. if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref procInfo)) {
  648. throw new Win32Exception (-procInfo.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
  649. "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.GetErrorMessage (-procInfo.pid));
  650. }
  651. } catch {
  652. if (startInfo.RedirectStandardInput) {
  653. if (stdin_read != IntPtr.Zero)
  654. MonoIO.Close (stdin_read, out error);
  655. if (stdin_write != IntPtr.Zero)
  656. MonoIO.Close (stdin_write, out error);
  657. }
  658. if (startInfo.RedirectStandardOutput) {
  659. if (stdout_read != IntPtr.Zero)
  660. MonoIO.Close (stdout_read, out error);
  661. if (stdout_write != IntPtr.Zero)
  662. MonoIO.Close (stdout_write, out error);
  663. }
  664. if (startInfo.RedirectStandardError) {
  665. if (stderr_read != IntPtr.Zero)
  666. MonoIO.Close (stderr_read, out error);
  667. if (stderr_write != IntPtr.Zero)
  668. MonoIO.Close (stderr_write, out error);
  669. }
  670. throw;
  671. } finally {
  672. if (procInfo.Password != IntPtr.Zero) {
  673. Marshal.ZeroFreeBSTR (procInfo.Password);
  674. procInfo.Password = IntPtr.Zero;
  675. }
  676. }
  677. SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
  678. SetProcessId (procInfo.pid);
  679. #pragma warning disable 618
  680. if (startInfo.RedirectStandardInput) {
  681. MonoIO.Close (stdin_read, out error);
  682. #if MOBILE
  683. var stdinEncoding = startInfo.StandardInputEncoding ?? Encoding.Default;
  684. #else
  685. var stdinEncoding = startInfo.StandardInputEncoding ?? Console.InputEncoding;
  686. #endif
  687. standardInput = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
  688. AutoFlush = true
  689. };
  690. }
  691. if (startInfo.RedirectStandardOutput) {
  692. MonoIO.Close (stdout_write, out error);
  693. Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.OutputEncoding;
  694. standardOutput = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
  695. }
  696. if (startInfo.RedirectStandardError) {
  697. MonoIO.Close (stderr_write, out error);
  698. Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.OutputEncoding;
  699. standardError = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
  700. }
  701. #pragma warning restore
  702. return true;
  703. }
  704. // Note that ProcInfo.Password must be freed.
  705. private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo procInfo)
  706. {
  707. if (startInfo.UserName.Length != 0) {
  708. procInfo.UserName = startInfo.UserName;
  709. procInfo.Domain = startInfo.Domain;
  710. if (startInfo.Password != null)
  711. procInfo.Password = Marshal.SecureStringToBSTR (startInfo.Password);
  712. else
  713. procInfo.Password = IntPtr.Zero;
  714. procInfo.LoadUserProfile = startInfo.LoadUserProfile;
  715. }
  716. }
  717. #else
  718. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  719. public bool Start ()
  720. {
  721. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  722. }
  723. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  724. public static Process Start (ProcessStartInfo startInfo)
  725. {
  726. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  727. }
  728. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  729. public static Process Start (string fileName)
  730. {
  731. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  732. }
  733. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  734. public static Process Start(string fileName, string arguments)
  735. {
  736. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  737. }
  738. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  739. public static Process Start(string fileName, string userName, SecureString password, string domain)
  740. {
  741. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  742. }
  743. [Obsolete ("Process.Start is not supported on the current platform.", true)]
  744. public static Process Start(string fileName, string arguments, string userName, SecureString password, string domain)
  745. {
  746. throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
  747. }
  748. #endif // MONO_FEATURE_PROCESS_START
  749. #if !MONO_FEATURE_PROCESS_START
  750. [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
  751. public void BeginOutputReadLine ()
  752. {
  753. throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
  754. }
  755. [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
  756. public void CancelOutputRead ()
  757. {
  758. throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
  759. }
  760. [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
  761. public void BeginErrorReadLine ()
  762. {
  763. throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
  764. }
  765. [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
  766. public void CancelErrorRead ()
  767. {
  768. throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
  769. }
  770. #endif // !MONO_FEATURE_PROCESS_START
  771. /// <devdoc>
  772. /// Raise the Exited event, but make sure we don't do it more than once.
  773. /// </devdoc>
  774. /// <internalonly/>
  775. void RaiseOnExited() {
  776. if (!watchForExit)
  777. return;
  778. if (!raisedOnExited) {
  779. lock (this) {
  780. if (!raisedOnExited) {
  781. raisedOnExited = true;
  782. OnExited();
  783. }
  784. }
  785. }
  786. }
  787. }
  788. }