Procesos

1 de 12 Ejecución de procesos Finalización de procesos Monitorización de procesos Operaciones de E/S Ejecución de proc

Views 175 Downloads 51 File size 137KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

1 de 12

Ejecución de procesos Finalización de procesos Monitorización de procesos Operaciones de E/S

Ejecución de procesos La clase System.Diagnostics.Process permite crear y monitorizar procesos (accediendo a la información que se visualiza en el Administrador de Tareas de Windows). El método Process.Start() equivale a la llamada ShellExecute del API de Windows (Win32) y es el que deberemos utilizar para lanzar un proceso. Los parámetros del proceso se especifican mediante un objeto de la clase ProcessStartInfo. Al encapsular una llamada al shell de Windows, el método Start también podemos usarlo para abrir un fichero de cualquier tipo de los que tengan acciones asociadas en el registro de Windows. Ejecución de procesos

2 de 12

Probar las distintas formas de lanzar un proceso escribiendo la respuesta al evento Click de cada botón de la ventana que se muestra en la imagen de encima: Lanzar proceso: System.Diagnostics.Process.Start("iexplore.exe"); Lanzar proceso con parámetros: string proceso = "iexplore.exe"; string args = "http://elvex.ugr.es/decsai/Csharp/"; System.Diagnostics.Process.Start("iexplore.exe", args); Lanzar un proceso utilizando ProcessStartInfo: using System.Diagnostics; ... ProcessStartInfo info = new ProcessStartInfo(); info.FileName = "iexplore.exe"; info.Arguments = "http://elvex.ugr.es/decsai/CSharp/";

3 de 12

info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized; Process.Start(info); Lanzar el proceso adecuado para un fichero cualquiera: OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.InitialDirectory = "c:\\" ; openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"; openFileDialog.FilterIndex = 2 ; openFileDialog.RestoreDirectory = true ; // Vuelve al directorio actual if (openFileDialog.ShowDialog() == DialogResult.OK) { System.Diagnostics.Process.Start(openFileDialog.FileName); } Abrir una URL: System.Diagnostics.Process.Start("http://elvex.ugr.es/decsai/Csharp/"); Uso de los verbos del shell: using System.Diagnostics; ... ProcessStartInfo info = new ProcessStartInfo(); info.FileName = "Ade.jpg"; info.WorkingDirectory = "f://"; info.Verb = "edit"; // vs. "open" || "print" Process.Start(info); // // // // // // //

Verbos comunes -------------open Abre un ejecutable, documento o carpeta edit Edita un documento print Imprime un documento explore Explora una carpeta find Inicia una búsqueda en el directorio especificado

4 de 12

RECOMENDACIÓN: Cuando se utiliza el método Process.Start, también se debería llamar siempre al método Process.Close para liberar la memoria asociada al objeto de tipo Process.

Finalización de procesos En los ejemplos anteriores, si quisiéramos que nuestra aplicación detuviese su ejecución hasta que el proceso lanzado finalizase su ejecución, sólo tendríamos que llamar al método WaitForExit:

Process proceso = Process.Start(...); proceso.WaitForExit(); proceso.Close();

La espera podría hacerse por un período de tiempo limitado si utilizamos un parámetro en la llamada al método WaitForExit: Ejecución invisible de comandos MS-DOS

Process proceso = new Process() string string

salida = Application.StartupPath + "/output.txt"; path = System.Environment.GetFolderPath (Environment.SpecialFolder.System);

proceso.StartInfo.FileName = "cmd.exe"; proceso.StartInfo.Arguments = "/C dir \""+path+"\" >> \"" + salida +"\" && exit";

5 de 12

proceso.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; proceso.StartInfo.CreateNoWindow = true; proceso.Start() proceso.WaitForExit(1000); if (!proceso.HasExited()) { proceso.Kill(); } else { ... }

// 1 segundo de timeout

// Finalizamos el proceso

Además, también podemos detectar cuándo finaliza un proceso que hayamos lanzado si empleamos el manejador de eventos Exited de la clase Process. De esta forma, no tenemos por qué bloquear la ejecución de nuestra aplicación mientras esperamos la terminación de un proceso: Evento asociado a la terminación de un proceso

