Tue Sep 25 18:03:37 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
1 //
2 // System.Diagnostics.Process.cs
3 //
4 // Authors:
5 //      Dick Porter (dick@ximian.com)
6 //      Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
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 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.IO;
36 using System.Text;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Security.Permissions;
42 using System.Collections;
43 using System.Security;
44 using System.Threading;
45
46 namespace System.Diagnostics {
47
48         [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
49         [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
50         [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
51         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
52 #if NET_2_0
53         [MonitoringDescription ("Represents a system process")]
54 #endif
55         public class Process : Component 
56         {
57                 [StructLayout(LayoutKind.Sequential)]
58                 private struct ProcInfo 
59                 {
60                         public IntPtr process_handle;
61                         /* If thread_handle is ever needed for
62                          * something, take out the CloseHandle() in
63                          * the Start_internal icall in
64                          * mono/metadata/process.c
65                          */
66                         public IntPtr thread_handle;
67                         public int pid; // Contains -GetLastError () on failure.
68                         public int tid;
69                         public string [] envKeys;
70                         public string [] envValues;
71                         public string UserName;
72                         public string Domain;
73                         public IntPtr Password;
74                         public bool LoadUserProfile;
75                 };
76                 
77                 IntPtr process_handle;
78                 int pid;
79                 bool enableRaisingEvents;
80                 bool already_waiting;
81                 ISynchronizeInvoke synchronizingObject;
82                 EventHandler exited_event;
83                 IntPtr stdout_rd;
84                 IntPtr stderr_rd;
85                 
86                 /* Private constructor called from other methods */
87                 private Process(IntPtr handle, int id) {
88                         process_handle=handle;
89                         pid=id;
90                 }
91                 
92                 public Process ()
93                 {
94                 }
95
96                 [MonoTODO]
97                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
98                 [MonitoringDescription ("Base process priority.")]
99                 public int BasePriority {
100                         get {
101                                 return(0);
102                         }
103                 }
104
105                 void StartExitCallbackIfNeeded ()
106                 {
107 #if !NET_2_1
108                         bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
109                         if (start && process_handle != IntPtr.Zero && !HasExited) {
110                                 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
111                                 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
112                                 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
113                                 already_waiting = true;
114                         }
115 #endif
116                 }
117
118                 [DefaultValue (false), Browsable (false)]
119                 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
120                 public bool EnableRaisingEvents {
121                         get {
122                                 return enableRaisingEvents;
123                         }
124                         set { 
125                                 bool prev = enableRaisingEvents;
126                                 enableRaisingEvents = value;
127                                 if (enableRaisingEvents && !prev)
128                                         StartExitCallbackIfNeeded ();
129                         }
130
131                 }
132
133                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134                 private extern static int ExitCode_internal(IntPtr handle);
135
136                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
137                 [MonitoringDescription ("The exit code of the process.")]
138                 public int ExitCode {
139                         get {
140                                 if (process_handle == IntPtr.Zero)
141                                         throw new InvalidOperationException ("Process has not been started.");
142
143                                 int code = ExitCode_internal (process_handle);
144                                 if (code == 259)
145                                         throw new InvalidOperationException ("The process must exit before " +
146                                                                         "getting the requested information.");
147
148                                 return code;
149                         }
150                 }
151
152                 /* Returns the process start time in Windows file
153                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
154                  */
155                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156                 private extern static long ExitTime_internal(IntPtr handle);
157                 
158                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
159                 [MonitoringDescription ("The exit time of the process.")]
160                 public DateTime ExitTime {
161                         get {
162                                 if (process_handle == IntPtr.Zero)
163                                         throw new InvalidOperationException ("Process has not been started.");
164
165                                 if (!HasExited)
166                                         throw new InvalidOperationException ("The process must exit before " +
167                                                                         "getting the requested information.");
168
169                                 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
170                         }
171                 }
172
173                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
174                 [MonitoringDescription ("Handle for this process.")]
175                 public IntPtr Handle {
176                         get {
177                                 return(process_handle);
178                         }
179                 }
180
181                 [MonoTODO]
182                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183                 [MonitoringDescription ("Handles for this process.")]
184                 public int HandleCount {
185                         get {
186                                 return(0);
187                         }
188                 }
189
190                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191                 [MonitoringDescription ("Determines if the process is still running.")]
192                 public bool HasExited {
193                         get {
194                                 if (process_handle == IntPtr.Zero)
195                                         throw new InvalidOperationException ("Process has not been started.");
196                                         
197                                 int exitcode = ExitCode_internal (process_handle);
198
199                                 if(exitcode==259) {
200                                         /* STILL_ACTIVE */
201                                         return(false);
202                                 } else {
203                                         return(true);
204                                 }
205                         }
206                 }
207
208                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209                 [MonitoringDescription ("Process identifier.")]
210                 public int Id {
211                         get {
212                                 if (pid == 0) {
213                                         throw new InvalidOperationException ("Process ID has not been set.");
214                                 }
215
216                                 return(pid);
217                         }
218                 }
219
220                 [MonoTODO]
221                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
222                 [MonitoringDescription ("The name of the computer running the process.")]
223                 public string MachineName {
224                         get {
225                                 return("localhost");
226                         }
227                 }
228
229                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
230                 [MonitoringDescription ("The main module of the process.")]
231                 public ProcessModule MainModule {
232                         get {
233                                 return(this.Modules[0]);
234                         }
235                 }
236
237                 [MonoTODO]
238                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
239                 [MonitoringDescription ("The handle of the main window of the process.")]
240                 public IntPtr MainWindowHandle {
241                         get {
242                                 return((IntPtr)0);
243                         }
244                 }
245
246                 [MonoTODO]
247                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
248                 [MonitoringDescription ("The title of the main window of the process.")]
249                 public string MainWindowTitle {
250                         get {
251                                 return("null");
252                         }
253                 }
254
255                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
256                 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
257                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
258                 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
259
260                 /* LAMESPEC: why is this an IntPtr not a plain int? */
261                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
262                 [MonitoringDescription ("The maximum working set for this process.")]
263                 public IntPtr MaxWorkingSet {
264                         get {
265                                 if(HasExited) {
266                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
267                                 }
268                                 
269                                 int min;
270                                 int max;
271                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
272                                 if(ok==false) {
273                                         throw new Win32Exception();
274                                 }
275                                 
276                                 return((IntPtr)max);
277                         }
278                         set {
279                                 if(HasExited) {
280                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
281                                 }
282                                 
283                                 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
284                                 if(ok==false) {
285                                         throw new Win32Exception();
286                                 }
287                         }
288                 }
289
290                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
291                 [MonitoringDescription ("The minimum working set for this process.")]
292                 public IntPtr MinWorkingSet {
293                         get {
294                                 if(HasExited) {
295                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
296                                 }
297                                 
298                                 int min;
299                                 int max;
300                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
301                                 if(ok==false) {
302                                         throw new Win32Exception();
303                                 }
304                                 
305                                 return((IntPtr)min);
306                         }
307                         set {
308                                 if(HasExited) {
309                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
310                                 }
311                                 
312                                 bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
313                                 if(ok==false) {
314                                         throw new Win32Exception();
315                                 }
316                         }
317                 }
318
319                 /* Returns the list of process modules.  The main module is
320                  * element 0.
321                  */
322                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
323                 private extern ProcessModule[] GetModules_internal();
324
325                 private ProcessModuleCollection module_collection;
326                 
327                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
328                 [MonitoringDescription ("The modules that are loaded as part of this process.")]
329                 public ProcessModuleCollection Modules {
330                         get {
331                                 if(module_collection==null) {
332                                         module_collection=new ProcessModuleCollection(GetModules_internal());
333                                 }
334
335                                 return(module_collection);
336                         }
337                 }
338
339                 [MonoTODO]
340 #if NET_2_0
341                 [Obsolete ("Use NonpagedSystemMemorySize64")]
342 #endif
343                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
344                 [MonitoringDescription ("The number of bytes that are not pageable.")]
345                 public int NonpagedSystemMemorySize {
346                         get {
347                                 return(0);
348                         }
349                 }
350
351                 [MonoTODO]
352 #if NET_2_0
353                 [Obsolete ("Use PagedMemorySize64")]
354 #endif
355                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
356                 [MonitoringDescription ("The number of bytes that are paged.")]
357                 public int PagedMemorySize {
358                         get {
359                                 return(0);
360                         }
361                 }
362
363                 [MonoTODO]
364 #if NET_2_0
365                 [Obsolete ("Use PagedSystemMemorySize64")]
366 #endif
367                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
368                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
369                 public int PagedSystemMemorySize {
370                         get {
371                                 return(0);
372                         }
373                 }
374
375                 [MonoTODO]
376 #if NET_2_0
377                 [Obsolete ("Use PeakPagedMemorySize64")]
378 #endif
379                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
380                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
381                 public int PeakPagedMemorySize {
382                         get {
383                                 return(0);
384                         }
385                 }
386
387                 [MonoTODO]
388 #if NET_2_0
389                 [Obsolete ("Use PeakVirtualMemorySize64")]
390 #endif
391                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
392                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
393                 public int PeakVirtualMemorySize {
394                         get {
395                                 return(0);
396                         }
397                 }
398
399                 [MonoTODO]
400 #if NET_2_0
401                 [Obsolete ("Use PeakWorkingSet64")]
402 #endif
403                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
404                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
405                 public int PeakWorkingSet {
406                         get {
407                                 return(0);
408                         }
409                 }
410
411 #if NET_2_0
412                 [MonoTODO]
413                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
414                 [MonitoringDescription ("The number of bytes that are not pageable.")]
415                 [ComVisible (false)]
416                 public long NonpagedSystemMemorySize64 {
417                         get {
418                                 return(0);
419                         }
420                 }
421
422                 [MonoTODO]
423                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
424                 [MonitoringDescription ("The number of bytes that are paged.")]
425                 [ComVisible (false)]
426                 public long PagedMemorySize64 {
427                         get {
428                                 return(0);
429                         }
430                 }
431
432                 [MonoTODO]
433                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
434                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
435                 [ComVisible (false)]
436                 public long PagedSystemMemorySize64 {
437                         get {
438                                 return(0);
439                         }
440                 }
441
442                 [MonoTODO]
443                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
444                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
445                 [ComVisible (false)]
446                 public long PeakPagedMemorySize64 {
447                         get {
448                                 return(0);
449                         }
450                 }
451
452                 [MonoTODO]
453                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
454                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
455                 [ComVisible (false)]
456                 public long PeakVirtualMemorySize64 {
457                         get {
458                                 return(0);
459                         }
460                 }
461
462                 [MonoTODO]
463                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
464                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
465                 [ComVisible (false)]
466                 public long PeakWorkingSet64 {
467                         get {
468                                 return(0);
469                         }
470                 }
471 #endif
472
473                 [MonoTODO]
474                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
475                 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
476                 public bool PriorityBoostEnabled {
477                         get {
478                                 return(false);
479                         }
480                         set {
481                         }
482                 }
483
484                 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
485                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
486                 [MonitoringDescription ("The relative process priority.")]
487                 public ProcessPriorityClass PriorityClass {
488                         get {
489                                 int error;
490                                 int prio = GetPriorityClass (process_handle, out error);
491                                 if (prio == 0)
492                                         throw new Win32Exception (error);
493                                 return (ProcessPriorityClass) prio;
494                         }
495                         set {
496                                 // LAMESPEC: not documented on MSDN for NET_1_1
497                                 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
498                                         throw new InvalidEnumArgumentException ();
499
500                                 int error;
501                                 if (!SetPriorityClass (process_handle, (int) value, out error))
502                                         throw new Win32Exception (error);
503                         }
504                 }
505
506                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
507                 static extern int GetPriorityClass (IntPtr handle, out int error);
508
509                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
510                 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
511
512                 [MonoTODO]
513                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
514                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
515 #if NET_2_0
516                 [Obsolete ("Use PrivateMemorySize64")]
517 #endif
518                 public int PrivateMemorySize {
519                         get {
520                                 return(0);
521                         }
522                 }
523
524                 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
525                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526                 private extern static long Times (IntPtr handle, int type);
527
528                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
529                 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
530                 public TimeSpan PrivilegedProcessorTime {
531                         get {
532                                 return new TimeSpan (Times (process_handle, 1));
533                         }
534                 }
535
536                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
537                 private extern static string ProcessName_internal(IntPtr handle);
538                 
539                 private string process_name=null;
540                 
541                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
542                 [MonitoringDescription ("The name of this process.")]
543                 public string ProcessName {
544                         get {
545                                 if(process_name==null) {
546                                         process_name=ProcessName_internal(process_handle);
547                                         /* If process_name is _still_
548                                          * null, assume the process
549                                          * has exited
550                                          */
551                                         if(process_name==null) {
552                                                 throw new SystemException("The process has exited");
553                                         }
554                                         
555                                         /* Strip the suffix (if it
556                                          * exists) simplistically
557                                          * instead of removing any
558                                          * trailing \.???, so we dont
559                                          * get stupid results on sane
560                                          * systems
561                                          */
562                                         if(process_name.EndsWith(".exe") ||
563                                            process_name.EndsWith(".bat") ||
564                                            process_name.EndsWith(".com")) {
565                                                 process_name=process_name.Substring(0, process_name.Length-4);
566                                         }
567                                 }
568                                 return(process_name);
569                         }
570                 }
571
572                 [MonoTODO]
573                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
574                 [MonitoringDescription ("Allowed processor that can be used by this process.")]
575                 public IntPtr ProcessorAffinity {
576                         get {
577                                 return((IntPtr)0);
578                         }
579                         set {
580                         }
581                 }
582
583                 [MonoTODO]
584                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
585                 [MonitoringDescription ("Is this process responsive.")]
586                 public bool Responding {
587                         get {
588                                 return(false);
589                         }
590                 }
591
592                 private StreamReader error_stream=null;
593                 
594                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
595                 [MonitoringDescription ("The standard error stream of this process.")]
596                 public StreamReader StandardError {
597                         get {
598                                 if (error_stream == null) {
599                                         throw new InvalidOperationException("Standard error has not been redirected");
600                                 }
601 #if NET_2_0
602                                 if ((async_mode & AsyncModes.AsyncError) != 0)
603                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
604
605                                 async_mode |= AsyncModes.SyncError;
606 #endif
607
608                                 return(error_stream);
609                         }
610                 }
611
612                 private StreamWriter input_stream=null;
613                 
614                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
615                 [MonitoringDescription ("The standard input stream of this process.")]
616                 public StreamWriter StandardInput {
617                         get {
618                                 if (input_stream == null) {
619                                         throw new InvalidOperationException("Standard input has not been redirected");
620                                 }
621
622                                 return(input_stream);
623                         }
624                 }
625
626                 private StreamReader output_stream=null;
627                 
628                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
629                 [MonitoringDescription ("The standard output stream of this process.")]
630                 public StreamReader StandardOutput {
631                         get {
632                                 if (output_stream == null) {
633                                         throw new InvalidOperationException("Standard output has not been redirected");
634                                 }
635 #if NET_2_0
636                                 if ((async_mode & AsyncModes.AsyncOutput) != 0)
637                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
638
639                                 async_mode |= AsyncModes.SyncOutput;
640 #endif
641
642                                 return(output_stream);
643                         }
644                 }
645
646                 private ProcessStartInfo start_info=null;
647                 
648                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
649                 [MonitoringDescription ("Information for the start of this process.")]
650                 public ProcessStartInfo StartInfo {
651                         get {
652                                 if(start_info==null) {
653                                         start_info=new ProcessStartInfo();
654                                 }
655                                 
656                                 return(start_info);
657                         }
658                         set {
659                                 if(value==null) {
660                                         throw new ArgumentException("value is null");
661                                 }
662                                 
663                                 start_info=value;
664                         }
665                 }
666
667                 /* Returns the process start time in Windows file
668                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
669                  */
670                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
671                 private extern static long StartTime_internal(IntPtr handle);
672                 
673                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
674                 [MonitoringDescription ("The time this process started.")]
675                 public DateTime StartTime {
676                         get {
677                                 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
678                         }
679                 }
680
681                 [DefaultValue (null), Browsable (false)]
682                 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
683                 public ISynchronizeInvoke SynchronizingObject {
684                         get { return synchronizingObject; }
685                         set { synchronizingObject = value; }
686                 }
687
688                 [MonoTODO]
689                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
690                 [MonitoringDescription ("The number of threads of this process.")]
691                 public ProcessThreadCollection Threads {
692                         get {
693                                 return(null);
694                         }
695                 }
696
697                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
698                 [MonitoringDescription ("The total CPU time spent for this process.")]
699                 public TimeSpan TotalProcessorTime {
700                         get {
701                                 return new TimeSpan (Times (process_handle, 2));
702                         }
703                 }
704
705                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
706                 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
707                 public TimeSpan UserProcessorTime {
708                         get {
709                                 return new TimeSpan (Times (process_handle, 0));
710                         }
711                 }
712
713                 [MonoTODO]
714 #if NET_2_0
715                 [Obsolete ("Use VirtualMemorySize64")]
716 #endif
717                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
718                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
719                 public int VirtualMemorySize {
720                         get {
721                                 return(0);
722                         }
723                 }
724
725                 [MonoTODO]
726 #if NET_2_0
727                 [Obsolete ("Use WorkingSet64")]
728 #endif
729                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
730                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
731                 public int WorkingSet {
732                         get {
733                                 return(0);
734                         }
735                 }
736
737 #if NET_2_0
738                 [MonoTODO]
739                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
740                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
741                 [ComVisible (false)]
742                 public long PrivateMemorySize64 {
743                         get {
744                                 return(0);
745                         }
746                 }
747
748                 [MonoTODO]
749                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
750                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
751                 [ComVisible (false)]
752                 public long VirtualMemorySize64 {
753                         get {
754                                 return(0);
755                         }
756                 }
757
758                 [MonoTODO]
759                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
760                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
761                 [ComVisible (false)]
762                 public long WorkingSet64 {
763                         get {
764                                 return(0);
765                         }
766                 }
767 #endif
768
769                 public void Close()
770                 {
771                         Dispose (true);
772                 }
773
774                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
775                 extern static bool Kill_internal (IntPtr handle, int signo);
776
777                 /* int kill -> 1 KILL, 2 CloseMainWindow */
778                 bool Close (int signo)
779                 {
780                         if (process_handle == IntPtr.Zero)
781                                 throw new SystemException ("No process to kill.");
782
783                         int exitcode = ExitCode_internal (process_handle);
784                         if (exitcode != 259)
785                                 throw new InvalidOperationException ("The process already finished.");
786
787                         return Kill_internal (process_handle, signo);
788                 }
789
790                 public bool CloseMainWindow ()
791                 {
792                         return Close (2);
793                 }
794
795                 [MonoTODO]
796                 public static void EnterDebugMode() {
797                 }
798
799                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
800                 private extern static IntPtr GetProcess_internal(int pid);
801                 
802                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
803                 private extern static int GetPid_internal();
804
805                 public static Process GetCurrentProcess()
806                 {
807                         int pid = GetPid_internal();
808                         IntPtr proc = GetProcess_internal(pid);
809                         
810                         if (proc == IntPtr.Zero) {
811                                 throw new SystemException("Can't find current process");
812                         }
813
814                         return (new Process (proc, pid));
815                 }
816
817                 public static Process GetProcessById(int processId)
818                 {
819                         IntPtr proc = GetProcess_internal(processId);
820                         
821                         if (proc == IntPtr.Zero) {
822                                 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
823                         }
824
825                         return (new Process (proc, processId));
826                 }
827
828                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
829                 public static Process GetProcessById(int processId, string machineName) {
830                         if (machineName == null)
831                                 throw new ArgumentNullException ("machineName");
832
833                         if (!IsLocalMachine (machineName))
834                                 throw new NotImplementedException ();
835
836                         return GetProcessById (processId);
837                 }
838
839                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
840                 private extern static int[] GetProcesses_internal();
841
842                 public static Process[] GetProcesses()
843                 {
844                         int [] pids = GetProcesses_internal ();
845                         ArrayList proclist = new ArrayList ();
846                         
847                         for (int i = 0; i < pids.Length; i++) {
848                                 try {
849                                         proclist.Add (GetProcessById (pids [i]));
850                                 } catch (SystemException) {
851                                         /* The process might exit
852                                          * between
853                                          * GetProcesses_internal and
854                                          * GetProcessById
855                                          */
856                                 }
857                         }
858
859                         return ((Process []) proclist.ToArray (typeof (Process)));
860                 }
861
862                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
863                 public static Process[] GetProcesses(string machineName) {
864                         if (machineName == null)
865                                 throw new ArgumentNullException ("machineName");
866
867                         if (!IsLocalMachine (machineName))
868                                 throw new NotImplementedException ();
869
870                         return GetProcesses ();
871                 }
872
873                 public static Process[] GetProcessesByName(string processName)
874                 {
875                         Process [] procs = GetProcesses();
876                         ArrayList proclist = new ArrayList();
877                         
878                         for (int i = 0; i < procs.Length; i++) {
879                                 /* Ignore case */
880                                 if (String.Compare (processName,
881                                                     procs [i].ProcessName,
882                                                     true) == 0) {
883                                         proclist.Add (procs [i]);
884                                 }
885                         }
886
887                         return ((Process[]) proclist.ToArray (typeof(Process)));
888                 }
889
890                 [MonoTODO]
891                 public static Process[] GetProcessesByName(string processName, string machineName) {
892                         throw new NotImplementedException();
893                 }
894
895                 public void Kill ()
896                 {
897                         Close (1);
898                 }
899
900                 [MonoTODO]
901                 public static void LeaveDebugMode() {
902                 }
903
904                 public void Refresh ()
905                 {
906                         // FIXME: should refresh any cached data we might have about
907                         // the process (currently we have none).
908                 }
909
910                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
911                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
912                                                                    ref ProcInfo proc_info);
913
914                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
915                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
916                                                                   IntPtr stdin,
917                                                                   IntPtr stdout,
918                                                                   IntPtr stderr,
919                                                                   ref ProcInfo proc_info);
920
921                 private static bool Start_shell (ProcessStartInfo startInfo,
922                                                  Process process)
923                 {
924                         ProcInfo proc_info=new ProcInfo();
925                         bool ret;
926
927                         if (startInfo.RedirectStandardInput ||
928                             startInfo.RedirectStandardOutput ||
929                             startInfo.RedirectStandardError) {
930                                 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
931                         }
932
933                         if (startInfo.HaveEnvVars) {
934                                 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
935                         }
936
937                         FillUserInfo (startInfo, ref proc_info);
938                         try {
939                                 ret = ShellExecuteEx_internal (startInfo,
940                                                                ref proc_info);
941                         } finally {
942                                 if (proc_info.Password != IntPtr.Zero)
943                                         Marshal.FreeBSTR (proc_info.Password);
944                                 proc_info.Password = IntPtr.Zero;
945                         }
946                         if (!ret) {
947                                 throw new Win32Exception (-proc_info.pid);
948                         }
949
950                         process.process_handle = proc_info.process_handle;
951                         process.pid = proc_info.pid;
952
953                         process.StartExitCallbackIfNeeded ();
954
955                         return(ret);
956                 }
957
958                 private static bool Start_noshell (ProcessStartInfo startInfo,
959                                                    Process process)
960                 {
961                         if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
962                                 throw new FileNotFoundException  ("Executable not found: " + startInfo.FileName);
963                         ProcInfo proc_info=new ProcInfo();
964                         IntPtr stdin_rd, stdin_wr;
965                         IntPtr stdout_wr;
966                         IntPtr stderr_wr;
967                         bool ret;
968                         MonoIOError error;
969
970                         if (startInfo.HaveEnvVars) {
971                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
972                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
973                                 proc_info.envKeys = strs;
974
975                                 strs = new string [startInfo.EnvironmentVariables.Count];
976                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
977                                 proc_info.envValues = strs;
978                         }
979
980                         if (startInfo.RedirectStandardInput == true) {
981                                 ret = MonoIO.CreatePipe (out stdin_rd,
982                                                          out stdin_wr);
983                                 if (ret == false) {
984                                         throw new IOException ("Error creating standard input pipe");
985                                 }
986                         } else {
987                                 stdin_rd = MonoIO.ConsoleInput;
988                                 /* This is required to stop the
989                                  * &$*£ing stupid compiler moaning
990                                  * that stdin_wr is unassigned, below.
991                                  */
992                                 stdin_wr = (IntPtr)0;
993                         }
994
995                         if (startInfo.RedirectStandardOutput == true) {
996                                 IntPtr out_rd;
997                                 ret = MonoIO.CreatePipe (out out_rd,
998                                                          out stdout_wr);
999
1000                                 process.stdout_rd = out_rd;
1001                                 if (ret == false) {
1002                                         if (startInfo.RedirectStandardInput == true) {
1003                                                 MonoIO.Close (stdin_rd, out error);
1004                                                 MonoIO.Close (stdin_wr, out error);
1005                                         }
1006
1007                                         throw new IOException ("Error creating standard output pipe");
1008                                 }
1009                         } else {
1010                                 process.stdout_rd = (IntPtr)0;
1011                                 stdout_wr = MonoIO.ConsoleOutput;
1012                         }
1013
1014                         if (startInfo.RedirectStandardError == true) {
1015                                 IntPtr err_rd;
1016                                 ret = MonoIO.CreatePipe (out err_rd,
1017                                                          out stderr_wr);
1018
1019                                 process.stderr_rd = err_rd;
1020                                 if (ret == false) {
1021                                         if (startInfo.RedirectStandardInput == true) {
1022                                                 MonoIO.Close (stdin_rd, out error);
1023                                                 MonoIO.Close (stdin_wr, out error);
1024                                         }
1025                                         if (startInfo.RedirectStandardOutput == true) {
1026                                                 MonoIO.Close (process.stdout_rd, out error);
1027                                                 MonoIO.Close (stdout_wr, out error);
1028                                         }
1029                                         
1030                                         throw new IOException ("Error creating standard error pipe");
1031                                 }
1032                         } else {
1033                                 process.stderr_rd = (IntPtr)0;
1034                                 stderr_wr = MonoIO.ConsoleError;
1035                         }
1036
1037                         FillUserInfo (startInfo, ref proc_info);
1038                         try {
1039                                 ret = CreateProcess_internal (startInfo,
1040                                                               stdin_rd, stdout_wr, stderr_wr,
1041                                                               ref proc_info);
1042                         } finally {
1043                                 if (proc_info.Password != IntPtr.Zero)
1044                                         Marshal.FreeBSTR (proc_info.Password);
1045                                 proc_info.Password = IntPtr.Zero;
1046                         }
1047                         if (!ret) {
1048                                 if (startInfo.RedirectStandardInput == true) {
1049                                         MonoIO.Close (stdin_rd, out error);
1050                                         MonoIO.Close (stdin_wr, out error);
1051                                 }
1052
1053                                 if (startInfo.RedirectStandardOutput == true) {
1054                                         MonoIO.Close (process.stdout_rd, out error);
1055                                         MonoIO.Close (stdout_wr, out error);
1056                                 }
1057
1058                                 if (startInfo.RedirectStandardError == true) {
1059                                         MonoIO.Close (process.stderr_rd, out error);
1060                                         MonoIO.Close (stderr_wr, out error);
1061                                 }
1062
1063                                 throw new Win32Exception (-proc_info.pid, 
1064                                         "ApplicationName='"+startInfo.FileName+
1065                                         "', CommandLine='"+startInfo.Arguments+
1066                                         "', CurrentDirectory='"+startInfo.WorkingDirectory+
1067                                         "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
1068                         }
1069
1070                         process.process_handle = proc_info.process_handle;
1071                         process.pid = proc_info.pid;
1072                         
1073                         if (startInfo.RedirectStandardInput == true) {
1074                                 MonoIO.Close (stdin_rd, out error);
1075                                 process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true), Console.Out.Encoding);
1076                                 process.input_stream.AutoFlush = true;
1077                         }
1078
1079 #if NET_2_0
1080                         Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1081                         Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1082 #else
1083                         Encoding stdoutEncoding = Console.Out.Encoding;
1084                         Encoding stderrEncoding = stdoutEncoding;
1085 #endif
1086
1087                         if (startInfo.RedirectStandardOutput == true) {
1088                                 MonoIO.Close (stdout_wr, out error);
1089                                 process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true), stdoutEncoding);
1090                         }
1091
1092                         if (startInfo.RedirectStandardError == true) {
1093                                 MonoIO.Close (stderr_wr, out error);
1094                                 process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true), stderrEncoding);
1095                         }
1096
1097                         process.StartExitCallbackIfNeeded ();
1098
1099                         return(ret);
1100                 }
1101
1102                 // Note that ProcInfo.Password must be freed.
1103                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1104                 {
1105 #if NET_2_0
1106                         if (startInfo.UserName != null) {
1107                                 proc_info.UserName = startInfo.UserName;
1108                                 proc_info.Domain = startInfo.Domain;
1109                                 if (startInfo.Password != null)
1110                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1111                                 else
1112                                         proc_info.Password = IntPtr.Zero;
1113                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1114                         }
1115 #endif
1116                 }
1117
1118                 private static bool Start_common (ProcessStartInfo startInfo,
1119                                                   Process process)
1120                 {
1121                         if(startInfo.FileName == null ||
1122                            startInfo.FileName == "") {
1123                                 throw new InvalidOperationException("File name has not been set");
1124                         }
1125                         
1126 #if NET_2_0
1127                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1128                                 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1129                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1130                                 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1131 #endif
1132                         
1133                         if (startInfo.UseShellExecute) {
1134 #if NET_2_0
1135                                 if (startInfo.UserName != null)
1136                                         throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1137 #endif
1138                                 return (Start_shell (startInfo, process));
1139                         } else {
1140                                 return (Start_noshell (startInfo, process));
1141                         }
1142                 }
1143                 
1144                 public bool Start() {
1145                         bool ret;
1146
1147                         if (process_handle != IntPtr.Zero) {
1148                                 Process_free_internal (process_handle);
1149                                 process_handle = IntPtr.Zero;
1150                         }
1151                         ret=Start_common(start_info, this);
1152                         
1153                         return(ret);
1154                 }
1155
1156                 public static Process Start(ProcessStartInfo startInfo) {
1157
1158                         Process process=new Process();
1159                         bool ret;
1160
1161                         process.StartInfo = startInfo;
1162                         ret=Start_common(startInfo, process);
1163                         
1164                         if(ret==true) {
1165                                 return(process);
1166                         } else {
1167                                 return(null);
1168                         }
1169                 }
1170
1171                 public static Process Start(string fileName) {
1172                        return Start(new ProcessStartInfo(fileName));
1173                 }
1174
1175                 public static Process Start(string fileName,
1176                                             string arguments) {
1177                        return Start(new ProcessStartInfo(fileName, arguments));
1178                 }
1179
1180 #if NET_2_0
1181                 public static Process Start(string fileName, string username, SecureString password, string domain) {
1182                         return Start(fileName, null, username, password, domain);
1183                 }
1184
1185                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1186                         ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1187                         psi.UserName = username;
1188                         psi.Password = password;
1189                         psi.Domain = domain;
1190                         psi.UseShellExecute = false;
1191                         return Start(psi);
1192                 }
1193 #endif
1194
1195                 public override string ToString() {
1196                         return(base.ToString() +
1197                                " (" + this.ProcessName + ")");
1198                 }
1199
1200                 /* Waits up to ms milliseconds for process 'handle' to
1201                  * exit.  ms can be <0 to mean wait forever.
1202                  */
1203                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1204                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1205
1206                 public void WaitForExit ()
1207                 {
1208                         WaitForExit (-1);
1209                 }
1210
1211                 public bool WaitForExit(int milliseconds) {
1212                         int ms = milliseconds;
1213                         if (ms == int.MaxValue)
1214                                 ms = -1;
1215
1216 #if NET_2_0
1217                         DateTime start = DateTime.UtcNow;
1218                         if (async_output != null && !async_output.IsCompleted) {
1219                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1220                                         return false; // Timed out
1221
1222                                 if (ms >= 0) {
1223                                         DateTime now = DateTime.UtcNow;
1224                                         ms -= (int) (now - start).TotalMilliseconds;
1225                                         if (ms <= 0)
1226                                                 return false;
1227                                         start = now;
1228                                 }
1229                         }
1230
1231                         if (async_error != null && !async_error.IsCompleted) {
1232                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1233                                         return false; // Timed out
1234
1235                                 if (ms >= 0) {
1236                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1237                                         if (ms <= 0)
1238                                                 return false;
1239                                 }
1240                         }
1241 #endif
1242                         return WaitForExit_internal (process_handle, ms);
1243                 }
1244
1245                 [MonoTODO]
1246                 public bool WaitForInputIdle() {
1247                         return(false);
1248                 }
1249
1250                 [MonoTODO]
1251                 public bool WaitForInputIdle(int milliseconds) {
1252                         return(false);
1253                 }
1254
1255                 private static bool IsLocalMachine (string machineName)
1256                 {
1257                         if (machineName == "." || machineName.Length == 0)
1258                                 return true;
1259
1260                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
1261                 }
1262
1263 #if NET_2_0
1264                 [Browsable (true)]
1265                 [MonitoringDescription ("Raised when it receives output data")]
1266                 public event DataReceivedEventHandler OutputDataReceived;
1267                 [Browsable (true)]
1268                 [MonitoringDescription ("Raised when it receives error data")]
1269                 public event DataReceivedEventHandler ErrorDataReceived;
1270
1271                 void OnOutputDataReceived (string str)
1272                 {
1273                         if (OutputDataReceived != null)
1274                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1275                 }
1276
1277                 void OnErrorDataReceived (string str)
1278                 {
1279                         if (ErrorDataReceived != null)
1280                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1281                 }
1282
1283                 [Flags]
1284                 enum AsyncModes {
1285                         NoneYet = 0,
1286                         SyncOutput = 1,
1287                         SyncError = 1 << 1,
1288                         AsyncOutput = 1 << 2,
1289                         AsyncError = 1 << 3
1290                 }
1291
1292                 [StructLayout (LayoutKind.Sequential)]
1293                 sealed class ProcessAsyncReader
1294                 {
1295                         /*
1296                            The following fields match those of SocketAsyncResult.
1297                            This is so that changes needed in the runtime to handle
1298                            asynchronous reads are trivial
1299                         */
1300                         /* DON'T shuffle fields around. DON'T remove fields */
1301                         public object Sock;
1302                         public IntPtr handle;
1303                         public object state;
1304                         public AsyncCallback callback;
1305                         public ManualResetEvent wait_handle;
1306
1307                         public Exception delayedException;
1308
1309                         public object EndPoint;
1310                         byte [] buffer = new byte [4196];
1311                         public int Offset;
1312                         public int Size;
1313                         public int SockFlags;
1314
1315                         public object acc_socket;
1316                         public int total;
1317                         public bool completed_sync;
1318                         bool completed;
1319                         bool err_out; // true -> stdout, false -> stderr
1320                         internal int error;
1321                         public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1322                         public object ares;
1323
1324
1325                         // These fields are not in SocketAsyncResult
1326                         Process process;
1327                         Stream stream;
1328                         StringBuilder sb = new StringBuilder ();
1329                         public AsyncReadHandler ReadHandler;
1330
1331                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1332                         {
1333                                 this.process = process;
1334                                 this.handle = handle;
1335                                 stream = new FileStream (handle, FileAccess.Read, false);
1336                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1337                                 this.err_out = err_out;
1338                         }
1339
1340                         public void AddInput ()
1341                         {
1342                                 lock (this) {
1343                                         int nread = stream.Read (buffer, 0, buffer.Length);
1344                                         if (nread == 0) {
1345                                                 completed = true;
1346                                                 if (wait_handle != null)
1347                                                         wait_handle.Set ();
1348                                                 Flush (true);
1349                                                 return;
1350                                         }
1351
1352                                         try {
1353                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1354                                         } catch {
1355                                                 // Just in case the encoding fails...
1356                                                 for (int i = 0; i < nread; i++) {
1357                                                         sb.Append ((char) buffer [i]);
1358                                                 }
1359                                         }
1360
1361                                         Flush (false);
1362                                         ReadHandler.BeginInvoke (null, this);
1363                                 }
1364                         }
1365
1366                         void Flush (bool last)
1367                         {
1368                                 if (sb.Length == 0 ||
1369                                     (err_out && process.output_canceled) ||
1370                                     (!err_out && process.error_canceled))
1371                                         return;
1372
1373                                 string total = sb.ToString ();
1374                                 sb.Length = 0;
1375                                 string [] strs = total.Split ('\n');
1376                                 int len = strs.Length;
1377                                 if (len == 0)
1378                                         return;
1379
1380                                 for (int i = 0; i < len - 1; i++) {
1381                                         if (err_out)
1382                                                 process.OnOutputDataReceived (strs [i]);
1383                                         else
1384                                                 process.OnErrorDataReceived (strs [i]);
1385                                 }
1386
1387                                 string end = strs [len - 1];
1388                                 if (last || (len == 1 && end == "")) {
1389                                         if (err_out) {
1390                                                 process.OnOutputDataReceived (end);
1391                                         } else {
1392                                                 process.OnErrorDataReceived (end);
1393                                         }
1394                                 } else {
1395                                         sb.Append (end);
1396                                 }
1397                         }
1398
1399                         public bool IsCompleted {
1400                                 get { return completed; }
1401                         }
1402
1403                         public WaitHandle WaitHandle {
1404                                 get {
1405                                         lock (this) {
1406                                                 if (wait_handle == null)
1407                                                         wait_handle = new ManualResetEvent (completed);
1408                                                 return wait_handle;
1409                                         }
1410                                 }
1411                         }
1412                 }
1413
1414                 AsyncModes async_mode;
1415                 bool output_canceled;
1416                 bool error_canceled;
1417                 ProcessAsyncReader async_output;
1418                 ProcessAsyncReader async_error;
1419                 delegate void AsyncReadHandler ();
1420
1421                 [ComVisibleAttribute(false)] 
1422                 public void BeginOutputReadLine ()
1423                 {
1424                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1425                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1426
1427                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1428                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1429
1430                         async_mode |= AsyncModes.AsyncOutput;
1431                         output_canceled = false;
1432                         if (async_output == null) {
1433                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1434                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1435                         }
1436                 }
1437
1438                 [ComVisibleAttribute(false)] 
1439                 public void CancelOutputRead ()
1440                 {
1441                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1442                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1443
1444                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1445                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1446
1447                         if (async_output == null)
1448                                 throw new InvalidOperationException ("No async operation in progress.");
1449
1450                         output_canceled = true;
1451                 }
1452
1453                 [ComVisibleAttribute(false)] 
1454                 public void BeginErrorReadLine ()
1455                 {
1456                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1457                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1458
1459                         if ((async_mode & AsyncModes.SyncError) != 0)
1460                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1461
1462                         async_mode |= AsyncModes.AsyncError;
1463                         error_canceled = false;
1464                         if (async_error == null) {
1465                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1466                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1467                         }
1468                 }
1469
1470                 [ComVisibleAttribute(false)] 
1471                 public void CancelErrorRead ()
1472                 {
1473                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1474                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1475
1476                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1477                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1478
1479                         if (async_error == null)
1480                                 throw new InvalidOperationException ("No async operation in progress.");
1481
1482                         error_canceled = true;
1483                 }
1484 #endif
1485
1486                 [Category ("Behavior")]
1487                 [MonitoringDescription ("Raised when this process exits.")]
1488                 public event EventHandler Exited {
1489                         add {
1490                                 if (process_handle != IntPtr.Zero && HasExited) {
1491                                         value.BeginInvoke (null, null, null, null);
1492                                 } else {
1493                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1494                                         if (exited_event != null)
1495                                                 StartExitCallbackIfNeeded ();
1496                                 }
1497                         }
1498                         remove {
1499                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1500                         }
1501                 }
1502
1503                 // Closes the system process handle
1504                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1505                 private extern void Process_free_internal(IntPtr handle);
1506                 
1507                 private bool disposed = false;
1508                 
1509                 protected override void Dispose(bool disposing) {
1510                         // Check to see if Dispose has already been called.
1511                         if(this.disposed == false) {
1512                                 this.disposed=true;
1513                                 // If this is a call to Dispose,
1514                                 // dispose all managed resources.
1515                                 if(disposing) {
1516                                         // Do stuff here
1517                                 }
1518                                 
1519                                 // Release unmanaged resources
1520
1521                                 lock(this) {
1522                                         if(process_handle!=IntPtr.Zero) {
1523                                                 
1524                                                 Process_free_internal(process_handle);
1525                                                 process_handle=IntPtr.Zero;
1526                                         }
1527
1528                                         if (input_stream != null) {
1529                                                 input_stream.Close();
1530                                                 input_stream = null;
1531                                         }
1532
1533                                         if (output_stream != null) {
1534                                                 output_stream.Close();
1535                                                 output_stream = null;
1536                                         }
1537
1538                                         if (error_stream != null) {
1539                                                 error_stream.Close();
1540                                                 error_stream = null;
1541                                         }
1542                                 }
1543                         }
1544                         base.Dispose (disposing);
1545                 }
1546
1547                 ~Process ()
1548                 {
1549                         Dispose (false);
1550                 }
1551
1552                 static void CBOnExit (object state, bool unused)
1553                 {
1554                         Process p = (Process) state;
1555                         p.OnExited ();
1556                 }
1557
1558                 protected void OnExited() 
1559                 {
1560                         if (exited_event == null)
1561                                 return;
1562
1563                         if (synchronizingObject == null) {
1564                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1565                                         try {
1566                                                 d (this, EventArgs.Empty);
1567                                         } catch {}
1568                                 }
1569                                 return;
1570                         }
1571                         
1572                         object [] args = new object [] {this, EventArgs.Empty};
1573                         synchronizingObject.BeginInvoke (exited_event, args);
1574                 }
1575
1576                 class ProcessWaitHandle : WaitHandle
1577                 {
1578                         public ProcessWaitHandle (IntPtr handle)
1579                         {
1580                                 Handle = handle;
1581                         }
1582
1583                         protected override void Dispose (bool explicitDisposing)
1584                         {
1585                                 // Do nothing, we don't own the handle and we won't close it.
1586                         }
1587                 }
1588         }
1589 }
1590