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
", (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.
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 :-)
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 <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)
}
This outputs:
Hi 世界