如何在Python中捕获DLL的stdout/stderr?

问题描述 投票:0回答:1

如何在 Windows 上的 Python 中捕获 DLL 的 stdout 和/或 stderr?例如,这将

"hello"
打印到 stderr,但应该可以将
"hello"
捕获为字符串而不是打印它:

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

这是行不通的:

  1. 临时将
    sys.stderr
    分配给
    StringIO
    (或等效地,使用
    contextlib.redirect_stdout
    )不会捕获输出,因为它来自 C 库函数,而不是 Python print 语句。这在 Linux 上也不起作用。
  2. 按照here
    的建议,使用
    os.dup2()并从单独线程上的管道读取,只会抑制输出而不捕获它。
  3. 按照
    here
    的建议使用
    ctypes.cdll.kernel32.GetStdHandle()
    ctypes.cdll.kernel32.SetStdHandle(),在尝试打印到修改后的stderr时会给出错误
    OSError: [WinError 6] The handle is invalid
  4. 此解决方案失败,因为
    ctypes.util.find_msvcrt()
    在 Python 3.5+ 中返回
    None
    ,据我了解,这是因为 Microsoft 已从 Microsoft Visual C++ Runtime (MSVCRT) 过渡到 Universal C Runtime (UCRT)。即使我将行
    msvcrt = CDLL(ctypes.util.find_msvcrt())
    更改为
    msvcrt = ctypes.cdll.msvcrt
    ,它也只是抑制输出而不捕获它。

我的总体印象是,适用于 Linux 的解决方案不适用于 Windows,并且由于过渡到 UCRT,过去适用于 Windows 的解决方案不再适用。

python windows dll msvcrt kernel32
1个回答
0
投票

这并不完全是你想要的,但你也许可以将你的 dll 调用包装在

subprocess

import subprocess

p = subprocess.Popen(
    ["python3"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,  # optional avoids .encode/decode
)

data = r"""
import ctypes
string = b'hello\n'
ctypes.cdll.msvcrt._write(2, string, len(string))
"""

out, err = p.communicate(data)
if p.returncode != 0:
    print("failed!")

print(out)
print(err)
© www.soinside.com 2019 - 2024. All rights reserved.