2009-08-20 9 views
19

Mam progaram, który można uruchomić zarówno jako winform, jak i z wiersza poleceń. Jeśli jest wywoływany z wiersza poleceń, wywołuję AttachConsole (-1), aby dołączyć do konsoli nadrzędnej.Korzystając z AttachConsole, użytkownik musi nacisnąć klawisz Enter, aby uzyskać regularną linię komend:

Jednak po zakończeniu mojego programu użytkownik musi nacisnąć klawisz Enter, aby powrócić do standardowego wiersza polecenia ("c: \>"). czy istnieje sposób na uniknięcie tej potrzeby?

Dzięki. Mogę opakować go w plik cmd, aby uniknąć tego problemu, ale chciałbym zrobić to od mojego exe.

+1

Czy kiedykolwiek to rozgryzłeś? Mam to samo i chciałbym wiedzieć, czy jest jakieś dzieło. – cgyDeveloper

+1

Nie, nie mam. Przepraszam. – Clangon

+0

Ten sam problem tutaj. Użytkownik znajduje się w standardowym wierszu poleceń, ale monit nie wyświetla się (do momentu naciśnięcia klawisza Enter, aby go ponownie wyświetlić). –

Odpowiedz

17

spróbuj dodać tę linię tuż przed swoimi wyjściami exe ...

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

Trochę włamania, ale najlepsze, co mogłem znaleźć, gdy napotkałem ten problem.

Rob

+0

Zadziałało, dziękuję. – Clangon

+0

LOL, to jest naprawdę oczywiste, ale nie mogłem tego rozgryźć przed Googlingiem: P – kizzx2

+2

To wydaje się naprawdę złe, ale wydaje się, że jest to jedyny oczywisty sposób na zrobienie tego. Dzięki. – mbrownnyc

1

Spróbuj wywołać funkcję FreeConsole przed wyjściem z pliku wykonywalnego.

+6

Próbowałem już tego, nie działa. dzięki i tak. – Clangon

1

Ok, nie mam rozwiązanie, ale wydaje się być, ponieważ cmd.exe nie czeka na rozpoczęły proces, natomiast z normalnych aplikacji konsoli cmd.exe czeka a¿ wyjścia aplikacji. Nie wiem, co powoduje, że program cmd.exe decyduje się czekać na aplikację lub nie, zwykłe aplikacje Windows Forms dopiero się zaczynają, a cmd.exe nie czeka na jej zakończenie. Może ta wskazówka wyzwala kogoś! W międzyczasie wykopię trochę głębiej.

Wout

3

Rob L's podejście jest dość niebezpieczne, ponieważ będzie ona wysłać Wejście do aktywnego okna. Lepszym rozwiązaniem jest faktyczne wysłanie Enter do poprawnego procesu (konsoli).

oto jak

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); 
      } 

To rozwiązanie jest budować na kodzie, który jest znaleźć tutaj:

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

+0

Właściwie nie twórz programu będącego jednocześnie graficznym interfejsem użytkownika i konsolą .. przeczytaj to: http://stackoverflow.com/questions/493536/can-one-executable-be-botha-a- console-and-gui-application/494000 # 494000 – invalidusername

+1

Zgadzam się, że rozwiązanie Roba jest niebezpieczne, ale wygląda na to, że twoja odpowiedź cierpi z powodu tego samego problemu za pomocą GetForegroundWindow. Może użyj interfejsu API, aby zobaczyć, który proces uruchomił twoją aplikację, lub użyj GetConsoleProcessList. – Herman

1

Oto najbezpieczniejszy hack rozwiązujący problem z klawiszem Enter bez względu na to, czy okno konsoli jest w t na pierwszym planie, w tle lub zminimalizowany. Możesz nawet uruchomić go w wielu oknach konsoli.

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

To jest odpowiedź, która pomogła rozwiązać mój problem. Wiem, że to prawie pół roku później, ale dzięki! – Chris

Powiązane problemy