2009-07-06 12 views
7

myPythonClient(下記)は​​を使用してDLLからロードされたringBell関数を呼び出したいとします。ただし、の名前を介してringBellにアクセスしようとすると、AttributeErrorになります。どうして?Python:ctypesを使用したDLL関数へのアクセス - 関数* name *によるアクセスが失敗しました

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が含まれている含まれているC++の名前がコンパイラによって壊さとRingBellとしてDLLからエクスポートされていないため、

おそらく
from ctypes import * 
cdll.RingBell[1]() # this invocation works fine 
cdll.RingBell.ringBell() # however, this invocation errors out 
# AttributeError: function 'ringBell' not found 

答えて

7

が含まれています。エクスポートされた名前にそのように表示されていることを確認しましたか?

+2

あなたは正しいです。 link.exe/dump/exports RingBell.dll と、DLL内で、関数の名前が "?ringBell @ MyClass @ MyNamespace @@ SAHXZであることが判明しました。 " ありがとうございます! –

+2

また、私はringBell関数への参照を得るためにPythonのgetattr関数を使用したことにも言及します: myRingBellFunction = getattr(cdll.RingBell、 "?ringBell @ MyClass @ MyNamespace @@ SAHXZ") myRingBellFunction()#関数を呼び出すもう一度 –

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

を次にあなたはDLL内の実際の関数名を確認するために、プログラムLINK.EXEを使用することができます

+0

あなたにもありがとう! 私は "extern"を試してみます。 –

+0

私は "extern"に試してみました。ソリューションは、将来の読者のために以下の通りです: の#include にextern "C" __declspec(のdllexport)int型__cdecl ringBell(無効) \t { \tのstd :: coutの<<は "\ A"; \t return 0; \t} –

7

すべてはあなたの記事を要約すると:)今取り組んでいます。 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 [email protected]@[email protected] = [email protected]@[email protected] (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,"[email protected]@[email protected]") #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 
関連する問題