Warm tip: This article is reproduced from serverfault.com, please click

How to use ctypes to call a DLL function with double underline function name?

发布于 2020-12-10 13:05:45

I'm trying to call a function in a DLL using Python 3.8 with the ctypes module.

The function name in the DLL is __apiJob(). Pay attention, this function starts with a double underline.

I want to call it in a self-defined object like:

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()

But as the function name starts with double underline, with the name mangling function in Python, it will be regarded as a private method. Therefore, when running this script, the __apiJob will be renamed to _Job_apiJob which results in an error: "_Job__apiJob" not found.

How can I deal with situation?

Questioner
Zikikov
Viewed
0
Mark Tolonen 2020-12-11 14:17:31

The function can be called with the following syntax as well, and bypasses the obfuscation Python applies to "dunder" attributes of class instances:

self.windll['__apiJob']()

Example below:

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)

Output:

123

As an aside, WinDLL is used for DLLs declaring functions using __stdcall calling convention in 32-bit DLLs. CDLL is used for the default __cdecl calling convention. 64-bit DLLs have only one calling convention, so either works, but for portability keep this in mind.