简体   繁体   English

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

[英]CGO: Convert between LPCWSTR and string

I'm writing CGO bindings for a library which uses LPCWSTR for all of its string types.我正在为一个使用LPCWSTR的所有字符串类型的库编写 CGO 绑定。 How do I convert from C.LPCWSTR to string and vice-versa?如何从C.LPCWSTR转换为string ,反之亦然?

You should be able to "cast" the LPCWSTR as a []uint16 , and use the utf16 package to decode the characters您应该能够将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)

You generally don't want to be passing Go pointers into your C code, so when converting from a string to an LPCWSTR, you will want to alloc the memory in C. A solution for converting from a Go string s might look like:你一般不希望被路过的围棋指针到你的C代码,所以从字符串转换为LPCWSTR时,你会想在页头C.解决办法的内存从一个围棋字符串转换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)
}

There may also be some MFC macros that could help convert to and from cstrings which you could take advantage of with simple wrapper functions in C. This way you could easily copy the data in and out just using the builtin C.CString and C.GoString functions.可能还有一些 MFC 宏可以帮助转换为 cstrings 和从 cstrings 转换,您可以利用 C 中的简单包装函数来利用这些宏。这样,您只需使用内置的C.CStringC.GoString就可以轻松地将数据复制进和出功能。

If you are sure input does not contain null bytes, you can do the encoding yourself:如果您确定输入不包含空字节,您可以自己进行编码:

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 https://golang.org/pkg/unicode/utf16

As an alternative to allocating memory in C, one could just call syscall.UTF16PtrFromString:作为在 C 中分配内存的另一种方法,可以调用 syscall.UTF16PtrFromString:

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

This assumes that the API you're trying to call (supposedly a win32 API since you're using an LPCWSTR) does not making any copies of the string pointers.这假设您尝试调用的 API(假设是 win32 API,因为您使用的是 LPCWSTR)没有制作任何字符串指针的副本。 If this is indeed the case, not allocating C memory should be safe if the GoLang's code scope is appropriate.如果确实如此,如果 GoLang 的代码范围合适,则不分配 C 内存应该是安全的。

For example, something along the lines of the code below should be okay:例如,下面的代码行应该没问题:

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

Here the memory allocated for the string should survive until CallWin32API() returns.这里为字符串分配的内存应该一直存在,直到 CallWin32API() 返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM