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

相关推荐
蒙娜丽宁2 天前
Go语言错误处理详解
ios·golang·go·xcode·go1.19
qq_172805593 天前
GO Govaluate
开发语言·后端·golang·go
littleschemer3 天前
Go缓存系统
缓存·go·cache·bigcache
程序者王大川4 天前
【GO开发】MacOS上搭建GO的基础环境-Hello World
开发语言·后端·macos·golang·go
Grassto4 天前
Gitlab 中几种不同的认证机制(Access Tokens,SSH Keys,Deploy Tokens,Deploy Keys)
go·ssh·gitlab·ci
高兴的才哥5 天前
kubevpn 教程
kubernetes·go·开发工具·telepresence·bridge to k8s
少林码僧6 天前
sqlx1.3.4版本的问题
go
蒙娜丽宁6 天前
Go语言结构体和元组全面解析
开发语言·后端·golang·go
蒙娜丽宁6 天前
深入解析Go语言的类型方法、接口与反射
java·开发语言·golang·go
三里清风_6 天前
Docker概述
运维·docker·容器·go