2 回答

TA貢獻1875條經(jīng)驗 獲得超3個贊
要將字符串傳遞給系統(tǒng)調(diào)用,您需要傳遞指向字符串第一個字符的指針。第一個問題是您的 DLL 函數(shù)需要什么字符串編碼。Go 字符串被編碼為 UTF-8 unicode,因此如果您的 C 函數(shù)需要其他內(nèi)容,您必須先轉(zhuǎn)換它們。以下是一些常見的情況:
1)ASCII字符串
假設(shè)您的 C 函數(shù)需要一個以零結(jié)尾的 ASCII 字符串,那么您可以執(zhí)行以下操作:
s := "some string"
b := append([]byte(s), 0)
syscall.Syscall(uintptr(proc), 1, uintptr(unsafe.Pointer(&b[0])), 0, 0)
首先將您的字符串轉(zhuǎn)換為字節(jié)數(shù)組,并在末尾添加 C 期望的零。然后將指針傳遞給第一個字節(jié)字符。
為了安全起見,您還應(yīng)該確保您實際上只傳入有效的 ASCII 字符串,沒有無效字符。通常只有 [0..127] 范圍內(nèi)的字符對通用 ASCII 有效。其余取決于當前代碼頁。
2) Windows 上的 UTF-16
如果您調(diào)用 Windows DLL,您通常希望使用該函數(shù)的 UTF-16 版本,例如SendMessageW,因此需要將您的字符串轉(zhuǎn)換為 UTF-16。幸運的是,在 Windows 下有一個包裝函數(shù),因此您只需執(zhí)行以下操作:
s := "some string"
s16, err := syscall.UTF16PtrFromString(s)
if err == nil {
syscall.Syscall(uintptr(proc), 1, uintptr(unsafe.Pointer(s16)), 0, 0)
}
這將轉(zhuǎn)換為 UTF-16 并在末尾為您附加預(yù)期的零。

TA貢獻1784條經(jīng)驗 獲得超8個贊
處理這個問題的一個好方法是使用mkwinsyscall工具。你可以像這樣創(chuàng)建一個 Go 文件:
package main
//go:generate mkwinsyscall -output zmsi.go msi.go
//sys MsiInstallProduct(path string, command string) (e error) = msi.MsiInstallProductW
然后運行g(shù)o generate,你會得到一個這樣的結(jié)果文件(為簡潔起見刪除了一些部分):
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
}
如您所見,它會自動處理字符串轉(zhuǎn)換、系統(tǒng)調(diào)用代碼,甚至錯誤處理。
- 2 回答
- 0 關(guān)注
- 249 瀏覽
添加回答
舉報