Python: Zugriff auf DLL-Funktion ctypes mit - Zugriff Funktion * Name * schlägt fehl
-
23-08-2019 - |
Frage
myPythonClient
(unten) will eine ringBell
Funktion (aus einer DLL mit ctypes
geladen) aufzurufen. Allerdings versucht ringBell
über seine Name für den Zugriff Ergebnisse in einem AttributeError
. Warum?
RingBell.h
enthält
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
RingBell.cpp
enthält
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
myPythonClient.py
enthält
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
Lösung
Vielleicht, weil der C ++ Name wird vom Compiler verstümmelt und nicht aus der DLL als RingBell
exportiert. Haben Sie überprüft, dass es in den exportierten Namen genau so angezeigt wird?
Andere Tipps
Ihre C ++ Compiler ist Mangeln der Namen aller von außen sichtbaren Objekten zu reflektieren (sowie die zugrunde liegenden Namen) ihre Namespaces, Klassen und Unterschriften (das ist, wie Überlastung möglich wird).
Um diese Mangeln zu vermeiden, benötigen Sie einen extern "C"
auf äußerlich sichtbare Namen, die Sie sichtbar von Nicht-C ++ Code sein soll (und daher solche Namen nicht überlastet werden, noch in C ++ Standard können sie inline sein, innerhalb von Namespaces, oder innerhalb von Klassen, obwohl einige C ++ Compiler den Standard in einigen dieser Richtungen erstrecken).
Alles funktioniert jetzt :) Ihre Beiträge Fassen wir zusammen:
Write DLL in C ++:
// 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;
}
Dann können Sie Programm link.exe verwenden, um echte Funktionsnamen in dll zu sehen. link.exe ist zum Beispiel in MSVC2010 hier:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
Verwendung:
link /dump /exports yourFileName.dll
Sie sehen etwas wie:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Dann in Python Sie können es als importieren:
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