Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 12, 2010 17:10:07

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с передачей данных в функцию из dll

Создаю простейшую с помощью 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)



Офлайн

#2 Фев. 12, 2010 17:58:52

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Проблема с передачей данных в функцию из dll

WINFUNCTYPE используется только для python callback.
Вам нужно писать что-то вроде
SomeFunction = windll.firts_dll
SomeFunction.argtypes =



Офлайн

#3 Фев. 12, 2010 18:13:19

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с передачей данных в функцию из dll

Попробовал так:

SomeFunction = windll.first_dll.SomeFunction
SomeFunction.argtypes = [c_double]
эффект тот же.



Офлайн

#4 Фев. 12, 2010 19:59:34

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Проблема с передачей данных в функцию из dll

Ээээ. calling conventions?
windll - это stdcall. По умолчанию в msvc используется cdecl, насколько я помню. Или меняйте windll на cdll или пишите в заголовке
extern “C” __declspec(dllexport) void __stdcall SomeFunction(double data);



Офлайн

#5 Фев. 12, 2010 21:24:35

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с передачей данных в функцию из dll

Андрей Светлов
Ээээ. calling conventions?
Если было бы так, то функции совсем бы не находились. Но они находятся, и даже данные передаются, но почему-то после передачи данных вызывается исключение.

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

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



Офлайн

#6 Фев. 12, 2010 21:58:30

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с передачей данных в функцию из dll

Вру. Прошел без исключений такой вариант (без __stdcall):

SomeFunction = cdll.first_dll.SomeFunction
SomeFunction.argtypes =

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

Ладно. Буду отсыпаться и читать теорию, может и пойму :)



Офлайн

#7 Фев. 12, 2010 22:21:25

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Проблема с передачей данных в функцию из dll

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

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

Вдогонку - http://en.wikipedia.org/wiki/Name_mangling



Отредактировано (Фев. 12, 2010 22:22:46)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version