9

myPythonClient(下)想要调用一个ringBell函数(使用 DLL 从 DLL 加载ctypes)。但是,尝试ringBell通过其名称访问会导致AttributeError. 为什么?

RingBell.h包含

namespace MyNamespace
    {
    class MyClass
        {
        public:
            static __declspec(dllexport) int ringBell ( void ) ;
        } ;
    }

RingBell.cpp包含

#include <iostream>
#include "RingBell.h"
namespace MyNamespace
    {
    int __cdecl MyClass::ringBell ( void )
        {
        std::cout << "\a" ;
        return 0 ;
        }
    }

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
4

3 回答 3

11

您的 C++ 编译器正在修改所有外部可见对象的名称以反映(以及它们的底层名称)它们的名称空间、类和签名(这就是重载成为可能的方式)。

为了避免这种混乱,您需要一个extern "C"外部可见的名称,您希望在非 C++ 代码中可见(因此这些名称不能被重载,在 C++ 标准中它们也不能是内联的、命名空间内的或类内的,尽管一些 C++ 编译器在其中一些方向上扩展了标准)。

于 2009-07-06T17:13:35.223 回答
10

现在一切正常 :) 总结您的帖子:

用 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;
} 

然后你可以使用程序li​​nk.exe查看dll中的真实函数名。link.exe 例如在 MSVC2010 中:

c:\program files\microsoft visual studio 10.0\VC\bin\link.exe

利用:

link /dump /exports yourFileName.dll

你会看到类似的东西:

ordinal hint RVA      name
      1    0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
      2    1 00001030 MyAdd = _MyAdd

然后在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
于 2011-12-12T12:02:01.130 回答
7

可能是因为 C++ 名称被编译器破坏,而不是从 DLL 导出为RingBell. 您是否检查过它是否完全像这样出现在导出的名称中?

于 2009-07-06T17:08:32.817 回答