8 python dll ctypes attributeerror
myPythonClient(下面)想要调用一个ringBell函数(使用DLL加载ctypes).但是,尝试ringBell通过其名称访问会导致AttributeError.为什么?
RingBell.h 包含
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
Run Code Online (Sandbox Code Playgroud)
RingBell.cpp 包含
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
Run Code Online (Sandbox Code Playgroud)
myPythonClient.py 包含
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 10
您的C++编译器正在破坏所有外部可见对象的名称,以反映其命名空间,类和签名(以及可能的重载方式)(以及它们的基础名称).
为了避免这种错位,你需要一个extern "C"外部可见的名称,你希望从非C++代码中看到它们(因此这些名称不能重载,也不能在C++标准中,它们可以是内联的,在命名空间内,或在类中,虽然一些C++编译器在某些方面扩展了标准).
现在一切正常:)总结你的帖子:
用C++编写DLL:
// Header
extern "C"
{ // Name in DLL will be "MyAdd" - but you won't be able to find parameters etc...
__declspec(dllexport) int MyAdd(int a, int b);
}
// Name will be with lot of prefixes but some other info is provided - IMHO better approach
__declspec(dllexport) int MyAdd2(int a, int b);
//.cpp Code
__declspec(dllexport) int MyAdd(int a, int b)
{ return a+b;
}
__declspec(dllexport) int MyAdd2(int a, int b)
{ return a+b;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用程序link.exe来查看dll中的实际函数名称.link.exe例如在MSVC2010中:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
Run Code Online (Sandbox Code Playgroud)
使用:
link /dump /exports yourFileName.dll
Run Code Online (Sandbox Code Playgroud)
你看到的东西:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Run Code Online (Sandbox Code Playgroud)
然后在python中你可以导入它:
import ctypes
mc = ctypes.CDLL('C:\\testDll3.dll')
#mc.MyAdd2(1,2) # this Won't Work - name is different in dll
myAdd2 = getattr(mc,"?MyAdd2@@YAHHH@Z") #to find name use: link.exe /dump /exports fileName.dll
print myAdd2(1,2)
#p1 = ctypes.c_int (1) #use rather c types
print mc[1](2,3) # use indexing - can be provided using link.exe
print mc.MyAdd(4,5)
print mc[2](6,7) # use indexing - can be provided using link.exe
Run Code Online (Sandbox Code Playgroud)
也许是因为C++名称被编译器破坏而不是从DLL导出RingBell.您是否检查过它出现的名称中是否完全相同?