Golang 调用 Visual Studio 2022 编译的C动态链接库DLL(入门)

主要记录一下调用方法和不同数据类型的传参和转换.


需要注意的: 在go中调用C的方法,基本上参数值/类型和返回类型都为uintptr(uint ptr 应该是无符号整型指针类型),具体可以看下边代码和注释


流程:

  1. 先编写C代码,然后生成动态dll
  2. 将dll放到需要调用的路径下(go代码可以指定路径)
  3. 编写go代码,测试运行结果.

需要了解的:

  1. 如何调用C的callback
  2. syscall.FreeLibrary()的使用时机

一.C代码示例

IInterface.h

c 复制代码
#ifdef LAUNCH_H
#define LAUNCH_H

#define LAUNCH_C_API __declspec(dllexport)

#ifdef __cplusplus
extern "C" //告诉编译器是C语言代码
{
#endif
	LAUNCH_C_API int __stdcall Init_c(int a, int b);
	LAUNCH_C_API int __stdcall GetName_c(int a, int b);
	LAUNCH_C_API int __stdcall ExpireTime();

#ifdef __cplusplus
}
#endif

#endif // LAUNCH_H

launch.c

c 复制代码
#include "IInterface_C.h"
#include "stdio.h"

//函数的实现
__declspec(dllexport) int __stdcall Init_c(int a, int b)
{
	printf("%d %d\n", a, b);
	return a+b;
}

__declspec(dllexport) int __stdcall GetName_c(int a, int b)
{
	printf("%d %d\n", a, b);
	return 0;
}

int a = 1699637857;
//单纯返回一个常量
__declspec(dllexport) int __stdcall ExpireTime()
{
	return a;
}

二.GO代码示例(不知道为什么GO代码没格式化???)

go 复制代码
package main  
  
import (  
"fmt"  
"os"  
"syscall"  
"time"  
"unsafe"  
)  
  
// 调用win api  
var (  
// user32, _ = syscall.LoadLibrary("user32.dll")  
// messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")  
)  
  
func main() {  

//加载dll
dll, err := syscall.LoadDLL("test.dll")  //这里可以参数可以指定路径
if err != nil {  
fmt.Println("dll未找到:", err)  
return  
}  

//找C函数
//proc, err := dll.FindProc("Init_c")  //C函数1
proc, err := dll.FindProc("ExpireTime") //C函数2
if err != nil {  
fmt.Println("没有找到对应函数:", err)  
return  
}  

//调用C函数,并传值
//call, _, err := proc.Call(TestNum1(1, 2), TestNum2(3, 4))  
//if err != nil {  
//fmt.Println("TestNum1 call 的err:", err)//一般err都不为空,此处err信息可以判断具体执行结果
//}

//此处call的类型可以直接和数值类型进行对比.
if call > 0 {  
fmt.Println("TestNum1 call 的结果:", call)  
}  
//启一个go程测试第二个C函数
go func() {  
for {  
call, _, err := proc.Call(GetExpireTime()) //这里直接调用的一个空方法,实际上做法很多,还没有具体测试 
if err != nil {  
fmt.Println("GetExpireTime call 的err:", err)  
}  
if call > 0 {  
fmt.Println("GetExpireTime call 的结果:", int64(call))  
}  
res := CalTime(int64(call))  //传入dll返回的unix时间戳做对比,返回类型为bool
if res == false {  
SendMessageBox("过期提醒", "时间到了..")  //这里自己封装了一个win api的原生弹框
os.Exit(0) //实际上弹框会阻塞进程退出.简单测试
}  
fmt.Println("距离过期还有:", int64(call)-time.Now().Unix(), "秒")  
time.Sleep(1 * time.Second)  
}  
}()  
select {}  
}  
  
  //------------------------------------------一些函数实现
  
  //封装的winAPi方法,具体使用可以去msdn查询
  //此处有个疑惑,有一些dll的调用需要释放,还没研究.
func SendMessageBox(title, msg string) {  
user32 := syscall.NewLazyDLL("user32.dll")  
msgBox := user32.NewProc("MessageBoxW")  
msgBox.Call(IntPtr(0), strToPtr(msg), strToPtr(title), IntPtr(0))  
}  
  
// 计算时间  
func CalTime(ExpireTime int64) bool {  
if time.Now().Unix() >= ExpireTime {  
fmt.Println("时间过期")  
return false  
}  
fmt.Println("-----------")  
return true  
}  

//字符串转指针,实际结果为*uint16
func strToPtr(s string) uintptr {  
b, _ := syscall.UTF16PtrFromString(s)
return uintptr(unsafe.Pointer(b))  
}  
  
//方法名字起的不是很好,实际上是转换为uintptr类型
func IntPtr(i int) uintptr {  
return uintptr(i)  
}  

// 正常数值  
func TestNum1(x, y int) uintptr {  
z := x + y  
return uintptr(z)  
}  
// 正常数值
func TestNum2(x, y int) uintptr {  
z := x + y  
return uintptr(z)  
}  
  
// 返回字符串(本身字符串就是一个指针,并不是基础数据类型)  
func testString(s string) uintptr {  
b, _ := syscall.BytePtrFromString(s)  
return uintptr(unsafe.Pointer(b))  
}  
  
// 返回数值指针  
func testNumPtr(i *int32) uintptr {  
return uintptr(unsafe.Pointer(i))  
}

测试结果调用C函数:Init_c():


测试结果调用C函数:ExpireTime():

相关推荐
桃园码工16 小时前
1-Gin介绍与环境搭建 --[Gin 框架入门精讲与实战案例]
go·gin·环境搭建
云中谷16 小时前
Golang 神器!go-decorator 一行注释搞定装饰器,v0.22版本发布
go·敏捷开发
苏三有春1 天前
五分钟学会如何在GitHub上自动化部署个人博客(hugo框架 + stack主题)
git·go·github
我是前端小学生2 天前
Go语言中的方法和函数
go
探索云原生2 天前
在 K8S 中创建 Pod 是如何使用到 GPU 的: nvidia device plugin 源码分析
ai·云原生·kubernetes·go·gpu
自在的LEE2 天前
当 Go 遇上 Windows:15.625ms 的时间更新困局
后端·kubernetes·go
Gvto3 天前
使用FakeSMTP创建本地SMTP服务器接收邮件具体实现。
go·smtp·mailtrap
白泽来了3 天前
【Go进阶】手写 Go websocket 库(一)|WebSocket 通信协议
开源·go
witton4 天前
将VSCode配置成Goland的视觉效果
ide·vscode·编辑器·go·字体·c/c++·goland
非凡的世界4 天前
5个用于构建Web应用程序的Go Web框架
golang·go·框架·web