Process proceso = new Process() ... proceso.Exited += new EventHandler(ExitHandler); proceso.Start() ... El método ExitHandler se encarga de realizar las tareas necesarias al finalizar la ejecución del proceso, como por ejemplo:

public void ExitHandler(object sender, EventArgs e) { Process proceso = (Process) sender; MessageBox.Show ( "PID: " + proceso.Id + System.Environment.NewLine

6 de 12

+ "Hora: " + proceso.ExitTime + System.Environment.NewLine + "Código: " + proceso.ExitCode ); proces.Close(); }

La clase Process también nos permite provocar la terminación de un proceso. Ésta se puede realizar explícitamente utilizando los métodos Kill() y CloseMainWindow(), siendo este último el método recomendado, pues equivale a que el usuario de la aplicación cierre ésta de la forma usual. Es decir, CloseMainWindow solicita cerrar la aplicación como si el propio usuario cerrase la ventana principal de la aplicación (lo cual puede provocar la aparición de mensajes de la aplicación), mientras que Kill finaliza el proceso "por las bravas", pudiendo ocasionar la pérdida de datos que no hayan sido previamente guardados. En la siguiente sección veremos cómo se puede forzar la finalización de un proceso y también aprenderemos a acceder a la información relativa a los procesos que se estén ejecutando en una máquina Windows (la misma información que figura en el Administrador de Tareas de Windows).

Monitorización de procesos Monitor de procesos

7 de 12

Creamos una aplicación Windows a la que denominamos WindowMonitor, cuyo formulario principal (Text="Procesos del sistema") contiene los siguientes componentes: ListBox listProcesses (ScrollAlwaysVisible=true). TextBox textInfo (BackColor=Info; Multiline=true). Button buttonClose (Text="WindowClose"; ForeColor=ForestGreen). Button buttonKill (Text="Kill"; ForeColor=DarkRed). Label labelWarning (TextAlign=MiddleCenter; Text="¡OJO! Kill puede ocasionar la pérdida de datos al forzar la terminación de un proceso..."). Al cargar el formulario, rellenamos la lista de procesos del sistema (evento FormLoad):

Process[] procesos = Process.GetProcesses();

8 de 12

listProcesses.Items.AddRange(procesos); Cuando el usuario selecciona un proceso concreto, mostramos información detallada acerca del proceso seleccionado (evento SelectedIndexChanged del ListBox):

