WIndows:新しいコンソールウィンドウを作成するサブプロセス、stdin/outを失う

私はWindows VistaとPython 2.7.2を使用していますが、答えはPythonである必要はありません。

ですから、 `dir
‘のようなコマンドラインプログラムでは、標準プロセスのstdin/stdout(Pythonを使って)を起動して対話することができます。

– しかしながら –
既存のcmd.exeウィンドウから実行されたとしても、新しいハンドルを使ってWindows(cursesではなく)上に新しいコンソールウィンドウを作成するのが好きです。
(奇妙なのは、それはVLCの “リモートコントロール”インターフェースです)。どちらの方法もありますか?

  1. プロセス製コンソールのstdin/outのハンドルを取得する。または
  2. 古いシェルの中で新しいシェルを動かす(bashの中からbashを起動するような)?

それでは、サブプロセスのコードをハックすることができるように、Windowsで新しいコンソールを設定し、入出力を転送する方法はありますか?

編集: 私。

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

しかし、新しいコンソールウィンドウには、キーボード入力も受け付けていません。

一方、通常:

>>> p = Popen(args=['cmd'],stdin=PIPE,stdout=PIPE)
>>> p.stdin.write("dirrn")
>>> p.stdin.flush()
>>> p.stdout.readline() #Don't just do this IRL, may block.
'Microsoft Windows [Version...
ベストアンサー

私はrcインタフェースがWindows上でパイプ接続されたstdin/stdoutで動作するようにはなっていません。
通信するか、 stdin に直接書き込むすべての試みで
IOError を取得します。 rcインタフェースをLinux上でスクリプト化できるようにするオプション
- rc-fake-tty がありますが、これはWindowsでは利用できません –
少なくとも若干古いバージョンのVLC(1.1.4) 。一方、ソケットインターフェイスを使用すると、正常に動作するようです。

startupinfo オプションに割り当てられ、Win32の
CreateProcess
関数で使用される構造体は、プロセスウィンドウを隠すように設定できます。しかし、VLC rcコンソールでは、既存の -
rc-quiet
オプションを使用する方が簡単だと思います。一般に、プロセスウィンドウを隠すように
startupinfo を設定する方法は次のとおりです:

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

ソケットを使って通信するには、 - rc-host
オプションを使用して調理したちょっとしたデモがあります。また、 - rc-quiet
を使用してコンソールを非表示にします。これは単にヘルプを表示して終了します。私は他の何かを試していません。
Pythonバージョン2.7.2と3.2.2で動作することを確認しました。
(私はあなたがこれを求めていないことを知っていますが、多分それはあなたにとって役に立つかもしれません。)

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'SoftwareVideoLANVLC'
    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)

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です