pythondllctypesfingerprint

OSError: exception: access violation reading|writing when calling any function after library instance creation


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

Solution

  • 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):

    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)