Process selected = (Process) listProcesses.SelectedItem; textInfo.Clear(); if (selected!=null) textInfo.Lines = new string[] { "Proceso: " + selected.ProcessName, "PID: " + selected.Id, // "Máquina: " + selected.MachineName, "Prioridad: " + selected.PriorityClass, "Uso de memoria: " + selected.WorkingSet + " bytes", // selected.PagedMemorySize // selected.VirtualMemorySize "Tiempo de CPU: " + selected.TotalProcessorTime, "Hora de inicio: " + selected.StartTime, "Módulo principal: " + selected.MainModule.FileName // selected.MainWindowTitle }; Finalmente, programamos la respuesta de la aplicación correspondiente a los dos botones de nuestra interfaz:

// Fuerza la finalización del proceso // (puede provocar la pérdida de datos) private void buttonKill_Click(object sender, System.EventArgs e) { Process selected = (Process) listProcesses.SelectedItem; if (selected!=null) selected.Kill(); }

9 de 12

// Solicita la terminación de un proceso // (como si el usuario solicitase cerrar la aplicación) private void buttonClose_Click(object sender, System.EventArgs e) { Process selected = (Process) listProcesses.SelectedItem; if (selected!=null) { if (selected.Id==Process.GetCurrentProcess().Id) MessageBox.Show("Ha decidido finalizar la aplicación actual"); selected.CloseMainWindow(); }

NOTA: En la barra de herramientas [toolbox], dentro del apartado "Components", podemos encontrar un componente denominado Process que nos permite trabajar con procesos de forma visual.

Operaciones de E/S En ocasiones nos interesa que la entrada de un proceso provenga directamente de la salida de otro proceso. Enviar la salida a un fichero y después leer el fichero no siempre es la mejor opción, ya que el uso de "pipes" resulta mucho más eficiente para conectar distintos procesos. La clase Process nos permite redireccionar los canales de E/S estándar (StdIn, StdOut y StdErr). Sólo tenemos que fijar a "true" las propiedades RedirectStandardInput, RedirectStandardOutput y RedirectStandardError, tras lo cual podemos acceder a las propiedades StandardInput, StandardOutput y StandardError del proceso (objetos de tipo StreamReader y StreamWriter). Una observación: Process.Start utiliza por defecto la función ShellExecute del API Win32. Cuando utilicemos redireccionamientos, la propiedad ProcessStartInfo.UseShellExecute debe estar puesta a "false" antes de invocar al método Process.Start.

10 de 12

Process proceso = new Process(); proceso.StartInfo.FileName = "cmd.exe"; proceso.StartInfo.UseShellExecute = false; proceso.StartInfo.CreateNoWindow = true; proceso.StartInfo.RedirectStandardInput = true; proceso.StartInfo.RedirectStandardOutput = true; proceso.StartInfo.RedirectStandardError = true; proceso.Start() StreamWriter sIn = proceso.StandardInput; sIn.AutoFlush = true; StreamReader sOut = proceso.StandardOutput; StreamReader sErr = proceso.StandardError; sIn.Write("dir c:\" + System.Environment.NewLine); sIn.Write("exit" + System.Environment.NewLine); string output = sOut.ReadToEnd(); sIn.Close(); sOut.Close(); sErr.Close(); proceso.Close(); MessageBox.Show(output);

Para los programas que no utilizan StdIn se puede utilizar el método SendKeys para simular la pulsación de teclas: Acceso al Bloc de Notas con SendKeys

Curso de C# - Procesos

11 de 12

Process proceso = new Process(); proceso.StartInfo.FileName = "notepad"; proceso.StartInfo.WindowStyle = ProcessWindowStyle.Normal; proceso.EnableRaisingEvents = true; proceso.Start(); proceso.WaitForInputIdle(1000); // 1 segundo de timeout if (proceso.Responding) System.Windows.Forms.SendKeys.SendWait ("Texto enviado con System.Windows.Forms.SendKeys");

Cualquier combinación de teclas se puede enviar con SendKeys, lo que permite hacer prácticamente cualquier cosa con una aplicación Windows (siempre que nos aseguremos de que es la aplicación activa, la que tiene el foco). No se pueden utilizar SendKeys hasta que no se haya creado y se visualice la ventana principal de la aplicación, por lo que en el ejemplo de arriba se empleó el método Process.WaitForInputIdle, que espera hasta que la aplicación pueda aceptar entradas por parte del usuario y cuyo funcionamiento es análogo a Process.WaitForExit. Acceso a recursos nativos de Windows Con SendKeys se puede simular la pulsación de cualquier combinación de teclas. No obstante, SendKeys se limita a enviar eventos de pulsación de teclas a la aplicación que esté activa en cada momento. Y no existe ninguna función estándar en .NET que nos permita establecer la aplicación activa, pero sí en el API nativo de Windows. El API de Windows incluye una gran cantidad de funciones (no métodos), del orden de miles. En el caso que nos ocupa, podemos recurrir a las funciones FindWindow y SetForegroundWindow del API Win32 para establecer la aplicación activa. Como estas funciones no forman parte de la biblioteca de clases .NET, tenemos que acceder a ellas usando los servicios de

12 de 12

interoperabilidad con COM. Estos servicios son los que nos permiten acceder a recursos nativos del sistema operativo y se pueden encontrar en el espacio de nombres System.Runtime.InteropServices. Para poder usar la función SetForegroundWindow, por ejemplo, tendremos que escribir algo parecido a lo siguiente:

using System.Runtime.InteropServices; ... [DllImport("User32",EntryPoint="SetForegroundWindow")] private static extern bool SetForegroundWindow(System.IntPtr hWnd); Una vez hecho esto, ya podemos acceder a la función SetForegroundWindow como si de un método más se tratase:

Process proceso = ... if (proceso.Responding) { SetForegroundWindow(proceso.MainWindowHandle); SendKeys.SendWait("Sorpresa!!!"); SetForegroundWindow(this.Handle); } Y ya podemos hacer prácticamente cualquier cosa con una aplicación Windows, controlándola desde nuestros propios programas.