我试图用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使用,它们与DLL具有相同的共享内存管理器,甚至不能用于所有这些版本。
因此,您将无法直接使用DLL,不能使用C而不使用ctypes。 String
没有映射到c_char_p
,也没有映射到ShortString
等。唯一匹配的类型是c_bool
,但这不会让你走得很远。
您可以与DLL的作者交谈并告诉他们阅读我关于如何编写可供其他语言使用的DLL的文章:DLLs dos and don'ts。
或者您可以找到为DLL编写包装器的人,使用Delphi或C ++ Bulder,它包装函数并将特定于Delphi的类型转换为C兼容类型,如char *
(PAnsiChar
)或wchar_t *
(PWideChar
)。
我无法读取您链接的页面,因此我不知道您是否可以访问源代码。如果是这样,您可以尝试找到更改导出的人,以便可以直接从C使用。那么您将不需要包装器。
FWIW,这些类型也可以在FreePascal中找到,但是你有同样的问题。解决方案也是一样的。