简体   繁体   English

WIndows:子进程创建新的控制台窗口,丢失stdin / out

[英]WIndows: subprocess making new console window, losing stdin/out

I'm using Windows Vista and Python 2.7.2, but answers needn't be in Python. 我使用的是Windows Vista和Python 2.7.2,但答案不一定是Python。

So I can start and interact with a subprocesses stdin/stdout normally (using python), for command-line programs such as `dir'. 所以我可以正常启动并与子进程stdin / stdout交互(使用python),用于命令行程序,如`dir'。
- however - - 但是 -
the program I now want to call likes to make a new console window for itself on Windows (not curses), with new handles, even when run from a pre-existing cmd.exe window. 我现在想调用的程序喜欢在Windows(而不是curses)上创建一个新的控制台窗口,使用新句柄,即使从预先存在的cmd.exe窗口运行也是如此。 (Odd, as it's the "remote control" interface of VLC.) Is there any way of either: (奇怪,因为它是VLC的“远程控制”界面。)有没有办法:

  1. getting the handles for the process-made console's stdin/out; 获取进程控制台的stdin / out的句柄; or 要么
  2. getting the new shell to run within the old (like invoking bash from within bash)? 让新的shell在旧的内部运行(比如从bash中调用bash)?

Failing that, so that I can hack the subprocesses' code, how would a new console be set up in Windows and in/output transferred? 如果失败了,那么我可以破解子进程的代码,如何在Windows中设置新的控制台并在/输出转移?

Edit: Ie 编辑:即

>>> p = Popen(args=['vlc','-I','rc'],stdin=PIPE,stdout=PIPE)
# [New console appears with text, asking for commands]
>>> p.stdin.write("quit\r\n")
Traceback:
    File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
>>> p.stdout.readline()
''
>>> p.stdout.readline()
''
# [...]

But the new console window that comes up doesn't accept keyboard input either. 但是出现的新控制台窗口也不接受键盘输入。

Whereas normally: 通常情况下:

>>> p = Popen(args=['cmd'],stdin=PIPE,stdout=PIPE)
>>> p.stdin.write("dir\r\n")
>>> p.stdin.flush()
>>> p.stdout.readline() #Don't just do this IRL, may block.
'Microsoft Windows [Version...

I haven't gotten the rc interface to work with a piped stdin/stdout on Windows; 我还没有让rc接口在Windows上使用管道stdin / stdout; I get IOError at all attempts to communicate or write directly to stdin . 在所有尝试communicate或直接写入stdin我得到IOError There's an option --rc-fake-tty that lets the rc interface be scripted on Linux, but it's not available in Windows -- at least not in my somewhat dated version of VLC (1.1.4). 有一个选项--rc-fake-tty允许rc接口在Linux上编写脚本,但它在Windows中不可用 - 至少在我有点过时版本的VLC(1.1.4)中没有。 Using the socket interface, on the other hand, seems to work fine. 另一方面,使用套接字接口似乎工作正常。

The structure assigned to the startupinfo option -- and used by the Win32 CreateProcess function -- can be configured to hide a process window. 分配给startupinfo选项的结构(由Win32 CreateProcess函数使用)可以配置为隐藏进程窗口。 However, for the VLC rc console, I think it's simpler to use the existing --rc-quiet option. 但是,对于VLC rc控制台,我认为使用现有的--rc-quiet选项更简单。 In general, here's how to configure startupinfo to hide a process window: 通常,以下是配置startupinfo以隐藏进程窗口的方法:

startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.Popen(cmd, startupinfo=startupinfo)

Just to be complete -- in case using pipes is failing on your system too -- here's a little demo I cooked up using the --rc-host option to communicate using a socket. 只是为了完成 - 如果使用管道也在你的系统上失败 - 这是一个小的演示,我使用--rc-host选项使用套接字进行通信。 It also uses --rc-quiet to hide the console. 它还使用--rc-quiet来隐藏控制台。 This just prints the help and quits. 这只是打印帮助和退出。 I haven't tested anything else. 我没有测试任何其他东西。 I checked that it works in Python versions 2.7.2 and 3.2.2. 我检查它在Python版本2.7.2和3.2.2中有效。 (I know you didn't ask for this, but maybe it will be useful to you nonetheless.) (我知道你没有要求这个,但也许它对你有用。)

import socket
import subprocess
from select import select

try:
    import winreg
except ImportError:
    import _winreg as winreg

def _get_vlc_path():
    views = [(winreg.HKEY_CURRENT_USER, 0),
             (winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_64KEY),
             (winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_32KEY)]
    subkey = r'Software\VideoLAN\VLC'
    access = winreg.KEY_QUERY_VALUE
    for hroot, flag in views:
        try:
            with winreg.OpenKey(hroot, subkey, 0, access | flag) as hkey:
                value, type_id = winreg.QueryValueEx(hkey, None)
                if type_id == winreg.REG_SZ:
                    return value
        except WindowsError:
            pass
    raise SystemExit("Error: VLC not found.")

g_vlc_path = _get_vlc_path()

def send_command(sock, cmd, get_result=False):
    try:
        cmd = (cmd + '\n').encode('ascii')
    except AttributeError:
        cmd += b'\n'
    sent = total = sock.send(cmd)
    while total < len(cmd):
        sent = sock.send(cmd[total:])
        if sent == 0:
            raise socket.error('Socket connection broken.')
        total += sent
    if get_result:
        return receive_result(sock)

def receive_result(sock):
    data = bytearray()
    sock.setblocking(0)
    while select([sock], [], [], 1.0)[0]:
        chunk = sock.recv(1024)
        if chunk == b'': 
            raise socket.error('Socket connection broken.')
        data.extend(chunk)
    sock.setblocking(1)
    return data.decode('utf-8')

def main(address, port):
    import time
    rc_host = '{0}:{1}'.format(address, port)
    vlc = subprocess.Popen([g_vlc_path, '-I', 'rc', '--rc-host', rc_host, 
                            '--rc-quiet'])
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect((address, port))
        help_msg = send_command(sock, 'help', True)
        print(help_msg)
        send_command(sock, 'quit')
    except socket.error as e:
        exit("Error: " + e.args[0])
    finally:
        sock.close()
        time.sleep(0.5)
        if vlc.poll() is None:
            vlc.terminate()

if __name__ == '__main__':
    main('localhost', 12345)

With reference to monitoring the stdOut which appears in the new Spawned Console Window. 参考监视出现在新的Spawned控制台窗口中的stdOut。

Here´s another question/answer that solves the problem. 这是解决问题的另一个问题/答案

In summary (as answered by Adam MW ): 总之(由Adam MW回答):

  • Suppress the new spawned console by launching vlc in quiet mode --intf=dummy --dummy-quiet or --intf=rc --rc-quiet . 通过以安静模式启动vlc来抑制新生成的控制台--intf=dummy --dummy-quiet--intf=rc --rc-quiet
  • Monitor stdErr of launched process 监视启动进程的stdErr

Note: As for stdIn commands for the rc interface, the --rc-host solution is described by eryksun´s answer 注意:对于rc接口的stdIn命令, --rc-host解决方案由eryksun的回答描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM