2

したがって、マイクロソフトが提供するコード( here )を変更して、WriteFileの代わりにWriteConsoleInputを使用しようとしていますが、ハンドルが最初に作成された方法など、ハンドルが無効であると表示されています(本当にばかげていると思います)。 .

私の質問ですが、WriteConsoleInput に必要なハンドルと WriteFile のハンドルの違いは何ですか?

WriteConsoleInput

書き込みファイル

CreateProcess/CreatePipe/DuplicateHandle プロセスによって作成された継承されたハンドルと比較して、CreateFile によって作成された HANDLE の権限フラグに関係していると推測しています。

問題を確認できれば簡単だと判断したので、ここに私の完全な解決策を示します (Visual Studio 2012 を使用) 子アプリと親アプリの両方が含まれています。

GitHub の ConsoleRedir

注意として、子アプリで ReadConsoleInput を使用する必要があり、それが不満の原因でした。

元の方法:

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

私の修正版(キーストロークを作成する必要があります):

/////////////////////////////////////////////////////////////////////// 
// 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;
}
4

1 に答える 1

3

WriteConsoleInputハンドルが「コンソール入力バッファへのハンドル」である必要があります。handle(質問のリンク先ページの入力パラメータの説明の最初の文)。

GetStdHandle適切なハンドルを取得するには、 のハンドルを使用する必要があります。

WriteConsoleInputリダイレクトされたパイプなどではなく、コンソールへの直接ハンドルでのみ機能します。

于 2013-07-15T09:09:42.397 に答える