C# ZKTeco Fingerprint Scanner Implementation (ZK4500, SLK20M, SLK20R, ZK9500 )

Share

There are requirements where you have to integrate a biometric device into your application for things like user authentication, verifying user information, backing up scanned templates into your system database or export it somewhere remotely etc.

For that very purpose, this blog post is written as a getting started guide with a few pieces of source code such that it helps C# developers to save some valuable time with all the troublesome work.

Table Of Contents

Device Specifications

This blog intends to provide solution for the device models that are listed below. For a complete list of hardware specification and selection guide, grab a copy of the official document.

ZK4500

Model : ZK4500

SDRAM : 320 KB

Comm : USB 2.0 / 1.1 / 1.0

Template : ZKFinger V10.0

SLK20R

Model : SLK20R

SDRAM : 16 MB

Comm : USB 2.0 / 1.1

Template : ZKFinger V10.0; ISO 19794-2; ANSI 379

Model : ZK9500

SDRAM : 16 MB

Comm : USB 2.0 / 1.1

Template : ZKFinger V10.0

Model : SLK20M

SDRAM : 16 MB

Comm : UART ( 115200bps/TTL3.3V) / USB 2.0

Template : ZKFinger V10.0; ISO 19794-2; ANSI 379

If you are using a different model of device like the ZKTeco K14 or iClock, check out my other article :

C# ZKTeco Biometric Device Getting Started

Background

Biometric Devices are being used extensively in many corporations through out the world these days. They are widely used in various fields like social insurance, public security, time attendance, fingerprint encryption, embedded systems and many others.

Companies like ZKTeco manufacture biometric access control and Time and Attendance in various shapes and sizes with different set of features per model. They provide a better way of user authentication and security in organizations comparing to the traditional authentication and authorization mechanisms.

Implementing The SDK

ZKFingerSDK is available for the Linux and the Windows platform. Create an account and head over to this link  in order to grab yourself a copy of the SDK.

The following steps will guide you and help you to successfully implement a ZKTECO Fingerprint scanner using C# code.

Step 1 - Install The Driver

Install the ZKFinger SDK 5.x / ZKOnline SDK 5.x which comes bundled along with the SDK package.

Step 2 - Add Reference To The Class Library

Once you have successfully installed the driver, depending on your operating system architecture, you will find a dll named libzkfpcsharp.dll either in the Windows/system32 or Windows/syswow64 folder.

You will need to add a reference to that dll from your systems folder in your C# project. Here is how to do it :

Add Reference 1
Add Reference to libzkfpcsharp.dll
Reference Added
After adding reference to libzkfpcsharp.dll

Using The Code

You are now ready to implement the fingerprint scanner in your application.

Implement The Provided Class

The libzkfpcsharp.dll provides you with a class named zkfp under the namespace libzkfpcsharp.

In your implementation class file, include the namespace libzkfpcsharp  and implement the class :

using libzkfpcsharp;    // <--- Implement the namespace

namespace YourProject
{
    public class YourClassName
    {
        zkfp fpInstance = new zkfp();  // <--- Create an instance 
    }
}

Initialize The Device

The first step before establishing a connection with a device would be to initialize the device. Return Values: 0 : Initialization Successful Others : Any kind of error
public void InitializeDevice()
{

    int callBackCode = fpInstance.Initialize();
    if (zkfp.ZKFP_ERR_OK == callBackCode)
    {
        int nCount = fpInstance.GetDeviceCount();
        if (nCount > 0)
        {
            for (int index = 1; index <= nCount; index++)
            {
                // Hold these indexes somewere
                // It represents the index of the device you wish to connect to 
            }
            // Connected Successfully
        }
    }
    else {  /* Unable to initialize, Clear previous resources */ }
}

Connect A Device

Connecting to a device requires the index of the device you wish to connect to. The index can be retrieved by calling the GetDeviceCount method from the above section.

Besides establishing a connection  to the device, you need to initialize a few more things like the fingerprint image height and width with can be obtained by calling the GetParameters method. It is recommended to use the  image size parameters  provided by the device instead of using a static height and width.

