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():

相关推荐
lekami_兰2 小时前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘5 小时前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤6 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt1118 小时前
AI DDD重构实践
go
Grassto2 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto4 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室5 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题5 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo
啊汉7 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想
asaotomo7 天前
一款 AI 驱动的新一代安全运维代理 —— DeepSentry(深哨)
运维·人工智能·安全·ai·go