Skip to content

Instantly share code, notes, and snippets.

@vsajip
Created September 25, 2021 15:33
Show Gist options
  • Save vsajip/60ff8b74a155c7311fc986bd81160ab4 to your computer and use it in GitHub Desktop.
Save vsajip/60ff8b74a155c7311fc986bd81160ab4 to your computer and use it in GitHub Desktop.
Duplicate stdio handles on Windows using ctypes
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2021 Red Dove Consultants Limited. BSD-3-Clause licensed.
#
from ctypes import *
from ctypes.wintypes import BYTE,WORD,DWORD,LPWSTR,LPCWSTR,HANDLE,LPVOID,BOOL
import os
import sys
DEBUGGING = 'PY_DEBUG' in os.environ
LPBYTE = POINTER(BYTE)
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
TRUE = 1
DUPLICATE_SAME_ACCESS = 2
class STARTUPINFOW(Structure):
_fields_ = [('cb', DWORD),
('lpReserved', LPWSTR),
('lpDesktop', LPWSTR),
('lpTitle', LPWSTR),
('dwX', DWORD),
('dwY', DWORD),
('dwXSize', DWORD),
('dwYSize', DWORD),
('dwXCountChars', DWORD),
('dwYCountChars', DWORD),
('dwFillAttribute',DWORD),
('dwFlags', DWORD),
('wShowWindow', WORD),
('cbReserved2', WORD),
('lpReserved2', LPBYTE),
('hStdInput', HANDLE),
('hStdOutput', HANDLE),
('hStdError', HANDLE)]
GetStdHandle = windll.kernel32.GetStdHandle
GetCurrentProcess = windll.kernel32.GetCurrentProcess
GetCurrentProcess.restype = HANDLE
DuplicateHandle = windll.kernel32.DuplicateHandle
DuplicateHandle.restype = BOOL
DuplicateHandle.argtypes = (HANDLE, HANDLE, HANDLE, POINTER(HANDLE),
DWORD, BOOL, DWORD)
def main():
si = STARTUPINFOW()
si.cb = sizeof(STARTUPINFOW)
process = GetCurrentProcess()
for ih in (STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE):
h = GetStdHandle(ih)
if ih == STD_INPUT_HANDLE:
f = STARTUPINFOW.hStdInput
addr = pointer(HANDLE.from_buffer(si, f.offset))
elif ih == STD_OUTPUT_HANDLE:
f = STARTUPINFOW.hStdOutput
addr = pointer(HANDLE.from_buffer(si, f.offset))
else:
f = STARTUPINFOW.hStdError
addr = pointer(HANDLE.from_buffer(si, f.offset))
ok = DuplicateHandle(process, h, process, addr, 0, TRUE, DUPLICATE_SAME_ACCESS)
print(ok)
if __name__ == '__main__':
try:
rc = main()
except KeyboardInterrupt:
rc = 2
except Exception as e:
if DEBUGGING:
s = ' %s:' % type(e).__name__
else:
s = ''
sys.stderr.write('Failed:%s %s\n' % (s, e))
if DEBUGGING: import traceback; traceback.print_exc()
rc = 1
sys.exit(rc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment