golang,调用GetVolumeInformation winapi函数

尝试从 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 函数并返回字符串作为结果。


www说
浏览 269回答 2
2回答

繁星淼淼

包裹不安全包 unsafe 包含绕过 Go 程序类型安全的操作。类型指针type Pointer *ArbitraryType指针表示指向任意类型的指针。有四种特殊操作可用于类型 Pointer,其他类型不可用。1) 任何类型的指针值都可以转换为指针。2) 指针可以转换为任何类型的指针值。3) uintptr 可以转换为指针。4) 可以将指针转换为 uintptr。因此,指针允许程序击败类型系统并读取和写入任意内存。它应该非常小心地使用。你没有注意unsafe.Pointer“应该非常小心地使用”的警告。尝试这个:package mainimport (    "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))}

白衣非少年

我不知道您遇到的确切问题,但我认为这可能是因为您没有使用https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go 中与从内核产生的格式转换为 Go 需要的格式。查看 UTF16ToString 的其他调用者,例如在 env_windows.go 中,以了解它们是如何使用的。
打开App,查看更多内容
随时随地看视频慕课网APP