One way to export a symbol is via an option to the linker:
cl testdll.c /LD /link /export:sum
This doesn't scale. A better option is to use the __declspec(dllexport)
modifier in the declaration. Refer to Exporting from a DLL in the Visual studio docs.
Apply it conditionally as follows:
#ifdef BUILD_TESTDLL
#define TESTAPI __declspec(dllexport)
#else
#define TESTAPI __declspec(dllimport)
#endif
/* declaration */
TESTAPI int sum(int a, int b);
/* definition */
int sum(int a, int b)
{
return(a+b);
}
When linking via the import lib, declarations should use __declspec(dllimport)
, which is the default for TESTAPI
. When building the DLL, define BUILD_TESTDLL
in the project settings or on the command-line via /D
.
Finally, for the ultimate in flexibility, use a .def file such as the following:
LIBRARY TESTDLL
EXPORTS
sum @ 10 NONAME
sum_alias=sum @ 20
This lets you export a function using a different name, or export by ordinal only. Add it as a source file as follows:
cl testdll.c testdll.def /LD
Then in Python, for example:
>>> from ctypes import *
>>> lib = cdll.testdll
>>> lib.sum_alias(1, 2)
3
>>> lib[10](1, 2)
3
>>> lib[20](1, 2)
3
BTW, ctypes doesn't preload the exports from a DLL. dir(lib)
won't show any function pointers at first. They're cached when accessed:
>>> from ctypes import *
>>> lib = cdll.testdll
>>> sorted(vars(lib))
['_FuncPtr', '_handle', '_name']
>>> lib.sum_alias(1, 2)
3
>>> sorted(vars(lib))
['_FuncPtr', '_handle', '_name', 'sum_alias']