Поскольку для library_version требуется символ **, они не хотят, чтобы вы выделяли символы (как вы делаете с 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 для указателя на символьный массив с нулевым символом в конце. Вероятно, так работает настоящий OBO_VERSION. Я проверил это с моей первоначально предложенной техникой выше, и она работает как предписано.