Вопрос по dll, python – Python: доступ к функции DLL с использованием ctypes - сбой по функции * name *

8

myPythonClient (ниже) хочет вызватьringBell функция (загружается из DLL с помощьюctypes). Тем не менее, пытаясь получить доступringBell через егоname приводит кAttributeError, Зачем?

RingBell.h содержит

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

RingBell.cpp содержит

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

myPythonClient.py содержит

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

Ваш Ответ

3   ответа
7

потому что имя C ++ искажено компилятором и не экспортируется из DLL какRingBell, Вы проверили, что он появляется в экспортированных именах именно так?

Вы были правы. Я использовал следующее, чтобы обнаружить «искалеченный» name: link.exe / dump / exports RingBell.dll и обнаружил, что в DLL имя функции было «? ringBell @ MyClass @ MyNamespace @@ SAHXZ». Спасибо!
Я также упомяну, что я использовал функцию getattr Python для получения ссылки на функцию ringBell: myRingBellFunction = getattr (cdll.RingBell, & quot;? RingBell @ MyClass @ MyNamespace @@ SAHXZ & quot;) функция myRingBellF () снова
10

чтобы отразить (а также их базовые имена) их пространства имен, классы и сигнатуры (таким образом, становится возможной перегрузка).

Чтобы избежать этого искажения, вам нуженextern "C" на внешне видимых именах, которые вы хотите видеть из кода не-C ++ (и поэтому такие имена не могут быть перегружены, ни в стандарте C ++ они не могут быть встроенными, в пространствах имен или в классах, хотя некоторые компиляторы C ++ расширяют стандарт в некоторых эти направления).

Я также благодарю вас! Я дам «extern». попытка
Я дал "extern" Попробуйте, и это сработало! Ниже приведено решение для будущих читателей: #include & lt; iostream & gt; extern "C" __declspec (dllexport) int __cdecl ringBell (void) {std :: cout & lt; & lt; & Quot; \ а & Quot; ; вернуть 0; }
7

Написать DLL в 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;
} 

Затем вы можете использовать программу link.exe, чтобы увидеть реальное имя функции в dll. link.exe находится, например, в MSVC2010 здесь:

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

использовать:

link /dump /exports yourFileName.dll

Вы видите что-то вроде:

ordinal hint RVA      name
      1    0 00001040 [email protected]@[email protected] = [email protected]@[email protected] (int __cdecl MyAdd2(int,int))
      2    1 00001030 MyAdd = _MyAdd

Затем в Python вы можете импортировать его как:

import ctypes

mc = ctypes.CDLL('C:\\testDll3.dll')

#mc.MyAdd2(1,2) # this Won't Work - name is different in dll
myAdd2 = getattr(mc,"[email protected]@[email protected]") #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

Похожие вопросы