DEV Community

Xiao Ling
Xiao Ling

Posted on • Originally published at dynamsoft.com

2 1

How to Build .NET 6 Barcode and QR Code SDK for Windows, Linux & macOS

Microsoft .NET 6 SDK empowers C# developers to build cross-platform DotNet applications for Windows, Linux, and macOS from one codebase. This article describes the steps to build a .NET 6 barcode and QR code decoding library based on Dynamsoft C/C++ Barcode SDK, as well as how to pack the library into a NuGet package.

.NET 6 SDK Installation

Dynamsoft Barcode Reader

  1. Download C/C++ SDK v9.0.
  2. Get a valid license key for activating the SDK.

Steps to Develop and Build .NET 6 Barcode and QR Code SDK

  1. Create a new library project:

    dotnet new classlib -o BarcodeQRCodeSDK
    
  2. Copy shared library files from the C/C++ SDK package to the project root directory. For different platforms, the minimum required shared library files are:

- Windows: `DynamsoftBarcodeReader.dll`, `vcomp110.dll`
- Linux: `libDynamsoftBarcodeReader.so`
- macOS: `libDynamsoftBarcodeReader.dylib`    
Enter fullscreen mode Exit fullscreen mode
  1. Rename Class1.cs to BarcodeQRCodeReader.cs.
  2. P/Invoke is the technology used for bridging C/C++ and .NET. In the BarcodeQRCodeReader.cs file, we use DllImport to load the unmanaged shared library (e.g. *.dll, *.so, *.dylib) and define some managed methods to communicate with the native component.

    [DllImport("DynamsoftBarcodeReader")]
    static extern IntPtr DBR_CreateInstance();
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern void DBR_DestroyInstance(IntPtr hBarcode);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern int DBR_InitLicense(string license, [Out] byte[] errorMsg, int errorMsgSize);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern int DBR_DecodeFile(IntPtr hBarcode, string filename, string template);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern int DBR_FreeTextResults(ref IntPtr pTextResultArray);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern void DBR_GetAllTextResults(IntPtr hBarcode, ref IntPtr pTextResultArray);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern int DBR_DecodeBuffer(IntPtr hBarcode, IntPtr pBufferBytes, int width, int height, int stride, ImagePixelFormat format, string template);
    
    [DllImport("DynamsoftBarcodeReader")]
    static extern int DBR_DecodeBase64String(IntPtr hBarcode, string base64string, string template);
    
  3. In addition, we need to define some native structs in C#:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct PTextResult
    {
        BarcodeFormat emBarcodeFormat;
        public string barcodeFormatString;
        BarcodeFormat_2 barcodeFormat_2;
        string barcodeFormatString_2;
        public string barcodeText;
        IntPtr barcodeBytes;
        int barcodeBytesLength;
        IntPtr localizationResult;
        IntPtr detailedResult;
        int resultsCount;
        IntPtr results;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)]
        char[] reserved;
    }
    
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TextResultArray
    {
        public int resultsCount;
        public IntPtr results;
    }
    
  4. The memory operation between the managed structure and the unmanaged pointer is a little bit tricky. We need to use Marshal to convert data:

    IntPtr pTextResultArray = IntPtr.Zero;
    
    DBR_GetAllTextResults(hBarcode, ref pTextResultArray);
    
    if (pTextResultArray != IntPtr.Zero)
    {
        string[]? resultArray = null;
        TextResultArray? results = (TextResultArray?)Marshal.PtrToStructure(pTextResultArray, typeof(TextResultArray));
        if (results != null)
        {
            int count = results.Value.resultsCount;
            if (count > 0)
            {
                IntPtr[] barcodes = new IntPtr[count];
                Marshal.Copy(results.Value.results, barcodes, 0, count);
                resultArray = new string[count];
    
                for (int i = 0; i < count; i++)
                {
                    PTextResult? result = (PTextResult?)Marshal.PtrToStructure(barcodes[i], typeof(PTextResult));
                    if (result != null)
                    {
                        resultArray[i] = result.Value.barcodeText;
                    }
                }
            }
        }
    
        DBR_FreeTextResults(ref pTextResultArray);
    
        return resultArray;
    }
    
  5. Once the communication problem between managed and unmanaged code is solved, we can define some high-level C# methods:

    public class BarcodeQRCodeReader
    {
        private IntPtr hBarcode;
        private static string? licenseKey;
    
        public static void InitLicense(string license) {
            byte[] errorMsg = new byte[512];
            licenseKey = license;
            DBR_InitLicense(license, errorMsg, 512);
            Console.WriteLine(Encoding.ASCII.GetString(errorMsg) + "\n");
        }
    
        private BarcodeQRCodeReader()
        {
            hBarcode = DBR_CreateInstance();
        }
    
        public static BarcodeQRCodeReader Create()
        {
            if (licenseKey == null)
            {
                throw new Exception("Please call InitLicense first.");
            }
            return new BarcodeQRCodeReader();
        }
    
        ~BarcodeQRCodeReader()
        {
            if (hBarcode != IntPtr.Zero)
            {
                DBR_DestroyInstance(hBarcode);
                hBarcode = IntPtr.Zero;
            }
        }
    
        public void Destroy()
        {
            if (hBarcode != IntPtr.Zero)
            {
                DBR_DestroyInstance(hBarcode);
                hBarcode = IntPtr.Zero;
            }
        }
    
        public string[]? DecodeFile(string filename)
        {
            if (hBarcode == IntPtr.Zero) return null;
    
            int ret = DBR_DecodeFile(hBarcode, filename, "");
            return OutputResults();
        }
    }
    
  6. Build the source code to generate the *.dll file.

    dotnet build --configuration Release
    

