Python: доступ к функции DLL с использованием ctypes – доступ по функции * имя * не работает

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

RingBell.h содержит

  • AttributeError: объект 'module' не имеет атрибута 'cbook'
  • Нет атрибута «SMTP», ошибка при попытке отправить электронную почту на Python
  • Python3 AttributeError: объект 'list' не имеет атрибута 'clear'
  • Python regex AttributeError: объект 'NoneType' не имеет атрибута 'group'
  • import urllib.parse не работает, когда Python запускается из командной строки
  • Ошибка при запуске библиотеки на python
  •  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 

  • python "import datetime" vs "из datetime import datetime"
  • Передать список Python во встроенную функцию Rust
  • Обтекание простого примера c ++ с помощью ctypes; ошибка сегментации
  • Python: простая загрузка dll ctypes дает ошибку
  • Python SqlAlchemy - AttributeError: mapper
  • python ctypes pragma pack для выровненного байта
  • 3 Solutions collect form web for “Python: доступ к функции DLL с использованием ctypes – доступ по функции * имя * не работает”

    Возможно, потому, что имя C ++ RingBell компилятором и не экспортировано из 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 
    Python - лучший язык программирования в мире.