Python: accesso funzione DLL utilizzando ctypes - accesso per funzione * Nome * fallisce
-
23-08-2019 - |
Domanda
myPythonClient
(sotto) vuole richiamare una funzione ringBell
(caricato da una DLL utilizzando ctypes
). Tuttavia, il tentativo di accesso ringBell
attraverso i suoi nome risultato in un AttributeError
. Perché?
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
Soluzione
Forse perché il nome C ++ è storpiato dal compilatore e non esportato dalla DLL come RingBell
. Hai controllato che appare nei nomi esportati esattamente così?
Altri suggerimenti
Il compilatore C ++ è pressare i nomi di tutti gli oggetti visibili esternamente per riflettere (così come i loro nomi sottostanti) i namespace, classi e firme (è così che diventa possibile sovraccarico).
Al fine di evitare questo storpiatura, è necessario un extern "C"
sui nomi visibili esternamente che si desidera rendere visibili dal codice non-C ++ (e quindi tali nomi non possono essere sovraccaricati, nè in serie C ++ che può essere in linea, all'interno di spazi dei nomi, o all'interno delle classi, anche se alcuni C ++ compilatori estendono lo standard in alcune di queste direzioni).
Tutto sta lavorando adesso :) Per riepilogare i tuoi messaggi:
Scrivi 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;
}
Quindi è possibile usare il programma per vedere link.exe vero nome della funzione nella DLL. link.exe è per esempio in MSVC2010 qui:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
utilizzo:
link /dump /exports yourFileName.dll
si vede qualcosa di simile:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Poi in Python è possibile importarlo come:
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