Вот я добрался и до Python. Так сказать – первые пробы пера. Но куда я в Python без Delphi? Сегодня столкнулся с тем, что в Python нужно было вызвать функцию из DLL, которая была написана много лет тому назад на Delphi.
Немного общей теории. Для вызова функций из сторонних библиотек в Python есть специальный модуль - ctypes. Этот модуль предоставляет разработчику C-совместимые типы данных и позволяет вызывать функции под различными операционными системами. Для загрузки динамических библиотек модуль ctypes предоставляет три метода:
Даже для меня, человека, который плохо знает Python, вызвать функцию из DLL оказалось очень легко.
Немного общей теории. Для вызова функций из сторонних библиотек в Python есть специальный модуль - ctypes. Этот модуль предоставляет разработчику C-совместимые типы данных и позволяет вызывать функции под различными операционными системами. Для загрузки динамических библиотек модуль ctypes предоставляет три метода:
- cdll - загружает библиотеки, которые экспортируют функции используя соглашение о вызовах cdecl;
- windll - загружает библиотеки, которые экспортируют функции используя соглашение о вызовах stdcall;
- oledll - загружает библиотеки, которые экспортируют функции используя соглашение о вызовах stdcall и предполагает, что результат функции имеет тип HRESULT (как это требуют COM/OLE).
library xyz; function TestW(const pText1, pText2: PChar): PChar; stdcall; begin Result := ...; end; function TestA(const pText1, pText2: PAnsiChar): PAnsiChar; stdcall; begin Result := ...; end; exports TestA, TestW; begin end.Как вы видите, DLL экспортируют функции используя соглашение о вызовах stdcall, поэтому загружаем ее с помощью метода windll:
import ctypes text1 = 'Привет' text2 = 'Delphi' # загружаем DLL lib = ctypes.WinDLL('xyz.dll') # получаем функцию funcTest = lib.TestW # задаем типы параметров функции funcTest.argtypes = ctypes.c_wchar_p, ctypes.c_wchar_p # задаем тип результата функции funcTest.restype = ctypes.c_wchar_p # вызываем функцию и выводим результат ее выполнения print(funcTest(text1, text2))Вызов функции с параметрами типа PAnsiChar немного сложнее:
import ctypes text1 = 'Привет' text2 = 'Delphi' lib = ctypes.WinDLL('xyz.dll') funcTest = lib.TestA funcTest.restype = ctypes.c_char_p funcTest.argtypes = ctypes.c_char_p, ctypes.c_char_p print(funcTest(text1.encode(), text2.encode()).decode())Как вы видите, кроме изменения типа параметров, в коде появились вызовы методов encode() и decode(). Метод encode() кодирует параметры в байтовые строки. Если это не сделать, то во время выполнения программы мы получим ошибку:
ctypes.ArgumentError: argument 1:Метод decode() выполняет обратную операцию – он декодирует результат выполнения функции из байтовой строки. Если это не сделать, то print, при выводе результата функции, вместо русских букв выведет байты. Например, строка "Привет Python" превратится в "b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82 Python'".: wrong type
Даже для меня, человека, который плохо знает Python, вызвать функцию из DLL оказалось очень легко.
ну ты герой, для меня питон это дичь конченная, одни отступы чего стоят...
ОтветитьУдалитьНу не знаю... Все вокруг как раз копья ломают по "begin-end" или "{-}", а тут просто идеальное решение.
ОтветитьУдалитьКакой шикарный код.
ОтветитьУдалитьfunction TestW(const pText1, pText2: PChar): PChar; stdcall;
Особенно в случаях когда строковый буфер будет разрушен после финализации функции и снаружи будет происходить работа с указателем на освобожденные данные :)))