在 Windows 上使用带有 Golang 系统调用的结构?

的EnumPrintersWin32函数需要和参数_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完成相同的操作?到目前为止,编译这么多,但我不知道如何将生成的字节切片转换为结构数组(不使用 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: unaligned arguments:


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)

}


白板的微信
浏览 151回答 1
1回答

德玛西亚99

uintptr(unsafe.Pointer(&pPrnInfo))上面代码中的两个地方都是错误的;它为您提供了一个指向切片头的指针,而不是指向实际支持数组的指针。你想要这个:uintptr(unsafe.Pointer(&pPrnInfo[0]))(由于支持数组是连续的,指向支持数组第一个元素的指针与指向支持数组本身的指针相同。)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go