doxrxwn2252 2015-11-18 00:33
浏览 166
已采纳

在Windows上将结构与Golang syscall一起使用?

The EnumPrinters Win32 function takes and argument _Out_ LPBYTE pPrinterEnum, a pointer to an allocated buffer. In C, it works like this:

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
", pPrinterInfo[i].pPrinterName);
}

How is the same accomplished in Go, using syscall instead of cgo? So far, this much compiles, but I don't know how to cast the resulting byte slice to an array of structs (without using 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)))

I have tried this, which prints one iteration successfully, then fails with 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)
}
  • 写回答

1条回答 默认 最新

  • dourang20110122 2015-11-18 12:49
    关注
    uintptr(unsafe.Pointer(&pPrnInfo))
    

    in both places in the code above is wrong; it gives you a pointer to the slice header, not to the actual backing array. You want this instead:

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

    (Since the backing array is contiguous, a pointer to the first element of the backing array is the same as a pointer to the backing array itself.)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站