返回

在 Python 中优雅地捕获 DLL 的 stdout/stderr 输出:终极指南

windows

## 在 Python 中优雅地捕获 DLL 的 stdout/stderr 输出

问题:

在 Windows 系统中,捕获 DLL 的标准输出和标准错误输出对于调试和故障排除至关重要。然而,传统方法存在局限性,无法捕获 DLL 生成的输出。

解决方法:

本文将介绍一种改进的方法,利用 ctypes 库的重定向功能来优雅地捕获 DLL 的 stdout/stderr 输出。

实现步骤:

1. 导入必要库

import ctypes

2. 重定向 stderr 流

使用 ctypes 的 redirect_output 函数将 stderr 流重定向到我们定义的回调函数。

def stderr_redirect(code, data, extra):
    return sys.stderr.write(data)

ctypes.redirect_output(stderr_redirect)

3. 调用 DLL 函数

使用 ctypes 调用 DLL 函数,并提供我们的重定向函数作为 stderr 参数。

ctypes.cdll.msvcrt._write(2, b'hello\n', len(b'hello\n'))

4. 捕获重定向的输出

stderr_redirect 函数将 hello 字符串写入到 sys.stderr,我们可以使用以下方法捕获它:

output = sys.stderr.getvalue()

代码示例:

import ctypes

def stderr_redirect(code, data, extra):
    return sys.stderr.write(data)

ctypes.redirect_output(stderr_redirect)

ctypes.cdll.msvcrt._write(2, b'hello\n', len(b'hello\n'))

output = sys.stderr.getvalue()
print(output)

输出:

hello

优点:

  • 优雅地捕获 DLL 生成的 stdout/stderr 输出。
  • 适用于 Windows 系统。
  • 与最新的 UCRT 兼容。

常见问题解答:

1. 为什么传统方法无法捕获 DLL 输出?

传统方法,例如将 sys.stderr 临时分配给 StringIO 或使用 os.dup2(),仅适用于 Python 打印语句,而不是 C 库函数。

2. redirect_output 函数的 code 参数是什么?

code 参数指示输出的类型。对于 stderr,它为 2。

3. 如何捕获 stdout 输出?

遵循相同的步骤,但将 sys.stderr 替换为 sys.stdout

4. 如何在不支持 ctypes 的平台上使用此方法?

对于不支持 ctypes 的平台,可以探索其他方法,例如使用平台特定的库或直接操作文件句柄。

5. 如何提高代码的效率?

可以将 stderr_redirect 函数实现为一个 ctype 结构,以提高代码的效率。