Hide console window for subprocesses on Windows

This commit is contained in:
Michal Krenek (Mikos) 2017-03-28 12:26:45 +02:00
parent fa462f885d
commit 05f4a59b66
8 changed files with 108 additions and 34 deletions

View File

@ -1,7 +1,9 @@
import os, glob, subprocess, threading
import os, threading
from Qt import QtCore
from qspectrumanalyzer import subprocess
class BaseInfo:
"""Default device metadata"""
@ -39,8 +41,8 @@ class BaseInfo:
def help_params(cls, executable):
try:
text = subprocess.check_output([executable, '-h'], universal_newlines=True,
stderr=subprocess.STDOUT,
env=dict(os.environ, COLUMNS='125'))
stderr=subprocess.STDOUT, env=dict(os.environ, COLUMNS='125'),
console=False)
except subprocess.CalledProcessError as e:
text = e.output
except OSError:

View File

@ -1,8 +1,9 @@
import subprocess, pprint, struct, shlex, sys, time
import pprint, struct, shlex, sys, time
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
@ -108,7 +109,7 @@ class PowerThread(BasePowerThread):
cmdline.extend(shlex.split(additional_params))
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=False)
universal_newlines=False, console=False)
def parse_output(self, buf):
"""Parse one buf of output from hackrf_sweep"""

View File

@ -1,8 +1,9 @@
import subprocess, pprint, shlex
import pprint, shlex
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
@ -66,7 +67,7 @@ class PowerThread(BasePowerThread):
cmdline.extend(shlex.split(additional_params))
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rtl_power"""

View File

@ -1,7 +1,8 @@
import subprocess, math, pprint, shlex
import math, pprint, shlex
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
@ -91,7 +92,7 @@ class PowerThread(BasePowerThread):
cmdline.extend(shlex.split(additional_params))
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rtl_power_fftw"""

View File

@ -1,8 +1,9 @@
import subprocess, pprint, shlex
import pprint, shlex
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
@ -71,7 +72,7 @@ class PowerThread(BasePowerThread):
cmdline.extend(shlex.split(additional_params))
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rx_power"""

View File

@ -1,8 +1,9 @@
import os, subprocess, pprint, sys, shlex, signal
import os, sys, pprint, shlex, signal
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
try:
@ -12,20 +13,6 @@ except ImportError:
print('soapy_power module not found!')
formatter = None
if sys.platform == 'win32':
import msvcrt
import _winapi
def _make_inheritable_handle(fd):
"""Return a duplicate of handle, which is inheritable"""
h = _winapi.DuplicateHandle(
_winapi.GetCurrentProcess(),
msvcrt.get_osfhandle(fd),
_winapi.GetCurrentProcess(), 0, 1,
_winapi.DUPLICATE_SAME_ACCESS
)
return subprocess.Handle(h)
class Info(BaseInfo):
"""soapy_power device metadata"""
@ -47,12 +34,12 @@ class Info(BaseInfo):
def help_device(cls, executable, device):
try:
text = subprocess.check_output([executable, '--detect'], universal_newlines=True,
stderr=subprocess.DEVNULL,
env=dict(os.environ, COLUMNS='125'))
stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'),
console=False)
text += '\n'
text += subprocess.check_output([executable, '--device', device, '--info'], universal_newlines=True,
stderr=subprocess.DEVNULL,
env=dict(os.environ, COLUMNS='125'))
stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'),
console=False)
except subprocess.CalledProcessError as e:
text = e.output
except OSError:
@ -101,7 +88,7 @@ class PowerThread(BasePowerThread):
os.set_inheritable(self.pipe_write_fd, True)
if sys.platform == 'win32':
self.pipe_write_handle = _make_inheritable_handle(self.pipe_write_fd)
self.pipe_write_handle = subprocess.make_inheritable_handle(self.pipe_write_fd)
# Prepare soapy_power cmdline parameters
settings = QtCore.QSettings()
@ -142,7 +129,7 @@ class PowerThread(BasePowerThread):
creationflags = 0
self.process = subprocess.Popen(cmdline, close_fds=False, universal_newlines=False,
creationflags=creationflags)
creationflags=creationflags, console=False)
os.close(self.pipe_write_fd)
if sys.platform == 'win32':

View File

@ -106,8 +106,8 @@ class DataStorage(QtCore.QObject):
def update(self, data):
"""Update data storage"""
if self.y is not None and len(data["y"]) != len(self.y):
print("{:d} bins coming from backend, expected {:d}".format(len(data["y"]), len(self.y)))
return
print("{:d} bins coming from backend, expected {:d}".format(len(data["y"]), len(self.y)))
return
self.average_counter += 1

View File

@ -0,0 +1,81 @@
import sys, subprocess
# Basic attributes and exceptions
PIPE = subprocess.PIPE
STDOUT = subprocess.STDOUT
DEVNULL = subprocess.DEVNULL
SubprocessError = subprocess.SubprocessError
TimeoutExpired = subprocess.TimeoutExpired
CalledProcessError = subprocess.CalledProcessError
# Windows-only attributes and functions
if sys.platform == 'win32':
import msvcrt
import _winapi
# creationflags
CREATE_NEW_CONSOLE = subprocess.CREATE_NEW_CONSOLE
CREATE_NEW_PROCESS_GROUP = subprocess.CREATE_NEW_PROCESS_GROUP
# startupinfo
STARTUPINFO = subprocess.STARTUPINFO
STARTF_USESTDHANDLES = subprocess.STARTF_USESTDHANDLES
STARTF_USESHOWWINDOW = subprocess.STARTF_USESHOWWINDOW
SW_HIDE = subprocess.SW_HIDE
# file handles
Handle = subprocess.Handle
STD_INPUT_HANDLE = subprocess.STD_INPUT_HANDLE
STD_OUTPUT_HANDLE = subprocess.STD_OUTPUT_HANDLE
STD_ERROR_HANDLE = subprocess.STD_ERROR_HANDLE
def make_inheritable_handle(fd):
"""Create inheritable duplicate of handle from file descriptor"""
h = _winapi.DuplicateHandle(
_winapi.GetCurrentProcess(),
msvcrt.get_osfhandle(fd),
_winapi.GetCurrentProcess(), 0, 1,
_winapi.DUPLICATE_SAME_ACCESS
)
return subprocess.Handle(h)
def hide_console_window(startupinfo=None):
"""Returns altered startupinfo to hide console window on Windows"""
if sys.platform != 'win32':
return None
if not startupinfo:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
return startupinfo
class Popen(subprocess.Popen):
"""subprocess.Popen with ability to hide console window on Windows"""
def __init__(self, *pargs, console=True, **kwargs):
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
super().__init__(*pargs, **kwargs)
def call(*pargs, console=True, **kwargs):
"""subprocess.call with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.call(*pargs, **kwargs)
def check_call(*pargs, console=True, **kwargs):
"""subprocess.check_call with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.check_call(*pargs, **kwargs)
def check_output(*pargs, console=True, **kwargs):
"""subprocess.check_output with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.check_output(*pargs, **kwargs)