Почему один HANDLE не работает для WriteConsoleInput, но работает для WriteFile?

Поэтому я пытаюсь изменить код, предоставленный Microsoft (Вот) использовать WriteConsoleInput вместо WriteFile, но он говорит, что дескриптор недействителен (держу пари, это что-то очень глупое), например, как дескриптор изначально создан или что-то в этом роде.

Итак, мой вопрос, в чем разница между дескрипторами, необходимыми для WriteConsoleInput, и дескриптором для WriteFile?

WriteConsoleInput

WriteFile

Я предполагаю, что это связано с флагом прав доступа HANDLE, созданного CreateFile, по сравнению с унаследованными дескрипторами, созданными процессом CreateProcess / CreatePipe / DuplicateHandle.

Я решил, что будет проще, если вы сможете увидеть проблему, поэтому вот мое полное решение (с использованием Visual Studio 2012). Включены как дочернее, так и родительское приложение.

ConsoleRedir на GitHub

Как примечание, мне нужно, чтобы дочернее приложение использовало 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;
}

2

Решение

WriteConsoleInput требует, чтобы дескриптор был «дескриптором буфера ввода консоли». (Первое предложение в описании handle входной параметр на связанной странице в вашем вопросе).

Вам нужно использовать ручку из GetStdHandle чтобы получить подходящую ручку.

WriteConsoleInput Работает ТОЛЬКО на прямой ручке консоли, а не на перенаправленной трубе или чем-то подобном.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]