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
- Download C/C++ SDK v9.0.
- Get a valid license key for activating the SDK.
Steps to Develop and Build .NET 6 Barcode and QR Code SDK
-
Create a new library project:
dotnet new classlib -o BarcodeQRCodeSDK
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`
- Rename
Class1.cs
toBarcodeQRCodeReader.cs
. -
P/Invoke is the technology used for bridging C/C++ and .NET. In the
BarcodeQRCodeReader.cs
file, we useDllImport
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);
-
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; }
-
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; }
-
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(); } }
-
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>
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>
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
or the NuGet online page.
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>
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>
A Simple .NET 6 Command-line Example
-
Create a new .NET console app:
dotnet new console -o Test
-
Install the .NET Barcode and QR Code SDK:
dotnet add package BarcodeQRCodeSDK
-
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(); } } } } }
-
Run the application in Windows, Linux or macOS:
dotnet run