为什么一个HANDLE不适用于WriteConsoleInput,但适用于WriteFile

Why does one HANDLE not work for WriteConsoleInput, but works for WriteFile?

本文关键字:适用于 WriteConsoleInput WriteFile 不适用 HANDLE 一个 为什么      更新时间:2023-10-16

所以我试图修改Microsoft(此处)提供的代码,使其使用WriteConsoleInput,而不是WriteFile,但它说句柄无效(我打赌这真的很愚蠢),比如句柄最初是如何创建的。

所以我的问题是,WriteConsoleInput所需的句柄和WriteFile所需的手柄之间有什么区别?

写入控制台输入

写入文件

我猜这与CreateFile创建的HANDLE的权限标志有关,与CreateProcess/CreatePipe/DuplicateHandle进程创建的继承句柄相比。

我决定如果你能看到这个问题会更容易,所以这里是我的完整解决方案(使用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] = ''; // 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;
}

WriteConsoleInput要求句柄是"控制台输入缓冲区的句柄"。(问题中链接页面中handle输入参数描述的第一句话)。

您需要使用GetStdHandle中的句柄来获得合适的句柄。

WriteConsoleInput仅适用于控制台的直接句柄,而不是重定向管道或类似管道。