【问题标题】:CGO: Convert between LPCWSTR and stringCGO:在 LPCWSTR 和字符串之间转换
【发布时间】:2016-08-12 21:27:20
【问题描述】:

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

【问题讨论】:

    标签: go cgo lpcwstr


    【解决方案1】:

    您应该能够将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 函数。

    【讨论】:

    • @iliacholy:添加了更多信息。您可能希望在 C 中分配内存,因为将该指针从 go 传递到您的 C 代码中可能并不总是安全的。
    • C.calloc() 需要与 C.free() 匹配以避免内存泄漏(与任何内存管理一样,需要了解对象的生命周期,并注意不要过早释放内存)
    【解决方案2】:

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

    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

    【讨论】:

      【解决方案3】:

      作为在 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() 返回。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-06
        • 2021-09-13
        • 2010-11-29
        • 1970-01-01
        • 2020-09-12
        • 1970-01-01
        • 2017-09-06
        相关资源
        最近更新 更多