2010-01-23 20 views
15

Necesito poder iniciar procesos (tanto en la consola como en ventanas) sin que se robe el foco. La única forma dentro del marco .NET que encontré para hacer esto es Microsoft.VisualBasic.Interaction.Shell con Microsoft.VisualBasic.AppWinStyle. [Minimized | Normal] NoFocus (cuyo mapa SW_SHOWMINNOACTIVE/SW_SHOWMA se pasa a ShellExecute).Iniciar un proceso sin robar el foco (C#)

En la versión actual de mi código (que roba el foco), estoy usando System.Diagnostics.Process y confiando en algunas de las funcionalidades que me proporcionan, que no es el método Interaction.Shell.

2 preguntas (uno grave, y una ventilación mi frustración que realmente no le espera una buena respuesta a)

1.) Estoy en lo cierto que no tengo más remedio que envuelva o CreateProcess ShellExecuteEx mí mismo, o me falta alguna otra solución? Realmente esperaba evitar esto, ya que Process es un envoltorio tan completo y útil que no es esta supervisión, y habría tanta funcionalidad para implementar, llamadas de P/Invoke para depuración y toda clase de dolores variados.

2.) ¿Por qué un equipo en Microsoft crearía una envoltura completa (de lo contrario) y luego excluiría la mitad de los posibles valores de ProcessWindowStyle, mientras que otro equipo creó una envoltura similar que era mucho menos completa pero proporcionó todas las estilos de ventana útiles?

+0

¿Está codificando algo que no quiere que el usuario sepa o no quiera molestar al usuario? Jajaja no importa ...: -/ – jasonco

+1

¿No hay otra opción? El espacio de nombres Microsoft.VisualBasic es parte del framework .NET y está disponible en cualquier instalación de .NET. No usarlo sería un error.Tiene muchos otros extras, pero no puede averiguar si no puede obtener el nombre del espacio de nombres. –

+0

Hola nobugz, me disculpo si di la impresión de que tuve un problema con el espacio de nombres. Ese no es mi problema, de hecho, uso un buen analizador de Microsoft.VisualBasic en otra parte del código. El problema es que Microsoft.VisualBasic.Interaction.Shell no me da la posibilidad de recibir una notificación al salir o abortar un proceso. Tendría que envolverlo de alguna manera para obtener esa funcionalidad, donde la clase Process me da esas dos cosas. – psm321

Respuesta

11

El equipo de VB.Net ha hecho mucho más para facilitar las cosas para el desarrollador con respecto a la instrumentación de Windows, y no veo ningún problema para agregar una referencia a un dll VB y usarlo en su programa C#.

Son dos equipos con diferente enfoque, eso es todo. Y no debería sentirse mal por usar Microsoft.VisualBasic.Interaction.Shell si resuelve su problema.

También puede usar Reflector para ver la implementación real e implementar el código usted mismo si no desea hacer referencia al dll.

[Editar - añadió ejemplo de código después del comentario de mostrar que puede combinar Interaction.Shell y Procesos]

int pid = Interaction.Shell("notepad.exe", AppWinStyle.NormalFocus); 
Process p = Process.GetProcessById(pid); 
p.Exited += ((o, e) => Console.WriteLine("Exit")); 
p.EnableRaisingEvents = true; 
Console.ReadLine(); 

Aquí, he utilizado el método Shell para poner en marcha el proceso, obtener un identificador para el proceso de del pid, y engancha los eventos. Incluso puede hacer p.Kill() para abortar el proceso.

[Editar - solución para cmd.exe]

Está empezando a ser un poco hacker de mi gusto, pero funciona. Reemplace "NEWWINDOW" con un guid al azar o algo para que sea único.

Microsoft.VisualBasic.Interaction.Shell(@"cmd.exe /c ""start cmd.exe /k title NEWWINDOW""", AppWinStyle.NormalFocus); 
foreach (var process in Process.GetProcessesByName("cmd")) 
{ 
    if (process.MainWindowTitle.EndsWith("NEWWINDOW")) 
    { 
     process.Exited += ((o, e) => Console.WriteLine("Exit")); 
     process.EnableRaisingEvents = true; 
    } 
} 
+0

No tengo un problema con el uso del espacio de nombres Microsoft.VisualBasic. Mi problema es la falta de otra funcionalidad en ese método (la falta de un evento Exited y la posibilidad de abortar un proceso). Miré la fuente de depuración que proporciona Microsoft para ambos métodos ... así es como aprendí sobre las llamadas subyacentes y las banderas pasadas para que esto funcione. Es también la forma en que pensé que tratar de manejar algunas de las funcionalidades que quiero solo sería muy doloroso, ya que parece que hay problemas de bloqueo complejos, y no puedo copiar el código ya que violaría la licencia. – psm321

+0

¡gran idea! Lo probaré el lunes y probablemente acepte la respuesta. ¡Gracias! – psm321

+0

Eso funcionó, pero hay una complicación ... parece llamar a Interaction.Shell() desde una aplicación de consola, para ejecutar una aplicación de consola, reutiliza la misma ventana de consola en lugar de ejecutar una nueva como Console.Start does. Alguna idea si es posible evitar eso? – psm321

2

un vistazo aquí:

 
System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(); 
procInfo.CreateNoWindow = true; 
procInfo.UseShellExecute = true; 
procInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
proc.StartInfo = procInfo; 
proc.EnableRaisingEvents = true; 
proc.Exited += new EventHandler(proc_Exited); 
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); 
proc.Start(...) 
// Do something with proc.Handle... 
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    /* Do something here... */ 
} 

void proc_Exited(object sender, EventArgs e) 
{ 
/* Do something here... */ 
} 

Editar: he modificado el código para mostrar los medios de eventos de recaudación y manejo de ellos, también, he demostrado el uso de la propiedad Handle, que es el manejar el proceso que se está ejecutando.

+0

Gracias por el puntero. Desafortunadamente, Hidden no hace lo que yo quiero, ya que 1.) de lo que deduzco, es solo un aviso para la aplicación iniciada y 2.) incluso si ese no es el caso, necesito que la aplicación sea visible para el usuario si/ella elige enfocarlo, simplemente no robando el foco por defecto. Creo que lo que realmente necesito es un comportamiento equivalente a SW_SHOWMINNOACTIVE o SW_SHOWMA (http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx), que el método Shell() proporciona, pero desafortunadamente no me devuelve un identificador de proceso en el que puedo establecer un evento salido, etc. – psm321

+0

@ psm321: Primero, el código que puse, hay un controlador de eventos Exited para el objeto de proc como se muestra ¡encima! ¿Por qué reinventar la rueda? En segundo lugar, sospecho que es una configuración global de todo el sistema, quizás tengas un complemento en algún lugar donde el enfoque de robo por defecto sea un comportamiento de Windows. Como una ventana de subida automática sin hacer clic en ella, que la pone en primer plano. – t0mm13b

+0

Y, por cierto, Handle es la propiedad del objeto de proceso en el que tiene un control de proceso ... – t0mm13b

Cuestiones relacionadas