将C代码转换为Golang的实现方法
将C代码转换为Golang的实现方法 我想将这段读取由Matlab/Simulink生成的DLL的C代码:
#include <windows.h>
void main() {
// types
void (*mdl_initialize)(void); // function
double* mdl_G; // value
// Dll load
void* dll = LoadLibrary("./teste_win64.dll");
// GetProcAddress
mdl_initialize = (void(*)(void))GetProcAddress(dll , "initialize");
mdl_G = ((double*)GetProcAddress(dll, "G"));
// Run initialize and capture the G value
mdl_initialize();
printf("G = %.2f",*mdl_G);
}
转换为Go语言。
我尝试了以下方法:
func main() {
dll, _ := syscall.LoadDLL("./teste_win64.dll")
mdl_init, _ := syscall.GetProcAddress(dll.Handle, "initialize")
mdl_G, _ := syscall.GetProcAddress(dll.Handle, "G")
real_init := (*func())(unsafe.Pointer(&mdl_G))
real_G := (*float64)(unsafe.Pointer(&mdl_G))
real_init()
log.Print(*real_G)
}
但没有成功。有什么建议吗?
更多关于将C代码转换为Golang的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
根据 WindowsDLLs · golang/go Wiki · GitHub 来看,您需要使用 uintptr 而不是 unsefe.Pointer,并且使用 syscall 而不是尝试将指针转换为 *func。
更多关于将C代码转换为Golang的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这意味着,如果你使用来自 syscall 的指针,go vet 会错误地发出警告,而你对此无能为力。
我成功使用了 NewLazyDLL 和 NewProc:
dll := syscall.NewLazyDLL("teste_win64.dll")
mdl_G := dll.NewProc("G")
G := (*float64)(unsafe.Pointer(mdl_G.Addr()))
但是 VSCode 报告说 unsafe.Pointer(mdl_G.Addr()) 使用不当。有没有更好的方法来实现这个功能?
在Go中调用DLL函数需要使用正确的调用约定和参数处理。以下是修正后的实现:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
// 加载DLL
dll, err := syscall.LoadDLL("./teste_win64.dll")
if err != nil {
panic(err)
}
defer dll.Release()
// 获取initialize函数地址
mdlInit, err := dll.FindProc("initialize")
if err != nil {
panic(err)
}
// 获取G变量地址
mdlG, err := dll.FindProc("G")
if err != nil {
panic(err)
}
// 调用initialize函数
_, _, err = mdlInit.Call()
if err != nil && err.Error() != "The operation completed successfully." {
panic(err)
}
// 读取G的值
gPtr := mdlG.Addr()
gValue := *(*float64)(unsafe.Pointer(gPtr))
fmt.Printf("G = %.2f\n", gValue)
}
或者使用更简洁的方式直接调用:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
dll := syscall.NewLazyDLL("./teste_win64.dll")
// 声明函数原型
mdlInit := dll.NewProc("initialize")
mdlG := dll.NewProc("G")
// 调用initialize
_, _, _ = mdlInit.Call()
// 读取G的值
gAddr, _, _ := mdlG.Call()
gValue := *(*float64)(unsafe.Pointer(gAddr))
fmt.Printf("G = %.2f\n", gValue)
}
如果需要处理返回值和错误检查:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
dll, err := syscall.LoadDLL("./teste_win64.dll")
if err != nil {
panic(fmt.Sprintf("加载DLL失败: %v", err))
}
defer dll.Release()
// 获取函数和变量
mdlInit, err := dll.FindProc("initialize")
if err != nil {
panic(fmt.Sprintf("找不到initialize函数: %v", err))
}
mdlG, err := dll.FindProc("G")
if err != nil {
panic(fmt.Sprintf("找不到G变量: %v", err))
}
// 调用initialize
ret, _, err := mdlInit.Call()
if err != nil && err != syscall.Errno(0) {
panic(fmt.Sprintf("调用initialize失败: %v", err))
}
_ = ret // 处理返回值
// 读取G的值
gPtr := mdlG.Addr()
if gPtr == 0 {
panic("获取G地址失败")
}
gValue := *(*float64)(unsafe.Pointer(gPtr))
fmt.Printf("G = %.2f\n", gValue)
}
关键点:
- 使用
FindProc而不是GetProcAddress - 通过
Addr()方法获取变量地址 - 使用
unsafe.Pointer进行类型转换 - 注意Windows调用约定(stdcall)

