Go调用dll及大部分问题的解决方案,附源码
准备工作
Go需要1.10版本,即支持动态链接库
基本调用代码
lib := syscall.NewLazyDLL("lib/plugin.dll") // 读取dll
f := lib.NewProc("Sum") // 调用dll函数
res, _, _ := f.Call(param) // 传值
fmt.Println(res)
可能出现的问题
%1 is not a valid Win32 application
这是由于调用的dll位数和系统版本位数不一致导致的,需要设置成与dll位数相同的编译环境,在cmd中使用以下命令
go env // 查看set GOARCH,如果系统是64位,则等于amd64,如果是32,则是386
go env -w GOARCH=386 // 设置32编译环境
go env -w GOARCH=amd64 // 设置64编译环境
The specified module could not be found
这个问题分为三种情况
dll路径不对
调整路径即可
dll依赖别的dll,依赖的dll缺失了
下载DependenciesGui,https://github.com/lucasg/Dependencies
打开后,菜单栏点击file->open,选择需要查看的dll
当出现红色感叹号时,则说明缺失这个dll,就需要将这个缺失的dll放在与选择的dll同目录,解决后
这个dll本身有依赖的dll,且dll与依赖dll在同一目录,但是go业务代码与dll,被依赖的dll不在同一目录,
把dll,被依赖的所有dll与业务代码放在同一目录
数据类型问题
当传值或者接收值时,f.Call(param)。所有值的类型应该都是uintptr,应该注意数据类型的转换,以下代码仅做参考:
// string到uintptr.
func StrPtr(s string) uintptr {
	p, _ := syscall.UTF16PtrFromString(s)
	return uintptr(unsafe.Pointer(p))
}
// uintptr到string.
func PtrStr(p uintptr) string {
	return syscall.UTF16ToString(*(*[]uint16)(unsafe.Pointer(&p)))
}
// bool到uintptr.
func BoolPtr(b bool) uintptr {
	if b {
		return uintptr(1)
	}
	return uintptr(0)
}
// float32到uintptr.
func Float32Ptr(f float32) uintptr {
	return uintptr(*(*uint32)(unsafe.Pointer(&f)))
}
// uintptr到float32.
func PtrToFloat32(p uintptr) float32 {
	u := uint32(p)
	return *(*float32)(unsafe.Pointer(&u))
}
// int到uintptr
func IntPtr(i int) uintptr {
	return uintptr(i)
}
// int到uintptr
func PtrInt(u uintptr) int {
	return int(u)
}
示例代码
package main
import (
	"fmt"
	"syscall"
)
var (
	ta        = syscall.NewLazyDLL("AIO_API.dll")
	taInit3   = ta.NewProc("TA_Init3")
	taConsume = ta.NewProc("TA_Consume")
)
func main() {
	aio()
}
func aio() {
	str := StrPtr("str")
	i := IntPtr(123)
	b := BoolPtr(true)
	// 调用接口示例
	res, _, _ := taConsume.Call(str, i, b)
    fmt.Printf("%v", IntPtr(res))
}
目录结构