1

我正在为一个LPCWSTR用于所有字符串类型的库编写 CGO 绑定。我如何从C.LPCWSTRto转换,string反之亦然?

4

3 回答 3

2

您应该能够将其“投射”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)

您通常不希望将 Go 指针传递到 C 代码中,因此当从字符串转换为 LPCWSTR 时,您需要在 C 中分配内存。从 Go 字符串转换的解决方案s 可能如下所示:

func Encode(s string) C.LPCWSTR {
    wstr := utf16.Encode([]rune(s))

    p := C.calloc(C.size_t(len(wstr)+1), C.sizeof_uint16_t)
    pp := (*[1 << 30]uint16)(p)
    copy(pp[:], wstr)

    return (C.LPCWSTR)(p)
}

可能还有一些 MFC 宏可以帮助转换为 cstrings 和从 cstrings 转换,您可以利用 C 中的简单包装函数来利用这些宏。这样,您只需使用内置函数C.CStringC.GoString函数就可以轻松地将数据复制进出。

于 2016-08-12T21:44:25.823 回答
1

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

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)
}

https://golang.org/pkg/unicode/utf16

于 2021-01-09T02:48:58.383 回答
0

作为在 C 中分配内存的替代方法,可以只调用 syscall.UTF16PtrFromString:

func Encode(s string) C.LPCWSTR {
    ptr, _ := syscall.UTF16PtrFromString(s)
    return C.LPCWSTR(unsafe.Pointer(ptr))
}

这假设您尝试调用的 API(假设是 win32 API,因为您使用的是 LPCWSTR)不会复制字符串指针。如果确实如此,如果 GoLang 的代码范围合适,不分配 C 内存应该是安全的。

例如,下面的代码行应该没问题:

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

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

于 2020-09-16T21:49:31.267 回答