2009-10-06 7 views
18

relacionadas:
Should I include a command line mode in my applications?
How to grab parent process standard output?
Can a console application detect if it has been run from Explorer?¿Es posible crear una aplicación de consola que no muestre una ventana de consola cuando se hace doble clic en ella?

Quiero construir una aplicación de consola, que normalmente se ejecuta desde la línea de comandos.

Pero, cuando se hace doble clic desde Explorer (en lugar de ejecutarlo desde el símbolo del sistema cmd.exe), me gustaría que el programa NO muestre una ventana de consola.

quiero evitar esto:

alt text http://i36.tinypic.com/1088p5s.jpg

¿Es posible?

EDITAR supongo otra forma de preguntar es, es posible que un programa para conocer la forma en que se invocó - ya sea haciendo doble clic o mediante línea de comandos?

Estoy trabajando en .NET, en Windows.

EDIT 2: De this Old New Thing blog post aprendí algunas cosas buenas. Esto es lo que sé ahora ...

En Windows, los archivos EXE están marcados como GUI o como GUI. Con csc.exe, esto se selecciona con /target:winexe o /target:exe. Antes de que se ejecute la primera instrucción en el proceso, el núcleo de Windows configura el entorno de ejecución. En ese momento, si el EXE está marcado GUI, el kernel establece stdin/stdout para el proceso en NULL, y si no es GUI (línea de comandos), el kernel crea una consola y establece el stdin/stdout para el proceso a ese consola.

Al iniciar el proceso, si no hay stdin/stdout (== /target:winexe), la llamada vuelve inmediatamente. Por lo tanto, al iniciar una aplicación gui desde un cmd.exe, recuperará de inmediato su solicitud de cmd. Si hay un stdin/stdout, y si se ejecuta desde cmd.exe, el cmd.exe padre espera la salida del proceso.

La "devolución inmediata" es importante porque si codifica una aplicación GUI para adjuntarla a la consola de su padre, podrá hacer console.writeline, etc. Pero el aviso de cmd.exe está activo. El usuario puede escribir nuevos comandos, iniciar un nuevo proceso, etc. En otras palabras, desde un winexe, simplemente adjuntar a la consola principal con AttachConsole(-1) no "convertirá" en una aplicación de consola.


En este punto, creo que la única manera de permitir que una aplicación utilice la consola si se invoca desde cmd.exe, y no utilizarla si se hace doble clic, es definir el exe como la consola regular exe (/target:exe) y ocultan la ventana en el inicio si corresponde. Todavía obtienes una ventana de consola que aparece brevemente.

Todavía no sé cómo se inició desde explorer o cmd.exe, pero me estoy acercando ...


RESPUESTAS

No es posible construir una aplicación de consola que no muestra una ventana de consola.

es posible construir una aplicación de consola que oculta su ventana muy rápidamente, pero no tan rápido que es como si la ventana nunca aparece.

Ahora, para determinar si una aplicación de consola fue lanzada desde el explorador, algunos han sugerido que mirar la consola se está ejecutando en
(de mgb's answer y KB article 99115):

int left = Console.CursorLeft; 
    int top = Console.CursorTop; 
    bool ProcessWasRunFromExplorer = (left==0 && top==0); 

Esto le indica si el proceso se inició en su propia consola, pero no si fue explorador. Un doble clic en el explorador haría esto, pero también un Start.Process() desde dentro de una aplicación haría lo mismo.

Si usted quiere tratar esas situaciones de manera diferente, usar esto para conocer el nombre del proceso padre:

System.Console.WriteLine("Process id: {0}", Process.GetCurrentProcess().Id); 
    string name = Process.GetCurrentProcess().ProcessName ; 
    System.Console.WriteLine("Process name: {0}", name); 
    PerformanceCounter pc = new PerformanceCounter("Process", "Creating Process Id", name); 
    Process p = Process.GetProcessById((int)pc.RawValue); 
    System.Console.WriteLine("Parent Process id: {0}", p.Id); 
    System.Console.WriteLine("Parent Process name: {0}", p.ProcessName); 

    // p.ProcessName == "cmd" or "Explorer" etc 

Para ocultar la ventana rápidamente después de que se puso en marcha el proceso, utilice esto:

private static readonly int SW_HIDE= 0; 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); 

    .... 
    { 
    IntPtr myHandle = Process.GetCurrentProcess().MainWindowHandle; 
    ShowWindow(myHandle, SW_HIDE); 
    } 

Si genera winexe (una aplicación de WinForms) y, opcionalmente, se conecta a la consola principal cuando corresponda con AttachConsole(-1), no obtendrá el equivalente de una aplicación de consola normal. Para un winexe, el proceso primario (como cmd.exe) volverá al símbolo del sistema inmediatamente después de iniciar una aplicación GUI. En otras palabras, el símbolo del sistema está activo y listo para la entrada mientras que el proceso recién lanzado puede estar emitiendo salida. Esto es confuso y probablemente solo sea útil para depurar aplicaciones de winforms.

