CGO:LPCWSTR和字符串之间的转换

CGO:LPCWSTR和字符串之间的转换,go,cgo,lpcwstr,Go,Cgo,Lpcwstr,我正在为一个库编写CGO绑定,该库对其所有字符串类型使用LPCWSTR。如何将C.LPCWSTR转换为string,反之亦然?您应该能够将LPCWSTR转换为[]uint16,并使用utf16包对字符进行解码 // take a C.wstr pointer, and convert it to a go slice // `sz` is the length of the LPCWSTR wstr := (*[1 << 30-1]uint16)(unsafe.Pointer(C.w

我正在为一个库编写CGO绑定,该库对其所有字符串类型使用
LPCWSTR
。如何将
C.LPCWSTR
转换为
string
,反之亦然?

您应该能够将
LPCWSTR
转换为
[]uint16
,并使用
utf16
包对字符进行解码

// take a C.wstr pointer, and convert it to a go slice
// `sz` is the length of the LPCWSTR
wstr := (*[1 << 30-1]uint16)(unsafe.Pointer(C.wstr))[:sz:sz]
runes := utf16.Decode(wstr)
goString := string(runes)

也可能有一些MFC宏可以帮助转换CString和从CString转换,您可以利用C中的简单包装函数。这样,您可以轻松地使用内置的
C.CString
C.GoString
函数复制数据

除了在C中分配内存之外,还可以调用syscall.UTF16PtrFromString:

func Encode(s string) C.LPCWSTR {
    ptr, _ := syscall.UTF16PtrFromString(s)
    return C.LPCWSTR(unsafe.Pointer(ptr))
}
这假设您尝试调用的API(由于您使用的是LPCWSTR,因此假定为win32 API)不复制字符串指针。如果确实如此,如果GoLang的代码范围合适,不分配C内存应该是安全的

例如,下面的代码应该可以:

func DoSomeWindowsStuff(arg string) {
  CallWin32API(Encode(arg))
}

在这里,分配给字符串的内存应该一直存在,直到CallWin32API()返回。

如果您确定输入不包含空字节,则可以进行编码 你自己:

import (
   // #include <windows.h>
   "C"
   "unicode/utf16"
   "unsafe"
)

func PtrFromString(s string) C.LPCWSTR {
   r := []rune(s + "\x00")
   e := utf16.Encode(r)
   p := unsafe.Pointer(&e[0])
   return (C.LPCWSTR)(p)
}
导入(
//#包括
“C”
“unicode/utf16”
“不安全”
)
func PtrFromString(s string)C.LPCWSTR{
r:=[]符文(s+“\x00”)
e:=utf16.编码(r)
p:=不安全。指针(&e[0])
返回(C.LPCWSTR)(p)
}

这看起来对吗@补充了更多的信息。您可能希望在C中分配内存,因为将指针从go传递到C代码中可能并不总是安全的。C.calloc()需要与C.free()匹配,以避免内存泄漏(与任何内存管理一样,需要了解对象的生命周期,并小心不要过早地取消分配内存)
import (
   // #include <windows.h>
   "C"
   "unicode/utf16"
   "unsafe"
)

func PtrFromString(s string) C.LPCWSTR {
   r := []rune(s + "\x00")
   e := utf16.Encode(r)
   p := unsafe.Pointer(&e[0])
   return (C.LPCWSTR)(p)
}