我如何正确调用netapi32!NetSessionEnum()?

时间:2016-03-09 07:27:26

标签: winapi go

我一直试图使用netapi32.dll,但我的结果好坏参与。

以下按预期工作

type SERVER_INFO_101 struct {
      PlatformID   uint32
      Name         *uint16
      VersionMajor uint32
      VersionMinor uint32
      Type         uint32
      Comment      *uint16
}


func NetServerGetInfo() {
      info := &SERVER_INFO_101{}
      ret, _, err := procNetServerGetInfo.Call(0, 101, uintptr(unsafe.Pointer(&info)))
      if ret != 0 {
              log.Fatal(err)
      }
      spew.Dump(info)
}

但是,我不确定为什么信息必须有&在unsafe.Pointer里面。

以下不起作用,我似乎无法找出原因。没有错误代码被抛出。结构或变量都没有填写。

type SESSION_INFO_10 struct {
      Cname    *uint16
      Username *uint16
      Time     uint32
      IdleTime uint32
}

func NetSessionEnum() {
      info := &SESSION_INFO_10{}
      var prefmaxlen int32 = -1
      var entriesread uint32
      var totalentries uint32
      var resumehandle uint32
      x, y, z := procNetSessionEnum.Call(0, 0, 0, 10, uintptr(unsafe.Pointer(info)), uintptr(prefmaxlen), uintptr(unsafe.Pointer(&entriesread)), uintptr(unsafe.Pointer(&totalentries)), uintptr(unsafe.Pointer(&resumehandle)))
      fmt.Println(x, y, z)
      fmt.Println(entriesread, totalentries)
      spew.Dump(info)
}

1 个答案:

答案 0 :(得分:1)

...因为您不应该将指针传递给您的内存块 - 引用the manual

  

此缓冲区由系统分配,必须使用NetApiBufferFree函数释放。

该指针的类型具有误导性,但您应该将指针传递给指针,如下所示:

func NetSessionEnum() {
      var pinfo *SESSION_INFO_10
      var prefmaxlen int32 = -1
      var entriesread uint32
      var totalentries uint32
      var resumehandle uint32
      x, y, z := procNetSessionEnum.Call(0, 0, 0, 10,
          uintptr(unsafe.Pointer(&pinfo)), uintptr(prefmaxlen),
          uintptr(unsafe.Pointer(&entriesread)),
          uintptr(unsafe.Pointer(&totalentries)),
          uintptr(unsafe.Pointer(&resumehandle)))
      fmt.Println(x, y, z)
      fmt.Println(entriesread, totalentries)
      spew.Dump(info)
}

// Now use `*pinfo.Cname` etc
// Don't forget to later call `NetApiBufferFree()` on that pointer.

这里会发生什么:

  1. 变量pinfo是指向SESSION_INFO_10类型值的指针。

  2. 您获取由该变量(指针)中保存的值占用的内存块的地址,并将其传递给NetSessionEnum()

  3. 该函数自行分配缓冲区并将其地址写入您传递给函数的地址所指向的内存块。

    由于您已传递pinfo变量的地址,因此缓冲区的地址最终会写入变量pinfo

  4. 然后使用pinfo中存储的地址访问NetSessionEnum()分配的内存。

  5. 这被称为“双重间接”,并在Win32 API的很多地方使用。希望你明白了。

    请仔细阅读手册页并研究其中包含的代码示例。

    更新:结果显示,原始代码存在更多问题,因此我花时间提供完整解决方案 - here是要点(使用Go 1.6 amd64测试)在Windows XP 32位,Windows 2003 R2 64位和Windows 8.1 64位上运行i386。