Question

So I am trying to modify the code provided by Microsoft(here) to use WriteConsoleInput, instead of WriteFile, but it says the handle is invalid (I'm betting it is something really silly), like how the handle is initially created or something.

So my question, what's the difference between the handles needed for WriteConsoleInput, and the handle for WriteFile?

WriteConsoleInput

WriteFile

I'm guessing it has to do with the permissions flag of the HANDLE created by CreateFile compared to the inherited handles created by the CreateProcess/CreatePipe/DuplicateHandle process.

I decided it would be easier if you can see the problem, so here is my full solution (Using Visual Studio 2012) Both the child and parent app are included.

ConsoleRedir on GitHub

As a note, I need the child app to use the ReadConsoleInput, and that's been the source of my frustration.

Original Method:

/////////////////////////////////////////////////////////////////////// 
// GetAndSendInputThreadOrig
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
// Original from http://support.microsoft.com/kb/190351
/////////////////////////////////////////////////////////////////////// 
DWORD WINAPI GetAndSendInputThreadOrig(LPVOID lpvThreadParam)
{
    CHAR read_buff[256];
    DWORD nBytesRead,nBytesWrote;
    HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

    // Get input from our console and send it to child through the pipe.
    while (bRunThread)
    {
        if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
            DisplayError("ReadConsole");

        read_buff[nBytesRead] = '\0'; // Follow input with a NULL.

        if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
        {
            if (GetLastError() == ERROR_NO_DATA)
                break; // Pipe was closed (normal exit path).
            else
                DisplayError("WriteFile");
        }
    }

    return 1;
}

My modified version (have to build keystroke):

/////////////////////////////////////////////////////////////////////// 
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
/////////////////////////////////////////////////////////////////////// 
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
    CHAR read_buff[256];
    DWORD nBytesWrote;
    HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

    // Get input from our console and send it to child through the pipe.
    while (bRunThread)
    {
        INPUT_RECORD inputRecords[4];
        // Build a keyboard event, press '?' and then press RETURN
        inputRecords[0].EventType = KEY_EVENT;
        inputRecords[0].Event.KeyEvent.bKeyDown = TRUE;
        inputRecords[0].Event.KeyEvent.uChar.UnicodeChar = '?';
        inputRecords[1].EventType = KEY_EVENT;
        inputRecords[1].Event.KeyEvent.bKeyDown = FALSE;
        inputRecords[1].Event.KeyEvent.uChar.UnicodeChar = '?';
        inputRecords[2].EventType = KEY_EVENT;
        inputRecords[2].Event.KeyEvent.bKeyDown = TRUE;
        inputRecords[2].Event.KeyEvent.dwControlKeyState = 0;
        inputRecords[2].Event.KeyEvent.uChar.UnicodeChar = '\r';
        inputRecords[2].Event.KeyEvent.wRepeatCount = 1;
        inputRecords[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
        inputRecords[2].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
        inputRecords[3].EventType = KEY_EVENT;
        inputRecords[3].Event.KeyEvent.bKeyDown = FALSE;
        inputRecords[3].Event.KeyEvent.dwControlKeyState = 0;
        inputRecords[3].Event.KeyEvent.uChar.UnicodeChar = '\r';
        inputRecords[3].Event.KeyEvent.wRepeatCount = 1;
        inputRecords[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
        inputRecords[3].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);


        if (!WriteConsoleInput(hPipeWrite,inputRecords,sizeof(inputRecords) / sizeof(*inputRecords),&nBytesWrote))
        {
            if (GetLastError() == ERROR_NO_DATA)
                break; // Pipe was closed (normal exit path).
            else
                DisplayError("WriteConsoleInput");
        }
    }

    return 1;
}
Was it helpful?

Solution

WriteConsoleInput requires that the handle is a "A handle to the console input buffer." (First sentence in the description of the handle input parameter in the linked page in your question).

You need to use the handle from GetStdHandle to get a suitable handle.

WriteConsoleInput ONLY works on a direct handle to the console, not a redirected pipe or similar.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top