Python: el acceso a la función DLL usando ctypes - el acceso de la función * Nombre * falla
-
23-08-2019 - |
Pregunta
myPythonClient
(abajo) quiere invocar una función ringBell
(cargado desde un archivo DLL usando ctypes
). Sin embargo, el intento de acceder a través de sus ringBell
nombre resultados en una AttributeError
. ¿Por qué?
RingBell.h
contiene
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
RingBell.cpp
contiene
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
myPythonClient.py
contiene
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
Solución
Tal vez porque el nombre de C ++ está destrozado por el compilador y no exporta desde el DLL como RingBell
. ¿Ha comprobado que aparezca en los nombres exportados exactamente así?
Otros consejos
Su compilador de C ++ está destrozando los nombres de todos los objetos visibles externamente para reflejar (así como sus nombres subyacentes) sus espacios de nombres, clases y firmas (así es como se hace posible sobrecarga).
Con el fin de evitar este mangling, necesita un extern "C"
sobre los nombres visibles externamente que desea ser visible desde el código no-C ++ (y por lo tanto tales nombres no pueden ser sobrecargados, ni en C ++ estándar puede que sea en línea, dentro de los espacios de nombres, o dentro de las clases, aunque compiladores algunos C ++ extienden el estándar en algunas de estas direcciones).
Todo está trabajando ahora :) Para resumir sus mensajes:
Escribir 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;
}
A continuación, puede utilizar link.exe programa para ver una función real en la DLL. link.exe es por ejemplo en MSVC2010 aquí:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
uso:
link /dump /exports yourFileName.dll
ves algo como:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
A continuación, en Python se puede importar como:
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