public void ConnectDevice(int deviceIndex)
{
    int openDeviceCallBackCode = fpInstance.OpenDevice(deviceIndex);

    if (zkfp.ZKFP_ERR_OK != openDeviceCallBackCode)
    {
        // Unable to connect with the device
        return;
    }

    RegisterCount = 0;
    regTempLen = 0;
    iFid = 1;

    for (int i = 0; i < REGISTER_FINGER_COUNT; i++)
    {
        RegTmps[i] = new byte[2048];
    }

    byte[] paramValue = new byte[4];


    // Retrieve the fingerprint image width 
    int size = 4;
    fpInstance.GetParameters(PARAM_CODE_IMAGE_WIDTH, paramValue, ref size);
    zkfp2.ByteArray2Int(paramValue, ref mfpWidth);

    // Retrieve the fingerprint image height
    size = 4;
    fpInstance.GetParameters(PARAM_CODE_IMAGE_HEIGHT, paramValue, ref size);
    zkfp2.ByteArray2Int(paramValue, ref mfpHeight);

    FPBuffer = new byte[mfpWidth * mfpHeight];
    
    // Create a thread to retrieve any new fingerprint and handle device events
    captureThread = new Thread(new ThreadStart(DoCapture));
    captureThread.IsBackground = true;
    captureThread.Start();

    bIsTimeToDie = false;

}

Acquiring Fingerprints

Acquiring fingerprint is normally handled by calling the AcquireFingerprint method which gets called upon time to time by the thread that we just setup in the previous section.

On a successful fingerprint capture, it passes the message to the form handle which then acts upon based on the type of message retrieved.

For sending message we need to setup a form handle such that the SendMessage command can pass the message to the respected Form.

const int MESSAGE_CAPTURED_OK = 0x0400 + 6;
byte[] CapTmp = new byte[2048];
int cbCapTmp = 2048;
IntPtr FormHandle = IntPtr.Zero; // To hold the handle of the form
private void DoCapture()
{
    try
    {
        while (!bIsTimeToDie)
        {
            cbCapTmp = 2048;
            int ret = fpInstance.AcquireFingerprint(FPBuffer, CapTmp, ref cbCapTmp);

            if (ret == zkfp.ZKFP_ERR_OK)
            {
                SendMessage(FormHandle, MESSAGE_CAPTURED_OK, IntPtr.Zero, IntPtr.Zero);
            }
            Thread.Sleep(100);
        }
    }
    catch { }
}


[DllImport("user32.dll", EntryPoint = "SendMessageA")]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
 
private void FingerPrintControl_Load(object sender, EventArgs e) { FormHandle = this.Handle; }
 

Handling Messages

The message that was passed by doing a PInvoke to the SendMessage method is handled by the  DefWndProc method
protected override void DefWndProc(ref Message m)
{
    switch (m.Msg)
    {
        case MESSAGE_CAPTURED_OK:
            // All your registration and verification code needs to be handled here
            if (isRegistering)
            {
                // Code to be executed in case of registration
                // Checkout the 'Registration Case' explained below
            }
            else
            {
                // Code to be executed in case of fingerprint verification 
                // and any random fingerprint 
                // Checkout the 'Identification and Match' case explained below 
            }

            break;

        default:
            base.DefWndProc(ref m);
            break;
    }
}

Fingerprint Acquisition : Registration Case

Registration is generally a 3 step process. i.e The current user must input his same fingerprint 3 times continuously in order to be successfully enrolled.

