I'm trying to make use of a SecuGen Fingerprint scanner using Python, the SDK lib I'm using is sgfplib.dll
. I have a C++ program that makes use of this DLL and access the hardware using C++ and the very same DLL.
I can also access the device using the Windows Biometric Framework (winbio.dll
), Python and ctypes but this framework don't have the functionallity I need.
The thing is, using the sgfplib.dll
, after creation of the main library object I get a handle of the dll just fine, but anytime I try to call any other function I'll get an OSError: exception: access violation reading|writing 0x###########
.
I've searched both the site and google looking for similar errors but nothing seems close to my problem. I got the DLLs in my system32
folder and I also tried putting them in the scripts dir without any luck
The address in the error does change if I change the devname or if I call a diff function.
Can anyone point me in the right direction or provide some more info on this kind of errors?
Here's a min reproducible example:
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
Listing [Python.Docs]: ctypes - A foreign function library for Python.
The error is widely encountered, I've answered a bunch of questions (on the same topic) here on SO.
Code is full of Undefined Behaviors. The most common one is [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer), encountered when calling functions.
Found SecuGen references (no official ones unfortunately):
[GitHub]: cbsan/secugen - (master) secugen/include/sgfplib.h
[RaviRajTech]: FDxSDK-Pro-Programming-Manual-Windows-SG1-0030A-013.pdf
I prepared a dummy example (downloaded a .dll for testing purposes, but couldn't fully test since I don't have the device).
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)