Convert C string to Go string without CGO

1.3k views Asked by At

I'm using the Go Windows syscall libraries to get data out of a function in a DLL. This all works great, but I can't figure out a way to convert a LPCTSTR (pointer to C String) into a proper Go string without using CGO.

I'd like to avoid CGO if at all possible, because the two options for CGO code on Windows (cross-compiling, and installing gcc on windows) are still fairly complex.

2

There are 2 answers

3
JimB On BEST ANSWER

If you have an 8 bit string, you can convert the LPCTSTR pointer to a []byte of the proper size, and copy it to a new string or slice.

a := (*[1 << 30-1]byte)(unsafe.Pointer(lpctstr))
size := bytes.IndexByte(a[:], 0)
// if you just want a string
// goString := string(a[:size:size])

// if you want a slice pointing to the original memory location without a copy
// goBytes := a[:size:size]

goBytes := make([]byte, size)
copy(goBytes, a)

If the LPCTSTR points to an LPCWSTR which contains 16bit unicode characters, you can convert that with the utf16 package.

a := (*[1 << 30-1]uint16)(unsafe.Pointer(lpctstr))
size := 0
for ; size < len(a); size++ {
    if a[size] == uint16(0) {
        break
    }
}   
runes := utf16.Decode(a[:size:size])
goString := string(runes)
0
WeakPointer On

If you can get a pointer to a cstring without CGO, and you can get the length of the string too, then perhaps you should create a byte slice from the cstring first.

import (
    "reflect"
    "unsafe"
)

func ToByteSlice() []byte {
    var bytes []byte

    shdr := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
    shdr.Cap = int(stringlen)
    shdr.Len = int(stringlen)
    shdr.Data = uintptr(unsafe.Pointer(cpointer))

    return bytes
}