for TARGET_J2EE only:
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
index 8e1b3e569c0c3397d01480fa25c4dcf91dda493e..07ed17f498eeea26807abc464fa7e9ef98c0c6ad 100644 (file)
@@ -40,6 +40,7 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security.Permissions;
 using System.Collections;
+using System.Security;
 using System.Threading;
 
 namespace System.Diagnostics {
@@ -67,6 +68,10 @@ namespace System.Diagnostics {
                        public int tid;
                        public string [] envKeys;
                        public string [] envValues;
+                       public string UserName;
+                       public string Domain;
+                       public IntPtr Password;
+                       public bool LoadUserProfile;
                };
                
                IntPtr process_handle;
@@ -77,10 +82,6 @@ namespace System.Diagnostics {
                EventHandler exited_event;
                IntPtr stdout_rd;
                IntPtr stderr_rd;
-#if NET_2_0
-               Encoding stdout_encoding;
-               Encoding stderr_encoding;
-#endif
                
                /* Private constructor called from other methods */
                private Process(IntPtr handle, int id) {
@@ -208,9 +209,8 @@ namespace System.Diagnostics {
                [MonitoringDescription ("Process identifier.")]
                public int Id {
                        get {
-                               if (pid == 0) {
+                               if (pid == 0)
                                        throw new InvalidOperationException ("Process ID has not been set.");
-                               }
 
                                return(pid);
                        }
@@ -261,9 +261,10 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The maximum working set for this process.")]
                public IntPtr MaxWorkingSet {
                        get {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               if(HasExited)
+                                       throw new InvalidOperationException(
+                                               "The process " + ProcessName +
+                                               " (ID " + Id + ") has exited");
                                
                                int min;
                                int max;
@@ -290,28 +291,27 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The minimum working set for this process.")]
                public IntPtr MinWorkingSet {
                        get {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               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) {
+                               bool ok= GetWorkingSet_internal (process_handle, out min, out max);
+                               if(!ok)
                                        throw new Win32Exception();
-                               }
-                               
-                               return((IntPtr)min);
+                               return ((IntPtr) min);
                        }
                        set {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               if(HasExited)
+                                       throw new InvalidOperationException(
+                                               "The process " + ProcessName +
+                                               " (ID " + Id + ") has exited");
                                
-                               bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
-                               if(ok==false) {
+                               bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
+                               if (!ok)
                                        throw new Win32Exception();
-                               }
                        }
                }
 
@@ -319,7 +319,7 @@ namespace System.Diagnostics {
                 * element 0.
                 */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern ProcessModule[] GetModules_internal();
+               private extern ProcessModule[] GetModules_internal(IntPtr handle);
 
                private ProcessModuleCollection module_collection;
                
@@ -327,10 +327,9 @@ namespace System.Diagnostics {
                [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());
-                               }
-
+                               if (module_collection == null)
+                                       module_collection = new ProcessModuleCollection(
+                                               GetModules_internal (process_handle));
                                return(module_collection);
                        }
                }
@@ -485,6 +484,9 @@ namespace System.Diagnostics {
                [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)
@@ -492,10 +494,14 @@ namespace System.Diagnostics {
                                return (ProcessPriorityClass) prio;
                        }
                        set {
-                               // LAMESPEC: not documented on MSDN for NET_1_1
                                if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
-                                       throw new InvalidEnumArgumentException ();
+                                       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);
@@ -520,6 +526,15 @@ namespace System.Diagnostics {
                        }
                }
 
+#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);
@@ -547,9 +562,8 @@ namespace System.Diagnostics {
                                         * null, assume the process
                                         * has exited
                                         */
-                                       if(process_name==null) {
+                                       if (process_name == null)
                                                throw new SystemException("The process has exited");
-                                       }
                                        
                                        /* Strip the suffix (if it
                                         * exists) simplistically
@@ -594,9 +608,9 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard error stream of this process.")]
                public StreamReader StandardError {
                        get {
-                               if (error_stream == null) {
+                               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.");
@@ -614,9 +628,8 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard input stream of this process.")]
                public StreamWriter StandardInput {
                        get {
-                               if (input_stream == null) {
+                               if (input_stream == null)
                                        throw new InvalidOperationException("Standard input has not been redirected");
-                               }
 
                                return(input_stream);
                        }
@@ -628,9 +641,9 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard output stream of this process.")]
                public StreamReader StandardOutput {
                        get {
-                               if (output_stream == null) {
+                               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.");
@@ -648,18 +661,14 @@ namespace System.Diagnostics {
                [MonitoringDescription ("Information for the start of this process.")]
                public ProcessStartInfo StartInfo {
                        get {
-                               if(start_info==null) {
-                                       start_info=new ProcessStartInfo();
-                               }
-                               
-                               return(start_info);
+                               if (start_info == null)
+                                       start_info = new ProcessStartInfo();
+                               return start_info;
                        }
                        set {
-                               if(value==null) {
-                                       throw new ArgumentException("value is null");
-                               }
-                               
-                               start_info=value;
+                               if (value == null)
+                                       throw new ArgumentNullException("value");
+                               start_info = value;
                        }
                }
 
@@ -689,7 +698,7 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The number of threads of this process.")]
                public ProcessThreadCollection Threads {
                        get {
-                               return(null);
+                               return ProcessThreadCollection.GetEmpty ();
                        }
                }
 
@@ -806,9 +815,8 @@ namespace System.Diagnostics {
                        int pid = GetPid_internal();
                        IntPtr proc = GetProcess_internal(pid);
                        
-                       if (proc == IntPtr.Zero) {
+                       if (proc == IntPtr.Zero)
                                throw new SystemException("Can't find current process");
-                       }
 
                        return (new Process (proc, pid));
                }
@@ -817,9 +825,8 @@ namespace System.Diagnostics {
                {
                        IntPtr proc = GetProcess_internal(processId);
                        
-                       if (proc == IntPtr.Zero) {
+                       if (proc == IntPtr.Zero)
                                throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
-                       }
 
                        return (new Process (proc, processId));
                }
@@ -901,7 +908,7 @@ namespace System.Diagnostics {
                }
 
                public void Refresh ()
-               {
+               {
                        // FIXME: should refresh any cached data we might have about
                        // the process (currently we have none).
                }
@@ -929,12 +936,18 @@ namespace System.Diagnostics {
                                throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
                        }
 
-                       if (startInfo.HaveEnvVars) {
+                       if (startInfo.HaveEnvVars)
                                throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
-                       }
 
-                       ret = ShellExecuteEx_internal (startInfo,
-                                                      ref proc_info);
+                       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);
                        }
@@ -950,8 +963,6 @@ namespace System.Diagnostics {
                private static bool Start_noshell (ProcessStartInfo startInfo,
                                                   Process process)
                {
-                       if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
-                               throw new FileNotFoundException  ("Executable not found: " + startInfo.FileName);
                        ProcInfo proc_info=new ProcInfo();
                        IntPtr stdin_rd, stdin_wr;
                        IntPtr stdout_wr;
@@ -1026,9 +1037,16 @@ namespace System.Diagnostics {
                                stderr_wr = MonoIO.ConsoleError;
                        }
 
-                       ret = CreateProcess_internal (startInfo,
-                                                     stdin_rd, stdout_wr, stderr_wr,
-                                                     ref proc_info);
+                       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);
@@ -1045,11 +1063,10 @@ namespace System.Diagnostics {
                                        MonoIO.Close (stderr_wr, out error);
                                }
 
-                               throw new Win32Exception (-proc_info.pid, 
-                                       "ApplicationName='"+startInfo.FileName+
-                                       "', CommandLine='"+startInfo.Arguments+
-                                       "', CurrentDirectory='"+startInfo.WorkingDirectory+
-                                       "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
+                               throw new Win32Exception (-proc_info.pid,
+                                       "ApplicationName='" + startInfo.FileName +
+                                       "', CommandLine='" + startInfo.Arguments +
+                                       "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
                        }
 
                        process.process_handle = proc_info.process_handle;
@@ -1057,28 +1074,26 @@ namespace System.Diagnostics {
                        
                        if (startInfo.RedirectStandardInput == true) {
                                MonoIO.Close (stdin_rd, out error);
-                               process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true), ConsoleEncoding.InputEncoding);
+                               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
-                       // TODO: which ones has precedence? The one from startInfo or the one set using
-                       // the Process instance properties?
-                       Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? process.StandardOutputEncoding;
-                       Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? process.StandardErrorEncoding;
+                       Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
+                       Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
 #else
-                       Encoding stdoutEncoding = ConsoleEncoding.OutputEncoding;
-                       Encoding stderrEncoding = ConsoleEncoding.OutputEncoding;
+                       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 FileStream (process.stdout_rd, FileAccess.Read, true), stdoutEncoding);
+                               process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding);
                        }
 
                        if (startInfo.RedirectStandardError == true) {
                                MonoIO.Close (stderr_wr, out error);
-                               process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true), stderrEncoding);
+                               process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding);
                        }
 
                        process.StartExitCallbackIfNeeded ();
@@ -1086,13 +1101,27 @@ namespace System.Diagnostics {
                        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 == "") {
+                       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)
@@ -1102,51 +1131,65 @@ namespace System.Diagnostics {
 #endif
                        
                        if (startInfo.UseShellExecute) {
+#if NET_2_0
+                               if (startInfo.UserName != null)
+                                       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() {
-                       bool ret;
-
+               public bool Start ()
+               {
                        if (process_handle != IntPtr.Zero) {
                                Process_free_internal (process_handle);
                                process_handle = IntPtr.Zero;
                        }
-                       ret=Start_common(start_info, this);
-                       
-                       return(ret);
+                       return Start_common(start_info, this);
                }
 
-               public static Process Start(ProcessStartInfo startInfo) {
+               public static Process Start (ProcessStartInfo startInfo)
+               {
+                       if (startInfo == null)
+                               throw new ArgumentNullException ("startInfo");
 
                        Process process=new Process();
-                       bool ret;
-
                        process.StartInfo = startInfo;
-                       ret=Start_common(startInfo, process);
-                       
-                       if(ret==true) {
-                               return(process);
-                       } else {
-                               return(null);
-                       }
+                       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) {
-                       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) {
-                       return Start(new ProcessStartInfo(fileName, arguments));
+               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 + ")");
+               public override string ToString()
+               {
+                       return(base.ToString() + " (" + this.ProcessName + ")");
                }
 
                /* Waits up to ms milliseconds for process 'handle' to
@@ -1525,32 +1568,6 @@ namespace System.Diagnostics {
                        synchronizingObject.BeginInvoke (exited_event, args);
                }
 
-#if NET_2_0
-               public Encoding StandardOutputEncoding {
-                       get {
-                               if (stdout_encoding != null) {
-                                       return stdout_encoding;
-                               }
-                               return ConsoleEncoding.OutputEncoding;
-                       }
-                       set {
-                               stdout_encoding = value; // if null, we'll use the default
-                       }
-               }
-
-               public Encoding StandardErrorEncoding {
-                       get {
-                               if (stderr_encoding != null) {
-                                       return stderr_encoding;
-                               }
-                               return ConsoleEncoding.OutputEncoding;
-                       }
-                       set {
-                               stderr_encoding = value; // if null, we'll use the default
-                       }
-               }
-#endif
-
                class ProcessWaitHandle : WaitHandle
                {
                        public ProcessWaitHandle (IntPtr handle)
@@ -1563,61 +1580,6 @@ namespace System.Diagnostics {
                                // Do nothing, we don't own the handle and we won't close it.
                        }
                }
-
-               class ConsoleEncoding
-               {
-                       [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
-                       private static extern int GetConsoleCP ();
-                       [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
-                       private static extern int GetConsoleOutputCP ();
-
-                       static bool RunningOnWindows {
-                               get {
-                                       return ((int) Environment.OSVersion.Platform != 4 &&
-#if NET_2_0
-                                               Environment.OSVersion.Platform != PlatformID.Unix);
-#else
-                                               (int) Environment.OSVersion.Platform != 128);
-#endif
-                               }
-                       }
-
-                       public static Encoding InputEncoding {
-                               get {
-                                       if(!RunningOnWindows) {
-                                               return Encoding.Default;
-                                       }
-
-#if !NET_2_0
-                                       try {
-                                               return Encoding.GetEncoding (GetConsoleCP ());
-                                       } catch {
-                                               return Encoding.GetEncoding (28591);
-                                       }
-#else
-                                       return Console.InputEncoding;
-#endif
-                               }
-                       }
-
-                       public static Encoding OutputEncoding {
-                               get {
-                                       if(!RunningOnWindows) {
-                                               return Encoding.Default;
-                                       }
-
-#if !NET_2_0
-                                       try {
-                                               return Encoding.GetEncoding (GetConsoleOutputCP ());
-                                       } catch {
-                                               return Encoding.GetEncoding (28591);
-                                       }
-#else
-                                       return Console.OutputEncoding;
-#endif
-                               }
-                       }
-               }
        }
 }