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/