Pergunta

myPythonClient (abaixo) quer para chamar uma função ringBell (carregado a partir de uma DLL usando ctypes). No entanto, tentando acessar ringBell através da sua nome resulta em um AttributeError. Por quê?

RingBell.h contém

namespace MyNamespace
    {
    class MyClass
        {
        public:
            static __declspec(dllexport) int ringBell ( void ) ;
        } ;
    }

RingBell.cpp contém

#include <iostream>
#include "RingBell.h"
namespace MyNamespace
    {
    int __cdecl MyClass::ringBell ( void )
        {
        std::cout << "\a" ;
        return 0 ;
        }
    }

myPythonClient.py contém

from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
Foi útil?

Solução

Talvez porque o nome do C ++ é massacrado pelo compilador e não exportados da DLL como RingBell. Você verificou que ele aparece nos nomes exportados exatamente assim?

Outras dicas

O seu compilador C ++ está mutilando os nomes de todos os objetos visíveis externamente para refletir (bem como seus nomes subjacentes) seus namespaces, classes e assinaturas (que é como a sobrecarga torna-se possível).

A fim de evitar este mangling, você precisa de um extern "C" sobre os nomes dos externamente visíveis que você quer ser visível a partir do código não-C ++ (e, portanto, esses nomes não podem ser sobrecarregados, nem no padrão C ++ que pode ser em linha, dentro de namespaces, ou dentro das classes, embora alguns compiladores C ++ estender o padrão em algumas destas indicações).

Tudo está trabalhando agora :) Para resumir suas mensagens:

Write DLL em 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;
} 

Em seguida, você pode usar o programa link.exe para ver o nome real função na dll. Link.exe é, por exemplo, em MSVC2010 aqui:

c:\program files\microsoft visual studio 10.0\VC\bin\link.exe

uso:

link /dump /exports yourFileName.dll

você ver 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

Então, em python, você pode importá-lo 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top