我正在尝试使用 Python 使用 SecuGen 指纹扫描仪,我使用的 SDK 库是
sgfplib.dll
。我有一个 C++ 程序,它使用这个 DLL 并使用 C++ 和相同的 DLL 访问硬件。
我还可以使用 Windows 生物识别框架 (winbio.dll
)、Python 和 ctypes 访问设备,但该框架没有我需要的功能。
问题是,使用
sgfplib.dll
,创建主库对象后,我可以很好地获得 dll 的句柄,但每当我尝试调用任何其他函数时,我都会得到 OSError: exception: access violation reading|writing 0x###########
。
我已经搜索了该网站和谷歌寻找类似的错误,但似乎没有什么接近我的问题。我在我的
system32
文件夹中找到了 DLL,我也尝试将它们放入脚本目录中,但没有任何运气
如果我更改 devname 或调用 diff 函数,错误中的地址确实会更改。
任何人都可以指出我正确的方向或提供有关此类错误的更多信息吗?
这是一个最小的可重现示例:
import ctypes
from ctypes import wintypes
lib = ctypes.WinDLL(r"..\pathToTheDLLsDir\sgfplib.dll")
session_handle = ctypes.c_uint32()
devname = ctypes.wintypes.DWORD()
devname = "SG_DEV_FDU05" # 5
err = lib.SGFPM_Create(ctypes.byref(session_handle)) # create an SGFPM object and
print('CREATE', err) # 0 # return a handle to the object
err = lib.SGFPM_Init(ctypes.byref(session_handle), devname) # OSError: exception: access
print('INIT', err) # violation reading 0x00000000AFE3FB10
清单 [Python.Docs]:ctypes - Python 的外部函数库。
这个错误很常见,我已经在 SO 上回答了一堆问题(关于同一主题)。
代码充满了Undefined Behavior。最常见的是 [SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案),在调用函数时遇到。
找到 SecuGen 参考文献(不幸的是没有官方参考文献):
我准备了一个虚拟示例(下载了一个.dll用于测试目的,但由于我没有设备而无法完全测试)。
code00.py:
#!/usr/bin/env python
import ctypes as cts
import ctypes.wintypes as wts
import sys
HSGFPM = cts.c_void_p
DLL_NAME = "./sgfplib.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
# @TODO - cfati: Can add all constants here
SG_DEV_FDU04 = 0x05
SG_DEV_FDU05 = 0x06
def is_error(error_code):
# @TODO - cfati: Assume functions return 0 on success
if error_code != 0:
return True
return False
def main(*argv):
dll = cts.WinDLL(DLL_NAME)
SGFPM_Create = dll.SGFPM_Create
SGFPM_Create.argtypes = (cts.POINTER(HSGFPM),)
SGFPM_Create.restype = wts.DWORD
SGFPM_Init = dll.SGFPM_Init
SGFPM_Init.argtypes = (HSGFPM, wts.DWORD)
SGFPM_Init.restype = wts.DWORD
SGFPM_Terminate = dll.SGFPM_Terminate
SGFPM_Terminate.argtypes = (HSGFPM,)
SGFPM_Terminate.restype = wts.DWORD
handle = HSGFPM()
res = SGFPM_Create(cts.byref(handle))
if is_error(res):
print("Error SGFPM_Create: {:d}".format(res))
return
dev = SG_DEV_FDU04
res = SGFPM_Init(handle, dev)
if is_error(res):
print("Error SGFPM_Init: {:d}".format(res))
SGFPM_Terminate(handle)
return
# Do your thing
SGFPM_Terminate(handle)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
结果我需要通过
GetModuleHandleA
库中的 kernel32
函数获取句柄,然后将其传递给 SGFPM_Create()
函数:
from ctypes import *
lib = ctypes.WinDLL(r"..\pathToTheDLLsDir\sgfplib.dll")
session_handle = windll.kernel32.GetModuleHandleA
lib.SGFPM_Create(ctypes.byref(pointer))
之后我就可以使用
sgfplib.dll
中的所有功能了。