Write AAMVA Driver's License Barcode - Windows C DLL

This tutorial shows how to create a Windows C/C++ API application that writes PDF417 AAMVA standard barcodes using the LEADTOOLS SDK.

Overview  
Summary This tutorial covers how to use LEADTOOLS AAMVA Builder SDK technology in a Windows C DLL Application.
Completion Time 30 minutes
Visual Studio Project Download tutorial project (20 KB)
Platform Windows C DLL Application
IDE Visual Studio 2017, 2019
Development License Download LEADTOOLS
Try it in another language

Required Knowledge

Before working on the Write AAMVA Driver's License Barcode - Windows C DLL tutorial, get familiar with the basic steps of creating a project and loading/displaying an image by reviewing the Add References and Set a License and Load, Display and Save Images tutorials.

Create the Project and Add LEADTOOLS References

Start with a copy of the 64-bit Windows API project created in the Load, Display and Save Images tutorial. If the project is not available, create it by following the steps in that tutorial.

To build AAMVA data and write barcodes using LEADTOOLS, add the required header and DLL files. Open the pre-compiled header file (either pch.h or stdafx.h, depending on the version of Visual Studio used) and add the following lines:

#include "C:\LEADTOOLS22\Include\Ltbar.h" 
#pragma comment (lib, "C:\\LEADTOOLS22\\Lib\\CDLL\\x64\\Ltbar_x.lib") // barcode and AAMVA support 

Note

For a full list of which DLLs are required for specific toolkit features or file formats, refer to Files to be Included With Your Application.

For details on needed Barcode DLLs, see the help topic Barcode Files to be Included With Your Application.

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit functionality is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Note

Adding LEADTOOLS references and setting a license are covered in more detail in the Add References and Set a License tutorial.

Add the AAMVA Build Data Code

With the project created, the references added, the license set, and the load and display image code added, coding can begin.

The steps below are for Visual Studio 2019; they could be different for other versions of Visual Studio.

Go to the Solution Explorer and double-click the resources file (.rc).

Add a new &Barcode drop down menu next to the File menu. In the newly added &Barcode menu, add a &Write AAMVA Barcode menu item. The new item's ID should be ID_BARCODE_WRITEAAMVABARCODE.

Go to the WndProc function and under the switch (wmId) statement that is below the WM_COMMAND case, add a new case:

switch (wmId) 
{ 
case ID_BARCODE_WRITEAAMVABARCODE: 
{ 
   // create empty bitmap and fill it with light color 
   BITMAPHANDLE BarcodeBmp = { 0 }; 
   int w = 700, h = 450; 
   L_CreateBitmap(&BarcodeBmp, sizeof LEADBmp, TYPE_CONV, w, h, 24, ORDER_BGR, NULL, BOTTOM_LEFT, NULL, 0); 
   BarcodeBmp.XResolution = BarcodeBmp.YResolution = 200; 
   L_FillBitmap(&BarcodeBmp, RGB(255, 200, 150)); 
   L_CHAR* data = NULL; 
   L_UINT dataLength = 0; 
   L_INT nRet = SetAAMVAIDInformation(&data, &dataLength); 
   if (nRet != SUCCESS) 
   { 
      MessageBox(hWnd, TEXT("Error setting AAMVA information"), TEXT("Barcode Demo"), MB_ICONERROR); 
      if (data) 
         L_BarCodeAAMVAMemoryFree(data); 
      break; 
   } 
   if (WritePdf417Barcode(hWnd, &BarcodeBmp, data, dataLength) == SUCCESS) 
   { 
      if (LEADBmp.Flags.Allocated) 
         L_FreeBitmap(&LEADBmp); 
      LEADBmp = BarcodeBmp; //this copies the structure without copying the image data 
      InvalidateRect(hWnd, NULL, TRUE); 
   } 
   if (data) 
      L_BarCodeAAMVAMemoryFree(data); 
} 
break; 
// keep rest of the code as is 

Add a new SetAAMVAIDInformation function and add the following code to it. This function can be placed above the WndProc function:

L_INT SetAAMVAIDInformation(L_CHAR** pData, L_UINT* pDataLength) 
{ 
   AAMVAIDBUILDER Builder = { 0 }; 
   L_INT nRet = L_BarCodeAAMVAIDBuilderInit(&Builder); 
   if (nRet != SUCCESS) return nRet; 
 
   nRet = L_BarCodeAAMVAIDBuilderSetJurisdiction(&Builder, L_AAMVA_JURISDICTION_PENNSYLVANIA, NULL); 
   if (nRet != SUCCESS) return nRet; 
 
   nRet = L_BarCodeAAMVAIDBuilderSetJurisdictionVersion(&Builder, "00"); 
   if (nRet != SUCCESS) return nRet; 
 
   nRet = L_BarCodeAAMVAIDBuilderSetVersion(&Builder, L_AAMVA_VERSION_2016); 
   if (nRet != SUCCESS) return nRet; 
 
   nRet = L_BarCodeAAMVAIDBuilderSetNumberOfEntries(&Builder, 1); 
   if (nRet != SUCCESS) return nRet; 
 
   nRet = L_BarCodeAAMVAIDBuilderSetSubfileType(&Builder, 0, L_AAMVA_SUBFILE_TYPE_DL, NULL); 
   if (nRet != SUCCESS) return nRet; 
 
   //Add all required data elements per AAMVA CDS  
   //Could use L_BarCodeAAMVAIDLookup* functions for data element values of enumerated D20 types 
 
// Macro to declare a date string variable and fill it with date 
// Date value equal to today's data offset forward or backward a number of years 
#define DeclareDate(szVar, nYearOffset) \ 
   char szVar[9]; \ 
   strcpy_s(szVar, 9, GetCurrentDate(nYearOffset)) 
 
   // Example below uses date values for 17 year old person 
   DeclareDate(szNow, 0);           // Today's date 
   DeclareDate(szExpiry, 6);        // Expires in 6 years 
   DeclareDate(szBirthday, -17);    // Born 17 years ago 
   DeclareDate(szBirthPlus21, 4);   // Will be 21 in 4 year 
   DeclareDate(szBirthPlus19, 2);   // Will be 19 in 2 years 
   DeclareDate(szBirthPlus18, 1);   // Will be 18 in 1 year 
 
   const char* driversLicenseData[][2] = { 
      {"DDF", "N"},                 // First name truncation (N = not truncated)  
      {"DDE", "N"},                 // Last name truncation (N = not truncated)  
      {"DCG", "USA"},               // Country identification  
      {"DCF", "NONE"},              // Document discriminator  
      {"DAQ", "1234567890"},        // ID Number  
      {"DAK", "123456     "},       // Postal code  
      {"DAJ", "PA"},                // Address Jurisdiction Code  
      {"DAI", "Any Town"},          // Address City  
      {"DAG", "123 Main Street"},   // Address Street 1  
      {"DAU", "072 in"},            // Height (inches or centimeters)  
      {"DAY", "BRO"},               // Eye color  
      {"DBC", "1"},                 // Sex (Male = 1, Female = 2, 9 = Not specified)  
      {"DBB", szBirthday},          // Date of Birth  
      {"DBD", szNow},               // Document Issue Date  
      {"DAD", "NONE"},              // Middle Name  
      {"DAC", "John"},              // First name  
      {"DCS", "Doe"},               // Last name  
      {"DBA", szExpiry},            // Expiration date  
      {"DCD", "M"},                 // Jurisdiction-specific endorsement codes  
      {"DCB", "NONE"},              // Jurisdiction-specific restriction codes  
      {"DCA", "C"},                 // Jurisdiction-specific vehicle class  
      {"DDJ", szBirthPlus21},       // Under 21 until  
      {"DDI", szBirthPlus19},       // Under 19 until  
      {"DDH", szBirthPlus18},       // Under 18 until  
      {"DAZ", "BRO"}                // Hair color  
   }; 
 
   int elementCount = sizeof driversLicenseData / sizeof driversLicenseData[0]; 
   for (int i = 0; i < elementCount; ++i) 
   { 
      L_UINT valueLen = (L_UINT)strlen(driversLicenseData[i][1]); 
      nRet = L_BarCodeAAMVAIDBuilderAddDataElementToSubfile(&Builder, 0, driversLicenseData[i][0], driversLicenseData[i][1], valueLen); 
      if (nRet != SUCCESS) return nRet; 
   } 
 
   nRet = L_BarCodeAAMVAIDBuilderBuild(&Builder); 
   if (nRet != SUCCESS) return nRet; 
   //Valid AAMVAID is now in pBuilder->OutputID  
   nRet = L_BarCodeWriteAAMVAData(Builder.OutputID, pData, pDataLength); 
   L_BarCodeFreeAAMVAID(Builder.OutputID); 
   return nRet; 
} 

Add a new helper function named GetDatePlusYears that returns the current date with the specified number of offset years. Any function that returns the date in yyyymmdd format can be used instead of it.

#include <time.h> 
L_CHAR* GetDatePlusYears(int nYears) 
{ 
   static char currentDate[9]; 
   time_t t = time(NULL); 
   struct tm local_t = { 0 }; 
   localtime_s(&local_t, &t); 
   wsprintfA(currentDate, "%4.4d%2.2d%2.2d", local_t.tm_year + 1900 + nYears, local_t.tm_mon + 1, local_t.tm_mday); 
   return currentDate; 
} 

Add the AAMVA PDF417 Write Barcode Code

Add a new WritePdf417Barcode function that writes the barcode on the image after the AAMVA data has been built successfully and add the following code to it:

L_INT WritePdf417Barcode(HWND hwnd, pBITMAPHANDLE pBarcodeBmp, L_CHAR* pData, L_INT nDataLen) 
{ 
   L_INT nRet = L_BarCodeInit(BARCODES_PDF_WRITE); 
   if (nRet != SUCCESS) 
      return nRet; 
 
   BARCODEDATA BarCodeData = { 0 }; 
   BARCODECOLOR BarColor = { 0 }; 
   BARCODEWRITEPDF BarCodePDF = { 0 }; 
 
   BarColor.uStructSize = sizeof BARCODECOLOR; 
   BarColor.dwColorBar = RGB(0, 0, 0); 
   BarColor.dwColorSpace = RGB(255, 255, 255); 
 
   BarCodeData.uStructSize = sizeof BarCodeData; 
   BarCodeData.rcBarLocation.left = 50; 
   BarCodeData.rcBarLocation.top = 50; 
   BarCodeData.rcBarLocation.right = 650; 
   BarCodeData.rcBarLocation.bottom = 400; 
   BarCodeData.nUnits = BARCODE_SCANLINES_PER_PIXELS; 
   BarCodeData.ulType = BARCODE_PDF417; 
   BarCodeData.pszBarCodeData = pData; 
   BarCodeData.nSizeofBarCodeData = nDataLen; 
 
   BarCodePDF.uStructSize = sizeof BarCodePDF; 
   BarCodePDF.wModule = 15; 
   BarCodePDF.wModAspectRatio = 3; 
   BarCodePDF.wEccLevel = BARCODE_PDF417_ECCLEVEL_5; 
   BarCodePDF.wAspectWidth = 4; 
 
   //Write the barcode 
   nRet = L_BarCodeWrite(pBarcodeBmp, &BarCodeData, &BarColor, BARCODE_USECOLORS, NULL, &BarCodePDF, NULL, NULL, NULL, NULL, NULL, NULL); 
 
   if (SUCCESS != nRet) 
      MessageBox(hwnd, TEXT("Could Not Write PDF417 Barcode"), TEXT("Barcode Demo"), MB_ICONERROR); 
   L_BarCodeExit(); 
   return nRet; 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps are followed correctly, the application will run and enable the user to select Barcode -> Write AAMVA Barcode to create an empty bitmap and write the AAMVA data on it.

The resulting image looks like this:

PDF417 barcode data written on image

Wrap-Up

This tutorial showed how to use the AAMVAIDBUILDER structure and related builder and barcode writer functions.

See Also

Help Version 22.0.2022.9.29
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.


Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.