Питон:доступ к функции DLL с использованием ctypes — доступ по функции *имя* невозможен

StackOverflow https://stackoverflow.com/questions/1088085

Вопрос

myPythonClient (ниже) хочет вызвать ringBell функция (загружается из DLL с помощью ctypes).Однако попытка получить доступ ringBell через свой имя приводит к 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
Это было полезно?

Решение

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

Другие советы

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

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

Теперь все работает :) Подводя итог вашим сообщениям:

Напишите 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 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (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,"?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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top