void StartGuiProcess(int sessionId) { TerminateProcess(ref mGuiProcess, ref mGuiMan, false); mDesktopGuiIsOn = ""; var desktop = mDesktopFromWatcher; mDesktopGuiIsOn = desktop; var pipeName = "OpenViewtop_gui_" + Util.GenerateRandomId(); // When on the default desktop, run as the user so the clipboard works properly. // For other desktops we need to run as system so the GUI has permission to copy the screen. // TBD: Seems like there should be a better way to do this WtsProcessType processType = desktop.ToLower() != DEFAULT_DESKTOP.ToLower() || sessionId == 0 ? WtsProcessType.System : WtsProcessType.UserFallbackToSystem; processType |= WtsProcessType.Admin | WtsProcessType.UIAccess; // Mange process communications Log.Write("*** Starting GUI: Session=" + sessionId + ", User="******", Desktop=" + desktop + ", Pipe=" + pipeName); mGuiMan = new ProcessManager(pipeName, true); Task.Run(() => { ProcessRemoteCommunications(mGuiMan, "GUI"); }); mGuiProcess = WtsProcess.StartInSession( sessionId, processType, System.Windows.Forms.Application.ExecutablePath, Program.PARAM_GUI + " " + Program.PARAM_CONTROL_PIPE + " " + pipeName + " " + Program.PARAM_DESKTOP + " " + desktop, desktop); }
/// <summary> /// Don't launch using Process.Start, or else it runs as "System" /// </summary> void ProcessStartAsLoggedOnUser(string fileName) { try { // Launch from helper task running as the user, also with the user environment // NOTE: This fails unless it's running in the system accont WtsProcess.StartInSession(Wts.GetActiveConsoleSessionId(), WtsProcessType.User, Application.ExecutablePath, Program.PARAM_START_BROWSER + " \"" + fileName + "\"").Dispose(); } catch { // NOTE: New versions run in as the logged on user and the above code fails. Process.Start(fileName); } }
void StartDesktopWatcherProcess(int sessionId) { TerminateProcess(ref mDesktopProcess, ref mDesktopMan, false); mDesktopFromWatcher = ""; // Create new process var pipeName = "OpenViewtop_desktop_" + Util.GenerateRandomId(); // Manage communications Log.Write("*** Starting DESKTOP: Session=" + sessionId + ", User="******", Pipe=" + pipeName); mDesktopMan = new ProcessManager(pipeName, true); Task.Run(() => { ProcessRemoteCommunications(mDesktopMan, "DESKTOP"); }); mDesktopProcess = WtsProcess.StartInSession( sessionId, WtsProcessType.System, System.Windows.Forms.Application.ExecutablePath, Program.PARAM_WATCH_DESKTOP + " " + Program.PARAM_CONTROL_PIPE + " " + pipeName); }
/// <summary> /// End the task gracefully if possible, forcefully if necessesary. /// Disposes both the pipe and the process when done. /// Wait up to timeoutMs milliseconds for the application to close itself. /// This is optionally a blocking call, but can also be a "fire and forget" /// function by setting block=false. /// </summary> void TerminateProcess(ref WtsProcess refProcess, ref ProcessManager refManager, bool block) { var process = refProcess; var manager = refManager; refProcess = null; refManager = null; // Quick exit if process is not running if (process == null || !process.IsRunning) { if (process != null) { process.Dispose(); } if (manager != null) { manager.Close(); } return; } // Force kill the process if the pipe is not connected if (manager == null || !manager.IsConnected) { // NOTE: Pipe was connected by WaitForPipeCommand Log.Write("FORCE KILL process because pipe is not connected: Pipe=" + manager.PipeName); process.Terminate(0); process.Dispose(); if (manager != null) { manager.Close(); } return; } // Send the process a request to close in background thread Log.Write("Closing process: Pipe=" + manager.PipeName); Task.Run(async() => { try { await manager.SendCommandAsync(ProcessManager.COMMAND_CLOSE); } catch (Exception ex) { Log.Write("Exception sending close command", ex); } }); // Wait for it to exit gracefully, but kill it if still running after the timeout var task = Task.Run(async() => { try { // Give it up to one second to kill itslef var now = DateTime.Now; while ((DateTime.Now - now).TotalMilliseconds < PROCESS_TERMINATE_TIMEOUT_MS && process.IsRunning) { await Task.Delay(10); } if (process.IsRunning) { Log.Write("FORCE KILL process after sending cose command: Pipe=" + manager.PipeName); process.Terminate(0); } else { Log.Write("Process closed gracefully: Pipe=" + manager.PipeName); } process.Dispose(); manager.Close(); } catch (Exception ex) { Log.Write("Cant kill process: Pipe=" + manager.PipeName, ex); } }); if (block) { task.Wait(); } }