我几乎可以肯定我一年前做过一次这样的事情......不仅仅是行不通。奇怪的。我必须在某个地方犯一个小错误......请帮助!
我有以下玩具代码:
// testdll.c
int sum(int a, int b)
{
return(a+b);
}
然后,由于我使用的是Windows 7,我使用WinSDK 7.1的x64 C / C ++编译器进行编译:
cl testdll.c /TC /LD
输出是testdll.dll。
然后,在我的Python 3.3中,我使用了:
In [12]: import ctypes
In [13]: lib = ctypes.cdll.LoadLibrary('./testdll.dll')
In [14]: lib
Out[14]: <CDLL './testdll.dll', handle f7000000 at a43ea58>
In [15]: lib.sum
Traceback (most recent call last):
File "<ipython-input-15-309017dbbec8>", line 1, in <module>
lib.sum
File "C:\WinPython2\python-2.7.6.amd64\lib\ctypes\__init__.py", line 378, in __getattr__
func = self.__getitem__(name)
File "C:\WinPython2\python-2.7.6.amd64\lib\ctypes\__init__.py", line 383, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'sum' not found
找不到这个功能!这让我疯狂。由于我使用了纯C,并且在编译期间使用了/ TC,因此它不应该是名称错误问题。
任何想法都会受到赞赏。非常感谢你们!
EDIT 2014/02/13 我试着用gcc编译它,但没有运气。发生同样的老问题。 我在python中使用了dir(),并且意识到一切都应该在其中 - 只是不正确的名称,我的意思是它不能通过fun.sum调用。它能够识别函数的结果类型是int。
In [34]: dir(lib)
Out[34]:
['_FuncPtr',
'__class__',
'__delattr__',
'__dict__',
'__doc__',
'__format__',
'__getattr__',
'__getattribute__',
'__getitem__',
'__hash__',
'__init__',
'__module__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'_func_flags_',
'_func_restype_',
'_handle',
'_name']
In [35]: lib._func_restype_
Out[35]: ctypes.c_long
答案 0 :(得分:3)
导出符号的一种方法是通过链接器的选项:
cl testdll.c /LD /link /export:sum
这不会扩展。更好的选择是在声明中使用__declspec(dllexport)
修饰符。请参阅Visual Studio文档中的Exporting from a DLL。
有条件地应用如下:
#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);
}
通过导入lib链接时,声明应使用__declspec(dllimport)
,这是TESTAPI
的默认值。构建DLL时,请在项目设置中或通过BUILD_TESTDLL
在命令行中定义/D
。
最后,为了获得最大的灵活性,请使用如下的.def文件:
LIBRARY TESTDLL
EXPORTS
sum @ 10 NONAME
sum_alias=sum @ 20
这允许您使用其他名称导出函数,或仅按顺序导出。将其添加为源文件,如下所示:
cl testdll.c testdll.def /LD
然后在Python中,例如:
>>> from ctypes import *
>>> lib = cdll.testdll
>>> lib.sum_alias(1, 2)
3
>>> lib[10](1, 2)
3
>>> lib[20](1, 2)
3
顺便说一下,ctypes不会从DLL预加载导出。 dir(lib)
一开始不会显示任何函数指针。他们在访问时被缓存:
>>> 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']