Esto funcionó para mí.

+0

¿Qué te gustaría que hiciera? –

+0

Quiero que sea invisible. – Cheeso

+0

La prueba para determinar si el programa se inició en su propia consola es incorrecta. Ingresar 'cls & program.exe' en la línea de comando indicará erróneamente que el programa se inició en su propia consola. Podría hacer lo mismo desde un archivo por lotes. Probablemente haya otras maneras de vencer la prueba. –

Respuesta

4

Simplemente compárelo como una aplicación de Windows Forms, pero no le dé una GUI. Desafortunadamente, entonces no obtendrá ningún resultado de la consola cuando se ejecute desde la línea de comando ... ¿es eso un problema?

+0

Hmm, sé cómo evitar * que *. ¡Gracias! – Cheeso

+0

Pensando en esto un poco más, no creo que esto funcione. Sé cómo hacer un EXE, ya sea una aplicación de consola o una aplicación WinForms en tiempo de ejecución, usando pinvoke en AttachConsole(). Pero no sé cómo determinar cuándo convertirla en una aplicación de consola o una aplicación de Winforms. No sé cómo detectar si se inició con un doble clic en el explorador o si se inició desde una ventana de la consola. – Cheeso

+0

¿Por qué no utilizar un argumento de línea de comando para seleccionar el modo de visualización de la consola? De esa forma, cuando se ejecuta desde Explorer, no tendrá uno; a menos que cree un acceso directo y agregue el argumento allí, lo que le permite tener ambos con y sin iniciaciones de consola desde Explorer. – Clifford

0

¿Sería esto más como un Servicio?

O

¿Qué pasa con una aplicación de Windows Forms que no tiene una forma visible? Aún aparecería en la lista de Procesos del Administrador de tareas.

5

herramientas Por lo tanto, he escrito tanto con una interfaz gráfica de usuario y una CLI. La parte difícil fue decidir cuál abrir, pero en nuestro caso, la versión de CLI requería parámetros, así que simplemente abrí la GUI si no había ningún parámetro. Entonces, si lo hacían querer una consola, llamar a una función que se ve algo como:

private const int ATTACH_PARENT_PROCESS = -1; 
private const int ERROR_INVALID_HANDLE = 6; 
[DllImport("kernel32.dll", SetLastError = true)] 
static extern bool AttachConsole(int dwProcessId); 
[DllImport("kernel32.dll")] 
static extern bool AllocConsole(); 
[DllImport("kernel32.dll")] 
static extern bool FreeConsole(); 

private static bool StartConsole() 
{ 
    if (!AttachConsole(ATTACH_PARENT_PROCESS)) // try connecting to an existing console 
    { 
     if (Marshal.GetLastWin32Error() == ERROR_INVALID_HANDLE) // we don't have a console yet 
     { 
      if (!AllocConsole()) // couldn't create a new console, either 
       return false; 
     } 
     else 
      return false; // some other error 
    } 
    return true; 
} 

Devuelve si la consola fue creada. ¡No olvides utilizar FreeConsole() cuando hayas terminado!

En nuestro caso, por supuesto, si no creamos una consola, creamos una GUI. Sin embargo, sería igual de fácil crear una consola o no UI.

EDITAR: Eso totalmente no respondió la pregunta en la edición que no estaba allí cuando comencé a escribir eso, por supuesto. Aparte de eso, nuestro truco fue simplemente verificar si se llamó con parámetros de línea de comandos o no.

+0

Esto es útil: me permite crear una aplicación de consola o no en tiempo de ejecución. La clave es cómo determinar si una consola está presente. Creo que es AttachConsole (-1), pero incluso cuando eso devuelve 0, no sé cómo suprimir la consola cuando no está presente. Tendré que probar algunas cosas. Gracias – Cheeso

0

No he leído la totalidad por medio, pero hizo esto (hace un rato, más pruebas necesita):

DWORD proc[2],procsfound=GetConsoleProcessList(proc,ELEMS(proc)); 
if (procsfound>1) 
// I'm started as a command in cmd.exe 
else 
// started from explorer or other non-console parent 

IFF hay más de un proc adjunto, que necesita restaurar la consola, que manipulé , de otra forma no. Puede ser útil, al menos es la simplicidad en sí misma. Iniciar el código de VS producirá un solo proceso adjunto, ejecutándolo desde el comando, activó la rama para limpiar mi desorden. Por cierto, una consola iniciada desde el explorador u otra aplicación que no sea de consola tendrá un título de longitud cero?

Cuestiones relacionadas