Golang:如何在没有cgo的情况下调用win32 API?

时间:2015-11-14 13:42:19

标签: windows winapi dll go

我正试图从GetUserNameEx拨打secur32.dll,如下所示:

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)

此代码编译良好,但GetUserNameEx.Call()将失败。我不知道为什么我不能得到UserName。有谁可以帮助我?

1 个答案:

答案 0 :(得分:6)

size是一个输入输出参数。进行调用时,必须将其设置为缓冲区的大小(arr)。它的类型也是PULONG,因此在Go中使用uint32。 Windows enter image description here类型是指向PULONG(范围为0..4294967295)的指针。请参阅ULONG

同样Call()返回3个值:

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

存储返回的lastErr并打印出来。你会这样做,你会发现错误:

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

fmt.Println(lastErr)

打印:

More data is available.

这意味着有更多数据可用于您传递的缓冲区 - 或更确切地说 - 您使用输入输出参数size指定的大小(您通过了{{1作为0)。

工作代码(注意由于unicode而除以2,对于用于大小计算的终止size字节/字符,减去1:

'\0'

在这种情况下,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) 将是:

lastErr

正确处理错误:

  

返回的错误始终为非The operation completed successfully. ,由nil的结果构成。在查询错误之前,调用者必须检查主要返回值以确定是否发生了错误(根据被调用的特定函数的语义)。该错误将保证包含GetLastError

示例:

syscall.Errno