如何使用 ctypes 调用具有双下划线函数名的 DLL 函数?

Posted

技术标签:

【中文标题】如何使用 ctypes 调用具有双下划线函数名的 DLL 函数?【英文标题】:How to use ctypes to call a DLL function with double underline function name? 【发布时间】:2021-03-21 21:51:55 【问题描述】:

我正在尝试使用带有 ctypes 模块的 Python 3.8 调用 DLL 中的函数。

DLL 中的函数名是__apiJob()。注意,这个函数以双下划线开头。

我想在自定义对象中调用它,例如:

class Job:

    def __init__(self,dll_path):
        self.windll = ctypes.WinDLL(dll_path)

    def execute(self):
        self.windll.__apiJob()

a = Job('api64.dll')
a.execute()

但是由于函数名以双下划线开头,在 Python 中以 mangling 函数命名,会被视为私有方法。因此,在运行此脚本时,__apiJob 将被重命名为 _Job_apiJob,从而导致错误:"_Job__apiJob" not found

我该如何处理这种情况?

【问题讨论】:

【参考方案1】:

也可以使用以下语法调用该函数,并绕过 Python 对类实例的“dunder”属性的混淆:

self.windll['__apiJob']()

下面的例子:

test.cpp

extern "C" __declspec(dllexport)
int __apiJob() 
    return 123;

test.py

import ctypes

class Job:

    def __init__(self):
        dll = ctypes.CDLL('./test')
        self.apiJob = dll['__apiJob'] # bypass "dunder" class name mangling
        self.apiJob.argtypes = ()
        self.apiJob.restype = ctypes.c_int

    def execute(self):
        return self.apiJob()

a = Job()
result = a.execute()
print(result)

输出:

123

顺便说一句,WinDLL 用于在 32 位 DLL 中使用 __stdcall 调用约定声明函数的 DLL。 CDLL 用于默认的 __cdecl 调用约定。 64 位 DLL 只有一个调用约定,因此任何一种都可以,但为了可移植性,请记住这一点。

【讨论】:

以上是关于如何使用 ctypes 调用具有双下划线函数名的 DLL 函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在具有相同函数名的派生类中调用基类的函数[重复]

python基础学习 第十七天

从 QMainWindow 调用具有变量名的 Python 函数

python 里面的单下划线与双下划线的区别

Python ctypes:如何调用应该返回字符串数组的函数?

初识函数