使用与CPython
3.x相同的C运行时(例如,3.3的msvcr100.dll)。还包括
fflush(NULL)在重定向之前和之后对的调用
stdout。
StandardOutput如果程序直接使用WindowsAPI,请采取措施重定向Windows句柄。
如果DLL使用不同的C运行时,则可能会变得复杂,C运行时具有自己的POSIX文件描述符集。就是说,如果您在重定向Windows之后加载它,应该没问题
StandardOutput。
编辑:
我已经修改了示例,使其可以在Python 3.5+中运行。VC ++ 14的新“ Universal CRT”使通过ctypes使用C标准I /O变得更加困难。
import osimport sysimport ctypes, ctypes.utilkernel32 = ctypes.WinDLL('kernel32')STD_OUTPUT_HANDLE = -11if sys.version_info < (3, 5): libc = ctypes.CDLL(ctypes.util.find_library('c'))else: if hasattr(sys, 'gettotalrefcount'): # debug build libc = ctypes.CDLL('ucrtbased') else: libc = ctypes.CDLL('api-ms-win-crt-stdio-l1-1-0') # VC 14.0 doesn't implement printf dynamically, just # __stdio_common_vfprintf. This take a va_array arglist, # which I won't implement, so I escape format specificiers. class _FILE(ctypes.Structure): """opaque C FILE type""" libc.__acrt_iob_func.restype = ctypes.POINTER(_FILE) def _vprintf(format, arglist_ignored): options = ctypes.c_longlong(0) # no legacy behavior stdout = libc.__acrt_iob_func(1) format = format.replace(b'%%', b' ') format = format.replace(b'%', b'%%') format = format.replace(b' ', b'%%') arglist = locale = None return libc.__stdio_common_vfprintf( options, stdout, format, locale, arglist) def _printf(format, *args): return _vprintf(format, args) libc.vprintf = _vprintf libc.printf = _printfdef do_print(label): print("%s: python print" % label) s = ("%s: libc _writen" % label).enpre('ascii') libc._write(1, s, len(s)) s = ("%s: libc printfn" % label).enpre('ascii') libc.printf(s) libc.fflush(None) # flush all C streamsif __name__ == '__main__': # save POSIX stdout and Windows StandardOutput fd_stdout = os.dup(1) hStandardOutput = kernel32.GetStdHandle(STD_OUTPUT_HANDLE) do_print("begin") # redirect POSIX and Windows with open("TEST.TXT", "w") as test: os.dup2(test.fileno(), 1) kernel32.SetStdHandle(STD_OUTPUT_HANDLE, libc._get_osfhandle(1)) do_print("redirected") # restore POSIX and Windows os.dup2(fd_stdout, 1) kernel32.SetStdHandle(STD_OUTPUT_HANDLE, hStandardOutput) do_print("end")


