使用SWIG桥接Golang和Windows DLL

最近看了下Go语言,利用Dynamsoft Barcode SDK做了一个简单的Golang条形码扫描。这里分享下如何使用SWIG来快速封装底层C/C++接口。

参考原文:How to Use SWIG to Link Windows DLL with Golang

作者:Xiao Ling

翻译:yushulx

下载安装

  • mingw-w64

  • SWIG

  • Go

  • Dynamsoft Barcode Reader

如何使用SWIG实现Cgo封装

运行cmd.exe,设置GOPATH:

set GOPATH=f:\go-project
set DBR=<Dynamsoft Barcode Reader Directory>

创建一个package:

mkdir %GOPATH%\src\github.com\dynamsoftsamples\go-barcode-reader\dbr

从SDK目录中把DynamsoftBarcodeReaderx64.dll拷贝到%GOPATH%\src\github.com\dynamsoftsamples\go-barcode-reader\dbr\bin

接下来把头文件都拷贝到%GOPATH%\src\github.com\dynamsoftsamples\go-barcode-reader\dbr\include

创建dbr.c:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "include/If_DBR.h"
 
__int64 GetFormat(int iIndex)
{
    __int64 llFormat = 0;
 
    switch(iIndex)
    {
    case 1:
        llFormat = OneD | QR_CODE | PDF417 |DATAMATRIX;
        break;
    case 2:
        llFormat = OneD;
        break;
    case 3:
        llFormat = QR_CODE;
        break;
    case 4:
        llFormat = CODE_39;
        break;
    case 5:
        llFormat = CODE_128;
        break;
    case 6:
        llFormat = CODE_93;
        break;
    case 7:
        llFormat = CODABAR;
        break;
    case 8:
        llFormat = ITF;
        break;
    case 9:
        llFormat = INDUSTRIAL_25;
        break;
    case 10:
        llFormat = EAN_13;
        break;
    case 11:
        llFormat = EAN_8;
        break;
    case 12:
        llFormat = UPC_A;
        break;
    case 13:
        llFormat = UPC_E;
        break;
    case 14:
        llFormat = PDF417;
        break;
    case 15:
        llFormat = DATAMATRIX;
        break;
    default:
        break;
    }
 
    return llFormat;
}
 
const char * GetFormatStr(__int64 format)
{
    if (format == CODE_39)
        return "CODE_39";
    if (format == CODE_128)
        return "CODE_128";
    if (format == CODE_93)
        return "CODE_93";
    if (format == CODABAR)
        return "CODABAR";
    if (format == ITF)
        return "ITF";
    if (format == UPC_A)
        return "UPC_A";
    if (format == UPC_E)
        return "UPC_E";
    if (format == EAN_13)
        return "EAN_13";
    if (format == EAN_8)
        return "EAN_8";
    if (format == INDUSTRIAL_25)
        return "INDUSTRIAL_25";
    if (format == QR_CODE)
        return "QR_CODE";
    if (format == PDF417)
        return "PDF417";
    if (format == DATAMATRIX)
        return "DATAMATRIX";
 
    return "UNKNOWN";
}
 
