winapi - 在 Windows 上将结构与 Golang 系统调用一起使用?

标签 winapi go

EnumPrinters Win32 函数采用参数_Out_ LPBYTE pPrinterEnum,即指向已分配缓冲区的指针。在 C 语言中,它的工作原理如下:

DWORD cbNeeded, nPrinters;
EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &cbNeeded, &nPrinters);

BYTE *pPrnInfo = malloc(cbNeeded);
EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, pPrnInfo, cbNeeded, &cbNeeded, &nPrinters);

PRINTER_INFO_5 *pPrinterInfo = (PRINTER_INFO_5 *) pPrnInfo;
for (int i=0; i < nPrinters; i++) {
  printf("pPrinterName: %s\n", pPrinterInfo[i].pPrinterName);
}

在 Go 中如何使用 syscall 而不是 cgo 来实现同样的功能?到目前为止,编译了这么多,但我不知道如何将生成的字节 slice 转换为结构数组(不使用 cgo)。

type PrinterInfo5 struct {
    pPrinterName             *uint16
    pPortName                *uint16
    attributes               uint32
    deviceNotSelectedTimeout uint32
    transmissionRetryTimeout uint32
}

...

dll := syscall.MustLoadDLL("winspool.drv")
f := dll.MustFindProc("EnumPrintersW")

var cbNeeded, nPrinters uint32
fmt.Println(cbNeeded, nPrinters)
f.Call(PRINTER_ENUM_LOCAL, 0, 5, 0, 0, uintptr(unsafe.Pointer(&cbNeeded)), uintptr(unsafe.Pointer(&nPrinters)))
fmt.Println(cbNeeded, nPrinters)

var pPrnInfo []byte = make([]byte, cbNeeded)
f.Call(PRINTER_ENUM_LOCAL, 0, 5, uintptr(unsafe.Pointer(&pPrnInfo)), uintptr(cbNeeded), uintptr(unsafe.Pointer(&cbNeeded)), uintptr(unsafe.Pointer(&nPrinters)))

我已经尝试过这个,它成功打印一次迭代,然后失败并出现 fatal error :heapBitsBulkBarrier:未对齐的参数:

hdr := reflect.SliceHeader{
  Data: uintptr(unsafe.Pointer(&pPrnInfo)),
  Len:  int(nPrinters),
  Cap:  int(nPrinters),
}
s := *(*[]PrinterInfo5)(unsafe.Pointer(&hdr))
for _, t := range s {
  fmt.Println(t)
}

最佳答案

uintptr(unsafe.Pointer(&pPrnInfo))

上面代码中的两个地方都是错误的;它为您提供了指向 slice 头的指针,而不是指向实际后备数组的指针。你想要这个:

uintptr(unsafe.Pointer(&pPrnInfo[0]))

(由于后备数组是连续的,因此指向后备数组第一个元素的指针与指向后备数组本身的指针相同。)

关于winapi - 在 Windows 上将结构与 Golang 系统调用一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33769766/

相关文章:

c++ - 如何修复ListView中的错误?封装控件时无法选择任何项目

c++ - WinAPI 从编辑控件中检索文本

c++ - 使用 WinAPI 的简单 AES 加密

go - 如何更改 Go 中的当前目录

go - 用 cookies 创建一个计数器

pointers - 简洁的 nil 检查结构字段指针?

winapi - 渲染音频流(WASAPI/WINAPI)

delphi - CreateVirtualDisk 给出错误 87(参数不正确。)

去 : model ( or interface ) function with input of different types

go - 在 Go 编程中使用 golang-Debian 包