Python: l'accès à la fonction DLL à l'aide ctypes - nom d'accès par la fonction * * échoue
-
23-08-2019 - |
Question
myPythonClient
(ci-dessous) souhaite invoquer une fonction de ringBell
(chargé à partir d'une DLL en utilisant ctypes
). Cependant, la tentative d'accès ringBell
via ses nom Résultats dans un AttributeError
. Pourquoi?
RingBell.h
contient
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
RingBell.cpp
contient
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
myPythonClient.py
contient
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
La solution
Peut-être parce que le nom C ++ est mutilée par le compilateur et non exportée de la DLL comme RingBell
. Avez-vous vérifié qu'il apparaît dans les noms exportés exactement comme ça?
Autres conseils
Votre compilateur C ++ est mutiler les noms de tous les objets visibles de l'extérieur pour refléter (ainsi que leurs noms sous-jacents) leurs espaces de noms, les classes et les signatures (c'est comment devient possible surcharge).
Pour éviter ce mutiler, vous avez besoin d'un extern "C"
sur les noms visibles de l'extérieur que vous souhaitez être visible à partir du code non-C ++ (et par conséquent ces noms ne peuvent être surchargées, ni en C ++ standard peuvent-ils en ligne, dans les espaces de noms, ou dans les classes, bien que certains C compilateurs étendent la norme dans certaines de ces directions).
Tout fonctionne maintenant :) Pour résumer vos messages:
Ecrire DLL en 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;
}
Ensuite, vous pouvez utiliser link.exe programme pour voir son vrai nom de fonction dll. link.exe est par exemple MSVC2010 ici:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
utilisation:
link /dump /exports yourFileName.dll
vous voyez quelque chose comme:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Ensuite, en python, vous pouvez l'importer comme:
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