2009-08-20 4 views
19

Ho un programma che può essere eseguito sia come winform, sia da riga di comando. Se viene richiamato da una riga di comando, chiamo AttachConsole (-1) per collegarlo alla console genitore.Usando AttachConsole, l'utente deve premere invio per ottenere regolare riga di comando

Tuttavia, al termine del programma, l'utente deve premere Invio per tornare al prompt dei comandi standard ("c: \>"). c'è un modo per evitare quel bisogno?

Grazie. Potrei avvolgerlo in un file cmd per evitare quel problema, ma mi piacerebbe farlo dal mio exe.

+1

Avete mai capito questo? Ho la stessa cosa e sarei interessato a sapere se c'è un lavoro in giro. – cgyDeveloper

+1

No, non l'ho fatto. Scusate. – Clangon

+0

Lo stesso problema qui. L'utente si trova su una riga di comando standard, ma il prompt non viene visualizzato (finché non si preme Invio, per visualizzarlo di nuovo) –

risposta

17

Prova ad aggiungere questa linea poco prima le vostre uscite exe ...

System.Windows.Forms.SendKeys.SendWait ("{ENTER}");

Bit di un hack, ma il meglio che ho potuto trovare quando ho incontrato quel problema.

Rob

+0

Ha funzionato, grazie. – Clangon

+0

LOL, questo è davvero ovvio ma non riuscivo a capirlo prima di usare Google: P – kizzx2

+2

Questo sembra davvero male, ma sembra essere l'unico modo apparente per farlo. Grazie. – mbrownnyc

1

Provare a chiamare la funzione FreeConsole prima di uscire dall'eseguibile.

+6

L'ho già provato, non sembra funzionare. grazie comunque. – Clangon

1

Ok, non ho la soluzione, ma sembra essere in quanto il cmd.exe non è in attesa sul processo avviato, mentre con un normale attende un'applicazione console cmd.exe fino alla la l'applicazione esce. Non so cosa faccia decidere a cmd.exe di aspettare o meno su un'applicazione, le normali applicazioni Windows Form sono appena state avviate e cmd.exe non aspetta che esca. Forse questo suggerimento fa scattare qualcuno! Scaverò un po 'più a fondo nel frattempo.

Wout

3

Rob L's approccio è un po 'pericoloso in quanto invierà un Invio per la finestra attiva. Un approccio migliore è quello di inviare effettivamente l'Invio al processo corretto (console).

ecco come

internal static class NativeMethods 
    { 
     [DllImport("kernel32.dll", SetLastError = true)] 
     internal static extern bool AllocConsole(); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     internal static extern bool FreeConsole(); 

     [DllImport("kernel32", SetLastError = true)] 
     internal static extern bool AttachConsole(int dwProcessId); 

     [DllImport("user32.dll")] 
     internal static extern IntPtr GetForegroundWindow(); 

     [DllImport("user32.dll", SetLastError = true)] 
     internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); 

     [DllImport("User32.Dll", EntryPoint = "PostMessageA")] 
     internal static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam); 

     internal const int VK_RETURN = 0x0D; 
     internal const int WM_KEYDOWN = 0x100; 
    } 

--snip--

  bool attached = false; 

      // Get uppermost window process 
      IntPtr ptr = NativeMethods.GetForegroundWindow(); 
      int u; 
      NativeMethods.GetWindowThreadProcessId(ptr, out u); 
      Process process = Process.GetProcessById(u); 

      if (string.Compare(process.ProcessName, "cmd", StringComparison.InvariantCultureIgnoreCase) == 0) 
      { 
       // attach to the current active console 
       NativeMethods.AttachConsole(process.Id); 
       attached = true; 
      } 
      else 
      { 
       // create new console 
       NativeMethods.AllocConsole(); 
      } 

      Console.Write("your output"); 

      NativeMethods.FreeConsole(); 

      if (attached) 
      { 
       var hWnd = process.MainWindowHandle; 
       NativeMethods.PostMessage(hWnd, NativeMethods.WM_KEYDOWN, NativeMethods.VK_RETURN, 0); 
      } 

Questa soluzione è costruire sul codice che si trova qui:

http://www.jankowskimichal.pl/en/2011/12/wpf-hybrid-application-with-parameters/

+0

In realtà, non creare un programma che sia una GUI e un'app console allo stesso tempo. Leggi questo: http://stackoverflow.com/questions/493536/can-one-executable-be-both-a- console-e-gui-application/494000 # 494000 – invalidusername

+1

Sono d'accordo che la soluzione di Rob non è sicura, ma sembra che la tua risposta soffra dello stesso problema attraverso l'uso di GetForegroundWindow. Forse utilizzare un'API per vedere quale processo ha avviato la tua app o utilizzare GetConsoleProcessList. – Herman

1

Ecco il hack più sicuro che risolve il problema chiave di Invio indipendentemente dal fatto che la finestra della console sia in t lui in primo piano, sullo sfondo o minimizzato. Puoi persino eseguirlo in più finestre della console.

using System; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 

namespace WindowsAndConsoleApp 
{ 
    static class Program 
    { 
    const uint WM_CHAR = 0x0102; 
    const int VK_ENTER = 0x0D; 

    [DllImport("kernel32.dll")] 
    static extern bool AttachConsole(int dwProcessId); 
    private const int ATTACH_PARENT_PROCESS = -1; 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern bool FreeConsole(); 

    [DllImport("kernel32.dll")] 
    static extern IntPtr GetConsoleWindow(); 

    [DllImport("user32.dll")] 
    static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 

    [STAThread] 
    static void Main(string[] args) 
    { 
     if (args.Length > 0) 
     { 
      // Do this first. 
      AttachConsole(ATTACH_PARENT_PROCESS); 

      Console.Title = "Console Window - Enter Key Test"; 
      Console.WriteLine("Getting the handle of the currently executing console window..."); 
      IntPtr cw = GetConsoleWindow(); 
      Console.WriteLine($"Console handle: {cw.ToInt32()}"); 
      Console.WriteLine("\nPut some windows in from of this one..."); 
      Thread.Sleep(5000); 
      Console.WriteLine("Take your time..."); 
      Thread.Sleep(5000); 
      Console.WriteLine("Sending the Enter key now..."); 

      // Send the Enter key to the console window no matter where it is. 
      SendMessage(cw, WM_CHAR, (IntPtr)VK_ENTER, IntPtr.Zero); 

      // Do this last. 
      FreeConsole(); 
     } 
     else 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new MainForm()); 
     } 
    } 
    } 
} 
+0

Questa è la risposta che ha aiutato a risolvere il mio problema. So che è quasi un anno e mezzo ma grazie! – Chris

Problemi correlati