golang,调用GetVolumeInformation winapi函数

时间:2016-02-06 08:23:03

标签: winapi go

尝试从golang调用GetVolumeInformation函数。想获得卷名。

使用api的规范:

BOOL WINAPI GetVolumeInformation(
  _In_opt_  LPCTSTR lpRootPathName,
  _Out_opt_ LPTSTR  lpVolumeNameBuffer,
  _In_      DWORD   nVolumeNameSize,
  _Out_opt_ LPDWORD lpVolumeSerialNumber,
  _Out_opt_ LPDWORD lpMaximumComponentLength,
  _Out_opt_ LPDWORD lpFileSystemFlags,
  _Out_opt_ LPTSTR  lpFileSystemNameBuffer,
  _In_      DWORD   nFileSystemNameSize
);

使用代码:

// test
package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

func main() {
    var lpRootPathName = "C:\\"
    var lpVolumeNameBuffer string
    var nVolumeNameSize uint64
    var lpVolumeSerialNumber uint64
    var lpMaximumComponentLength uint64
    var lpFileSystemFlags uint64
    var lpFileSystemNameBuffer string
    var nFileSystemNameSize uint32

    kernel32, _ := syscall.LoadLibrary("kernel32.dll")
    getVolume, _ := syscall.GetProcAddress(kernel32, "GetVolumeInformationW")

    var nargs uintptr = 8
    ret, _, callErr := syscall.Syscall9(uintptr(getVolume),
        nargs,
        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpRootPathName))),
        uintptr(unsafe.Pointer(&lpVolumeNameBuffer)),
        uintptr(unsafe.Pointer(&nVolumeNameSize)),
        uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
        uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
        uintptr(unsafe.Pointer(&lpFileSystemFlags)),
        uintptr(unsafe.Pointer(&lpFileSystemNameBuffer)),
        uintptr(unsafe.Pointer(&nFileSystemNameSize)),
        0)
    fmt.Println(ret, callErr, lpVolumeNameBuffer)
}

......最后有错误:(

unexpected fault address 0xffffffffffffffff
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xffffffffffffffff pc=0x456b11]

不要理解,谷歌不能帮助调用winapi函数并返回字符串作为结果。

感谢' S

2 个答案:

答案 0 :(得分:0)

我不知道您遇到的确切问题,但我认为可能是因为您没有使用https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go中与从内核格式转换为Go的相关函数需要。查看UTF16ToString的其他调用者,就像在env_windows.go中一样,看看它们是如何被使用的。

答案 1 :(得分:0)

  

Package unsafe

     

包unsafe包含围绕类型安全性的操作   去节目。

     

type Pointer

type Pointer *ArbitraryType
     

指针表示指向任意类型的指针。有四个   特殊操作可用于类型指针,但不可用   对于其他类型。

     

1)任何类型的指针值都可以转换为指针。

     

2)指针可以转换为任何类型的指针值。

     

3)uintptr可以转换为指针。

     

4)指针可以转换为uintptr。

     

指针因此允许程序打败类型系统并读取   并写入任意内存。它应该非常小心使用。

你没有注意到应该谨慎使用unsafe.Pointer“的警告。”

试试这个:

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

func main() {
    var RootPathName = `C:\`
    var VolumeNameBuffer = make([]uint16, syscall.MAX_PATH+1)
    var nVolumeNameSize = uint32(len(VolumeNameBuffer))
    var VolumeSerialNumber uint32
    var MaximumComponentLength uint32
    var FileSystemFlags uint32
    var FileSystemNameBuffer = make([]uint16, 255)
    var nFileSystemNameSize uint32 = syscall.MAX_PATH + 1

    kernel32, _ := syscall.LoadLibrary("kernel32.dll")
    getVolume, _ := syscall.GetProcAddress(kernel32, "GetVolumeInformationW")

    var nargs uintptr = 8
    ret, _, callErr := syscall.Syscall9(uintptr(getVolume),
        nargs,
        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(RootPathName))),
        uintptr(unsafe.Pointer(&VolumeNameBuffer[0])),
        uintptr(nVolumeNameSize),
        uintptr(unsafe.Pointer(&VolumeSerialNumber)),
        uintptr(unsafe.Pointer(&MaximumComponentLength)),
        uintptr(unsafe.Pointer(&FileSystemFlags)),
        uintptr(unsafe.Pointer(&FileSystemNameBuffer[0])),
        uintptr(nFileSystemNameSize),
        0)
    fmt.Println(ret, callErr, syscall.UTF16ToString(VolumeNameBuffer))
}