How to Generate and Publish NuGet Package

To generate the *.nupkg file, the easiest way is to add <GeneratePackageOnBuild>true</GeneratePackageOnBuild> to the *.csproj file:

<PropertyGroup>
  ...
  <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  ...
</PropertyGroup>
Enter fullscreen mode Exit fullscreen mode

Then the *.nupkg file will be generated automatically when you build the project.

Our package contains some native library files. To pack them into the *.nupkg file correctly, we set the corresponding PackagePath in *.csproj file according to the Runtime Identifier:

<ItemGroup>
  <None CopyToOutputDirectory="Always" Include="DynamsoftBarcodeReader.dll" Pack="true" PackagePath="runtimes/win-x64/native/DynamsoftBarcodeReader.dll" />
  <None CopyToOutputDirectory="Always" Include="vcomp110.dll" Pack="true" PackagePath="runtimes/win-x64/native/vcomp110.dll" />
  <None CopyToOutputDirectory="Always" Include="libDynamsoftBarcodeReader.dylib" Pack="true" PackagePath="runtimes/osx-x64/native/libDynamsoftBarcodeReader.dylib" />
  <None CopyToOutputDirectory="Always" Include="libDynamsoftBarcodeReader.so" Pack="true" PackagePath="runtimes/linux-x64/native/libDynamsoftBarcodeReader.so" />
</ItemGroup>
Enter fullscreen mode Exit fullscreen mode

As the *.nupkg file is ready, we can publish it to the NuGet Gallery either via the dotnet command:

dotnet nuget push *.nupkg -k <api-key> -s https://api.nuget.org/v3/index.json
Enter fullscreen mode Exit fullscreen mode

or the NuGet online page.

nuget package upload

Here is the final page of BarcodeQRCodeSDK:
https://www.nuget.org/packages/BarcodeQRCodeSDK/

How to Add a .NET Library Project as a Reference Locally

For source code, add <ProjectReference> in *.csproj file:

<ItemGroup>
    <ProjectReference Include="..\..\BarcodeQRCodeSDK.csproj" />
</ItemGroup>
Enter fullscreen mode Exit fullscreen mode

For generated *.nupkg file, add the package directory to NuGet source list and then install the package via dotnet add package:

dotnet nuget add source <package directory>
dotnet add package <package name>
Enter fullscreen mode Exit fullscreen mode

A Simple .NET 6 Command-line Example

  1. Create a new .NET console app:

    dotnet new console -o Test
    
  2. Install the .NET Barcode and QR Code SDK:

    dotnet add package BarcodeQRCodeSDK
    
  3. Use the following code to decode barcode and QR code from an image file:

    using System;
    using System.Runtime.InteropServices;
    using Dynamsoft;
    
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                BarcodeQRCodeReader.InitLicense("LICENSE-KEY");
                BarcodeQRCodeReader? reader = null;
                try {
                    reader = BarcodeQRCodeReader.Create();
                    Console.WriteLine("Please enter an image file: ");
                    string? filename = Console.ReadLine();
                    if (filename != null) {
                        string[]? results = reader.DecodeFile(filename);
                        if (results != null) {
                            foreach (string result in results) {
                                Console.WriteLine(result);
                            }
                        }
                        else {
                            Console.WriteLine("No barcode found.");
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Destroy();
                    }
                }
            }
        }
    }
    
  4. Run the application in Windows, Linux or macOS:

    dotnet run
    

    command-line .NET barcode and QR code reader

Source Code

https://github.com/yushulx/dotnet-barcode-qr-code-sdk

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay