So I am learning to make use of Python ctypes module.
Here is simple C file which I compiled with gcc -shared (version 4.8) on Windows to get sample .dll:
#include <stdio.h>
int addition(int a, int b){
return a+b;
}
I am now able to access it from Python like this:
>>>from ctypes import *
>>>mylibc = CDLL(r"somepath\mysample.dll")
>>>mylibc.addition
<_FuncPtr object at 0x00000000031456C8>
>>>mylibc.addition(2,3)
5
Now I try to do same with different, bigger and more complicated .c file which contains this function:
__declspec(dllexport) void __stdcall
flopequity(HW hero[], HW villain[], double hcounters[],
double vcounters[], double hsums[], double vsums[], ulong board,
__int32 lenh, __int32 lenv)
where HW is typedef for a struct. I compile it with GCC and can access that function as before however when I remove __declspec(dllexport) or _stdcall (or both) the function is no longer accessible.
My question is what could be the reason for me being able to access the simple function from first example but me being unable to access a more complicated function.
What are the rules for using calling conventions/_declspec when compiling C code and accessing it from ctypes ?
gcc
seems to export functions by default, you can use any PE viewer like PE Explorer (View > Export) to view the exported functions:
But, If you try to compile this code with VC++, it won't export this function for you, you'll see that there is not exported function:
You need to ask it to export this function:
__declspec(dllexport) int addition(int a, int b){
return a+b;
}
As for calling conventions, the rule is simple:
If your function uses __stdcall
, as most Win32API, you need to import the DLL with WinDLL('mylib.dll')
or windll.mylib
, example:
> type mylib.c
__declspec(dllexport) int __stdcall addition(int a, int b) {
return a+b;
}
***********************************************************************
> cl mylib.c /link /dll /out:mylib.dll
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
mylib.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.
/out:mylib.exe
/dll
/out:mylib.dll
mylib.obj
Creating library mylib.lib and object mylib.exp
***********************************************************************
> python
>>> from ctypes import *
>>>
>>> WinDLL('mylib.dll').addition(1, 2)
3
>>> windll.mylib.addition(1, 2)
3
>>>
If your function uses __cdecl
, witch is the default calling convention, you need to import the DLL with CDLL('mylib.dll')
or cdll.mylib'
, example:
> type mylib.c
// `__cdecl` is not needed, since it's the default calling convention
__declspec(dllexport) int addition(int a, int b){
return a+b;
}
***********************************************************************
> cl mylib.c /link /dll /out:mylib.dll
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
mylib.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.
/out:mylib.exe
/dll
/out:mylib.dll
mylib.obj
Creating library mylib.lib and object mylib.exp
***********************************************************************
> python
>>> from ctypes import *
>>>
>>> CDLL('mylib.dll').addition(1, 2)
3
>>> cdll.mylib.addition(1, 2)
3
>>>