2015-11-14 9 views
5

sto cercando di chiamare GetUserNameEx da secur32.dll come questo:Golang: come posso chiamare win32 API senza cgo?

dll, err := syscall.LoadDLL("secur32.dll") 
if err != nil { 
    log.Fatal(err) 
} 
defer dll.Release() 

GetUserNameEx, err := dll.FindProc("GetUserNameExW") 
if err != nil { 
    log.Fatal(err) 
} 
arr := make([]uint8, 256) 
var size uint 
GetUserNameEx.Call(3, uintptr(unsafe.Pointer(&arr[0])), uintptr(unsafe.Pointer(&size))) 
fmt.Println(arr) 
fmt.Println(size) 

Questo codice compila bene, ma GetUserNameEx.Call() fallirà. Non so perché non riesco a ottenere UserName. Qualcuno può aiutarmi?

risposta

4

size è un parametro in-out. Quando si effettua la chiamata, è necessario impostarlo sulla dimensione del buffer (arr). Anche il suo tipo è PULONG, quindi in Vai usare uint32. Il tipo di Windows PULONG è un puntatore a ULONG (che ha intervallo 0..4294967295). Vedi source.

anche Call() restituisce 3 valori:

func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) 

Conservare il ritorno lastErr e stamparlo. Avresti fatto così, si dovrebbe trovare l'errore in precedenza:

_, _, lastErr := GetUserNameEx.Call(
    3, uintptr(unsafe.Pointer(&arr[0])), uintptr(unsafe.Pointer(&size))) 

fmt.Println(lastErr) 

Stampe:

More data is available. 

Questo significa più dati sono disponibili di quello che si inserisce nel buffer si passa - o meglio - by la dimensione indicata con il parametro in-out size (hai superato 0 come size).

codice di lavoro (si noti la divisione per 2 a causa unicode e meno 1 per la terminazione '\0' byte/caratteri per il calcolo della dimensione):

arr := make([]uint8, 256) 
var size uint32 = uint32(len(arr))/2 - 1 
_, _, lastErr := GetUserNameEx.Call(
    3, uintptr(unsafe.Pointer(&arr[0])), uintptr(unsafe.Pointer(&size))) 

fmt.Println(lastErr) 
fmt.Println(string(arr)) 
fmt.Println(arr) 
fmt.Println(size) 

In questo caso lastErr saranno:

The operation completed successfully. 

per gestire correttamente l'errore:

The returned error is always non- nil , constructed from the result of GetLastError . Callers must inspect the primary return value to decide whether an error occurred (according to the semantics of the specific function being called) before consulting the error. The error will be guaranteed to contain syscall.Errno .

Esempio:

r1, _, lastErr := GetUserNameEx.Call(
    3, uintptr(unsafe.Pointer(&arr[0])), uintptr(unsafe.Pointer(&size))) 

if r1 == 0 { 
    fmt.Println("ERROR:", lastErr.Error()) 
    return 
} 
// No error, proceed to print/use arr 
+0

> la dimensione è un parametro in-out omg non lo so. Grazie a Icza, ora il mio codice funziona bene. – enugami

+0

@ エ ヌ ガ ミ Si prega di consultare il codice modificato, aggiunta la gestione degli errori che aiuta notevolmente a rilevare gli errori. – icza