在 python 中的 Delphi 上使用 DLL
Using DLL on Delphi in python
我正在尝试从 python 3.4 中的 dll 调用具有以下签名的函数(更多:http://www.lawlabs.ru/parser_address.htm):
function GetAddressFields(
AddressStr: String;
var FullStr: String;
var QualifiedStr: String;
Separator: ShortString = #13#10;
IsRussia: Boolean = True;
WithDescription: Boolean = True;
WithExceptions: Boolean = True;
LastIsHome: Boolean = True;
Subject: Boolean = True;
WithUnrecognized: Boolean = True): String;
我认为语法是 Delphi 并且在使用 ctypes 作为此签名时出现错误。
我对 delphi 和 ctypes 类型的预期匹配:
String -> c_char_p
ShortString -> c_char_p
var String -> POINTER(c_char_p)
boolean -> c_bool
因此 Python 中的函数签名(其中 dll = windll.LoadLibrary(...)):
dll.GetAddressFields.argtypes = (
c_char_p,
POINTER (c_char_p),
POINTER (c_char_p),
c_char_p,
c_bool,
c_bool,
c_bool,
c_bool,
c_bool,
c_bool)
dll.GetAddressFields.restype = c_char_p
但是,此签名出现错误。
尝试传递参数:
param_1 = c_char_p("".encode("ascii"))
param_2 = c_char_p("".encode("ascii"))
result = dll.GetAddressFields(
c_char_p('test'.encode("ascii")),
byref(param_1),
byref(param_2),
c_char_p("\r\n".encode("ascii")),
True,
True,
True,
True,
True,
True)
完整的错误代码为:
OSError: exception: access violation reading 0x00000001
有趣的是,当用 False 替换第一个布尔参数时,我们有
OSError error: exception: access violation reading 0x00000000
当您尝试通过引用传递布尔参数时,随机地址发生错误
如何解决这个问题?
你是对的:那是 Delphi(或 FreePascal),这就是问题所在。
写这个DLL的人恐怕没有想过这个DLL是如何被其他语言使用的。它们导出带有 Delphi 特定参数的函数,例如 string
和 ShortString
, 只能由 Delphi 或 C++Builder[=41= 使用] 与 DLL 具有相同的共享内存管理器,甚至不是所有版本。
所以你将无法直接使用DLL,不能使用C,也不能使用ctypes。 String
不映射到 c_char_p
, 不同的 类型也不映射 ShortString
,等等。唯一匹配的类型是 c_bool
,但这不会让你走得太远。
您可以与 DLL 的作者交谈并告诉他们阅读我关于如何编写也可以被其他语言使用的 DLL 的文章:DLLs dos and don'ts.
或者您可以找到使用 Delphi 或 C++Bulder 为 DLL 编写包装器的人,它包装函数并将特定于 Delphi 的类型转换为 C 兼容类型类型如 char *
(PAnsiChar
) 或 wchar_t *
(PWideChar
).
我无法阅读您链接到的页面,所以我不知道您是否可以访问源代码。如果是这样,您可以尝试找人更改导出,以便它们可以直接从 C 中使用。那么您就不需要包装器了。
FWIW,这些类型也可以在 FreePascal 中找到,但在那里你会遇到同样的问题。解决办法也是一样的。
我正在尝试从 python 3.4 中的 dll 调用具有以下签名的函数(更多:http://www.lawlabs.ru/parser_address.htm):
function GetAddressFields(
AddressStr: String;
var FullStr: String;
var QualifiedStr: String;
Separator: ShortString = #13#10;
IsRussia: Boolean = True;
WithDescription: Boolean = True;
WithExceptions: Boolean = True;
LastIsHome: Boolean = True;
Subject: Boolean = True;
WithUnrecognized: Boolean = True): String;
我认为语法是 Delphi 并且在使用 ctypes 作为此签名时出现错误。
我对 delphi 和 ctypes 类型的预期匹配:
String -> c_char_p
ShortString -> c_char_p
var String -> POINTER(c_char_p)
boolean -> c_bool
因此 Python 中的函数签名(其中 dll = windll.LoadLibrary(...)):
dll.GetAddressFields.argtypes = (
c_char_p,
POINTER (c_char_p),
POINTER (c_char_p),
c_char_p,
c_bool,
c_bool,
c_bool,
c_bool,
c_bool,
c_bool)
dll.GetAddressFields.restype = c_char_p
但是,此签名出现错误。
尝试传递参数:
param_1 = c_char_p("".encode("ascii"))
param_2 = c_char_p("".encode("ascii"))
result = dll.GetAddressFields(
c_char_p('test'.encode("ascii")),
byref(param_1),
byref(param_2),
c_char_p("\r\n".encode("ascii")),
True,
True,
True,
True,
True,
True)
完整的错误代码为:
OSError: exception: access violation reading 0x00000001
有趣的是,当用 False 替换第一个布尔参数时,我们有
OSError error: exception: access violation reading 0x00000000
当您尝试通过引用传递布尔参数时,随机地址发生错误
如何解决这个问题?
你是对的:那是 Delphi(或 FreePascal),这就是问题所在。
写这个DLL的人恐怕没有想过这个DLL是如何被其他语言使用的。它们导出带有 Delphi 特定参数的函数,例如 string
和 ShortString
, 只能由 Delphi 或 C++Builder[=41= 使用] 与 DLL 具有相同的共享内存管理器,甚至不是所有版本。
所以你将无法直接使用DLL,不能使用C,也不能使用ctypes。 String
不映射到 c_char_p
, 不同的 类型也不映射 ShortString
,等等。唯一匹配的类型是 c_bool
,但这不会让你走得太远。
您可以与 DLL 的作者交谈并告诉他们阅读我关于如何编写也可以被其他语言使用的 DLL 的文章:DLLs dos and don'ts.
或者您可以找到使用 Delphi 或 C++Bulder 为 DLL 编写包装器的人,它包装函数并将特定于 Delphi 的类型转换为 C 兼容类型类型如 char *
(PAnsiChar
) 或 wchar_t *
(PWideChar
).
我无法阅读您链接到的页面,所以我不知道您是否可以访问源代码。如果是这样,您可以尝试找人更改导出,以便它们可以直接从 C 中使用。那么您就不需要包装器了。
FWIW,这些类型也可以在 FreePascal 中找到,但在那里你会遇到同样的问题。解决办法也是一样的。