使用 Python 从 C/C++ DLL 调用方法

Posted

技术标签:

【中文标题】使用 Python 从 C/C++ DLL 调用方法【英文标题】:Calling methods from C/C++ DLL with Python 【发布时间】:2016-08-17 13:20:57 【问题描述】:

我这里有一个关于从 c/c++ dll 调用函数的教程,示例是从official tutorial 编写的。

WINUSERAPI int WINAPI
MessageBoxA(
    HWND hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType);

Here is the wrapping with ctypes:

>>>
>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
>>>
The MessageBox foreign function can now be called in these ways:

>>>
>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")
>>>
A second example demonstrates output parameters. The win32 GetWindowRect function retrieves the dimensions of a specified window by copying them into RECT structure that the caller has to supply. Here is the C declaration:

WINUSERAPI BOOL WINAPI
GetWindowRect(
     HWND hWnd,
     LPRECT lpRect);
Here is the wrapping with ctypes:

>>>
>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
>>> from ctypes.wintypes import BOOL, HWND, RECT
>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
>>> paramflags = (1, "hwnd"), (2, "lprect")
>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
>>>

这个例子在函数是外部的时候有效,但是,假设我有一个对象的引用,我想用参数从那个对象调用一个函数,我该怎么做?

我确实从 'dumpbin -exports' 中看到了所有函数签名的日志,我尝试使用函数的全名,但它仍然不起作用。

任何其他想法都会受到祝福。

【问题讨论】:

你怎么知道它不起作用? 我尝试以与教程相同的方式激活它,只是将名称替换为导出中的签名,但我仍然收到来自 python 日志的错误,说它无法调用该函数, 'tuple' 的东西...我不在同一台计算机上工作,我正在输入它,所以这一切都来自记忆,如果您需要任何特定数据,请告诉我 我认为我们需要详细信息;我们正在这里进行故障排除。 Extending Python with C/C++的可能重复 我看到了一个叫 SWIG 的工具,它可以做我需要的吗?从对象引用中调用方法 【参考方案1】:

不幸的是,您无法使用 ctypes 轻松且便携地做到这一点。

ctypes 旨在调用具有 C 兼容数据 类型的 DLL 中的函数

由于 C++ 没有standard binary interface,您应该知道生成 DLL 的编译器是如何生成代码的(即类布局...)。

更好的解决方案是创建一个新的 DLL,它使用当前的 DLL 并将方法包装为纯 c 函数。请参阅boost.python 或SWIG 了解更多详情。

【讨论】:

在DLL中调用方法有什么解决办法吗? 您可以使用普通的 c 函数调用来包装方法调用或使用答案中的工具。 想到了那个.. 我还看到了一个叫 SWIG 的工具,它可以做我需要的吗?从对象引用中调用方法 ctypes 不同,它加载 DLL 并在运行时调用其函数 - 使用这些工具,您可以创建一个包装方法的新 DLL。您将能够使用来自 python 的新 DLL。

以上是关于使用 Python 从 C/C++ DLL 调用方法的主要内容,如果未能解决你的问题,请参考以下文章

如何从 python 调用带有 Char** 参数和 int* 参数的 C 方法?

从python加载dll

如何在非托管 c++ dll 中查找调用方程序集名称

从 C# .NET 应用程序调用 C/C++ 代码

带点指针的C函数

使用参数从 Python 调用 C/C++ 代码