I'm trying to use a third-party DLL in my code and I have to call a function from that DLL using Python. According to documentation, the DLL has got just 4 functions, and none of those can be called from my Python code. I've tried both x86 and x64 DLLs (with the corresponding Python distribution). I tried Python 3.7, 3.9, 3.10 and 3.11, all those cannot call any of the functions.
from ctypes import cdll
sdk = cdll.LoadLibrary("./Library.dll")
get_data = sdk.sdk_get_data
print(get_data)
This returns an error:
File "D:\sandbox\еуые.py", line 7, in <module>
get_data = sdk.sdk_get_data
File "C:\Python39-64\lib\ctypes\__init__.py", line 387, in __getattr__
func = self.__getitem__(name)
File "C:\Python39-64\lib\ctypes\__init__.py", line 392, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'sdk_get_data' not found
I've used lucasg's Dependencies tool to make sure the function documented exists in the DLL and here is the output:
1 (0x0001), (0x), int __cdecl sdk_get_data(char * __ptr64,int,unsigned short * __ptr64,unsigned char * __ptr64), 0x00001b30, Microsoft
How do I call functions from this DLL? Perhaps writing a wrapper in C++ is necessary?
C ABI exports don't have the information to list the parameter types, so that indicates the function is a C++ function. Since the parameters are C-compatible, you may get away with using the C++ decorated name of the function. It looks like ?sdk_get_data@@YAHPEADHPEAGPEAE@Z
using the Windows SDK dumpbin /exports
tool, but can vary by compiler.
For example, with a C++-compiled function with your given signature in test.cpp
with the Microsoft compiler:
__declspec(dllexport)
int __cdecl sdk_get_data(char* p, int n, unsigned short* w, unsigned char* data) {
return 1;
}
The following will look up the function:
import ctypes as ct
dll = ct.CDLL('./test')
func = dll['?sdk_get_data@@YAHPEADHPEAGPEAE@Z']
print(func()) # outputs 1
But if you make a C-wrapper such as the following that forwards the parameters to the C++ function using an exported C function and link it to your 3rd-party DLL, then your original code should work without a decorated name:
extern "C" __declspec(dllexport)
int sdk_get_data_c(char* p, int n, unsigned short w, unsigned char* data) {
return sdk_get_data(p, n, w, data);
}