C++ 用重定向stdin处理子进程中的kbhit
我编写了一个程序,该程序使用windows API(CreateProcess、CreatePipe等)启动另一个进程并将其标准I/O重定向到管道 程序应该启动多个不同的控制台程序,并使用stdio与它们通信 在我尝试启动一个使用kbhit的程序并与之通信之前,这一切都运行得很好(我可以写入进程的stdin并使用管道读取进程) 为了简化它,我想用标准输入启动该程序:C++ 用重定向stdin处理子进程中的kbhit,c++,windows,winapi,C++,Windows,Winapi,我编写了一个程序,该程序使用windows API(CreateProcess、CreatePipe等)启动另一个进程并将其标准I/O重定向到管道 程序应该启动多个不同的控制台程序,并使用stdio与它们通信 在我尝试启动一个使用kbhit的程序并与之通信之前,这一切都运行得很好(我可以写入进程的stdin并使用管道读取进程) 为了简化它,我想用标准输入启动该程序: while(1) { if(kbhit()) { fgets(line, sizeof(line)
while(1)
{
if(kbhit())
{
fgets(line, sizeof(line), stdin);
//do something with line
}
Sleep(100);
}
结果是fgets永远不会被调用,因为kbhit不会返回true,即使我已经将stdin重定向到了管道中。我知道这一点,因为我已经调试到了另一个程序中。我尝试删除kbhit的调用,然后它确实起作用,但我无法更改该代码
是否有一种方法可以将某些内容发送到进程,以便子进程中的kbhit返回true 该功能检查控制台最近的击键。它从不检查stdin,而是打开CONIN$(控制台输入)并始终从这里读取
所以把stdin重定向到这里,什么都不给。如果我们和孩子共享同一个控制台,我们就可以使用它来完成这个任务。将字符串写入子对象的示例:
void write_to_conin(PCWSTR msg)
{
if (ULONG len = (ULONG)wcslen(msg))
{
if (INPUT_RECORD* lpBuffer = new INPUT_RECORD[len])
{
INPUT_RECORD* pir = lpBuffer;
ULONG n = len;
do
{
WCHAR UnicodeChar = *msg++;
WORD wVirtualKeyCode = UnicodeChar;
DWORD dwControlKeyState = CAPSLOCK_ON;
if ((USHORT)(UnicodeChar - 'a') <= (USHORT)('z' - 'a'))
{
dwControlKeyState = 0;
wVirtualKeyCode &= ~0x20;
}
pir->Event.KeyEvent.bKeyDown = TRUE;
pir->Event.KeyEvent.dwControlKeyState = dwControlKeyState;
pir->Event.KeyEvent.wRepeatCount = 1;
pir->Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
pir->Event.KeyEvent.wVirtualKeyCode = wVirtualKeyCode;
pir->Event.KeyEvent.wVirtualScanCode = (WORD)MapVirtualKey(wVirtualKeyCode, MAPVK_VK_TO_VSC);
pir++->EventType = KEY_EVENT;
} while (--n);
HANDLE hcon = CreateFileW(L"CONIN$", FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hcon != INVALID_HANDLE_VALUE)
{
WriteConsoleInput(hcon, lpBuffer, len, &n);
CloseHandle(hcon);
}
delete [] lpBuffer;
}
}
}
void write_to_conin(PCWSTR msg)
{
如果(ULONG len=(ULONG)wcslen(msg))
{
if(输入\记录*lpBuffer=新输入\记录[len])
{
输入_记录*pir=lpBuffer;
ULONG n=len;
做
{
WCHAR UnicodeChar=*msg++;
单词wVirtualKeyCode=UnicodeChar;
DWORD dwControlKeyState=CAPSLOCK_ON;
如果((USHORT)(UnicodeChar-'a')Event.KeyEvent.bKeyDown=TRUE;
pir->Event.KeyEvent.dwControlKeyState=dwControlKeyState;
pir->Event.KeyEvent.wRepeatCount=1;
pir->Event.KeyEvent.uChar.UnicodeChar=UnicodeChar;
pir->Event.KeyEvent.wVirtualKeyCode=wVirtualKeyCode;
pir->Event.KeyEvent.wVirtualScanCode=(WORD)映射VirtualKey(wVirtualKey代码,映射到VSC);
pir++->EventType=按键事件;
}而(--n);
HANDLE hcon=CreateFileW(L“CONIN$”,文件\通用\写入,文件\共享\有效\标志,0,打开\存在,0,0);
if(hcon!=无效的句柄值)
{
WriteConsoleInput(hcon、lpBuffer、len和n);
闭合手柄(hcon);
}
删除[]lpBuffer;
}
}
}
我想kbhit
直接读取键盘,而不是通过stdin读取。为什么这里需要kbhit
?这是一个吗?我没有制作的另一个程序使用kbhit,我无法更改它kbhit()不是C++中的标准函数。为了了解如何与其他程序交互,需要读取编译器/库的文档,假设它是可能的。<代码> IKBHIT < /Cord>从控制台读取(<代码> CONIN $< /CKE>设备)。它忽略stdin。你对stdin所写的内容将被忽略。没有办法在那里写东西吗?你的解释很有道理。我曾尝试以各种方式使用你的代码,但我只是通过创建一个调用实际进程的包装进程来实现它。@JimmyT.,你必须连接到同一个控制台。如果你有GUI应用程序,你将无法使用它ed到任一调用AttachConsole(子pid)
或者更简单地说,事先调用alloconsole
让孩子继承你的控制台。使用Windows 10秋季更新中提供的新ConPTY系统,这类问题将更容易处理。ConPTY提供一个指向conhost.exe实例的I/O通道。目标受众是另一个控制台应用程序例如ConEmu,生成和使用UTF-8虚拟终端序列。但这对于与控制台应用程序交互的类似pexpect的库也同样有效。问题是我需要启动多个进程并与之通信,所以我不能让它们共享同一个控制台,这就是为什么需要使用为每个进程实例提供单独的控制台。@JimmyT。是的,我如何写答案-如果我们与子进程共享同一个控制台