Skip to content

Commit b2c7b34

Browse files
gh-85028: Honor startupinfo.wShowWindow with shell=True (GH-20975)
On Windows, subprocess.Popen() with shell=True no longer overrides wShowWindow of the startupinfo argument, so the console window of the started program can be shown. Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 5181a6e commit b2c7b34

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

Lib/subprocess.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,8 +1688,9 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
16881688
close_fds = False
16891689

16901690
if shell:
1691-
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
1692-
startupinfo.wShowWindow = _winapi.SW_HIDE
1691+
if not startupinfo.dwFlags & _winapi.STARTF_USESHOWWINDOW:
1692+
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
1693+
startupinfo.wShowWindow = _winapi.SW_HIDE
16931694
if not executable:
16941695
# gh-101283: without a fully-qualified path, before Windows
16951696
# checks the system directories, it first looks in the

Lib/test/test_subprocess.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3777,6 +3777,34 @@ def test_startupinfo_copy(self):
37773777
self.assertEqual(startupinfo.wShowWindow, subprocess.SW_HIDE)
37783778
self.assertEqual(startupinfo.lpAttributeList, {"handle_list": []})
37793779

3780+
def test_startupinfo_shell_show_window(self):
3781+
# gh-85028: shell=True must not override wShowWindow set by the caller
3782+
import _winapi
3783+
SW_MAXIMIZE = 3
3784+
used = []
3785+
create_process = _winapi.CreateProcess
3786+
3787+
def spy(*args):
3788+
# The startup info is the last argument of CreateProcess()
3789+
used.append(args[-1])
3790+
return create_process(*args)
3791+
3792+
startupinfo = subprocess.STARTUPINFO(
3793+
dwFlags=subprocess.STARTF_USESHOWWINDOW,
3794+
wShowWindow=SW_MAXIMIZE)
3795+
with mock.patch.object(_winapi, 'CreateProcess', spy):
3796+
rc = subprocess.call(ZERO_RETURN_CMD, shell=True,
3797+
startupinfo=startupinfo)
3798+
self.assertEqual(rc, 0)
3799+
rc = subprocess.call(ZERO_RETURN_CMD, shell=True)
3800+
self.assertEqual(rc, 0)
3801+
3802+
requested, default = used
3803+
self.assertEqual(requested.wShowWindow, SW_MAXIMIZE)
3804+
# Without STARTF_USESHOWWINDOW the shell window is still hidden.
3805+
self.assertTrue(default.dwFlags & subprocess.STARTF_USESHOWWINDOW)
3806+
self.assertEqual(default.wShowWindow, subprocess.SW_HIDE)
3807+
37803808
# CREATE_NEW_CONSOLE creates a "popup" window.
37813809
@support.requires_resource('gui')
37823810
def test_creationflags(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:class:`subprocess.Popen` with ``shell=True`` on Windows now honors
2+
``wShowWindow`` of the *startupinfo* argument, so the console window of the
3+
started program can be shown. Previously it was always hidden.

0 commit comments

Comments
 (0)