GoLang Convert C.wchar_t to go string

huangapple go评论90阅读模式
英文:

GoLang Convert C.wchar_t to go string

问题

我正在寻找将[32]C.wchar_t转换为Go字符串的方法。

在我所使用的dll中,该数组定义如下:

typedef struct myStruct {
    WCHAR someString[32];
}

我在Go中定义结构体如下:

type myStruct struct {
    someString [32]C.wchar_t
}

我有一个在dll中的方法:

DLLINTERFACE HRESULT __stdcall GetMyStruct (myStruct* ptrMyStruct);

该方法将填充myStructsomeString字段。

我这样调用该方法(我认为这个调用是正确的,但我无法查看someString的内容):

func getMyStruct() (*myStruct, uintptr) {
    var getMyStruct = dll.MustFindProc("GetMyStruct")
    var args = new(myStruct)
    ret, _, _ := getMyStruct.Call(uintptr(unsafe.Pointer(args)))

    fmt.Printf("Return: %d\n", (int)(ret))
    return args, ret
}

我需要将someString转换为Go字符串。我尝试使用"github.com/GeertJohan/cgo.wchar",但它没有提供将[]C.wchar_t转换为Go字符串的方法。

目前我不确定我的Go结构体是否正确。我也不确定在将其发送到dll之前是否正确初始化了myStruct

非常感谢任何帮助。

英文:

I am looking to convert a [32]C.wchar_t to a go string.

The array is defined as follows in the dll I am talking to:

typedef struct myStruct {
    WCHAR someString[32];
}

I am defining the struct in go as follows:

type myStruct struct {
	someString [32]C.wchar_t
}

I have a method in the dll:

DLLINTERFACE HRESULT __stdcall GetMyStruct (myStruct* ptrMyStruct);

This method will populate the someString field of myStruct.

I am calling the method like so (this is working correctly, I think, I have not been able to see the contents of someString):

func getMyStruct() (*myStruct, uintptr) {
    var getMyStruct = dll.MustFindProc("GetMyStruct")
    var args = new(myStruct)
    ret, _, _ := getMyStruct .Call(uintptr(unsafe.Pointer(args)))

    fmt.Printf("Return: %d\n", (int)(ret))
    return args, ret
}

I need to convert someString to a go string. I have tried using "github.com/GeertJohan/cgo.wchar", but it does not have a method for converting []C.whar_t to go string.

Currently I'm not sure if my go struct is correct. I'm also not sure if I am initializing myStruct correctly before sending it to the dll.

Any help will be greatly appreciated.

答案1

得分: 1

在Windows上,wchar_t通常是UTF-16编码(小端序)。它们通常不带有BOM(字节顺序标记,用于让解码器检测存储的字节顺序是大端还是小端)。

有一个utf16包,但它只能转换单个符文。然而,还有一个额外的unicode文本编码包可以帮助解决这个问题。

你可以尝试以下代码:

dec := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()
out, err := dec.Bytes([]byte(args.someString))
if err != nil {
    // 处理错误
}
// 字符串以空字符结尾,只需要获取到空字符之前的内容
i := bytes.IndexByte(out, 0)
if i == -1 {
    i = len(out)
}
s := string(out[:i])

不过,我建议将someString声明为[64]byte,这是一个32个字符所需的字节数(每个字符占用16位,即2个字节)。这样可以避免使用不安全的类型转换,但其他部分应该与上述代码相同。

我凭记忆写的代码,上面的代码只是一个示例,可能不一定能正常工作,请谨慎使用。

英文:

On Windows, wchar_t is normally UTF-16 (little-endian). They don't normally start with a BOM (which is present so a decoder can detect if they are stored in big or little endian form).

There is a utf16 package but this only translates individual runes. However, there is an additional unicode text encoding package that can help.

You would probably do something like this:

dec:=unicode.UTF16(unicode.LittleEndian,unicode.UseBOM).NewDecoder()
out,err:= dec.Bytes(([]byte)(unsafe.Pointer(args.someString)))
if err!=nil {
	//handle error
}
// Strings are null terminated, only want content up to null byte
i:=bytes.IndexByte(out,0)
if i==-1 {
   i = len(out)
}
s:=string(out[:i]) 

However, I'd be tempted to declare someString as [64]byte which is the amount of bytes that a 32 character (16 bites = 2 bytes per character) would need. This would avoid the unsafe typecasting but otherwise should work as above.

I'm doing this off the top of my head so the code above is meant as an example & may not necessarily work - use at your peril GoLang Convert C.wchar_t to go string

答案2

得分: 0

似乎GeertJohan的库还没有针对最新的cgo更改进行更新,但有一个分支已经更新了,可以尝试使用github.com/vitaminwater/cgo.wchargodoc)。

如果C函数写入C类型,请传递一个相应的C类型的变量。

以下是一个(不太可靠的)示例:

package main

/*
#include <wchar.h>
#include <string.h>

typedef struct myStruct {
    wchar_t someString[32];
} myStruct;

wchar_t sample[6] = {0x0048, 0x0069, 0x0020, 0x4e16, 0x754c, 0};

void writeSample(myStruct *m) {
    memcpy(m->someString, &sample, sizeof(wchar_t) * 6);
}
*/
import "C"
import (
    "fmt"
    "log"
    "unsafe"

    "github.com/vitaminwater/cgo.wchar"
)

func main() {

    m := C.myStruct{}

    C.writeSample(&m)

    s, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(&m.someString))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(s)
}

这将输出:

Hi 世界

英文:

It seems GeertJohan's library hasn't been updated for the more recent cgo changes, but a fork has, try github.com/vitaminwater/cgo.wchar (godoc) instead.

If the C function writes to a C type, pass a variable of the C type.

A (dodgy) example:

package main

/*
#include &lt;wchar.h&gt;
#include &lt;string.h&gt;

typedef struct myStruct {
    wchar_t someString[32];
} myStruct;

wchar_t sample[6] = {0x0048, 0x0069, 0x0020, 0x4e16, 0x754c, 0};

void writeSample(myStruct *m) {
	memcpy(m-&gt;someString, &amp;sample, sizeof(wchar_t) * 6);
}
*/
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;unsafe&quot;

	&quot;github.com/vitaminwater/cgo.wchar&quot;
)

func main() {

	m := C.myStruct{}

	C.writeSample(&amp;m)

	s, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(&amp;m.someString))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)
}

This outputs:

Hi 世界

huangapple
  • 本文由 发表于 2017年7月27日 15:38:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/45344285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定