private void RegistrationCase()
{
    int fid = 0, score = 0;
    int returnValue = fpInstance.Identify(CapTmp, ref fid, ref score);

    if (zkfp.ZKFP_ERR_OK == returnValue)
    {
        // Remove the previous fingerprint from memory
        int deleteCode = fpInstance.DelRegTemplate(fid);   
        if (deleteCode != zkfp.ZKFP_ERR_OK)
        {
            // The fingerprint is already registered
            return;
        }
    }

    // Check if the user has enterd the fingerprint 3 times or not
    if (RegisterCount > 0 && fpInstance.Match(CapTmp, RegTmps[RegisterCount - 1]) <= 0)
    {
        return;
    }

    Array.Copy(CapTmp, RegTmps[RegisterCount], cbCapTmp);

    RegisterCount++;
    if (RegisterCount >= REGISTER_FINGER_COUNT)
    {

        RegisterCount = 0;
        // Generate a fingerprint template by the combination of 3 successfully fingerprint acquisition
        returnValue = fpInstance.GenerateRegTemplate(RegTmps[0], RegTmps[1], RegTmps[2], RegTmp, ref regTempLen);

        if (zkfp.ZKFP_ERR_OK == returnValue)
        {

            // LOAD TEMPLATE TO MEMORY
            returnValue = fpInstance.AddRegTemplate(iFid, RegTmp);        

            if (zkfp.ZKFP_ERR_OK == returnValue)
            {
                string fingerPrintTemplate = string.Empty;
                zkfp.Blob2Base64String(RegTmp, regTempLen, ref fingerPrintTemplate);

                // ******** fingerPrintTemplate holdes the successfully enrolled fingerprint *******

            }
            else
            {
                // Failed to add template
            }

        }
        else
        {
            // Unable to enroll due to some reason
        }

        return;
    }
    else
    {
        // Requires 3 fingerprints to successfully enroll
        // Ask for the same fingerprint 2 more times
        int remainingCont = REGISTER_FINGER_COUNT - RegisterCount;
    }

}

Fingerprint Acquisition : Identification and Match Case

Besides registration, fingerprint can also be retrieved in order to identify a certain user or match his or her fingerprint template. This process is handled by the second condition in the DefWndProc method
private void RandomFingerprintCase()
{
    // Identifying, Matching and handling anonymous fingerprints needs to be done here

    if (regTempLen <= 0)
    {
        // Un-identified fingerprint
        return;
    }

    if (isIdentifying)
    {
        int ret = zkfp.ZKFP_ERR_OK;
        int fid = 0, score = 0;
        ret = fpInstance.Identify(CapTmp, ref fid, ref score);
        if (zkfp.ZKFP_ERR_OK == ret)
        {
            // Identification Success
            return;
        }
        else
        {
            // Identification Failed
            return;
        }
    }
    else
    {
        int ret = fpInstance.Match(CapTmp, RegTmp);
        if (0 < ret)
        {
            // Match Success
            return;
        }
        else
        {
            // Match Failed
            return;
        }
    }
}

Disconnect The Device

While disconnecting from the device, you also need to abort any running threads and free up the resources. Here is how you should do it :

private void DisconnectDevice()
{
    int result = fpInstance.CloseDevice();  // Close the connection
    captureThread.Abort();     // Abort any running threads

    if (result == zkfp.ZKFP_ERR_OK)
    {
        result = fpInstance.Finalize();   // Clear the resources
        if (result == zkfp.ZKFP_ERR_OK)
        {
            // Reset any variables and data if necessary
        }
        
    }
}

Head over to the GitHub code sample and see it in full action.

