我熟悉python但不熟悉ctypes。
我一直在玩这个特定的功能(VCS_GetErrorInfo),但无法让它工作。我的问题是访问返回参数。我正在使用Windows 64 Bit,但在Linux下也尝试过。完整的文档,在这种情况下,可以找到Windows库here。
我想打电话的功能就像那样。
BOOL VCS_GetErrorInfo(DWORD ErrorCodeValue, char *pErrorInfo, WORD MaxStrSize)
在pErrorInfo中,我期待"没有通信错误"。
我的代码(已编辑) ...
import ctypes
from ctypes import wintypes
lib = wintypes.WinDLL(r"...\EposCmd64.dll")
lib.VCS_GetErrorInfo.restype = wintypes.BOOL
error_buf_size = ctypes.create_string_buffer(10) # creates a buffer
pErrorInfo = ctypes.c_char_p(ctypes.addressof(error_buf_size)) # creates a pErrorInfo from the error buffer
# And when passing in the function make sure to wrap in the ctypes.byref
result = lib.VCS_GetErrorInfo(wintypes.DWORD(0), ctypes.byref(pErrorInfo), wintypes.WORD(10))
print result
# Later to get the value of the error string
print pErrorInfo, pErrorInfo.value
输出
1
c_char_p('')
仍然没有输出。
错误文档
0x0000 0000, No Communication Error
0x0503 0000, Toggle Error
0x0504 0000, SDO Time Out
...
如果我尝试使用其他错误代码。
result = lib.VCS_GetErrorInfo(wintypes.DWORD(0x05030000), ctypes.byref(pErrorInfo), wintypes.WORD(10))
print result
0
c_char_p('')
我可能错误地传递了ErrorCodeValue。
我也尝试过使用Ubuntu的方法:
import ctypes
ctypes.cdll.LoadLibrary("/path/to/libftd2xx.so")
lib = ctypes.cdll.LoadLibrary("/path/to/libEposCmd.so.5.0.0.3")
def VCS_GetErrorInfo(ErrorCodeValue, MaxStrSize):
lib.VCS_GetErrorInfo.restype = ctypes.c_bool
error_buf_size = ctypes.create_string_buffer(MaxStrSize)
pErrorInfo = ctypes.c_char_p(ctypes.addressof(error_buf_size))
result = lib.VCS_GetErrorInfo(ctypes.c_uint32(ErrorCodeValue), ctypes.byref(pErrorInfo), ctypes.c_uint16(MaxStrSize))
if not result:
raise RuntimeError('get error info failed = {}'.format(pErrorInfo.value))
return pErrorInfo.value
结果看起来很奇怪。
print repr(VCS_GetErrorInfo(0, 10))
'\x05'
print repr(VCS_GetErrorInfo(0, 20))
'0\xe7$\xd7j\x7f'
print repr(VCS_GetErrorInfo(0x05040000, 20))
RuntimeError: get error info failed =
print repr(VCS_GetErrorInfo(0x05040000, 30))
Segmentation fault (core dumped)
答案 0 :(得分:2)
使用__cdecl
调用约定而不是__stdcall
的DLL,因此使用CDLL
而不是WinDLL
:
>>> from ctypes import *
>>> lib=CDLL('EposCmd64')
>>> buf=create_string_buffer(80)
>>> lib.VCS_GetErrorInfo(0x05030000,buf,80)
1
>>> buf.value
b'Toggle Error'
请注意,例如,所有额外的对象构造wintypes.DWORD(0x05030000)
都不是必需的。如果它是一个整数或一个指针,ctypes
会弄清楚它,但需要告诉它结构和浮点值。在这种情况下不需要它,但这是如何显式定义参数和返回值:
>>> from ctypes import *
>>> from ctypes import wintypes
>>> lib=CDLL('EposCmd64')
>>> lib.VCS_GetErrorInfo.argtypes=[wintypes.DWORD,c_char_p,wintypes.DWORD]
>>> lib.VCS_GetErrorInfo.restype=wintypes.BOOL
>>> buf=create_string_buffer(80)
>>> lib.VCS_GetErrorInfo(0x05040000,buf,80)
1
>>> buf.value
b'SDO Protocol Timeout'
由于额外的类型检查和参数匹配,它还可以防止错误地调用函数:
>>> lib.VCS_GetErrorInfo(0x05040000,buf)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: this function takes at least 3 arguments (2 given)
为0
返回空字符串(无错误):
>>> lib.VCS_GetErrorInfo(0,buf,80)
1
>>> buf.value
b''
答案 1 :(得分:0)
通常我使用类似的东西来创建错误消息缓冲区:
error_buf_size = ctypes.create_string_buffer(10) # creates a buffer
pErrorInfo = ctypes.c_char_p(ctypes.addressof(error_buf_size)) # creates a pErrorInfo from the error buffer
# And when passing in the function make sure to wrap in the ctypes.byref
result = lib.VCS_GetErrorInfo(wintypes.DWORD(0), ctypes.byref(pErrorInfo), wintypes.WORD(10))
# Later to get the value of the error string
if pErrorInfo.value:
print (pErrorInfo.value)