Windows Universal App中集成C/C++ DLL

筅森魡賤 提交于 2019-12-02 03:30:48

借助Windows 10的普及,微软开始推Universal应用开发。Universal应用其实和Android和iOS应用一样,运行在sandbox中,在桌面环境里exe不能双击运行。打成一个appx包之后可以提交到Windows Store。任何运行Windows 10的设备都可以运行。那么在开发的时候,现有的C/C++ SDK是否可以兼容呢?答案是可以的,不过会有一些限制。如果你想让SDK兼容所有的设备,需要提供行x86, x64, arm三个版本DLL。我用Dynamsoft Barcode SDK做了试验。

参考原文:How to Create a Universal Barcode Reader on Windows 10 with C/C++ Legacy Code

作者:Xiao Ling

翻译:yushulx

准备工作

Hello World

编写Hello World很简单,可以学习微软的在线教程https://msdn.microsoft.com/en-us/library/windows/apps/dn996906.aspx

在Universal App中集成C/C++ SDK

创建一个Universal应用。

 MainPage.xaml中添加ImageButtonTextBlock

<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>
 

使用FileOpenPicker来加载文件:

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

WriteableBitmap中获取图像数据的C++指针:

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;
}
 

使用DecodeBuffer检测图像数据。因为没有对应的接口,需要自己构造数据 (BITMAPINFOHEADER + Image data)。BITMAPINFOHEADER为40个字节,再加上实际的数据:

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);
 

获取barcode结果:

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);
 

接下来就是要想办法把C String转换成Platform::String^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);
    }

<Dynamsoft Barcode SDK>\Redist\C_C++目录拷贝DynamsoftBarcodeReaderx86.dllDynamsoftBarcodeReader\Debug\DynamsoftBarcodeReader\AppX目录。

现在可以通过CTRL+F5或者菜单来运行程序了。

Universal Barcode Reader 截图:

已知问题

  • 开发Universal应用的时候,有些C的接口是受到限制的,因此SDK中提供的DecodeFile接口用不了,因为需要调用fopen。具体限制可以参考CRT functions not supported in Universal Windows Platform apps

  • SDK中提供的QR二维码解码失效。

  • DecodeBuffer的时候只能使用BMP图像。

源码

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!