int decode_file(const char *pszImageFile)
{
    if (!pszImageFile)
    {
        return -1;
    }
 
  // const char *pszImageFile = "f:\\AllSupportedBarcodeTypes.tif";
    __int64 llFormat = (OneD | QR_CODE | PDF417 | DATAMATRIX);
    char pszBuffer[512] = {0};
 
    int iMaxCount = 0x7FFFFFFF;
    int iIndex = 0;
    ReaderOptions ro = {0};
    pBarcodeResultArray paryResult = NULL;
    int iRet = -1;
    char * pszTemp = NULL;
    char * pszTemp1 = NULL;
    unsigned __int64 ullTimeBegin = 0;
    unsigned __int64 ullTimeEnd = 0;
    size_t iLen;
    FILE* fp = NULL;
    int iExitFlag = 0;
 
    DBR_InitLicense("38B9B94D8B0E2B41DB1CC80A58946567");
 
    // Read barcode
    ullTimeBegin = GetTickCount();
    ro.llBarcodeFormat = llFormat;
    ro.iMaxBarcodesNumPerPage = iMaxCount;
    iRet = DBR_DecodeFile(pszImageFile, &ro, &paryResult);
    ullTimeEnd = GetTickCount();
 
    // Output barcode result
    pszTemp = (char*)malloc(4096);
    if (iRet != DBR_OK)
    {
        sprintf(pszTemp, "Failed to read barcode: %s\r\n", DBR_GetErrorString(iRet));
        printf(pszTemp);
        free(pszTemp);
        return 0;
    }
 
    if (paryResult->iBarcodeCount == 0)
    {
        sprintf(pszTemp, "No barcode found. Total time spent: %.3f seconds.\r\n", ((float)(ullTimeEnd - ullTimeBegin)/1000));
        printf(pszTemp);
        free(pszTemp);
        DBR_FreeBarcodeResults(&paryResult);
        return 0;
    }
 
    sprintf(pszTemp, "Total barcode(s) found: %d. Total time spent: %.3f seconds\r\n\r\n", paryResult->iBarcodeCount, ((float)(ullTimeEnd - ullTimeBegin)/1000));
    printf(pszTemp);
    for (iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)
    {
        sprintf(pszTemp, "Barcode %d:\r\n", iIndex + 1);
        printf(pszTemp);
        sprintf(pszTemp, "    Page: %d\r\n", paryResult->ppBarcodes[iIndex]->iPageNum);
        printf(pszTemp);
        sprintf(pszTemp, "    Type: %s\r\n", GetFormatStr(paryResult->ppBarcodes[iIndex]->llFormat));
        printf(pszTemp);
        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, "    Value: %s\r\n", pszTemp1);
        printf(pszTemp);
        free(pszTemp1);
        sprintf(pszTemp, "    Region: {Left: %d, Top: %d, Width: %d, Height: %d}\r\n\r\n",
            paryResult->ppBarcodes[iIndex]->iLeft, paryResult->ppBarcodes[iIndex]->iTop,
            paryResult->ppBarcodes[iIndex]->iWidth, paryResult->ppBarcodes[iIndex]->iHeight);
        printf(pszTemp);
    }
 
    free(pszTemp);
    DBR_FreeBarcodeResults(&paryResult);
 
    return 0;
}

创建对应的dbr.i:

/* dbr.i */
 %module dbr
 %{
 /* Put header files here or function declarations like below */
 extern int decode_file(const char *pszImageFile);
 %}
 
 extern int decode_file(const char *pszImageFile);

生成dbr.go和dbr_wrapper.c:

swig -go -cgo -intgosize 32 dbr.i

这个时候看到的目录结构:

使用SWIG桥接Golang和Windows DLL_第1张图片

打开dbr.go,添加头文件和库文件路径:

#cgo CFLAGS: -I .
#cgo LDFLAGS: -L ./bin -lDynamsoftBarcodeReaderx64

使用SWIG桥接Golang和Windows DLL_第2张图片

切换路径到根目录%GOPATH%,编译安装:

go install github.com\dynamsoftsamples\go-barcode-reader\dbr

如果在package目录中,可以直接使用:

go install

这个时候会在%GOPATH%\pkg\windows_amd64\github.com\dynamsoftsamples\go-barcode-reader中生成一个包dbr.a

使用SWIG桥接Golang和Windows DLL_第3张图片

Windows上实现Golang条码扫描应用

创建%GOPATH%\github.com\dynamsoftsamples\go-barcode-reader\BarcodeReader\BarcodeReader.go:

package main
 
import (
  "github.com/dynamsoftsamples/go-barcode-reader/dbr"
  "os"
)
 
func main() {
  if len(os.Args) == 1 { // read the default image
    dbr.Decode_file("AllSupportedBarcodeTypes.tif")
  } else {
    dbr.Decode_file(os.Args[1])
  }
}

拷贝DynamsoftBarcodeReaderx64.dll%GOPATH%\bin

在根目录使用下面的命令行生成可执行文件:

go install github.com\dynamsoftsamples\go-barcode-reader\BarcodeReader

使用SWIG桥接Golang和Windows DLL_第4张图片

测试程序:

%GOPATH%bin\BarcodeReader.exe <barcode image>

使用SWIG桥接Golang和Windows DLL_第5张图片

参考

  • Cgo: https://github.com/golang/go/wiki/cgo

  • SWIG and Go: http://www.swig.org/Doc3.0/Go.html

源码

https://github.com/dynamsoftsamples/go-barcode-reader


你可能感兴趣的:(Go,golang,barcode)