myPythonClient (a continuación) quiere invocar una función ringBell (cargada desde una DLL usando ctypes). Sin embargo, intentar acceder a ringBell a través de su nombre da como resultado un 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
8
JaysonFix 6 jul. 2009 a las 21:02

3 respuestas

La mejor respuesta

Tal vez porque el nombre de C ++ está maltratado por el compilador y no se exporta desde la DLL como RingBell. ¿Has comprobado que aparece en los nombres exportados exactamente así?

7
Vinay Sajip 6 jul. 2009 a las 17:08

Su compilador de C ++ está manipulando los nombres de todos los objetos visibles externamente para reflejar (así como sus nombres subyacentes) sus espacios de nombres, clases y firmas (así es posible la sobrecarga).

Para evitar esta manipulación, necesita un extern "C" en los nombres visibles externamente que desea que sean visibles desde el código que no sea C ++ (y, por lo tanto, dichos nombres no se pueden sobrecargar, ni en el estándar C ++ pueden estar en línea, dentro de los espacios de nombres , o dentro de las clases, aunque algunos compiladores de C ++ extienden el estándar en algunas de estas direcciones).

10
Alex Martelli 6 jul. 2009 a las 17:13

Todo está funcionando ahora :) Para resumir tus publicaciones:

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

Entonces puede usar el programa link.exe para ver el nombre real de la función en 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

Luego, en python puedes importarlo 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
9
101 22 jul. 2015 a las 07:03