将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


请参阅 cmd/vet: “possible misuse of unsafe.Pointer” check false positive rate may be too high · Issue #41205 · golang/go · GitHub 等。

这意味着,如果你使用来自 syscall 的指针,go vet 会错误地发出警告,而你对此无能为力。

我成功使用了 NewLazyDLLNewProc

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)
}

关键点:

  1. 使用FindProc而不是GetProcAddress
  2. 通过Addr()方法获取变量地址
  3. 使用unsafe.Pointer进行类型转换
  4. 注意Windows调用约定(stdcall)
回到顶部