-1

The issue recreated in code:

class Program
{
    private const int VK_ESCAPE = 0x1B;
    private const int WM_KEYDOWN = 0x0100;

    [DllImport("User32.dll")]
    private static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

    static void Main(string[] args)
    {
        Task.Run(() =>
        {
            var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
            bool hasSucceeded = PostMessage(hWnd, WM_KEYDOWN, VK_ESCAPE, 0);
            return;
        });

        Console.WriteLine("PostMessage works as expected in Debug >> Start Debugging mode.");
        if ((Console.ReadKey()).Key == ConsoleKey.Escape)
        return;
    }
}

I'm trying to cancel Console.ReadKey() by calling PostMessage from a worker thread. This works when I run the code under Debug >> Start Debugging mode.

However, when I run the code under Debug >> Start Without Debugging mode it hangs? Any responses/solutions are greatly appreciated.

Jack Zhai
  • 6,230
  • 1
  • 12
  • 20
DannyS9
  • 1
  • 1
  • 2
    There could be all kinds of weirdness going on here. Console apps don't really *have* a main window - the console subsystem creates windows but they belong to it rather than to the applications running within. – Damien_The_Unbeliever Aug 04 '17 at 06:27
  • As Damien's comment might suggest, if I printout that value of `hWnd` I get a non-zero value when run under the debugger and a 0 value when run without the debugger. – Michael Burr Aug 04 '17 at 06:57

1 Answers1

3

Raymond Chen has written a nice blog post titled "You can't simulate keyboard input with PostMessage". You may want to review this, before continuing with your approach.

Having that said, the immediate issue may be that you must use the GetConsoleWindow function (from Kernel32.dll) to get a handle to your own console window. Because, as other have already commented, your process does not really own the window (it belongs to the associated conhost.exe process).

Given that, the following code sort of "works":

class Program
{
    private const int VK_ESCAPE = 0x1B;
    private const int WM_KEYDOWN = 0x0100;

    [DllImport("User32.dll")]
    private static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

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

    static void Main(string[] args)
    {
        Task.Run(() =>
        {
            bool hasSucceeded = PostMessage(GetConsoleWindow(), WM_KEYDOWN, VK_ESCAPE, 0);
            return;
        });

        Console.WriteLine("PostMessage works as expected in Debug >> Start Debugging mode.");
        if ((Console.ReadKey()).Key == ConsoleKey.Escape)
            return;
    }
}

But then, this approach is probably not the right approach to achieve what you want (cancelling a Console.ReadKey, as you state).

See this for a way to use a timeout instead.

Christian.K
  • 47,778
  • 10
  • 99
  • 143