2002-10-23 Dick Porter <dick@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 //
7 // (C) 2002 Ximian, Inc.
8 //
9
10 using System;
11 using System.IO;
12 using System.ComponentModel;
13 using System.Runtime.CompilerServices;
14 using System.Runtime.InteropServices;
15 using System.Collections;
16
17 namespace System.Diagnostics {
18         public class Process : Component {
19                 [StructLayout(LayoutKind.Sequential)]
20                 private struct ProcInfo {
21                         public IntPtr process_handle;
22                         public IntPtr thread_handle;
23                         public int pid;
24                         public int tid;
25                 };
26                 
27                 IntPtr process_handle;
28                 int pid;
29                 
30                 /* Private constructor called from other methods */
31                 private Process(IntPtr handle, int id) {
32                         process_handle=handle;
33                         pid=id;
34                 }
35                 
36                 [MonoTODO]
37                 public Process() {
38                 }
39
40                 [MonoTODO]
41                 public int BasePriority {
42                         get {
43                                 return(0);
44                         }
45                 }
46
47                 [MonoTODO]
48                 public bool EnableRaisingEvents {
49                         get {
50                                 return(false);
51                         }
52                         set {
53                         }
54                 }
55
56                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
57                 private extern static int ExitCode_internal(IntPtr handle);
58
59                 public int ExitCode {
60                         get {
61                                 return(ExitCode_internal(process_handle));
62                         }
63                 }
64
65                 /* Returns the process start time in Windows file
66                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
67                  */
68                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
69                 private extern static long ExitTime_internal(IntPtr handle);
70                 
71                 public DateTime ExitTime {
72                         get {
73                                 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
74                         }
75                 }
76
77                 public IntPtr Handle {
78                         get {
79                                 return(process_handle);
80                         }
81                 }
82
83                 [MonoTODO]
84                 public int HandleCount {
85                         get {
86                                 return(0);
87                         }
88                 }
89
90                 [MonoTODO]
91                 public bool HasExited {
92                         get {
93                                 return(false);
94                         }
95                 }
96
97                 public int Id {
98                         get {
99                                 return(pid);
100                         }
101                 }
102
103                 [MonoTODO]
104                 public string MachineName {
105                         get {
106                                 return("localhost");
107                         }
108                 }
109
110                 public ProcessModule MainModule {
111                         get {
112                                 return(this.Modules[0]);
113                         }
114                 }
115
116                 [MonoTODO]
117                 public IntPtr MainWindowHandle {
118                         get {
119                                 return((IntPtr)0);
120                         }
121                 }
122
123                 [MonoTODO]
124                 public string MainWindowTitle {
125                         get {
126                                 return("null");
127                         }
128                 }
129
130                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
131                 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
132                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
133                 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
134
135                 /* LAMESPEC: why is this an IntPtr not a plain int? */
136                 public IntPtr MaxWorkingSet {
137                         get {
138                                 if(HasExited) {
139                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
140                                 }
141                                 
142                                 int min;
143                                 int max;
144                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
145                                 if(ok==false) {
146                                         throw new Win32Exception();
147                                 }
148                                 
149                                 return((IntPtr)max);
150                         }
151                         set {
152                                 if(HasExited) {
153                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
154                                 }
155                                 
156                                 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
157                                 if(ok==false) {
158                                         throw new Win32Exception();
159                                 }
160                         }
161                 }
162
163                 public IntPtr MinWorkingSet {
164                         get {
165                                 if(HasExited) {
166                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
167                                 }
168                                 
169                                 int min;
170                                 int max;
171                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
172                                 if(ok==false) {
173                                         throw new Win32Exception();
174                                 }
175                                 
176                                 return((IntPtr)min);
177                         }
178                         set {
179                                 if(HasExited) {
180                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
181                                 }
182                                 
183                                 bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
184                                 if(ok==false) {
185                                         throw new Win32Exception();
186                                 }
187                         }
188                 }
189
190                 /* Returns the list of process modules.  The main module is
191                  * element 0.
192                  */
193                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
194                 private extern ProcessModule[] GetModules_internal();
195
196                 private ProcessModuleCollection module_collection;
197                 
198                 public ProcessModuleCollection Modules {
199                         get {
200                                 if(module_collection==null) {
201                                         module_collection=new ProcessModuleCollection(GetModules_internal());
202                                 }
203
204                                 return(module_collection);
205                         }
206                 }
207
208                 [MonoTODO]
209                 public int NonpagedSystemMemorySize {
210                         get {
211                                 return(0);
212                         }
213                 }
214
215                 [MonoTODO]
216                 public int PagedMemorySize {
217                         get {
218                                 return(0);
219                         }
220                 }
221
222                 [MonoTODO]
223                 public int PagedSystemMemorySize {
224                         get {
225                                 return(0);
226                         }
227                 }
228
229                 [MonoTODO]
230                 public int PeakPagedMemorySize {
231                         get {
232                                 return(0);
233                         }
234                 }
235
236                 [MonoTODO]
237                 public int PeakVirtualMemorySize {
238                         get {
239                                 return(0);
240                         }
241                 }
242
243                 [MonoTODO]
244                 public int PeakWorkingSet {
245                         get {
246                                 return(0);
247                         }
248                 }
249
250                 [MonoTODO]
251                 public bool PriorityBoostEnabled {
252                         get {
253                                 return(false);
254                         }
255                         set {
256                         }
257                 }
258
259                 [MonoTODO]
260                 public ProcessPriorityClass PriorityClass {
261                         get {
262                                 return(ProcessPriorityClass.Normal);
263                         }
264                         set {
265                         }
266                 }
267
268                 [MonoTODO]
269                 public int PrivateMemorySize {
270                         get {
271                                 return(0);
272                         }
273                 }
274
275                 [MonoTODO]
276                 public TimeSpan PrivilegedProcessorTime {
277                         get {
278                                 return(new TimeSpan(0));
279                         }
280                 }
281
282                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
283                 private extern static string ProcessName_internal(IntPtr handle);
284                 
285                 private string process_name=null;
286                 
287                 public string ProcessName {
288                         get {
289                                 if(process_name==null) {
290                                         process_name=ProcessName_internal(process_handle);
291                                         /* If process_name is _still_
292                                          * null, assume the process
293                                          * has exited
294                                          */
295                                         if(process_name==null) {
296                                                 throw new SystemException("The process has exited");
297                                         }
298                                         
299                                         /* Strip the suffix (if it
300                                          * exists) simplistically
301                                          * instead of removing any
302                                          * trailing \.???, so we dont
303                                          * get stupid results on sane
304                                          * systems
305                                          */
306                                         if(process_name.EndsWith(".exe") ||
307                                            process_name.EndsWith(".bat") ||
308                                            process_name.EndsWith(".com")) {
309                                                 process_name=process_name.Substring(0, process_name.Length-4);
310                                         }
311                                 }
312                                 return(process_name);
313                         }
314                 }
315
316                 [MonoTODO]
317                 public IntPtr ProcessorAffinity {
318                         get {
319                                 return((IntPtr)0);
320                         }
321                         set {
322                         }
323                 }
324
325                 [MonoTODO]
326                 public bool Responding {
327                         get {
328                                 return(false);
329                         }
330                 }
331
332                 private StreamReader error_stream=null;
333                 
334                 public StreamReader StandardError {
335                         get {
336                                 return(error_stream);
337                         }
338                 }
339
340                 private StreamWriter input_stream=null;
341                 
342                 public StreamWriter StandardInput {
343                         get {
344                                 return(input_stream);
345                         }
346                 }
347
348                 private StreamReader output_stream=null;
349                 
350                 public StreamReader StandardOutput {
351                         get {
352                                 return(output_stream);
353                         }
354                 }
355
356                 private ProcessStartInfo start_info=null;
357                 
358                 public ProcessStartInfo StartInfo {
359                         get {
360                                 if(start_info==null) {
361                                         start_info=new ProcessStartInfo();
362                                 }
363                                 
364                                 return(start_info);
365                         }
366                         set {
367                                 if(value==null) {
368                                         throw new ArgumentException("value is null");
369                                 }
370                                 
371                                 start_info=value;
372                         }
373                 }
374
375                 /* Returns the process start time in Windows file
376                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
377                  */
378                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
379                 private extern static long StartTime_internal(IntPtr handle);
380                 
381                 public DateTime StartTime {
382                         get {
383                                 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
384                         }
385                 }
386
387                 [MonoTODO]
388                 public ISynchronizeInvoke SynchronizingObject {
389                         get {
390                                 return(null);
391                         }
392                         set {
393                         }
394                 }
395
396                 [MonoTODO]
397                 public ProcessThreadCollection Threads {
398                         get {
399                                 return(null);
400                         }
401                 }
402
403                 [MonoTODO]
404                 public TimeSpan TotalProcessorTime {
405                         get {
406                                 return(new TimeSpan(0));
407                         }
408                 }
409
410                 [MonoTODO]
411                 public TimeSpan UserProcessorTime {
412                         get {
413                                 return(new TimeSpan(0));
414                         }
415                 }
416
417                 [MonoTODO]
418                 public int VirtualMemorySize {
419                         get {
420                                 return(0);
421                         }
422                 }
423
424                 [MonoTODO]
425                 public int WorkingSet {
426                         get {
427                                 return(0);
428                         }
429                 }
430
431                 [MonoTODO]
432                 public void Close() {
433                 }
434
435                 [MonoTODO]
436                 public bool CloseMainWindow() {
437                         return(false);
438                 }
439
440                 [MonoTODO]
441                 public static void EnterDebugMode() {
442                 }
443
444                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
445                 private extern static IntPtr GetProcess_internal(int pid);
446                 
447                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
448                 private extern static int GetPid_internal();
449
450                 public static Process GetCurrentProcess() {
451                         int pid=GetPid_internal();
452                         IntPtr proc=GetProcess_internal(pid);
453                         
454                         if(proc==IntPtr.Zero) {
455                                 throw new SystemException("Can't find current process");
456                         }
457
458                         return(new Process(proc, pid));
459                 }
460
461                 public static Process GetProcessById(int processId) {
462                         IntPtr proc=GetProcess_internal(processId);
463                         
464                         if(proc==IntPtr.Zero) {
465                                 throw new ArgumentException("Can't find process with ID " + processId.ToString());
466                         }
467
468                         return(new Process(proc, processId));
469                 }
470
471                 [MonoTODO]
472                 public static Process GetProcessById(int processId, string machineName) {
473                         throw new NotImplementedException();
474                 }
475
476                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
477                 private extern static int[] GetProcesses_internal();
478
479                 public static Process[] GetProcesses() {
480                         int[] pids=GetProcesses_internal();
481                         ArrayList proclist=new ArrayList();
482                         
483                         for(int i=0; i<pids.Length; i++) {
484                                 try {
485                                         proclist.Add(GetProcessById(pids[i]));
486                                 } catch (SystemException) {
487                                         /* The process might exit
488                                          * between
489                                          * GetProcesses_internal and
490                                          * GetProcessById
491                                          */
492                                 }
493                         }
494
495                         return((Process[])proclist.ToArray(typeof(Process)));
496                 }
497
498                 [MonoTODO]
499                 public static Process[] GetProcesses(string machineName) {
500                         throw new NotImplementedException();
501                 }
502
503                 public static Process[] GetProcessesByName(string processName) {
504                         Process[] procs=GetProcesses();
505                         ArrayList proclist=new ArrayList();
506                         
507                         for(int i=0; i<procs.Length; i++) {
508                                 /* Ignore case */
509                                 if(String.Compare(processName,
510                                                   procs[i].ProcessName,
511                                                   true)==0) {
512                                         proclist.Add(procs[i]);
513                                 }
514                         }
515
516                         return((Process[])proclist.ToArray(typeof(Process)));
517                 }
518
519                 [MonoTODO]
520                 public static Process[] GetProcessesByName(string processName, string machineName) {
521                         throw new NotImplementedException();
522                 }
523
524                 [MonoTODO]
525                 public void Kill() {
526                 }
527
528                 [MonoTODO]
529                 public static void LeaveDebugMode() {
530                 }
531
532                 [MonoTODO]
533                 public void Refresh() {
534                 }
535
536                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
537                 private extern static bool Start_internal(string cmd,
538                                                           string dir,
539                                                           IntPtr stdin,
540                                                           IntPtr stdout,
541                                                           IntPtr stderr,
542                                                           ref ProcInfo proc_info);
543
544                 private static bool Start_common(ProcessStartInfo startInfo,
545                                                  Process process) {
546                         ProcInfo proc_info=new ProcInfo();
547                         IntPtr stdin_rd, stdin_wr;
548                         IntPtr stdout_rd, stdout_wr;
549                         IntPtr stderr_rd, stderr_wr;
550                         bool ret;
551                         
552                         if(startInfo.FileName == "") {
553                                 throw new InvalidOperationException("File name has not been set");
554                         }
555                         
556                         if(startInfo.RedirectStandardInput==true) {
557                                 ret=MonoIO.CreatePipe(out stdin_rd,
558                                                       out stdin_wr);
559                         } else {
560                                 stdin_rd=MonoIO.ConsoleInput;
561                                 /* This is required to stop the
562                                  * &$*£ing stupid compiler moaning
563                                  * that stdin_wr is unassigned, below.
564                                  */
565                                 stdin_wr=(IntPtr)0;
566                         }
567
568                         if(startInfo.RedirectStandardOutput==true) {
569                                 ret=MonoIO.CreatePipe(out stdout_rd,
570                                                       out stdout_wr);
571                         } else {
572                                 stdout_rd=(IntPtr)0;
573                                 stdout_wr=MonoIO.ConsoleOutput;
574                         }
575
576                         if(startInfo.RedirectStandardError==true) {
577                                 ret=MonoIO.CreatePipe(out stderr_rd,
578                                                       out stderr_wr);
579                         } else {
580                                 stderr_rd=(IntPtr)0;
581                                 stderr_wr=MonoIO.ConsoleError;
582                         }
583                         
584                         ret=Start_internal(startInfo.FileName + " " +
585                                            startInfo.Arguments,
586                                            startInfo.WorkingDirectory,
587                                            stdin_rd, stdout_wr, stderr_wr,
588                                            ref proc_info);
589
590                         process.process_handle=proc_info.process_handle;
591                         process.pid=proc_info.pid;
592                         
593                         if(startInfo.RedirectStandardInput==true) {
594                                 MonoIO.Close(stdin_rd);
595                                 process.input_stream=new StreamWriter(new FileStream(stdin_wr, FileAccess.Write, true));
596                                 process.input_stream.AutoFlush=true;
597                         }
598
599                         if(startInfo.RedirectStandardOutput==true) {
600                                 MonoIO.Close(stdout_wr);
601                                 process.output_stream=new StreamReader(new FileStream(stdout_rd, FileAccess.Read, true));
602                         }
603
604                         if(startInfo.RedirectStandardError==true) {
605                                 MonoIO.Close(stderr_wr);
606                                 process.error_stream=new StreamReader(new FileStream(stderr_rd, FileAccess.Read, true));
607                         }
608
609                         return(ret);
610                 }
611                 
612                 public bool Start() {
613                         bool ret;
614                         
615                         ret=Start_common(start_info, this);
616                         
617                         return(ret);
618                 }
619
620                 public static Process Start(ProcessStartInfo startInfo) {
621                         Process process=new Process();
622                         bool ret;
623
624                         ret=Start_common(startInfo, process);
625                         
626                         if(ret==true) {
627                                 return(process);
628                         } else {
629                                 return(null);
630                         }
631                 }
632
633                 [MonoTODO]
634                 public static Process Start(string fileName) {
635                         throw new NotImplementedException();
636                 }
637
638                 [MonoTODO]
639                 public static Process Start(string fileName,
640                                             string arguments) {
641                         throw new NotImplementedException();
642                 }
643
644                 public override string ToString() {
645                         return(base.ToString() +
646                                " (" + this.ProcessName + ")");
647                 }
648
649                 /* Waits up to ms milliseconds for process 'handle' to
650                  * exit.  ms can be <0 to mean wait forever.
651                  */
652                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
653                 private extern bool WaitForExit_internal(IntPtr handle,
654                                                          int ms);
655
656                 public void WaitForExit() {
657                         WaitForExit_internal(process_handle, -1);
658                 }
659
660                 public bool WaitForExit(int milliseconds) {
661                         return(WaitForExit_internal(process_handle,
662                                                     milliseconds));
663                 }
664
665                 [MonoTODO]
666                 public bool WaitForInputIdle() {
667                         return(false);
668                 }
669
670                 [MonoTODO]
671                 public bool WaitForInputIdle(int milliseconds) {
672                         return(false);
673                 }
674
675                 [MonoTODO]
676                 public event EventHandler Exited;
677
678                 // Closes the system process handle
679                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
680                 private extern void Process_free_internal(IntPtr handle);
681                 
682                 private bool disposed = false;
683                 
684                 protected override void Dispose(bool disposing) {
685                         // Check to see if Dispose has already been called.
686                         if(this.disposed) {
687                                 this.disposed=true;
688                                 // If this is a call to Dispose,
689                                 // dispose all managed resources.
690                                 if(disposing) {
691                                         // Do stuff here
692                                 }
693                                 
694                                 // Release unmanaged resources
695
696                                 lock(this) {
697                                         if(process_handle!=IntPtr.Zero) {
698                                                 
699                                                 Process_free_internal(process_handle);
700                                                 process_handle=IntPtr.Zero;
701                                         }
702                                 }
703                         }
704                         base.Dispose (disposing);
705                 }
706
707                 [MonoTODO]
708                 protected void OnExited() {
709                 }
710         }
711 }
712