2016-12-21 65 views
1

我使用Go Windows的syscall類庫將數據從DLL中的某個函數中取出。這一切都很好,但我不知道如何將LPCTSTR(指向C字符串的指針)轉換爲合適的Go字符串,而不使用CGO將C字符串轉換爲不含CGO的字符串

如果可能的話,我想盡量避免CGO,因爲Windows上CGO代碼的兩個選項(交叉編譯和在窗口上安裝gcc)仍然相當複雜。

+0

我不*認爲*有一個簡單的方法,除了CGO之外,沒有做一些黑客行爲。你不需要gcc來處理CGO,你可以通過設置env var'CC = '來設置CGO的編譯器。我對windows的c編譯器知之甚少,或者對於windows的env vars。 –

+0

你當然可以轉換字符串,但問題是LPCTSTR有條件地是LPCSTR或LPCWSTR的typedef。你有什麼方法來確保類型? – 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點,其中包含16位Unicode字符LPCWSTR,您可以轉換與UTF-16封裝。

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

如果你可以在沒有CGO的情況下獲得一個指向cstring的指針,並且你也可以獲得字符串的長度,那麼也許你應該首先從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 
}