将字符串传递给 Syscall(uintptr)

我需要将字符串作为参数传递给 golang 中的 C DLL,我想得到这样的东西:


  proc, e = syscall.GetProcAddress(h, "JLINKARM_ExecCommand") //One of the functions


    vals := []string{"device = STM32F429ZI"}

    start := uintptr(unsafe.Pointer(&vals[0]))


    asd, _, _ = syscall.Syscall6(uintptr(proc), 3, start, 0, 0, 0, 0, 0) 

但它不起作用。系统调用将 uintptr 作为参数。我不能使用 C 包,因为它不能在 Windows 上构建。


在 C 中,它的工作方式如下:


strcpy(acIn, "device = STM32F407IE");


JLINKARM_ExecCommand(acIn, &acOut[0], sizeof(acOut));

那么 C DLL 是否有机会获取字符串参数并正确使用它?


qq_花开花谢_0
浏览 172回答 2
2回答

翻过高山走不出你

要将字符串传递给系统调用,您需要传递指向字符串第一个字符的指针。第一个问题是您的 DLL 函数需要什么字符串编码。Go 字符串被编码为 UTF-8 unicode,因此如果您的 C 函数需要其他内容,您必须先转换它们。以下是一些常见的情况:1)ASCII字符串假设您的 C 函数需要一个以零结尾的 ASCII 字符串,那么您可以执行以下操作:s := "some string"b := append([]byte(s), 0)syscall.Syscall(uintptr(proc), 1, uintptr(unsafe.Pointer(&b[0])), 0, 0)首先将您的字符串转换为字节数组,并在末尾添加 C 期望的零。然后将指针传递给第一个字节字符。为了安全起见,您还应该确保您实际上只传入有效的 ASCII 字符串,没有无效字符。通常只有 [0..127] 范围内的字符对通用 ASCII 有效。其余取决于当前代码页。2) Windows 上的 UTF-16如果您调用 Windows DLL,您通常希望使用该函数的 UTF-16 版本,例如SendMessageW,因此需要将您的字符串转换为 UTF-16。幸运的是,在 Windows 下有一个包装函数,因此您只需执行以下操作:s := "some string"s16, err := syscall.UTF16PtrFromString(s)if err == nil {    syscall.Syscall(uintptr(proc), 1, uintptr(unsafe.Pointer(s16)), 0, 0)}这将转换为 UTF-16 并在末尾为您附加预期的零。

青春有我

处理这个问题的一个好方法是使用mkwinsyscall工具。你可以像这样创建一个 Go 文件:package main//go:generate mkwinsyscall -output zmsi.go msi.go//sys MsiInstallProduct(path string, command string) (e error) = msi.MsiInstallProductW然后运行go generate,你会得到一个这样的结果文件(为简洁起见删除了一些部分):func MsiInstallProduct(path string, command string) (e error) {    var _p0 *uint16    _p0, e = syscall.UTF16PtrFromString(path)    if e != nil {        return    }    var _p1 *uint16    _p1, e = syscall.UTF16PtrFromString(command)    if e != nil {        return    }    return _MsiInstallProduct(_p0, _p1)}func _MsiInstallProduct(path *uint16, command *uint16) (e error) {    r0, _, _ := syscall.Syscall(procMsiInstallProductW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(command)), 0)    if r0 != 0 {        e = syscall.Errno(r0)    }    return}如您所见,它会自动处理字符串转换、系统调用代码,甚至错误处理。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go