Process.cs :  » 2.6.4-mono-.net-core » System.Diagnostics » System » Diagnostics » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Diagnostics 
System.Diagnostics » System » Diagnostics » Process.cs
//
// System.Diagnostics.Process.cs
//
// Authors:
//   Dick Porter (dick@ximian.com)
//   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
//  Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// (C) 2002 Ximian, Inc.
// (C) 2003 Andreas Nahr
// (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
//

//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System.IO;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Collections;
using System.Security;
using System.Threading;

namespace System.Diagnostics{

  [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
  [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
  [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
  [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
#if NET_2_0
  [MonitoringDescription ("Represents a system process")]
#endif
  public class Process : Component 
  {
    [StructLayout(LayoutKind.Sequential)]
    private struct ProcInfo 
    {
      public IntPtr process_handle;
      /* If thread_handle is ever needed for
       * something, take out the CloseHandle() in
       * the Start_internal icall in
       * mono/metadata/process.c
       */
      public IntPtr thread_handle;
      public int pid; // Contains -GetLastError () on failure.
      public int tid;
      public string [] envKeys;
      public string [] envValues;
      public string UserName;
      public string Domain;
      public IntPtr Password;
      public bool LoadUserProfile;
    };
    
    IntPtr process_handle;
    int pid;
    bool enableRaisingEvents;
    bool already_waiting;
    ISynchronizeInvoke synchronizingObject;
    EventHandler exited_event;
    IntPtr stdout_rd;
    IntPtr stderr_rd;
    
    /* Private constructor called from other methods */
    private Process(IntPtr handle, int id) {
      process_handle=handle;
      pid=id;
    }
    
    public Process ()
    {
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Base process priority.")]
    public int BasePriority {
      get {
        return(0);
      }
    }

    void StartExitCallbackIfNeeded ()
    {
#if !NET_2_1
      bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
      if (start && process_handle != IntPtr.Zero) {
        WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
        ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
        ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
        already_waiting = true;
      }
#endif
    }

    [DefaultValue (false), Browsable (false)]
    [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
    public bool EnableRaisingEvents {
      get {
        return enableRaisingEvents;
      }
      set { 
        bool prev = enableRaisingEvents;
        enableRaisingEvents = value;
        if (enableRaisingEvents && !prev)
          StartExitCallbackIfNeeded ();
      }

    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static int ExitCode_internal(IntPtr handle);

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The exit code of the process.")]
    public int ExitCode {
      get {
        if (process_handle == IntPtr.Zero)
          throw new InvalidOperationException ("Process has not been started.");

        int code = ExitCode_internal (process_handle);
        if (code == 259)
          throw new InvalidOperationException ("The process must exit before " +
                  "getting the requested information.");

        return code;
      }
    }

    /* Returns the process start time in Windows file
     * times (ticks from DateTime(1/1/1601 00:00 GMT))
     */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static long ExitTime_internal(IntPtr handle);
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The exit time of the process.")]
    public DateTime ExitTime {
      get {
        if (process_handle == IntPtr.Zero)
          throw new InvalidOperationException ("Process has not been started.");

        if (!HasExited)
          throw new InvalidOperationException ("The process must exit before " +
                  "getting the requested information.");

        return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("Handle for this process.")]
    public IntPtr Handle {
      get {
        return(process_handle);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Handles for this process.")]
    public int HandleCount {
      get {
        return(0);
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("Determines if the process is still running.")]
    public bool HasExited {
      get {
        if (process_handle == IntPtr.Zero)
          throw new InvalidOperationException ("Process has not been started.");
          
        int exitcode = ExitCode_internal (process_handle);

        if(exitcode==259) {
          /* STILL_ACTIVE */
          return(false);
        } else {
          return(true);
        }
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Process identifier.")]
    public int Id {
      get {
        if (pid == 0)
          throw new InvalidOperationException ("Process ID has not been set.");

        return(pid);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The name of the computer running the process.")]
    public string MachineName {
      get {
        return("localhost");
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The main module of the process.")]
    public ProcessModule MainModule {
      get {
        return(this.Modules[0]);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The handle of the main window of the process.")]
    public IntPtr MainWindowHandle {
      get {
        return((IntPtr)0);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The title of the main window of the process.")]
    public string MainWindowTitle {
      get {
        return("null");
      }
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);

    /* LAMESPEC: why is this an IntPtr not a plain int? */
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum working set for this process.")]
    public IntPtr MaxWorkingSet {
      get {
        if(HasExited)
          throw new InvalidOperationException(
            "The process " + ProcessName +
            " (ID " + Id + ") has exited");
        
        int min;
        int max;
        bool ok=GetWorkingSet_internal(process_handle, out min, out max);
        if(ok==false) {
          throw new Win32Exception();
        }
        
        return((IntPtr)max);
      }
      set {
        if(HasExited) {
          throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
        }
        
        bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
        if(ok==false) {
          throw new Win32Exception();
        }
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The minimum working set for this process.")]
    public IntPtr MinWorkingSet {
      get {
        if(HasExited)
          throw new InvalidOperationException(
            "The process " + ProcessName +
            " (ID " + Id + ") has exited");
        
        int min;
        int max;
        bool ok= GetWorkingSet_internal (process_handle, out min, out max);
        if(!ok)
          throw new Win32Exception();
        return ((IntPtr) min);
      }
      set {
        if(HasExited)
          throw new InvalidOperationException(
            "The process " + ProcessName +
            " (ID " + Id + ") has exited");
        
        bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
        if (!ok)
          throw new Win32Exception();
      }
    }

    /* Returns the list of process modules.  The main module is
     * element 0.
     */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern ProcessModule[] GetModules_internal(IntPtr handle);

    private ProcessModuleCollection module_collection;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The modules that are loaded as part of this process.")]
    public ProcessModuleCollection Modules {
      get {
        if (module_collection == null)
          module_collection = new ProcessModuleCollection(
            GetModules_internal (process_handle));
        return(module_collection);
      }
    }

    /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static long GetProcessData (int pid, int data_type, out int error);

    [MonoTODO]
#if NET_2_0
    [Obsolete ("Use NonpagedSystemMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The number of bytes that are not pageable.")]
    public int NonpagedSystemMemorySize {
      get {
        return(0);
      }
    }

    [MonoTODO]
#if NET_2_0
    [Obsolete ("Use PagedMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The number of bytes that are paged.")]
    public int PagedMemorySize {
      get {
        return(0);
      }
    }

    [MonoTODO]
#if NET_2_0
    [Obsolete ("Use PagedSystemMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of paged system memory in bytes.")]
    public int PagedSystemMemorySize {
      get {
        return(0);
      }
    }

    [MonoTODO]
#if NET_2_0
    [Obsolete ("Use PeakPagedMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
    public int PeakPagedMemorySize {
      get {
        return(0);
      }
    }

#if NET_2_0
    [Obsolete ("Use PeakVirtualMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
    public int PeakVirtualMemorySize {
      get {
        int error;
        return (int)GetProcessData (pid, 8, out error);
      }
    }

#if NET_2_0
    [Obsolete ("Use PeakWorkingSet64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of system memory used by this process.")]
    public int PeakWorkingSet {
      get {
        int error;
        return (int)GetProcessData (pid, 5, out error);
      }
    }

#if NET_2_0
    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The number of bytes that are not pageable.")]
    [ComVisible (false)]
    public long NonpagedSystemMemorySize64 {
      get {
        return(0);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The number of bytes that are paged.")]
    [ComVisible (false)]
    public long PagedMemorySize64 {
      get {
        return(0);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of paged system memory in bytes.")]
    [ComVisible (false)]
    public long PagedSystemMemorySize64 {
      get {
        return(0);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
    [ComVisible (false)]
    public long PeakPagedMemorySize64 {
      get {
        return(0);
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
    [ComVisible (false)]
    public long PeakVirtualMemorySize64 {
      get {
        int error;
        return GetProcessData (pid, 8, out error);
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The maximum amount of system memory used by this process.")]
    [ComVisible (false)]
    public long PeakWorkingSet64 {
      get {
        int error;
        return GetProcessData (pid, 5, out error);
      }
    }
#endif

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
    public bool PriorityBoostEnabled {
      get {
        return(false);
      }
      set {
      }
    }

    [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The relative process priority.")]
    public ProcessPriorityClass PriorityClass {
      get {
        if (process_handle == IntPtr.Zero)
          throw new InvalidOperationException ("Process has not been started.");
        
        int error;
        int prio = GetPriorityClass (process_handle, out error);
        if (prio == 0)
          throw new Win32Exception (error);
        return (ProcessPriorityClass) prio;
      }
      set {
        if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
          throw new InvalidEnumArgumentException (
            "value", (int) value,
            typeof (ProcessPriorityClass));

        if (process_handle == IntPtr.Zero)
          throw new InvalidOperationException ("Process has not been started.");
        
        int error;
        if (!SetPriorityClass (process_handle, (int) value, out error))
          throw new Win32Exception (error);
      }
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    static extern int GetPriorityClass (IntPtr handle, out int error);

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of memory exclusively used by this process.")]
#if NET_2_0
    [Obsolete ("Use PrivateMemorySize64")]
#endif
    public int PrivateMemorySize {
      get {
        int error;
        return (int)GetProcessData (pid, 6, out error);
      }
    }

#if NET_2_0
    [MonoNotSupported ("")]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The session ID for this process.")]
    public int SessionId {
      get { throw new NotImplementedException (); }
    }
#endif

    /* the meaning of type is as follows: 0: user, 1: system, 2: total */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static long Times (IntPtr handle, int type);

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
    public TimeSpan PrivilegedProcessorTime {
      get {
        return new TimeSpan (Times (process_handle, 1));
      }
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static string ProcessName_internal(IntPtr handle);
    
    private string process_name=null;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The name of this process.")]
    public string ProcessName {
      get {
        if(process_name==null) {
          
          if (process_handle == IntPtr.Zero)
            throw new InvalidOperationException ("No process is associated with this object.");
          
          process_name=ProcessName_internal(process_handle);
          /* If process_name is _still_
           * null, assume the process
           * has exited
           */
          if (process_name == null)
            throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
          
          /* Strip the suffix (if it
           * exists) simplistically
           * instead of removing any
           * trailing \.???, so we dont
           * get stupid results on sane
           * systems
           */
          if(process_name.EndsWith(".exe") ||
             process_name.EndsWith(".bat") ||
             process_name.EndsWith(".com")) {
            process_name=process_name.Substring(0, process_name.Length-4);
          }
        }
        return(process_name);
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Allowed processor that can be used by this process.")]
    public IntPtr ProcessorAffinity {
      get {
        return((IntPtr)0);
      }
      set {
      }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("Is this process responsive.")]
    public bool Responding {
      get {
        return(false);
      }
    }

    private StreamReader error_stream=null;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The standard error stream of this process.")]
    public StreamReader StandardError {
      get {
        if (error_stream == null)
          throw new InvalidOperationException("Standard error has not been redirected");

#if NET_2_0
        if ((async_mode & AsyncModes.AsyncError) != 0)
          throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");

        async_mode |= AsyncModes.SyncError;
#endif

        return(error_stream);
      }
    }

    private StreamWriter input_stream=null;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The standard input stream of this process.")]
    public StreamWriter StandardInput {
      get {
        if (input_stream == null)
          throw new InvalidOperationException("Standard input has not been redirected");

        return(input_stream);
      }
    }

    private StreamReader output_stream=null;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The standard output stream of this process.")]
    public StreamReader StandardOutput {
      get {
        if (output_stream == null)
          throw new InvalidOperationException("Standard output has not been redirected");

#if NET_2_0
        if ((async_mode & AsyncModes.AsyncOutput) != 0)
          throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");

        async_mode |= AsyncModes.SyncOutput;
#endif

        return(output_stream);
      }
    }

    private ProcessStartInfo start_info=null;
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
    [MonitoringDescription ("Information for the start of this process.")]
    public ProcessStartInfo StartInfo {
      get {
        if (start_info == null)
          start_info = new ProcessStartInfo();
        return start_info;
      }
      set {
        if (value == null)
          throw new ArgumentNullException("value");
        start_info = value;
      }
    }

    /* Returns the process start time in Windows file
     * times (ticks from DateTime(1/1/1601 00:00 GMT))
     */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static long StartTime_internal(IntPtr handle);
    
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The time this process started.")]
    public DateTime StartTime {
      get {
        return(DateTime.FromFileTime(StartTime_internal(process_handle)));
      }
    }

    [DefaultValue (null), Browsable (false)]
    [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
    public ISynchronizeInvoke SynchronizingObject {
      get { return synchronizingObject; }
      set { synchronizingObject = value; }
    }

    [MonoTODO]
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
    [MonitoringDescription ("The number of threads of this process.")]
    public ProcessThreadCollection Threads {
      get {
        return ProcessThreadCollection.GetEmpty ();
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The total CPU time spent for this process.")]
    public TimeSpan TotalProcessorTime {
      get {
        return new TimeSpan (Times (process_handle, 2));
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The CPU time spent for this process in user mode.")]
    public TimeSpan UserProcessorTime {
      get {
        return new TimeSpan (Times (process_handle, 0));
      }
    }

#if NET_2_0
    [Obsolete ("Use VirtualMemorySize64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
    public int VirtualMemorySize {
      get {
        int error;
        return (int)GetProcessData (pid, 7, out error);
      }
    }

#if NET_2_0
    [Obsolete ("Use WorkingSet64")]
#endif
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of physical memory currently used for this process.")]
    public int WorkingSet {
      get {
        int error;
        return (int)GetProcessData (pid, 4, out error);
      }
    }

#if NET_2_0
    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of memory exclusively used by this process.")]
    [ComVisible (false)]
    public long PrivateMemorySize64 {
      get {
        int error;
        return GetProcessData (pid, 6, out error);
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
    [ComVisible (false)]
    public long VirtualMemorySize64 {
      get {
        int error;
        return GetProcessData (pid, 7, out error);
      }
    }

    [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
    [MonitoringDescription ("The amount of physical memory currently used for this process.")]
    [ComVisible (false)]
    public long WorkingSet64 {
      get {
        int error;
        return GetProcessData (pid, 4, out error);
      }
    }
#endif

    public void Close()
    {
      Dispose (true);
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    extern static bool Kill_internal (IntPtr handle, int signo);

    /* int kill -> 1 KILL, 2 CloseMainWindow */
    bool Close (int signo)
    {
      if (process_handle == IntPtr.Zero)
        throw new SystemException ("No process to kill.");

      int exitcode = ExitCode_internal (process_handle);
      if (exitcode != 259)
        throw new InvalidOperationException ("The process already finished.");

      return Kill_internal (process_handle, signo);
    }

    public bool CloseMainWindow ()
    {
      return Close (2);
    }

    [MonoTODO]
    public static void EnterDebugMode() {
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static IntPtr GetProcess_internal(int pid);
    
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static int GetPid_internal();

    public static Process GetCurrentProcess()
    {
      int pid = GetPid_internal();
      IntPtr proc = GetProcess_internal(pid);
      
      if (proc == IntPtr.Zero)
        throw new SystemException("Can't find current process");

      return (new Process (proc, pid));
    }

    public static Process GetProcessById(int processId)
    {
      IntPtr proc = GetProcess_internal(processId);
      
      if (proc == IntPtr.Zero)
        throw new ArgumentException ("Can't find process with ID " + processId.ToString ());

      return (new Process (proc, processId));
    }

    [MonoTODO ("There is no support for retrieving process information from a remote machine")]
    public static Process GetProcessById(int processId, string machineName) {
      if (machineName == null)
        throw new ArgumentNullException ("machineName");

      if (!IsLocalMachine (machineName))
        throw new NotImplementedException ();

      return GetProcessById (processId);
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static int[] GetProcesses_internal();

    public static Process[] GetProcesses()
    {
      int [] pids = GetProcesses_internal ();
      ArrayList proclist = new ArrayList ();

      if (pids == null)
        return new Process [0];
      
      for (int i = 0; i < pids.Length; i++) {
        try {
          proclist.Add (GetProcessById (pids [i]));
        } catch (SystemException) {
          /* The process might exit
           * between
           * GetProcesses_internal and
           * GetProcessById
           */
        }
      }

      return ((Process []) proclist.ToArray (typeof (Process)));
    }

    [MonoTODO ("There is no support for retrieving process information from a remote machine")]
    public static Process[] GetProcesses(string machineName) {
      if (machineName == null)
        throw new ArgumentNullException ("machineName");

      if (!IsLocalMachine (machineName))
        throw new NotImplementedException ();

      return GetProcesses ();
    }

    public static Process[] GetProcessesByName(string processName)
    {
      Process [] procs = GetProcesses();
      ArrayList proclist = new ArrayList();
      
      for (int i = 0; i < procs.Length; i++) {
        /* Ignore case */
        if (String.Compare (processName,
                procs [i].ProcessName,
                true) == 0) {
          proclist.Add (procs [i]);
        }
      }

      return ((Process[]) proclist.ToArray (typeof(Process)));
    }

    [MonoTODO]
    public static Process[] GetProcessesByName(string processName, string machineName) {
      throw new NotImplementedException();
    }

    public void Kill ()
    {
      Close (1);
    }

    [MonoTODO]
    public static void LeaveDebugMode() {
    }

    public void Refresh ()
    {
      // FIXME: should refresh any cached data we might have about
      // the process (currently we have none).
    }

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
                   ref ProcInfo proc_info);

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
                  IntPtr stdin,
                  IntPtr stdout,
                  IntPtr stderr,
                  ref ProcInfo proc_info);

    private static bool Start_shell (ProcessStartInfo startInfo,
             Process process)
    {
      ProcInfo proc_info=new ProcInfo();
      bool ret;

      if (startInfo.RedirectStandardInput ||
          startInfo.RedirectStandardOutput ||
          startInfo.RedirectStandardError) {
        throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
      }

      if (startInfo.HaveEnvVars)
        throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");

      FillUserInfo (startInfo, ref proc_info);
      try {
        ret = ShellExecuteEx_internal (startInfo,
                     ref proc_info);
      } finally {
        if (proc_info.Password != IntPtr.Zero)
          Marshal.FreeBSTR (proc_info.Password);
        proc_info.Password = IntPtr.Zero;
      }
      if (!ret) {
        throw new Win32Exception (-proc_info.pid);
      }

      process.process_handle = proc_info.process_handle;
      process.pid = proc_info.pid;

      process.StartExitCallbackIfNeeded ();

      return(ret);
    }

    private static bool Start_noshell (ProcessStartInfo startInfo,
               Process process)
    {
      ProcInfo proc_info=new ProcInfo();
      IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
      IntPtr stdout_wr;
      IntPtr stderr_wr;
      bool ret;
      MonoIOError error;

      if (startInfo.HaveEnvVars) {
        string [] strs = new string [startInfo.EnvironmentVariables.Count];
        startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
        proc_info.envKeys = strs;

        strs = new string [startInfo.EnvironmentVariables.Count];
        startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
        proc_info.envValues = strs;
      }

      if (startInfo.RedirectStandardInput == true) {
        if (IsWindows) {
          int DUPLICATE_SAME_ACCESS = 0x00000002;
          IntPtr stdin_wr_tmp;

          ret = MonoIO.CreatePipe (out stdin_rd,
                   out stdin_wr_tmp);
          if (ret) {
            ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
            Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
            MonoIO.Close (stdin_wr_tmp, out error);
          }
        }
        else
        {
          ret = MonoIO.CreatePipe (out stdin_rd,
                   out stdin_wr);
        }
        if (ret == false) {
          throw new IOException ("Error creating standard input pipe");
        }
      } else {
        stdin_rd = MonoIO.ConsoleInput;
        /* This is required to stop the
         * &$*ing stupid compiler moaning
         * that stdin_wr is unassigned, below.
         */
        stdin_wr = (IntPtr)0;
      }

      if (startInfo.RedirectStandardOutput == true) {
        IntPtr out_rd = IntPtr.Zero;
        if (IsWindows) {
          IntPtr out_rd_tmp;
          int DUPLICATE_SAME_ACCESS = 0x00000002;

          ret = MonoIO.CreatePipe (out out_rd_tmp,
                   out stdout_wr);
          if (ret) {
            MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
            Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
            MonoIO.Close (out_rd_tmp, out error);
          }
        }
        else {
          ret = MonoIO.CreatePipe (out out_rd,
                   out stdout_wr);
        }

        process.stdout_rd = out_rd;
        if (ret == false) {
          if (startInfo.RedirectStandardInput == true) {
            MonoIO.Close (stdin_rd, out error);
            MonoIO.Close (stdin_wr, out error);
          }

          throw new IOException ("Error creating standard output pipe");
        }
      } else {
        process.stdout_rd = (IntPtr)0;
        stdout_wr = MonoIO.ConsoleOutput;
      }

      if (startInfo.RedirectStandardError == true) {
        IntPtr err_rd = IntPtr.Zero;
        if (IsWindows) {
          IntPtr err_rd_tmp;
          int DUPLICATE_SAME_ACCESS = 0x00000002;

          ret = MonoIO.CreatePipe (out err_rd_tmp,
                   out stderr_wr);
          if (ret) {
            MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
            Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
            MonoIO.Close (err_rd_tmp, out error);
          }
        }
        else {
          ret = MonoIO.CreatePipe (out err_rd,
                   out stderr_wr);
        }

        process.stderr_rd = err_rd;
        if (ret == false) {
          if (startInfo.RedirectStandardInput == true) {
            MonoIO.Close (stdin_rd, out error);
            MonoIO.Close (stdin_wr, out error);
          }
          if (startInfo.RedirectStandardOutput == true) {
            MonoIO.Close (process.stdout_rd, out error);
            MonoIO.Close (stdout_wr, out error);
          }
          
          throw new IOException ("Error creating standard error pipe");
        }
      } else {
        process.stderr_rd = (IntPtr)0;
        stderr_wr = MonoIO.ConsoleError;
      }

      FillUserInfo (startInfo, ref proc_info);
      try {
        ret = CreateProcess_internal (startInfo,
                    stdin_rd, stdout_wr, stderr_wr,
                    ref proc_info);
      } finally {
        if (proc_info.Password != IntPtr.Zero)
          Marshal.FreeBSTR (proc_info.Password);
        proc_info.Password = IntPtr.Zero;
      }
      if (!ret) {
        if (startInfo.RedirectStandardInput == true) {
          MonoIO.Close (stdin_rd, out error);
          MonoIO.Close (stdin_wr, out error);
        }

        if (startInfo.RedirectStandardOutput == true) {
          MonoIO.Close (process.stdout_rd, out error);
          MonoIO.Close (stdout_wr, out error);
        }

        if (startInfo.RedirectStandardError == true) {
          MonoIO.Close (process.stderr_rd, out error);
          MonoIO.Close (stderr_wr, out error);
        }

        throw new Win32Exception (-proc_info.pid,
          "ApplicationName='" + startInfo.FileName +
          "', CommandLine='" + startInfo.Arguments +
          "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
      }

      process.process_handle = proc_info.process_handle;
      process.pid = proc_info.pid;
      
      if (startInfo.RedirectStandardInput == true) {
        MonoIO.Close (stdin_rd, out error);
        process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
        process.input_stream.AutoFlush = true;
      }

#if NET_2_0
      Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
      Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
#else
      Encoding stdoutEncoding = Console.Out.Encoding;
      Encoding stderrEncoding = stdoutEncoding;
#endif

      if (startInfo.RedirectStandardOutput == true) {
        MonoIO.Close (stdout_wr, out error);
        process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
      }

      if (startInfo.RedirectStandardError == true) {
        MonoIO.Close (stderr_wr, out error);
        process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
      }

      process.StartExitCallbackIfNeeded ();

      return(ret);
    }

    // Note that ProcInfo.Password must be freed.
    private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
    {
#if NET_2_0
      if (startInfo.UserName != null) {
        proc_info.UserName = startInfo.UserName;
        proc_info.Domain = startInfo.Domain;
        if (startInfo.Password != null)
          proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
        else
          proc_info.Password = IntPtr.Zero;
        proc_info.LoadUserProfile = startInfo.LoadUserProfile;
      }
#endif
    }

    private static bool Start_common (ProcessStartInfo startInfo,
              Process process)
    {
      if (startInfo.FileName == null || startInfo.FileName.Length == 0)
        throw new InvalidOperationException("File name has not been set");
      
#if NET_2_0
      if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
        throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
      if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
        throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
#endif
      
      if (startInfo.UseShellExecute) {
#if NET_2_0
        if (!String.IsNullOrEmpty (startInfo.UserName))
          throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
#endif
        return (Start_shell (startInfo, process));
      } else {
        return (Start_noshell (startInfo, process));
      }
    }
    
    public bool Start ()
    {
      if (process_handle != IntPtr.Zero) {
        Process_free_internal (process_handle);
        process_handle = IntPtr.Zero;
      }
      return Start_common(start_info, this);
    }

    public static Process Start (ProcessStartInfo startInfo)
    {
      if (startInfo == null)
        throw new ArgumentNullException ("startInfo");

      Process process=new Process();
      process.StartInfo = startInfo;
      if (Start_common(startInfo, process))
        return process;
      return null;
    }

    public static Process Start (string fileName)
    {
      return Start (new ProcessStartInfo (fileName));
    }

    public static Process Start(string fileName, string arguments)
    {
      return Start (new ProcessStartInfo (fileName, arguments));
    }

#if NET_2_0
    public static Process Start(string fileName, string username, SecureString password, string domain) {
      return Start(fileName, null, username, password, domain);
    }

    public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
      ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
      psi.UserName = username;
      psi.Password = password;
      psi.Domain = domain;
      psi.UseShellExecute = false;
      return Start(psi);
    }
#endif

    public override string ToString()
    {
      return(base.ToString() + " (" + this.ProcessName + ")");
    }

    /* Waits up to ms milliseconds for process 'handle' to
     * exit.  ms can be <0 to mean wait forever.
     */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern bool WaitForExit_internal(IntPtr handle, int ms);

    public void WaitForExit ()
    {
      WaitForExit (-1);
    }

    public bool WaitForExit(int milliseconds) {
      int ms = milliseconds;
      if (ms == int.MaxValue)
        ms = -1;

#if NET_2_0
      DateTime start = DateTime.UtcNow;
      if (async_output != null && !async_output.IsCompleted) {
        if (false == async_output.WaitHandle.WaitOne (ms, false))
          return false; // Timed out

        if (ms >= 0) {
          DateTime now = DateTime.UtcNow;
          ms -= (int) (now - start).TotalMilliseconds;
          if (ms <= 0)
            return false;
          start = now;
        }
      }

      if (async_error != null && !async_error.IsCompleted) {
        if (false == async_error.WaitHandle.WaitOne (ms, false))
          return false; // Timed out

        if (ms >= 0) {
          ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
          if (ms <= 0)
            return false;
        }
      }
#endif
      return WaitForExit_internal (process_handle, ms);
    }

    /* Waits up to ms milliseconds for process 'handle' to 
     * wait for input.  ms can be <0 to mean wait forever.
     */
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);

    // The internal call is only implemented properly on Windows.
    [MonoTODO]
    public bool WaitForInputIdle() {
      return WaitForInputIdle (-1);
    }

    // The internal call is only implemented properly on Windows.
    [MonoTODO]
    public bool WaitForInputIdle(int milliseconds) {
      return WaitForInputIdle_internal (process_handle, milliseconds);
    }

    private static bool IsLocalMachine (string machineName)
    {
      if (machineName == "." || machineName.Length == 0)
        return true;

      return (string.Compare (machineName, Environment.MachineName, true) == 0);
    }

#if NET_2_0
    [Browsable (true)]
    [MonitoringDescription ("Raised when it receives output data")]
    public event DataReceivedEventHandler OutputDataReceived;
    [Browsable (true)]
    [MonitoringDescription ("Raised when it receives error data")]
    public event DataReceivedEventHandler ErrorDataReceived;

    void OnOutputDataReceived (string str)
    {
      if (OutputDataReceived != null)
        OutputDataReceived (this, new DataReceivedEventArgs (str));
    }

    void OnErrorDataReceived (string str)
    {
      if (ErrorDataReceived != null)
        ErrorDataReceived (this, new DataReceivedEventArgs (str));
    }

    [Flags]
    enum AsyncModes {
      NoneYet = 0,
      SyncOutput = 1,
      SyncError = 1 << 1,
      AsyncOutput = 1 << 2,
      AsyncError = 1 << 3
    }

    [StructLayout (LayoutKind.Sequential)]
    sealed class ProcessAsyncReader
    {
      /*
         The following fields match those of SocketAsyncResult.
         This is so that changes needed in the runtime to handle
         asynchronous reads are trivial
         Keep this in sync with SocketAsyncResult in 
         ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
         in metadata/socket-io.h.
      */
      /* DON'T shuffle fields around. DON'T remove fields */
      public object Sock;
      public IntPtr handle;
      public object state;
      public AsyncCallback callback;
      public ManualResetEvent wait_handle;

      public Exception delayedException;

      public object EndPoint;
      byte [] buffer = new byte [4196];
      public int Offset;
      public int Size;
      public int SockFlags;

      public object AcceptSocket;
      public object[] Addresses;
      public int port;
      public object Buffers;          // Reserve this slot in older profiles
      public bool ReuseSocket;        // Disconnect
      public object acc_socket;
      public int total;
      public bool completed_sync;
      bool completed;
      bool err_out; // true -> stdout, false -> stderr
      internal int error;
      public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
      public object ares;
      public int EndCalled;

      // These fields are not in SocketAsyncResult
      Process process;
      Stream stream;
      StringBuilder sb = new StringBuilder ();
      public AsyncReadHandler ReadHandler;

      public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
      {
        this.process = process;
        this.handle = handle;
        stream = new FileStream (handle, FileAccess.Read, false);
        this.ReadHandler = new AsyncReadHandler (AddInput);
        this.err_out = err_out;
      }

      public void AddInput ()
      {
        lock (this) {
          int nread = stream.Read (buffer, 0, buffer.Length);
          if (nread == 0) {
            completed = true;
            if (wait_handle != null)
              wait_handle.Set ();
            FlushLast ();
            return;
          }

          try {
            sb.Append (Encoding.Default.GetString (buffer, 0, nread));
          } catch {
            // Just in case the encoding fails...
            for (int i = 0; i < nread; i++) {
              sb.Append ((char) buffer [i]);
            }
          }

          Flush (false);
          ReadHandler.BeginInvoke (null, this);
        }
      }

      void FlushLast ()
      {
        Flush (true);
        if (err_out) {
          process.OnOutputDataReceived (null);
        } else {
          process.OnErrorDataReceived (null);
        }
      }
      
      void Flush (bool last)
      {
        if (sb.Length == 0 ||
            (err_out && process.output_canceled) ||
            (!err_out && process.error_canceled))
          return;

        string total = sb.ToString ();
        sb.Length = 0;
        string [] strs = total.Split ('\n');
        int len = strs.Length;
        if (len == 0)
          return;

        for (int i = 0; i < len - 1; i++) {
          if (err_out)
            process.OnOutputDataReceived (strs [i]);
          else
            process.OnErrorDataReceived (strs [i]);
        }

        string end = strs [len - 1];
        if (last || (len == 1 && end == "")) {
          if (err_out) {
            process.OnOutputDataReceived (end);
          } else {
            process.OnErrorDataReceived (end);
          }
        } else {
          sb.Append (end);
        }
      }

      public bool IsCompleted {
        get { return completed; }
      }

      public WaitHandle WaitHandle {
        get {
          lock (this) {
            if (wait_handle == null)
              wait_handle = new ManualResetEvent (completed);
            return wait_handle;
          }
        }
      }

      public void Close () {
        stream.Close ();
      }
    }

    AsyncModes async_mode;
    bool output_canceled;
    bool error_canceled;
    ProcessAsyncReader async_output;
    ProcessAsyncReader async_error;
    delegate void AsyncReadHandler ();

    [ComVisibleAttribute(false)] 
    public void BeginOutputReadLine ()
    {
      if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
        throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");

      if ((async_mode & AsyncModes.SyncOutput) != 0)
        throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");

      async_mode |= AsyncModes.AsyncOutput;
      output_canceled = false;
      if (async_output == null) {
        async_output = new ProcessAsyncReader (this, stdout_rd, true);
        async_output.ReadHandler.BeginInvoke (null, async_output);
      }
    }

    [ComVisibleAttribute(false)] 
    public void CancelOutputRead ()
    {
      if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
        throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");

      if ((async_mode & AsyncModes.SyncOutput) != 0)
        throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");

      if (async_output == null)
        throw new InvalidOperationException ("No async operation in progress.");

      output_canceled = true;
    }

    [ComVisibleAttribute(false)] 
    public void BeginErrorReadLine ()
    {
      if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
        throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");

      if ((async_mode & AsyncModes.SyncError) != 0)
        throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");

      async_mode |= AsyncModes.AsyncError;
      error_canceled = false;
      if (async_error == null) {
        async_error = new ProcessAsyncReader (this, stderr_rd, false);
        async_error.ReadHandler.BeginInvoke (null, async_error);
      }
    }

    [ComVisibleAttribute(false)] 
    public void CancelErrorRead ()
    {
      if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
        throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");

      if ((async_mode & AsyncModes.SyncOutput) != 0)
        throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");

      if (async_error == null)
        throw new InvalidOperationException ("No async operation in progress.");

      error_canceled = true;
    }
#endif

    [Category ("Behavior")]
    [MonitoringDescription ("Raised when this process exits.")]
    public event EventHandler Exited {
      add {
        if (process_handle != IntPtr.Zero && HasExited) {
          value.BeginInvoke (null, null, null, null);
        } else {
          exited_event = (EventHandler) Delegate.Combine (exited_event, value);
          if (exited_event != null)
            StartExitCallbackIfNeeded ();
        }
      }
      remove {
        exited_event = (EventHandler) Delegate.Remove (exited_event, value);
      }
    }

    // Closes the system process handle
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    private extern void Process_free_internal(IntPtr handle);
    
    private bool disposed = false;
    
    protected override void Dispose(bool disposing) {
      // Check to see if Dispose has already been called.
      if(this.disposed == false) {
        this.disposed=true;
        // If this is a call to Dispose,
        // dispose all managed resources.
        if(disposing) {
          // Do stuff here
          lock (this) {
            /* These have open FileStreams on the pipes we are about to close */
            if (async_output != null)
              async_output.Close ();
            if (async_error != null)
              async_error.Close ();
          }
        }
        
        // Release unmanaged resources

        lock(this) {
          if(process_handle!=IntPtr.Zero) {
            Process_free_internal(process_handle);
            process_handle=IntPtr.Zero;
          }

          if (input_stream != null) {
            input_stream.Close();
            input_stream = null;
          }

          if (output_stream != null) {
            output_stream.Close();
            output_stream = null;
          }

          if (error_stream != null) {
            error_stream.Close();
            error_stream = null;
          }
        }
      }
      base.Dispose (disposing);
    }

    ~Process ()
    {
      Dispose (false);
    }

    static void CBOnExit (object state, bool unused)
    {
      Process p = (Process) state;
      p.OnExited ();
    }

    protected void OnExited() 
    {
      if (exited_event == null)
        return;

      if (synchronizingObject == null) {
        foreach (EventHandler d in exited_event.GetInvocationList ()) {
          try {
            d (this, EventArgs.Empty);
          } catch {}
        }
        return;
      }
      
      object [] args = new object [] {this, EventArgs.Empty};
      synchronizingObject.BeginInvoke (exited_event, args);
    }

    static bool IsWindows
    {
      get
      {
        PlatformID platform = Environment.OSVersion.Platform;
        if (platform == PlatformID.Win32S ||
          platform == PlatformID.Win32Windows ||
          platform == PlatformID.Win32NT ||
          platform == PlatformID.WinCE) {
          return true;
        }
        return false;
      }
    }

    class ProcessWaitHandle : WaitHandle
    {
      [MethodImplAttribute (MethodImplOptions.InternalCall)]
      private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
      
      public ProcessWaitHandle (IntPtr handle)
      {
        // Need to keep a reference to this handle,
        // in case the Process object is collected
        Handle = ProcessHandle_duplicate (handle);

        // When the wait handle is disposed, the duplicated handle will be
        // closed, so no need to override dispose (bug #464628).
      }
    }
  }
}

www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.