How to Create a Universal Barcode Reader on Windows 10 with C/C++ Legacy Code

Probably many Windows developers have upgraded operating systems to Windows 10. On Windows 10, Microsoft suggests developers create Universal Windows Apps (UWP) for a variety of devices, including PC, tablet, mobile phone, Hololens and so on. For development, I wonder whether legacy C/C++ SDKs can also seamlessly work on Windows 10, such as Dynamsoft Barcode SDK, which does not officially support UWP development yet. The answer is yes. Let’s see the tricks.

Prerequisites

Where do We Start?

Follow Microsoft’s tutorial to write your first “Hello World” App:

https://msdn.microsoft.com/en-us/library/windows/apps/dn996906.aspx

What’s the difference between Universal Windows app and desktop app?

Unlike Windows desktop app, Universal app is compiled into a package appx, which contains all resources, configurations and executable file. The application can only run in the context of an app container.

How to Invoke C/C++ APIs of Dynamsoft Barcode SDK in UWP App?

Create a new Universal Windows App.

uwp project

Add Image, Button and TextBlock to MainPage.xaml:

<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto" VerticalAlignment="Top">
                <StackPanel>
                    <Grid x:Name="Image" Margin="0,0,0,5" VerticalAlignment="Top">
                        <Image x:Name="PreviewImage" HorizontalAlignment="Left" VerticalAlignment="Top" MaxWidth="600"/>
                    </Grid>
                    <StackPanel Orientation="Horizontal" Margin="0, 0, 0, 5" VerticalAlignment="Top">
                        <Button x:Name="button" Margin="0, 0, 5, 0" Click="button_Click" VerticalAlignment="Top">
                            <Viewbox MaxHeight="40" MaxWidth="40">
                                <SymbolIcon Symbol="OpenFile"/>
                            </Viewbox>
                        </Button>
                        <TextBlock x:Name="BarcodeResults" Margin="0,0,0,10" TextWrapping="Wrap" Text="Results:" Height="600" Width="300" VerticalAlignment="Stretch" HorizontalAlignment="Left" />
                    </StackPanel>
                </StackPanel>
            </ScrollViewer>

Loading barcode images with FileOpenPicker:

FileOpenPicker^ picker = ref new FileOpenPicker();
picker->FileTypeFilter->Append(".bmp");
picker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;

To get the C++ pointer of the image data buffers from WriteableBitmap, we can refer to the article – Obtaining pointers to data buffers. Here is the code:

byte* GetPointerToPixelData(IBuffer^ pixelBuffer, unsigned int *length)
{
	if (length != nullptr)
	{
		*length = pixelBuffer->Length;
	}
	// Query the IBufferByteAccess interface.
	ComPtr<IBufferByteAccess> bufferByteAccess;
	reinterpret_cast<IInspectable*>(pixelBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));

	// Retrieve the buffer data.
	byte* pixels = nullptr;
	bufferByteAccess->Buffer(&pixels);
	return pixels;
}

We’ll use the API DecodeBuffer, but the underlying required data structure is different. We need to construct the data buffer (BITMAPINFOHEADER + Image data) ourselves:

char *total = (char *)malloc(len + 40);
BITMAPINFOHEADER bitmap_info = { 40, width, height, 0, 32, 0, len, 0, 0, 0, 0 };
memcpy(total, &bitmap_info, 40);
char *data = total + 40;
memcpy(data, buffer, len);

Read barcode image and return results:

iRet = reader.DecodeBuffer((unsigned char*)total, len + 40);

	// Output barcode result
	pszTemp = (char*)malloc(4096);
	if (iRet != DBR_OK)
	{
		sprintf(pszTemp, "Failed to read barcode: %s\r\n", DBR_GetErrorString(iRet));
		free(pszTemp);
		return nullptr;
	}

	pBarcodeResultArray paryResult = NULL;
	reader.GetBarcodes(&paryResult);

After getting the barcode results, convert C String to Platform::String^. I found the solution from StackOverflow.

results = ref new Array<String^>(paryResult->iBarcodeCount);
	for (iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)
	{
		sprintf(pszTemp, "Barcode %d:\r\n", iIndex + 1);
		sprintf(pszTemp, "%s    Page: %d\r\n", pszTemp, paryResult->ppBarcodes[iIndex]->iPageNum);
		sprintf(pszTemp, "%s    Type: %s\r\n", pszTemp, GetFormatStr(paryResult->ppBarcodes[iIndex]->llFormat));
		pszTemp1 = (char*)malloc(paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
		memset(pszTemp1, 0, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
		memcpy(pszTemp1, paryResult->ppBarcodes[iIndex]->pBarcodeData, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength);
		sprintf(pszTemp, "%s    Value: %s\r\n", pszTemp, pszTemp1);

		// http://stackoverflow.com/questions/11545951/how-to-convert-from-char-to-platformstring-c-cli
		std::string s_str = std::string(pszTemp);
		std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
		const wchar_t* w_char = wid_str.c_str();
		OutputDebugString(w_char);
		barcode_result = ref new String(w_char);
		results->set(iIndex, barcode_result);
		free(pszTemp1);
	}

Copy DynamsoftBarcodeReaderx86.dll from <Dynamsoft Barcode SDK>\Redist\C_C++ to DynamsoftBarcodeReader\Debug\DynamsoftBarcodeReader\AppX.

appx

Run the UWP Barcode Reader directly from Visual Studio by CTRL+F5 or the Start menu:

UWP from start menu

See the screenshot:

universal windows barcode reader

Known Issues

Source Code

https://github.com/dynamsoftsamples/universal-windows-barcode-reader