Here is a demo app if you wish to see how if functions. Don`t forget to install the driver first.

Go Beyond the frontiers of yourself. Peace !!!

You may also like...

31 Responses

  1. Valentin Hernandez says:

    Hello,

    I’m trying to use your example code with a project, using SQL server, but I can’t find where is the variable to save at my Database , and compare with the registers, I think this variable is ret but this his a int, can you helpme whit this?

    I’m using the biometric model SLK20R and SQLServer in C#

  2. Salman says:

    nable to load DLL ‘libzkfp.dll’: The specified module could not be found. (Exception from HRESULT: 0x8007007E)

  3. Motee shaban says:

    Hello Ozesh,
    Thank you for the source code it worked very well in my Laptop and connected perfect with zk4500 but when i try to connect zk4500 in my PC the application return code -6
    Unable to connect with the device! ( Return Code: -6 )
    what should i do to solve it?

    the button Free resources Not work !

    thank you

    • Ozesh says:

      Hello Motee,

      There might be many reasons behind your current issue.
      Two possible reasons might include:

      1. The device driver is not properly installed.
      2. There is something wrong with the usb port where you have connected the device.

      Also do check for potential issues in the windows event viewer regarding the connected device.

  4. Mario I says:

    Hello,
    Thank you for the code, I try to pass to the fpInstance.AddRegTemplate the template that it´s save in a DB, but always the function return -13 any idea?
    I don´t call the fpInstance.GenerateRegTemplate because in teory the template that is save in the DB it’s the real

    • Ozesh says:

      Hello Mario,
      -13 is the error code for possibly an invalid fingerprint template.
      1. Check to see if the RegTmp that you are providing to the device is a valid template which you have obtained with 3 successful enrollments.
      2. The Zkteco Scanner can only accept a verified template from any zkteco devices and not any other model of devices rather than a Zkteco model.

  5. Rikus says:

    Hello Ozesh,
    How do you get the registerted finger template as an image?

  6. Aubrey Ballesteros says:

    Hello Ozesh,
    Thank you for the source code. I have learned a lot from it. I just want to ask if there are any possibilities that those libraries may work with this ZK TX628 model of biometrics device. I am unable to detect any connected device so far. Am I missing anything? Please advice. Thank you.

  7. Zahid says:

    Can you help me with WPF application?
    I want to show this in a user control.
    Protected override void DefWndProc(ref Message m) I can’t use it for WPF its belong to WinForm

  8. Shafeek Babu says:

    How to implement this on asp.net web application? Is it possible?
    If i tried its only working asp.net windows application.
    Your replays are highly appreciated

    • Ozesh says:

      Hello Shafeek,

      No, you can`t integrate a ZKTeco Fingerprint scanner in a web application directly.
      However, there are other approaches to achieve the web application integration.
      Some of them are :
      1. Via an intermediate custom application to handle fingerprint enrollments and exporting data to the web api or server.
      2. Via the ADMS feature which are available in some of ZKTeco models.

  9. Rikus says:

    Thank you Ozesh. But I am trying to create a image of the 3 finger images that are merged? Can I save that merged template to my database for a small attendance program I am writing and then match it with a new scanned finger print to verify it?

    • Ozesh says:

      Hello Rikus,

      Yes, the merged template can be easily saved and later on used to verify the user.
      But note that, the fingerprint template and the fingerprint image are two different things.

  10. Upnext says:

    Hello my device is Bio31M. The application can’t detect the device. May i know what is the problem?

  11. Joe says:

    Guys does anybody know if this lib can be used to vb6 classic? If not, is there a library for zk9500 designed for vb6 classic?

    Thank you for your response.

  12. anjum ilyas says:

    Hello.
    I need your help to develop web service for my asp.net project. i want to syncing my devices. please share your contact where i will communicate you. thank you very much.

  13. Rajaram Amirthalingam says:

    Does this libzkfpcsharp supports ZK7500 FINGER PRINT READER DEVICE?

    • Ozesh says:

      Hello Rajaram,
      I have not got the chance to try it out with the ZK7500 model.
      If you have tested it out and if it works for you, Please do inform.
      I will include ZK7500 as well as one of the supported devices.

      Thank you.

  14. Luis says:

    Hello Ozesh, thank you.
    I need capture the fingerprint with the SLK20R and then put them on the SilkBio-100TC device. It’s possible?
    Tank you so much.
    Sorry for my english 🙂

    • Ozesh says:

      Hello Luis,

      I think so. I tried out something similar once and it worked.
      There is a sort of backward compatibility with the Zkteco devices.

      It seems that a higher model of device which uses a higher version of the biometric algorithm supports fingerprint templates from those of a lower one.
      However, a lower model device using a lower biometric algorithm might not support a fingerprint template from a higher one.

      Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *