Найти - Пользователи
Полная версия: Проблема с передачей данных в функцию из dll
Начало » Python для новичков » Проблема с передачей данных в функцию из dll
1
Kogrom
Создаю простейшую с помощью MinGW dll с двумя функциями:
#include <windows.h>
extern "C" __declspec(dllexport) void SomeFunction(double data)
{
if (data < 0)
MessageBoxA(0, "less than zero", "DLL Message", MB_OK | MB_ICONERROR);
}
extern "C" __declspec(dllexport) void EmptyFunction()
{
MessageBoxA(0, "EmptyFunction", "DLL Message", MB_OK | MB_ICONERROR);
}
Затем пытаюсь запустить с помощью скрипта:
from ctypes import *
from ctypes.wintypes import*

EmptyFunction = WINFUNCTYPE(None)(
("EmptyFunction", windll.first_dll))

SomeFunction = WINFUNCTYPE(None, c_double)(
("SomeFunction", windll.first_dll), ((1, "data", 0.0),))

EmptyFunction()
SomeFunction(-1.0)
Так вот EmptyFunction срабатывает без проблем, а SomeFunction тоже срабатывает, MessageBox выдается с учетом знака, но после неё выдаётся исключение:
Traceback (most recent call last):
File "....py", line 11, in <module>
SomeFunction(-1.0)
ValueError: Procedure probably called with too many arguments (8 bytes in excess)
Андрей Светлов
WINFUNCTYPE используется только для python callback.
Вам нужно писать что-то вроде
SomeFunction = windll.firts_dll
SomeFunction.argtypes =
Kogrom
Попробовал так:
SomeFunction = windll.first_dll.SomeFunction
SomeFunction.argtypes = [c_double]
эффект тот же.
Андрей Светлов
Ээээ. calling conventions?
windll - это stdcall. По умолчанию в msvc используется cdecl, насколько я помню. Или меняйте windll на cdll или пишите в заголовке
extern “C” __declspec(dllexport) void __stdcall SomeFunction(double data);
Kogrom
Андрей Светлов
Ээээ. calling conventions?
Если было бы так, то функции совсем бы не находились. Но они находятся, и даже данные передаются, но почему-то после передачи данных вызывается исключение.

Но я всякие варианты пробовал. Но или вообще функции не находятся или данные передаются с исключением (как в приведенном мною примере). Конечно, можно пойти на плохокодерскую меру - ловить исключение и глушить его. Тогда работает без проблем. Главное, чтобы в функции данные шли в одну сторону.

Скорее всего, действительно чего-то я в C++ коде напутал. Ну, может ещё сказывается то, что питон собран микрософтовским компилятором, а dll-ка - с помощью MinGW.
Kogrom
Вру. Прошел без исключений такой вариант (без __stdcall):

SomeFunction = cdll.first_dll.SomeFunction
SomeFunction.argtypes =

Однако, со __stdcall и windll почему то не сработало.

Ладно. Буду отсыпаться и читать теорию, может и пойму :)
Андрей Светлов
Есть два ортогональных понятия: calling conventions и name mangling.
Первое отвечает за то, как параметры ложатся на стек и регистры, откуда берется возвращаемое значение и кто стек чистит. К слову, в amd64 (он же x86_64) есть только один calling convention и это здорово. Он вполне универсален и подходит на все случаи жизни.
Второе пришло с С++. Когда-то был только С и имена в нем просто имели префикс “_”. Потом появился С++ и стало нужно как-то записывать “функция-член f класса A”. Каждый компилятор решал проблему по своему (не было и до сих пор нет единого стандарта). При этом для перегрузки функций по сигнатуре кодируют еще и типы принимаемых параметров.

Исключение про “что-то на стеке порушилось” относится к первому случаю.

Вдогонку - http://en.wikipedia.org/wiki/Name_mangling
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB