winapi - golang,调用GetVolumeInformation winapi函数

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

谢谢。

最佳答案

Package unsafe

Package unsafe contains operations that step around the type safety of Go programs.

type Pointer

type Pointer *ArbitraryType

Pointer represents a pointer to an arbitrary type. There are four special operations available for type Pointer that are not available for other types.

1) A pointer value of any type can be converted to a Pointer.

2) A Pointer can be converted to a pointer value of any type.

3) A uintptr can be converted to a Pointer.

4) A Pointer can be converted to a uintptr.

Pointer therefore allows a program to defeat the type system and read and write arbitrary memory. It should be used with extreme care.

您没有注意到 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))
}

关于winapi - golang,调用GetVolumeInformation winapi函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35238933/

相关文章:

c# - SetWindowsHookEx(WH_KEYBOARD) 仅产生第一个事件、顺序事件

performance - 进行分析

go - 为整个 golang 项目设置一次变量

go - Golang 中的 RLock() 和 Lock() 有什么区别?

winapi - ListView 网格线问题

windows - GetLastError返回ERROR_OPERATION_ABORTED时,GetOverlappedResult的lpNumberOfBytesTransfered参数是否有效?

c# - 获取任务栏中所有窗口的句柄

c++ - 使用 GLFW 渲染和 WinAPI 处理消息

go - 如何通过struct field Name取值

go - gl.DrawElements似乎使用了错误的索引