2011-11-14 85 views
3

我试图自动执行用C++编写的交互式命令行工具。process.communicate和getche()失败

启动时,二进制等待字母S,Q或P(状态,退出或暂停)。它采用了非标准的msvcrt函数“getche”获取击键(而不是得到()为例),而无需按下回车键的用户。

我尝试以标准方式与进程进行通信(写入stdin并使用process.communicate []),但它没有得到输入。尝试不同的事情了几个小时后,我创建了两个小样本项目在Visual Studio中复制的问题,并确保我理智(ISH)。

这是用来调用二进制的python脚本:

import subprocess 
import time 

cmd = ["test-getch.exe"] 
process = subprocess.Popen(cmd, stderr = subprocess.PIPE, stdin = subprocess.PIPE, stdout = subprocess.PIPE) 
i = process.stdin 
#msvcrt.ungetch('s') 
i.write("S\n") 
print process.communicate()[0] 
i.close() 
time.sleep(3) 
print "DONE" 

这是两个二进制文件。这第一个我可以与之通信:

#include "stdafx.h" 
#include <conio.h> 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    char response [2]; 
    printf("Enter \"s\":\n"); 
    gets(response); 
    printf("You entered %s", response); 
    return 0; 
} 

这一次,我不能沟通:

#include "stdafx.h" 
#include <conio.h> 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int response; 
    printf("Enter \"a\":\n"); 
    response = getche(); 
    printf("You entered %c", response); 
    return 0; 
} 

看来,getche()不标准输入听,可能监听某种键盘事件。任何人都知道如何处理这个问题?

编辑: 我还应该提到我发现了使用IDA Pro捕获输入的方法。我没有写我尝试自动化的原始二进制文件。它是一个封闭的源代码工具,所以我没有办法重新编写它如何接受输入而不修补二进制文件。

我实际上选择了一个相当疯狂的解决方案......我知道pydbg相当不错,它似乎附加到过程并通过过程工具调用我需要的功能。这完全是过分的,但我可以在之后脱离这个过程。并让它正常运行。

[1] Pydbg:http://pedram.redhive.com/PyDbg/docs/

+0

使用'process.communicate( “S \ n” 个)的''代替i.write()'。如果使用'.communicate()',请不要触摸'process.stdin'。虽然它不会帮助你的情况。 – jfs

回答

2

getche控制台读取,而不是从标准输入。如果你的Python过程是在一个控制台窗口中运行,那么你的子进程仍然会尝试从同一个控制台,而不是它作为标准输入传递的管道读取输入。

可能会创建另一个不可见的控制台窗口,将其附加到子进程并为其提供输入,但这非常复杂且容易出错。

我会建议,而不是只使用getche()来重写您的程序只读取标准输入。如果你真的想拥有它的反应按键,而不需要用户按Enter键,那么我建议有它改变其依赖于标准输入是否是来自终端的行为。如果是,使用getche,如果没有,就直接从stdin读取。您可以测试此使用_isatty(或POSIX等价isatty;出于某种原因,微软已经决定弃用其运行时POSIX名)。例如:

int ReadChar() 
{ 
    if(_isatty(0)) 
    { 
     // stdin is a terminal 
     return _getche(); 
    } 
    else 
    { 
     // stdin is not a terminal 
     return getchar(); 
    } 
} 
+0

我编辑了原始问题,以包含我没有写入原始二进制文件的事实。我发现程序如何使用IDA Pro接受输入,并创建了示例项目以消除处理整个二进制文件的复杂性。 –

2

如果您可以修改被调用程序的行为,Adam Rosenfield的答案是一个明智的方法。否则,如果您确实需要写入控制台输入缓冲区,请尝试PyWin32的win32console模块。也就是说,我不确定如何在输出stdout时使字符回显部分正常工作。它最终打印到该行的开头。

C:

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int response; 
    printf("Enter \"a\": "); 
    response = getche(); 
    printf("\nYou entered \"%c\" ", response); 
    return 0; 
} 

/* gcc test_getch.c -o test_getch.exe */ 

的Python:

import subprocess 
import win32console 

def make_buf(c): 
    buf = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT) 
    buf.KeyDown = 1 
    buf.RepeatCount = 1 
    buf.Char = c 
    return buf 

con_in = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE) 

cmd = ["test_getch.exe"] 
p = subprocess.Popen(cmd, stdin=subprocess.PIPE) 

buf = make_buf('a') 
con_in.WriteConsoleInput([buf]) 
+0

感谢您的建议。我会考虑今天晚上使用win32console。 –