2016-12-21 9 views
1

Я использую библиотеки сценариев Go Windows, чтобы получить данные из функции в DLL. Все это отлично работает, но я не могу понять, как преобразовать LPCTSTR (указатель на C String) в правильную строку Go без использования CGO.Преобразование строки C в строку Go без CGO

Я бы хотел избежать CGO, если это вообще возможно, потому что два варианта кода CGO на Windows (кросс-компиляция и установка gcc на windows) по-прежнему довольно сложны.

+0

Я не * думаю * есть простой способ, кроме CGO, не делая что-то взломанное. Вам не нужен gcc для CGO, вы можете установить компилятор CGO, установив env var 'CC = <желаемый компилятор>'. Я не очень разбираюсь в компиляторе windows c, хотя в Windows это просто vvv vars. –

+0

Вы можете, конечно, преобразовать строки, но проблема в том, что LPCTSTR условно является typedef для LPCSTR или LPCWSTR. У вас есть какой-либо способ обеспечить тип? – JimB

+0

@JimB, да, я думаю, что тип строки подразумевается функцией, которую я вызываю, которая имеет суффикс «A» или «W» для двух типов данных. – brooks94

ответ

2

Если у вас есть 8 битовую строку, вы можете преобразовать указатель LPCTSTR к []byte надлежащего размера, и скопируйте его в новую строку или ломтиком.

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) 

Если LPCTSTR указывает на LPCWSTR, который содержит 16-битные символы Unicode, вы можете преобразовать его в пакет utf16.

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

приятно. Зачем нужна копия, если вы просто не хотите использовать строку? – Mark

+1

@Mark: преобразование его в строку неявно делает копию байтов. Если вы вернете срез непосредственно из массива, он укажет на исходную ячейку памяти, которая может или не может быть безопасна для доступа позже. – JimB

0

Если вы можете получить указатель на cstring без CGO, и вы также можете получить длину строки, то, возможно, сначала вы должны создать байтовый срез из cstring.

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 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^