2 回答
TA贡献1875条经验 获得超3个赞
要将字符串传递给系统调用,您需要传递指向字符串第一个字符的指针。第一个问题是您的 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 并在末尾为您附加预期的零。
TA贡献1784条经验 获得超8个赞
处理这个问题的一个好方法是使用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
}
如您所见,它会自动处理字符串转换、系统调用代码,甚至错误处理。
- 2 回答
- 0 关注
- 171 浏览
添加回答
举报