将字符串传递给Syscall(uintptr)

Frn*_*Wdl 2 dll go

我需要在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) 
Run Code Online (Sandbox Code Playgroud)

但它不起作用.Syscall采取param uintptr.我不能使用C包,因为它不会在Windows上构建.

在C中它的工作原理如下:

strcpy(acIn, "device = STM32F407IE");

JLINKARM_ExecCommand(acIn, &acOut[0], sizeof(acOut));
Run Code Online (Sandbox Code Playgroud)

那么C DLL是否可以获得字符串参数并正确使用它?

gon*_*utz 6

要将字符串传递给syscall,您需要将指针传递给字符串的第一个字符.第一个问题是你的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)
Run Code Online (Sandbox Code Playgroud)

首先将您的字符串转换为字节数组,然后添加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)
}
Run Code Online (Sandbox Code Playgroud)

这将转换为UTF-16并在最后为您追加预期的零.