Golang 加载 dll 动态链接库

2,551 阅读2分钟

最近接了一个需求要用到USB狗这种方式来对特定用户进行授权,公司给了一个类似U盘的东西和一个工具包,然后就让开干了

看了文档后发现好像没有直接使用的Go SDK,所以就只能使用人家提供的APIdll库了,go加载dll库有好几种方式,下面记录一下懒加载的这种,代码如下:

C API

// 找到设备
findHardware(
unsigned char* hid,  //入参:设备id
int * count         // 出参:查找到的设备个数
)
返回值:
0x01:执行成功,返回设备个数。// 代码:SUCCESS
0x02:没有可以用的硬件,此时 Count 值为 0//代码:NOT_FOUND// 打开设备
open(
HANDLE* hHandle,  //出参:打开设备的句柄,返回给用户,供以后的函数调用;
unsigned char*hid, //入参:设备 id
int index          // 入参:选择打开哪个设备
)
返回值:
0x01:打开成功  // 代码:SUCCESS
0x03:打开失败  //代码:OPEN_FAILED// 获取设备中的数据
getData(
HANDLE hHandle,  //入参:设备句柄
unsigned char* data //出参:返回的数据
)
返回值:
0x01:读取数据成功  // 代码:SUCCESS
0x04:读取数据失败  //代码:READ_FAILED

golang代码:

func main() {
    dllPath: = "api.dll"
    //判断文件存不存在
    if _, err = os.Stat(dllPath); err != nil {
        if os.IsExist(err) {
            log.Fatalf("file not exist:%s", err)
        }
        log.Fatalf("%v", err)
    }
    
    // load dll,使用懒加载模式,也就是真正调用 API 的时候才会加载
    lib := syscall.NewLazyDLL(dllPath)
    
    // 找到设备
    proc := lib.NewProc("findHardware")
    
    // byte from string
    str2Byte, err := syscall.BytePtrFromString("123456")
    if err != nil {
        log.Fatalf("change string to byte ptr failed:[%v]", err)
    }
    var count int
    ret, _, _ := proc.Call(uintptr(unsafe.Pointer(str2Byte)), uintptr(unsafe.Pointer(&count)))
    if ret == NOT_FOUND {
        log.Fatalf("NOT FOUND")
    }
    if count == 0 {
        log.Fatalf("NOT FOUND")
    }
    logrus.Infof("find hardware success....")
    
    // open hardware
    openFunc := lib.NewProc("open")
    // get lock handler
    var handler uintptr //因为不知道句柄具体类型是什么,那就用一个指针存储
    ret, _, _ := openFunc.Call(uintptr(unsafe.Pointer(&handler)), uintptr(unsafe.Pointer(str2Byte)), uintptr(1))
    if ret != OPEN_FAILED {
        log.Fatalf("OPEN FAILED")
    }
    logrus.Infof("open success")
    
    // get data
    getSN := lib.NewProc("getData")
    var hid [8]byte //因为返回的数据是 8 字节数组
    ret, _, _ = getSN.Call(handler, uintptr(unsafe.Pointer(&hid)))
    if ret != ET_SUCCESS {
        log.Fatalf("Get Data Failed")
    }
    //将其转化成 16 进制输出
    fmt.Printf("%x\n",hid)
​
    // close hardware
    closeFunc := lib.NewProc("close")
    ret, _, _ = closeFunc.Call(handler)
    if ret != ET_SUCCESS {
        log.Fatalf("failed")
    }
    logrus.Infof("close success...", i)
}