Process.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
  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.ComponentModel;
  36. using System.ComponentModel.Design;
  37. using System.Runtime.CompilerServices;
  38. using System.Runtime.InteropServices;
  39. using System.Runtime.Remoting.Messaging;
  40. using System.Security.Permissions;
  41. using System.Collections.Generic;
  42. using System.Security;
  43. using System.Threading;
  44. using Microsoft.Win32.SafeHandles;
  45. namespace System.Diagnostics {
  46. [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
  47. [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
  48. [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
  49. [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
  50. [MonitoringDescription ("Represents a system process")]
  51. public class Process : Component
  52. {
  53. [StructLayout(LayoutKind.Sequential)]
  54. private struct ProcInfo
  55. {
  56. public IntPtr process_handle;
  57. /* If thread_handle is ever needed for
  58. * something, take out the CloseHandle() in
  59. * the Start_internal icall in
  60. * mono/metadata/process.c
  61. */
  62. public IntPtr thread_handle;
  63. public int pid; // Contains -GetLastError () on failure.
  64. public int tid;
  65. public string [] envKeys;
  66. public string [] envValues;
  67. public string UserName;
  68. public string Domain;
  69. public IntPtr Password;
  70. public bool LoadUserProfile;
  71. };
  72. IntPtr process_handle;
  73. int pid;
  74. int enable_raising_events;
  75. Thread background_wait_for_exit_thread;
  76. ISynchronizeInvoke synchronizingObject;
  77. EventHandler exited_event;
  78. /* Private constructor called from other methods */
  79. private Process(IntPtr handle, int id) {
  80. process_handle = handle;
  81. pid=id;
  82. }
  83. public Process ()
  84. {
  85. }
  86. [MonoTODO]
  87. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  88. [MonitoringDescription ("Base process priority.")]
  89. public int BasePriority {
  90. get { return 0; }
  91. }
  92. [DefaultValue (false), Browsable (false)]
  93. [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
  94. public bool EnableRaisingEvents {
  95. get {
  96. return enable_raising_events == 1;
  97. }
  98. set {
  99. if (value && Interlocked.Exchange (ref enable_raising_events, 1) == 0)
  100. StartBackgroundWaitForExit ();
  101. }
  102. }
  103. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  104. private extern static int ExitCode_internal(IntPtr handle);
  105. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  106. [MonitoringDescription ("The exit code of the process.")]
  107. public int ExitCode {
  108. get {
  109. if (process_handle == IntPtr.Zero)
  110. throw new InvalidOperationException ("Process has not been started.");
  111. int code = ExitCode_internal (process_handle);
  112. if (code == 259)
  113. throw new InvalidOperationException ("The process must exit before getting the requested information.");
  114. return code;
  115. }
  116. }
  117. /* Returns the process start time in Windows file
  118. * times (ticks from DateTime(1/1/1601 00:00 GMT))
  119. */
  120. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  121. private extern static long ExitTime_internal(IntPtr handle);
  122. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  123. [MonitoringDescription ("The exit time of the process.")]
  124. public DateTime ExitTime {
  125. get {
  126. if (process_handle == IntPtr.Zero)
  127. throw new InvalidOperationException ("Process has not been started.");
  128. if (!HasExited)
  129. throw new InvalidOperationException ("The process must exit before " +
  130. "getting the requested information.");
  131. return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
  132. }
  133. }
  134. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  135. [MonitoringDescription ("Handle for this process.")]
  136. public IntPtr Handle {
  137. get {
  138. if (process_handle == IntPtr.Zero)
  139. throw new InvalidOperationException ("No process is associated with this object.");
  140. return(process_handle);
  141. }
  142. }
  143. [MonoTODO]
  144. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  145. [MonitoringDescription ("Handles for this process.")]
  146. public int HandleCount {
  147. get {
  148. return(0);
  149. }
  150. }
  151. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  152. [MonitoringDescription ("Determines if the process is still running.")]
  153. public bool HasExited {
  154. get {
  155. if (process_handle == IntPtr.Zero)
  156. throw new InvalidOperationException ("Process has not been started.");
  157. int exitcode = ExitCode_internal (process_handle);
  158. if(exitcode==259) {
  159. /* STILL_ACTIVE */
  160. return(false);
  161. } else {
  162. return(true);
  163. }
  164. }
  165. }
  166. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  167. [MonitoringDescription ("Process identifier.")]
  168. public int Id {
  169. get {
  170. if (pid == 0)
  171. throw new InvalidOperationException ("Process ID has not been set.");
  172. return(pid);
  173. }
  174. }
  175. [MonoTODO]
  176. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  177. [MonitoringDescription ("The name of the computer running the process.")]
  178. public string MachineName {
  179. get {
  180. return("localhost");
  181. }
  182. }
  183. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  184. [MonitoringDescription ("The main module of the process.")]
  185. public ProcessModule MainModule {
  186. get {
  187. return(this.Modules[0]);
  188. }
  189. }
  190. [MonoTODO]
  191. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  192. [MonitoringDescription ("The handle of the main window of the process.")]
  193. public IntPtr MainWindowHandle {
  194. get {
  195. return((IntPtr)0);
  196. }
  197. }
  198. [MonoTODO]
  199. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  200. [MonitoringDescription ("The title of the main window of the process.")]
  201. public string MainWindowTitle {
  202. get {
  203. return("null");
  204. }
  205. }
  206. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  207. private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
  208. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  209. private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
  210. /* LAMESPEC: why is this an IntPtr not a plain int? */
  211. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  212. [MonitoringDescription ("The maximum working set for this process.")]
  213. public IntPtr MaxWorkingSet {
  214. get {
  215. if(HasExited)
  216. throw new InvalidOperationException(
  217. "The process " + ProcessName +
  218. " (ID " + Id + ") has exited");
  219. int min;
  220. int max;
  221. bool ok=GetWorkingSet_internal(process_handle, out min, out max);
  222. if(ok==false) {
  223. throw new Win32Exception();
  224. }
  225. return((IntPtr)max);
  226. }
  227. set {
  228. if(HasExited) {
  229. throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
  230. }
  231. bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
  232. if(ok==false) {
  233. throw new Win32Exception();
  234. }
  235. }
  236. }
  237. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  238. [MonitoringDescription ("The minimum working set for this process.")]
  239. public IntPtr MinWorkingSet {
  240. get {
  241. if(HasExited)
  242. throw new InvalidOperationException(
  243. "The process " + ProcessName +
  244. " (ID " + Id + ") has exited");
  245. int min;
  246. int max;
  247. bool ok= GetWorkingSet_internal (process_handle, out min, out max);
  248. if(!ok)
  249. throw new Win32Exception();
  250. return ((IntPtr) min);
  251. }
  252. set {
  253. if(HasExited)
  254. throw new InvalidOperationException(
  255. "The process " + ProcessName +
  256. " (ID " + Id + ") has exited");
  257. bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
  258. if (!ok)
  259. throw new Win32Exception();
  260. }
  261. }
  262. /* Returns the list of process modules. The main module is
  263. * element 0.
  264. */
  265. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  266. private extern ProcessModule[] GetModules_internal(IntPtr handle);
  267. private ProcessModuleCollection module_collection;
  268. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  269. [MonitoringDescription ("The modules that are loaded as part of this process.")]
  270. public ProcessModuleCollection Modules {
  271. get {
  272. if (module_collection == null)
  273. module_collection = new ProcessModuleCollection(
  274. GetModules_internal (process_handle));
  275. return(module_collection);
  276. }
  277. }
  278. /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
  279. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  280. private extern static long GetProcessData (int pid, int data_type, out int error);
  281. [MonoTODO]
  282. [Obsolete ("Use NonpagedSystemMemorySize64")]
  283. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  284. [MonitoringDescription ("The number of bytes that are not pageable.")]
  285. public int NonpagedSystemMemorySize {
  286. get {
  287. return(0);
  288. }
  289. }
  290. [Obsolete ("Use PagedMemorySize64")]
  291. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  292. [MonitoringDescription ("The number of bytes that are paged.")]
  293. public int PagedMemorySize {
  294. get {
  295. return(int)PagedMemorySize64;
  296. }
  297. }
  298. [Obsolete ("Use PagedSystemMemorySize64")]
  299. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  300. [MonitoringDescription ("The amount of paged system memory in bytes.")]
  301. public int PagedSystemMemorySize {
  302. get {
  303. return(int)PagedMemorySize64;
  304. }
  305. }
  306. [MonoTODO]
  307. [Obsolete ("Use PeakPagedMemorySize64")]
  308. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  309. [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
  310. public int PeakPagedMemorySize {
  311. get {
  312. return(0);
  313. }
  314. }
  315. [Obsolete ("Use PeakVirtualMemorySize64")]
  316. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  317. [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
  318. public int PeakVirtualMemorySize {
  319. get {
  320. int error;
  321. return (int)GetProcessData (pid, 8, out error);
  322. }
  323. }
  324. [Obsolete ("Use PeakWorkingSet64")]
  325. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  326. [MonitoringDescription ("The maximum amount of system memory used by this process.")]
  327. public int PeakWorkingSet {
  328. get {
  329. int error;
  330. return (int)GetProcessData (pid, 5, out error);
  331. }
  332. }
  333. [MonoTODO]
  334. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  335. [MonitoringDescription ("The number of bytes that are not pageable.")]
  336. [ComVisible (false)]
  337. public long NonpagedSystemMemorySize64 {
  338. get {
  339. return(0);
  340. }
  341. }
  342. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  343. [MonitoringDescription ("The number of bytes that are paged.")]
  344. [ComVisible (false)]
  345. public long PagedMemorySize64 {
  346. get {
  347. int error;
  348. return GetProcessData (pid, 12, out error);
  349. }
  350. }
  351. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  352. [MonitoringDescription ("The amount of paged system memory in bytes.")]
  353. [ComVisible (false)]
  354. public long PagedSystemMemorySize64 {
  355. get {
  356. return PagedMemorySize64;
  357. }
  358. }
  359. [MonoTODO]
  360. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  361. [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
  362. [ComVisible (false)]
  363. public long PeakPagedMemorySize64 {
  364. get {
  365. return(0);
  366. }
  367. }
  368. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  369. [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
  370. [ComVisible (false)]
  371. public long PeakVirtualMemorySize64 {
  372. get {
  373. int error;
  374. return GetProcessData (pid, 8, out error);
  375. }
  376. }
  377. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  378. [MonitoringDescription ("The maximum amount of system memory used by this process.")]
  379. [ComVisible (false)]
  380. public long PeakWorkingSet64 {
  381. get {
  382. int error;
  383. return GetProcessData (pid, 5, out error);
  384. }
  385. }
  386. [MonoTODO]
  387. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  388. [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
  389. public bool PriorityBoostEnabled {
  390. get {
  391. return(false);
  392. }
  393. set {
  394. }
  395. }
  396. [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
  397. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  398. [MonitoringDescription ("The relative process priority.")]
  399. public ProcessPriorityClass PriorityClass {
  400. get {
  401. if (process_handle == IntPtr.Zero)
  402. throw new InvalidOperationException ("Process has not been started.");
  403. int error;
  404. int prio = GetPriorityClass (process_handle, out error);
  405. if (prio == 0)
  406. throw new Win32Exception (error);
  407. return (ProcessPriorityClass) prio;
  408. }
  409. set {
  410. if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
  411. throw new InvalidEnumArgumentException (
  412. "value", (int) value,
  413. typeof (ProcessPriorityClass));
  414. if (process_handle == IntPtr.Zero)
  415. throw new InvalidOperationException ("Process has not been started.");
  416. int error;
  417. if (!SetPriorityClass (process_handle, (int) value, out error)) {
  418. CheckExited ();
  419. throw new Win32Exception (error);
  420. }
  421. }
  422. }
  423. void CheckExited () {
  424. if (HasExited)
  425. throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
  426. }
  427. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  428. static extern int GetPriorityClass (IntPtr handle, out int error);
  429. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  430. static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
  431. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  432. [MonitoringDescription ("The amount of memory exclusively used by this process.")]
  433. [Obsolete ("Use PrivateMemorySize64")]
  434. public int PrivateMemorySize {
  435. get {
  436. int error;
  437. return (int)GetProcessData (pid, 6, out error);
  438. }
  439. }
  440. [MonoNotSupported ("")]
  441. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  442. [MonitoringDescription ("The session ID for this process.")]
  443. public int SessionId {
  444. get { throw new NotImplementedException (); }
  445. }
  446. /* the meaning of type is as follows: 0: user, 1: system, 2: total */
  447. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  448. private extern static long Times (IntPtr handle, int type);
  449. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  450. [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
  451. public TimeSpan PrivilegedProcessorTime {
  452. get {
  453. return new TimeSpan (Times (process_handle, 1));
  454. }
  455. }
  456. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  457. private extern static string ProcessName_internal(IntPtr handle);
  458. private string process_name=null;
  459. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  460. [MonitoringDescription ("The name of this process.")]
  461. public string ProcessName {
  462. get {
  463. if(process_name==null) {
  464. if (process_handle == IntPtr.Zero)
  465. throw new InvalidOperationException ("No process is associated with this object.");
  466. process_name=ProcessName_internal(process_handle);
  467. /* If process_name is _still_
  468. * null, assume the process
  469. * has exited
  470. */
  471. if (process_name == null)
  472. throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
  473. /* Strip the suffix (if it
  474. * exists) simplistically
  475. * instead of removing any
  476. * trailing \.???, so we dont
  477. * get stupid results on sane
  478. * systems
  479. */
  480. if(process_name.EndsWith(".exe") ||
  481. process_name.EndsWith(".bat") ||
  482. process_name.EndsWith(".com")) {
  483. process_name=process_name.Substring(0, process_name.Length-4);
  484. }
  485. }
  486. return(process_name);
  487. }
  488. }
  489. [MonoTODO]
  490. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  491. [MonitoringDescription ("Allowed processor that can be used by this process.")]
  492. public IntPtr ProcessorAffinity {
  493. get {
  494. return((IntPtr)0);
  495. }
  496. set {
  497. }
  498. }
  499. [MonoTODO]
  500. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  501. [MonitoringDescription ("Is this process responsive.")]
  502. public bool Responding {
  503. get {
  504. return(false);
  505. }
  506. }
  507. private StreamReader error_stream=null;
  508. bool error_stream_exposed;
  509. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  510. [MonitoringDescription ("The standard error stream of this process.")]
  511. public StreamReader StandardError {
  512. get {
  513. if (error_stream == null)
  514. throw new InvalidOperationException("Standard error has not been redirected");
  515. if ((async_mode & AsyncModes.AsyncError) != 0)
  516. throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
  517. async_mode |= AsyncModes.SyncError;
  518. error_stream_exposed = true;
  519. return(error_stream);
  520. }
  521. }
  522. private StreamWriter input_stream=null;
  523. bool input_stream_exposed;
  524. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  525. [MonitoringDescription ("The standard input stream of this process.")]
  526. public StreamWriter StandardInput {
  527. get {
  528. if (input_stream == null)
  529. throw new InvalidOperationException("Standard input has not been redirected");
  530. input_stream_exposed = true;
  531. return(input_stream);
  532. }
  533. }
  534. private StreamReader output_stream=null;
  535. bool output_stream_exposed;
  536. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
  537. [MonitoringDescription ("The standard output stream of this process.")]
  538. public StreamReader StandardOutput {
  539. get {
  540. if (output_stream == null)
  541. throw new InvalidOperationException("Standard output has not been redirected");
  542. if ((async_mode & AsyncModes.AsyncOutput) != 0)
  543. throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
  544. async_mode |= AsyncModes.SyncOutput;
  545. output_stream_exposed = true;
  546. return(output_stream);
  547. }
  548. }
  549. private ProcessStartInfo start_info=null;
  550. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
  551. [MonitoringDescription ("Information for the start of this process.")]
  552. public ProcessStartInfo StartInfo {
  553. get {
  554. if (start_info == null)
  555. start_info = new ProcessStartInfo();
  556. return start_info;
  557. }
  558. set {
  559. if (value == null)
  560. throw new ArgumentNullException("value");
  561. start_info = value;
  562. }
  563. }
  564. /* Returns the process start time in Windows file
  565. * times (ticks from DateTime(1/1/1601 00:00 GMT))
  566. */
  567. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  568. private extern static long StartTime_internal(IntPtr handle);
  569. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  570. [MonitoringDescription ("The time this process started.")]
  571. public DateTime StartTime {
  572. get {
  573. return(DateTime.FromFileTime(StartTime_internal(process_handle)));
  574. }
  575. }
  576. [DefaultValue (null), Browsable (false)]
  577. [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
  578. public ISynchronizeInvoke SynchronizingObject {
  579. get { return synchronizingObject; }
  580. set { synchronizingObject = value; }
  581. }
  582. [MonoTODO]
  583. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  584. [MonitoringDescription ("The number of threads of this process.")]
  585. public ProcessThreadCollection Threads {
  586. get {
  587. // This'll return a correctly-sized array of empty ProcessThreads for now.
  588. int error;
  589. return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
  590. }
  591. }
  592. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  593. [MonitoringDescription ("The total CPU time spent for this process.")]
  594. public TimeSpan TotalProcessorTime {
  595. get {
  596. return new TimeSpan (Times (process_handle, 2));
  597. }
  598. }
  599. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  600. [MonitoringDescription ("The CPU time spent for this process in user mode.")]
  601. public TimeSpan UserProcessorTime {
  602. get {
  603. return new TimeSpan (Times (process_handle, 0));
  604. }
  605. }
  606. [Obsolete ("Use VirtualMemorySize64")]
  607. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  608. [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
  609. public int VirtualMemorySize {
  610. get {
  611. int error;
  612. return (int)GetProcessData (pid, 7, out error);
  613. }
  614. }
  615. [Obsolete ("Use WorkingSet64")]
  616. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  617. [MonitoringDescription ("The amount of physical memory currently used for this process.")]
  618. public int WorkingSet {
  619. get {
  620. int error;
  621. return (int)GetProcessData (pid, 4, out error);
  622. }
  623. }
  624. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  625. [MonitoringDescription ("The amount of memory exclusively used by this process.")]
  626. [ComVisible (false)]
  627. public long PrivateMemorySize64 {
  628. get {
  629. int error;
  630. return GetProcessData (pid, 6, out error);
  631. }
  632. }
  633. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  634. [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
  635. [ComVisible (false)]
  636. public long VirtualMemorySize64 {
  637. get {
  638. int error;
  639. return GetProcessData (pid, 7, out error);
  640. }
  641. }
  642. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  643. [MonitoringDescription ("The amount of physical memory currently used for this process.")]
  644. [ComVisible (false)]
  645. public long WorkingSet64 {
  646. get {
  647. int error;
  648. return GetProcessData (pid, 4, out error);
  649. }
  650. }
  651. public void Close()
  652. {
  653. Dispose (true);
  654. }
  655. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  656. extern static bool Kill_internal (IntPtr handle, int signo);
  657. /* int kill -> 1 KILL, 2 CloseMainWindow */
  658. bool Close (int signo)
  659. {
  660. if (process_handle == IntPtr.Zero)
  661. throw new SystemException ("No process to kill.");
  662. int exitcode = ExitCode_internal (process_handle);
  663. if (exitcode != 259)
  664. throw new InvalidOperationException ("The process already finished.");
  665. return Kill_internal (process_handle, signo);
  666. }
  667. public bool CloseMainWindow ()
  668. {
  669. return Close (2);
  670. }
  671. [MonoTODO]
  672. public static void EnterDebugMode() {
  673. }
  674. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  675. private extern static IntPtr GetProcess_internal(int pid);
  676. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  677. private extern static int GetPid_internal();
  678. public static Process GetCurrentProcess()
  679. {
  680. int pid = GetPid_internal();
  681. IntPtr proc = GetProcess_internal(pid);
  682. if (proc == IntPtr.Zero)
  683. throw new SystemException("Can't find current process");
  684. return (new Process (proc, pid));
  685. }
  686. public static Process GetProcessById(int processId)
  687. {
  688. IntPtr proc = GetProcess_internal(processId);
  689. if (proc == IntPtr.Zero)
  690. throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
  691. return (new Process (proc, processId));
  692. }
  693. [MonoTODO ("There is no support for retrieving process information from a remote machine")]
  694. public static Process GetProcessById(int processId, string machineName) {
  695. if (machineName == null)
  696. throw new ArgumentNullException ("machineName");
  697. if (!IsLocalMachine (machineName))
  698. throw new NotImplementedException ();
  699. return GetProcessById (processId);
  700. }
  701. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  702. private extern static int[] GetProcesses_internal();
  703. public static Process[] GetProcesses ()
  704. {
  705. int [] pids = GetProcesses_internal ();
  706. if (pids == null)
  707. return new Process [0];
  708. var proclist = new List<Process> (pids.Length);
  709. for (int i = 0; i < pids.Length; i++) {
  710. try {
  711. proclist.Add (GetProcessById (pids [i]));
  712. } catch (SystemException) {
  713. /* The process might exit
  714. * between
  715. * GetProcesses_internal and
  716. * GetProcessById
  717. */
  718. }
  719. }
  720. return proclist.ToArray ();
  721. }
  722. [MonoTODO ("There is no support for retrieving process information from a remote machine")]
  723. public static Process[] GetProcesses(string machineName) {
  724. if (machineName == null)
  725. throw new ArgumentNullException ("machineName");
  726. if (!IsLocalMachine (machineName))
  727. throw new NotImplementedException ();
  728. return GetProcesses ();
  729. }
  730. public static Process[] GetProcessesByName(string processName)
  731. {
  732. int [] pids = GetProcesses_internal ();
  733. if (pids == null)
  734. return new Process [0];
  735. var proclist = new List<Process> (pids.Length);
  736. for (int i = 0; i < pids.Length; i++) {
  737. try {
  738. Process p = GetProcessById (pids [i]);
  739. if (String.Compare (processName, p.ProcessName, true) == 0)
  740. proclist.Add (p);
  741. } catch (SystemException) {
  742. /* The process might exit
  743. * between
  744. * GetProcesses_internal and
  745. * GetProcessById
  746. */
  747. }
  748. }
  749. return proclist.ToArray ();
  750. }
  751. [MonoTODO]
  752. public static Process[] GetProcessesByName(string processName, string machineName) {
  753. throw new NotImplementedException();
  754. }
  755. public void Kill ()
  756. {
  757. Close (1);
  758. }
  759. [MonoTODO]
  760. public static void LeaveDebugMode() {
  761. }
  762. public void Refresh ()
  763. {
  764. // FIXME: should refresh any cached data we might have about
  765. // the process (currently we have none).
  766. }
  767. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  768. private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
  769. ref ProcInfo proc_info);
  770. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  771. private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
  772. IntPtr stdin,
  773. IntPtr stdout,
  774. IntPtr stderr,
  775. ref ProcInfo proc_info);
  776. private static bool Start_shell (ProcessStartInfo startInfo, Process process)
  777. {
  778. ProcInfo proc_info=new ProcInfo();
  779. bool ret;
  780. if (startInfo.RedirectStandardInput ||
  781. startInfo.RedirectStandardOutput ||
  782. startInfo.RedirectStandardError) {
  783. throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
  784. }
  785. if (startInfo.HaveEnvVars)
  786. throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
  787. FillUserInfo (startInfo, ref proc_info);
  788. try {
  789. ret = ShellExecuteEx_internal (startInfo,
  790. ref proc_info);
  791. } finally {
  792. if (proc_info.Password != IntPtr.Zero)
  793. Marshal.ZeroFreeBSTR (proc_info.Password);
  794. proc_info.Password = IntPtr.Zero;
  795. }
  796. if (!ret) {
  797. throw new Win32Exception (-proc_info.pid);
  798. }
  799. process.process_handle = proc_info.process_handle;
  800. process.pid = proc_info.pid;
  801. process.StartBackgroundWaitForExit ();
  802. return(ret);
  803. }
  804. //
  805. // Creates a pipe with read and write descriptors
  806. //
  807. static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
  808. {
  809. MonoIOError error;
  810. //
  811. // Creates read/write pipe from parent -> child perspective
  812. // a child process uses same descriptors after fork. That's
  813. // 4 descriptors in total where only 2. One in child, one in parent
  814. // should be active and the other 2 closed. Which ones depends on
  815. // comunication direction
  816. //
  817. // parent --------> child (parent can write, child can read)
  818. //
  819. // read: closed read: used
  820. // write: used write: closed
  821. //
  822. //
  823. // parent <-------- child (parent can read, child can write)
  824. //
  825. // read: used read: closed
  826. // write: closed write: used
  827. //
  828. // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
  829. //
  830. if (!MonoIO.CreatePipe (out read, out write, out error))
  831. throw MonoIO.GetException (error);
  832. if (IsWindows) {
  833. const int DUPLICATE_SAME_ACCESS = 0x00000002;
  834. var tmp = writeDirection ? write : read;
  835. if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
  836. throw MonoIO.GetException (error);
  837. if (writeDirection) {
  838. if (!MonoIO.Close (write, out error))
  839. throw MonoIO.GetException (error);
  840. write = tmp;
  841. } else {
  842. if (!MonoIO.Close (read, out error))
  843. throw MonoIO.GetException (error);
  844. read = tmp;
  845. }
  846. }
  847. }
  848. static bool Start_noshell (ProcessStartInfo startInfo, Process process)
  849. {
  850. var proc_info = new ProcInfo ();
  851. if (startInfo.HaveEnvVars) {
  852. string [] strs = new string [startInfo.EnvironmentVariables.Count];
  853. startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
  854. proc_info.envKeys = strs;
  855. strs = new string [startInfo.EnvironmentVariables.Count];
  856. startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
  857. proc_info.envValues = strs;
  858. }
  859. MonoIOError error;
  860. IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
  861. IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
  862. IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
  863. try {
  864. if (startInfo.RedirectStandardInput) {
  865. CreatePipe (out stdin_read, out stdin_write, true);
  866. } else {
  867. stdin_read = MonoIO.ConsoleInput;
  868. stdin_write = IntPtr.Zero;
  869. }
  870. if (startInfo.RedirectStandardOutput) {
  871. CreatePipe (out stdout_read, out stdout_write, false);
  872. } else {
  873. stdout_read = IntPtr.Zero;
  874. stdout_write = MonoIO.ConsoleOutput;
  875. }
  876. if (startInfo.RedirectStandardError) {
  877. CreatePipe (out stderr_read, out stderr_write, false);
  878. } else {
  879. stderr_read = IntPtr.Zero;
  880. stderr_write = MonoIO.ConsoleError;
  881. }
  882. FillUserInfo (startInfo, ref proc_info);
  883. //
  884. // FIXME: For redirected pipes we need to send descriptors of
  885. // stdin_write, stdout_read, stderr_read to child process and
  886. // close them there (fork makes exact copy of parent's descriptors)
  887. //
  888. if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
  889. throw new Win32Exception (-proc_info.pid,
  890. "ApplicationName='" + startInfo.FileName +
  891. "', CommandLine='" + startInfo.Arguments +
  892. "', CurrentDirectory='" + startInfo.WorkingDirectory +
  893. "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
  894. }
  895. } catch {
  896. if (startInfo.RedirectStandardInput) {
  897. if (stdin_read != IntPtr.Zero)
  898. MonoIO.Close (stdin_read, out error);
  899. if (stdin_write != IntPtr.Zero)
  900. MonoIO.Close (stdin_write, out error);
  901. }
  902. if (startInfo.RedirectStandardOutput) {
  903. if (stdout_read != IntPtr.Zero)
  904. MonoIO.Close (stdout_read, out error);
  905. if (stdout_write != IntPtr.Zero)
  906. MonoIO.Close (stdout_write, out error);
  907. }
  908. if (startInfo.RedirectStandardError) {
  909. if (stderr_read != IntPtr.Zero)
  910. MonoIO.Close (stderr_read, out error);
  911. if (stderr_write != IntPtr.Zero)
  912. MonoIO.Close (stderr_write, out error);
  913. }
  914. throw;
  915. } finally {
  916. if (proc_info.Password != IntPtr.Zero) {
  917. Marshal.ZeroFreeBSTR (proc_info.Password);
  918. proc_info.Password = IntPtr.Zero;
  919. }
  920. }
  921. process.process_handle = proc_info.process_handle;
  922. process.pid = proc_info.pid;
  923. if (startInfo.RedirectStandardInput) {
  924. //
  925. // FIXME: The descriptor needs to be closed but due to wapi io-layer
  926. // not coping with duplicated descriptors any StandardInput write fails
  927. //
  928. // MonoIO.Close (stdin_read, out error);
  929. #if MOBILE
  930. var stdinEncoding = Encoding.Default;
  931. #else
  932. var stdinEncoding = Console.InputEncoding;
  933. #endif
  934. process.input_stream = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
  935. AutoFlush = true
  936. };
  937. }
  938. if (startInfo.RedirectStandardOutput) {
  939. MonoIO.Close (stdout_write, out error);
  940. Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
  941. process.output_stream = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
  942. }
  943. if (startInfo.RedirectStandardError) {
  944. MonoIO.Close (stderr_write, out error);
  945. Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
  946. process.error_stream = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
  947. }
  948. process.StartBackgroundWaitForExit ();
  949. return true;
  950. }
  951. // Note that ProcInfo.Password must be freed.
  952. private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
  953. {
  954. if (startInfo.UserName.Length != 0) {
  955. proc_info.UserName = startInfo.UserName;
  956. proc_info.Domain = startInfo.Domain;
  957. if (startInfo.Password != null)
  958. proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
  959. else
  960. proc_info.Password = IntPtr.Zero;
  961. proc_info.LoadUserProfile = startInfo.LoadUserProfile;
  962. }
  963. }
  964. private static bool Start_common (ProcessStartInfo startInfo,
  965. Process process)
  966. {
  967. if (startInfo.FileName.Length == 0)
  968. throw new InvalidOperationException("File name has not been set");
  969. if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
  970. throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
  971. if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
  972. throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
  973. if (startInfo.UseShellExecute) {
  974. if (startInfo.UserName.Length != 0)
  975. throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
  976. return (Start_shell (startInfo, process));
  977. } else {
  978. return (Start_noshell (startInfo, process));
  979. }
  980. }
  981. public bool Start ()
  982. {
  983. if (process_handle != IntPtr.Zero) {
  984. Process_free_internal (process_handle);
  985. process_handle = IntPtr.Zero;
  986. }
  987. return Start_common(start_info, this);
  988. }
  989. public static Process Start (ProcessStartInfo startInfo)
  990. {
  991. if (startInfo == null)
  992. throw new ArgumentNullException ("startInfo");
  993. Process process = new Process();
  994. process.StartInfo = startInfo;
  995. if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
  996. return process;
  997. return null;
  998. }
  999. public static Process Start (string fileName)
  1000. {
  1001. return Start (new ProcessStartInfo (fileName));
  1002. }
  1003. public static Process Start(string fileName, string arguments)
  1004. {
  1005. return Start (new ProcessStartInfo (fileName, arguments));
  1006. }
  1007. public static Process Start(string fileName, string username, SecureString password, string domain) {
  1008. return Start(fileName, null, username, password, domain);
  1009. }
  1010. public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
  1011. ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
  1012. psi.UserName = username;
  1013. psi.Password = password;
  1014. psi.Domain = domain;
  1015. psi.UseShellExecute = false;
  1016. return Start(psi);
  1017. }
  1018. public override string ToString()
  1019. {
  1020. return(base.ToString() + " (" + this.ProcessName + ")");
  1021. }
  1022. /* Waits up to ms milliseconds for process 'handle' to
  1023. * exit. ms can be <0 to mean wait forever.
  1024. */
  1025. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1026. private extern bool WaitForExit_internal(IntPtr handle, int ms);
  1027. public void WaitForExit ()
  1028. {
  1029. WaitForExit (-1);
  1030. }
  1031. public bool WaitForExit(int milliseconds) {
  1032. int ms = milliseconds;
  1033. if (ms == int.MaxValue)
  1034. ms = -1;
  1035. if (process_handle == IntPtr.Zero)
  1036. throw new InvalidOperationException ("No process is associated with this object.");
  1037. if (!WaitForExit_internal (process_handle, ms))
  1038. return false;
  1039. if (async_output != null && !async_output.IsCompleted)
  1040. async_output.AsyncWaitHandle.WaitOne ();
  1041. if (async_error != null && !async_error.IsCompleted)
  1042. async_error.AsyncWaitHandle.WaitOne ();
  1043. OnExited ();
  1044. return true;
  1045. }
  1046. /* Waits up to ms milliseconds for process 'handle' to
  1047. * wait for input. ms can be <0 to mean wait forever.
  1048. */
  1049. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1050. private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
  1051. // The internal call is only implemented properly on Windows.
  1052. [MonoTODO]
  1053. public bool WaitForInputIdle() {
  1054. return WaitForInputIdle (-1);
  1055. }
  1056. // The internal call is only implemented properly on Windows.
  1057. [MonoTODO]
  1058. public bool WaitForInputIdle(int milliseconds) {
  1059. return WaitForInputIdle_internal (process_handle, milliseconds);
  1060. }
  1061. private static bool IsLocalMachine (string machineName)
  1062. {
  1063. if (machineName == "." || machineName.Length == 0)
  1064. return true;
  1065. return (string.Compare (machineName, Environment.MachineName, true) == 0);
  1066. }
  1067. [Browsable (true)]
  1068. [MonitoringDescription ("Raised when it receives output data")]
  1069. public event DataReceivedEventHandler OutputDataReceived;
  1070. [Browsable (true)]
  1071. [MonitoringDescription ("Raised when it receives error data")]
  1072. public event DataReceivedEventHandler ErrorDataReceived;
  1073. void OnOutputDataReceived (string str)
  1074. {
  1075. DataReceivedEventHandler cb = OutputDataReceived;
  1076. if (cb != null)
  1077. cb (this, new DataReceivedEventArgs (str));
  1078. }
  1079. void OnErrorDataReceived (string str)
  1080. {
  1081. DataReceivedEventHandler cb = ErrorDataReceived;
  1082. if (cb != null)
  1083. cb (this, new DataReceivedEventArgs (str));
  1084. }
  1085. [Flags]
  1086. enum AsyncModes {
  1087. NoneYet = 0,
  1088. SyncOutput = 1,
  1089. SyncError = 1 << 1,
  1090. AsyncOutput = 1 << 2,
  1091. AsyncError = 1 << 3
  1092. }
  1093. [StructLayout (LayoutKind.Sequential)]
  1094. sealed class ProcessAsyncReader : IOAsyncResult
  1095. {
  1096. Process process;
  1097. IntPtr handle;
  1098. Stream stream;
  1099. bool err_out;
  1100. StringBuilder sb = new StringBuilder ();
  1101. byte[] buffer = new byte [4096];
  1102. const int ERROR_INVALID_HANDLE = 6;
  1103. public ProcessAsyncReader (Process process, FileStream stream, bool err_out)
  1104. : base (null, null)
  1105. {
  1106. this.process = process;
  1107. this.handle = stream.SafeFileHandle.DangerousGetHandle ();
  1108. this.stream = stream;
  1109. this.err_out = err_out;
  1110. }
  1111. public void BeginReadLine ()
  1112. {
  1113. IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
  1114. }
  1115. void Read ()
  1116. {
  1117. int nread = 0;
  1118. try {
  1119. nread = stream.Read (buffer, 0, buffer.Length);
  1120. } catch (ObjectDisposedException) {
  1121. } catch (IOException ex) {
  1122. if (ex.HResult != (unchecked((int) 0x80070000) | (int) ERROR_INVALID_HANDLE))
  1123. throw;
  1124. } catch (NotSupportedException) {
  1125. if (stream.CanRead)
  1126. throw;
  1127. }
  1128. if (nread == 0) {
  1129. Flush (true);
  1130. if (err_out)
  1131. process.OnOutputDataReceived (null);
  1132. else
  1133. process.OnErrorDataReceived (null);
  1134. IsCompleted = true;
  1135. return;
  1136. }
  1137. try {
  1138. sb.Append (Encoding.Default.GetString (buffer, 0, nread));
  1139. } catch {
  1140. // Just in case the encoding fails...
  1141. for (int i = 0; i < nread; i++) {
  1142. sb.Append ((char) buffer [i]);
  1143. }
  1144. }
  1145. Flush (false);
  1146. IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
  1147. }
  1148. void Flush (bool last)
  1149. {
  1150. if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
  1151. return;
  1152. string[] strs = sb.ToString ().Split ('\n');
  1153. sb.Length = 0;
  1154. if (strs.Length == 0)
  1155. return;
  1156. for (int i = 0; i < strs.Length - 1; i++) {
  1157. if (err_out)
  1158. process.OnOutputDataReceived (strs [i]);
  1159. else
  1160. process.OnErrorDataReceived (strs [i]);
  1161. }
  1162. string end = strs [strs.Length - 1];
  1163. if (last || (strs.Length == 1 && end == "")) {
  1164. if (err_out)
  1165. process.OnOutputDataReceived (end);
  1166. else
  1167. process.OnErrorDataReceived (end);
  1168. } else {
  1169. sb.Append (end);
  1170. }
  1171. }
  1172. public void Close ()
  1173. {
  1174. IOSelector.Remove (handle);
  1175. }
  1176. internal override void CompleteDisposed ()
  1177. {
  1178. throw new NotSupportedException ();
  1179. }
  1180. }
  1181. AsyncModes async_mode;
  1182. bool output_canceled;
  1183. bool error_canceled;
  1184. ProcessAsyncReader async_output;
  1185. ProcessAsyncReader async_error;
  1186. [ComVisibleAttribute(false)]
  1187. public void BeginOutputReadLine ()
  1188. {
  1189. if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
  1190. throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
  1191. if ((async_mode & AsyncModes.SyncOutput) != 0)
  1192. throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
  1193. async_mode |= AsyncModes.AsyncOutput;
  1194. output_canceled = false;
  1195. if (async_output == null) {
  1196. async_output = new ProcessAsyncReader (this, (FileStream) output_stream.BaseStream, true);
  1197. async_output.BeginReadLine ();
  1198. }
  1199. }
  1200. [ComVisibleAttribute(false)]
  1201. public void CancelOutputRead ()
  1202. {
  1203. if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
  1204. throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
  1205. if ((async_mode & AsyncModes.SyncOutput) != 0)
  1206. throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
  1207. if (async_output == null)
  1208. throw new InvalidOperationException ("No async operation in progress.");
  1209. output_canceled = true;
  1210. }
  1211. [ComVisibleAttribute(false)]
  1212. public void BeginErrorReadLine ()
  1213. {
  1214. if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
  1215. throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
  1216. if ((async_mode & AsyncModes.SyncError) != 0)
  1217. throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
  1218. async_mode |= AsyncModes.AsyncError;
  1219. error_canceled = false;
  1220. if (async_error == null) {
  1221. async_error = new ProcessAsyncReader (this, (FileStream) error_stream.BaseStream, false);
  1222. async_error.BeginReadLine ();
  1223. }
  1224. }
  1225. [ComVisibleAttribute(false)]
  1226. public void CancelErrorRead ()
  1227. {
  1228. if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
  1229. throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
  1230. if ((async_mode & AsyncModes.SyncOutput) != 0)
  1231. throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
  1232. if (async_error == null)
  1233. throw new InvalidOperationException ("No async operation in progress.");
  1234. error_canceled = true;
  1235. }
  1236. [Category ("Behavior")]
  1237. [MonitoringDescription ("Raised when this process exits.")]
  1238. public event EventHandler Exited {
  1239. add {
  1240. if (process_handle != IntPtr.Zero && HasExited) {
  1241. value.BeginInvoke (null, null, null, null);
  1242. } else {
  1243. exited_event += value;
  1244. if (exited_event != null)
  1245. StartBackgroundWaitForExit ();
  1246. }
  1247. }
  1248. remove {
  1249. exited_event -= value;
  1250. }
  1251. }
  1252. // Closes the system process handle
  1253. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1254. private extern void Process_free_internal(IntPtr handle);
  1255. int disposed;
  1256. protected override void Dispose(bool disposing) {
  1257. // Check to see if Dispose has already been called.
  1258. if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
  1259. return;
  1260. // If this is a call to Dispose,
  1261. // dispose all managed resources.
  1262. if (disposing) {
  1263. /* These have open FileStreams on the pipes we are about to close */
  1264. if (async_output != null)
  1265. async_output.Close ();
  1266. if (async_error != null)
  1267. async_error.Close ();
  1268. if (input_stream != null) {
  1269. if (!input_stream_exposed)
  1270. input_stream.Close ();
  1271. input_stream = null;
  1272. }
  1273. if (output_stream != null) {
  1274. if (!output_stream_exposed)
  1275. output_stream.Close ();
  1276. output_stream = null;
  1277. }
  1278. if (error_stream != null) {
  1279. if (!error_stream_exposed)
  1280. error_stream.Close ();
  1281. error_stream = null;
  1282. }
  1283. }
  1284. // Release unmanaged resources
  1285. if (process_handle!=IntPtr.Zero) {
  1286. Process_free_internal (process_handle);
  1287. process_handle = IntPtr.Zero;
  1288. }
  1289. base.Dispose (disposing);
  1290. }
  1291. ~Process ()
  1292. {
  1293. Dispose (false);
  1294. }
  1295. int on_exited_called = 0;
  1296. protected void OnExited()
  1297. {
  1298. if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
  1299. return;
  1300. var cb = exited_event;
  1301. if (cb == null)
  1302. return;
  1303. if (synchronizingObject != null) {
  1304. synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
  1305. } else {
  1306. foreach (EventHandler d in cb.GetInvocationList ()) {
  1307. try {
  1308. d (this, EventArgs.Empty);
  1309. } catch {
  1310. }
  1311. }
  1312. }
  1313. }
  1314. static bool IsWindows
  1315. {
  1316. get
  1317. {
  1318. PlatformID platform = Environment.OSVersion.Platform;
  1319. if (platform == PlatformID.Win32S ||
  1320. platform == PlatformID.Win32Windows ||
  1321. platform == PlatformID.Win32NT ||
  1322. platform == PlatformID.WinCE) {
  1323. return true;
  1324. }
  1325. return false;
  1326. }
  1327. }
  1328. void StartBackgroundWaitForExit ()
  1329. {
  1330. if (enable_raising_events == 0)
  1331. return;
  1332. if (exited_event == null)
  1333. return;
  1334. if (process_handle == IntPtr.Zero)
  1335. return;
  1336. if (background_wait_for_exit_thread != null)
  1337. return;
  1338. Thread t = new Thread (_ => WaitForExit ()) { IsBackground = true };
  1339. if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
  1340. t.Start ();
  1341. }
  1342. class ProcessWaitHandle : WaitHandle
  1343. {
  1344. [MethodImplAttribute (MethodImplOptions.InternalCall)]
  1345. private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
  1346. public ProcessWaitHandle (IntPtr handle)
  1347. {
  1348. // Need to keep a reference to this handle,
  1349. // in case the Process object is collected
  1350. Handle = ProcessHandle_duplicate (handle);
  1351. // When the wait handle is disposed, the duplicated handle will be
  1352. // closed, so no need to override dispose (bug #464628).
  1353. }
  1354. }
  1355. }
  1356. }