You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中通过Win32 msvcrt.dll获取FILE*并输出内容

问题:通过ctypes调用msvcrt.dll实现标准输出打印(不使用print/msvcrt/os库)

需要不依赖print、msvcrt及os库,仅用ctypes调用Win32的msvcrt.dll打开标准输出并打印字符串。尝试用_fdopen和_fputs时持续触发OSError: exception: access violation reading 0x0000000036B5FAA8错误,推测是Python无法直接持有FILE*,转成int后无法转回有效指针,也可能存在其他操作问题。

出错的代码

c = __import__('ctypes.util')
c_lib = c.CDLL(c.util.find_library('msvcrt'))

fptr = c_lib._get_osfhandle(
  c.cast(
    1,
    c.POINTER(c.c_int),
  )
)

realf = c_lib._open_osfhandle(
  fptr,
  c.cast(
    8,
    c.POINTER(c.c_int),
  )
)

fd = c_lib._fdopen(realf,
  c.cast(
    b'w',
    c.POINTER(c.c_char),
  )
)

c_lib.fputs(
 c.cast(
    b'Hello msvcrt!',
    c.POINTER(c.c_char),
  ),
    fd
)

c_lib._flushall()
c_lib._close(realf)

c_lib._exit(
  c.cast(
    0,
    c.POINTER(c.c_int)
  )
)

可正常运行的对比代码(依赖msvcrt/os库)

import msvcrt, os

fptr = msvcrt.get_osfhandle(1)
realf = msvcrt.open_osfhandle(fptr, os.O_APPEND)
fd = os.fdopen(realf, 'w')

fd.write('hello')
fd.flush()

os.close(realf)

解决方案

核心是修正ctypes的类型声明和参数传递逻辑,具体修正如下:

  • 显式声明每个msvcrt函数的参数类型(argtypes)和返回值类型(restype),避免默认类型转换错误
  • 直接传递整数参数,无需将int转为指针类型
  • 用c_void_p表示FILE*指针,确保指针有效性
  • 使用正确的文件打开标志(O_APPEND对应数值0x400)
  • 避免双重释放资源,_fdopen接管文件描述符后无需手动调用_close

修正后的代码

import ctypes
from ctypes.util import find_library

msvcrt = ctypes.CDLL(find_library('msvcrt'))

# 声明函数类型
msvcrt._get_osfhandle.argtypes = [ctypes.c_int]
msvcrt._get_osfhandle.restype = ctypes.c_void_p

msvcrt._open_osfhandle.argtypes = [ctypes.c_void_p, ctypes.c_int]
msvcrt._open_osfhandle.restype = ctypes.c_int

msvcrt._fdopen.argtypes = [ctypes.c_int, ctypes.c_char_p]
msvcrt._fdopen.restype = ctypes.c_void_p

msvcrt.fputs.argtypes = [ctypes.c_char_p, ctypes.c_void_p]
msvcrt.fputs.restype = ctypes.c_int

msvcrt._flushall.argtypes = []
msvcrt._flushall.restype = ctypes.c_int

msvcrt._exit.argtypes = [ctypes.c_int]
msvcrt._exit.restype = None

# 标准输出的文件描述符是1
stdout_fd = 1
# 获取OS文件句柄
os_handle = msvcrt._get_osfhandle(stdout_fd)
# 打开句柄,O_APPEND对应0x400
new_fd = msvcrt._open_osfhandle(os_handle, 0x400)
# 转为FILE*指针
file_ptr = msvcrt._fdopen(new_fd, b'w')

# 打印字符串
msvcrt.fputs(b'Hello msvcrt!', file_ptr)
# 刷新缓冲区
msvcrt._flushall()

# 退出程序
msvcrt._exit(0)

内容的提问来源于stack exchange,提问作者sawbez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 13:01:04