我试图弄清楚为什么在经过多次大量混乱后才能使用
obo.librar_version是一个c函数,它需要char **作为输入并执行strcpy 通过char。
from ctypes import *
_OBO_C_DLL = 'obo.dll'
STRING = c_char_p
OBO_VERSION = _stdcall_libraries[_OBO_C_DLL].OBO_VERSION
OBO_VERSION.restype = c_int
OBO_VERSION.argtypes = [POINTER(STRING)]
def library_version():
s = create_string_buffer('\000' * 32)
t = cast(s, c_char_p)
res = obo.library_version(byref(t))
if res != 0:
raise Error("OBO error %r" % res)
return t.value, s.raw, s.value
library_version()
上面的代码返回
('OBO Version 1.0.1', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', '')
我不明白为什么's'没有任何价值?有人有主意吗? THX
答案 0 :(得分:1)
当您将s
投射到c_char_p
时,您会在t
中存储新对象,而不是参考。因此,当您通过引用将t
传递给您的函数时,s
不会更新。
<强>更新强>
你确实是对的:
cast有两个参数,一个ctypes 是或可以转换为的对象 某种指针和一个ctypes 指针类型。它返回一个实例 第二个论点,哪个 引用相同的内存块 第一个论点。
为了获得对字符串缓冲区的引用,您需要使用以下内容进行转换:
t = cast(s, POINTER(c_char*33))
我不知道为什么c_char_p
没有创建引用,但是你去了。
答案 1 :(得分:0)
因为library_version需要char **,所以他们不希望你分配字符(就像你在使用create_string_buffer一样。相反,他们只是希望你传入对指针的引用,这样他们就可以返回地址了在哪里找到版本字符串。
所以你需要做的就是分配指针,然后传入对该指针的引用。
以下代码应该可以工作,虽然我没有obo.dll(或者知道合适的替代品)来测试它。
from ctypes import *
_OBO_C_DLL = 'obo.dll'
STRING = c_char_p
_stdcall_libraries = dict()
_stdcall_libraries[_OBO_C_DLL] = WinDLL(_OBO_C_DLL)
OBO_VERSION = _stdcall_libraries[_OBO_C_DLL].OBO_VERSION
OBO_VERSION.restype = c_int
OBO_VERSION.argtypes = [POINTER(STRING)]
def library_version():
s_res = c_char_p()
res = OBO_VERSION(byref(s_res))
if res != 0:
raise Error("OBO error %r" % res)
return s_res.value
library_version()
[编辑]
我更进一步,编写了自己的DLL,实现了OBO_VERSION的可能实现,不需要分配字符缓冲区,也不会受到任何内存泄漏。
int OBO_VERSION(char **pp_version)
{
static char result[] = "Version 2.0";
*pp_version = result;
return 0; // success
}
如您所见,OBO_VERSION只是将* pp_version的值设置为指向以null结尾的字符数组的指针。这可能是真正的OBO_VERSION的工作原理。我已根据我上面提到的技术对此进行了测试,并按规定运行。