当前位置: 首页 > 面试题库 >

golang,调用WinVolumeInformation winapi函数

帅彦
2023-03-14
问题内容

尝试从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]

不理解,Google无法帮助调用winapi函数和returng字符串作为结果。

谢谢。


问题答案:

包裹不安全

不安全的软件包包含绕过Go程序的类型安全的操作。

类型指针

type Pointer *ArbitraryType

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

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

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

3)可以将uintptr转换为Pointer。

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))
}


 类似资料:
  • 问题内容: 我正在编写一个调用Windows DLL的Go应用程序。该DLL是用MSVC编写的,并且使用__declspec(dllexport)具有外部“ C”导出。 我的Go应用程序的顶部如下: 我从这样的模块中调用函数: 问题是,当我尝试运行此应用程序时,出现以下错误: 我用DUMPBIN查看了DLL导出的符号,它确切显示了“moduleImpl_len”作为导出的符号。这也是MyModul

  • Go 语言和 C 语言一样也有函数的概念,Go 语言中函数除了定义格式和不用声明以外,其它方面几乎和 C 语言一模一样,格式: func 函数名称(形参列表)(返回值列表){ 函数体; } 无参数无返回值函数 func say() { fmt.Println("Hello World!!!") } 有参数无返回值函数 func say(name string) { fmt

  • Go 语言中没有提供其它面向对象语言的析构函数,但是 Go 语言提供了 defer 语句用于实现其它面向对象语言析构函数的功能 defer 语句常用于 释放资源、解除锁定 以及 错误处理 等 例如C语言中我们申请了一块内存空间,那么不使用时我们就必须释放这块存储空间 例如C语言中我们打开了一个文件,那么我们不使用时就要关闭这个文件 例如C语言中我们打开了一个数据库, 那么我们不使用时就要关闭这个数

  • golang 里面有两个保留的函数: init 函数(能够应用于所有的 package) main 函数(只能应用于 package main) 这两个函数在定义时不能有任何的参数和返回值 go 程序会自动调用 init() 和 main(),所以你 不能 在任何地方调用这两个函数 package main 必须包含一个 main 函数,但是每个 package 中的 init 函数都是可选的 一

  • 问题内容: 我有一个类似于以下的代码 这不是实际的生产代码,但这是简化的版本。 问题:-如果取消注释该行,则会出现编译错误 如何执行通过Invoke()函数作为参数接收的函数? 什么是实现此目标的正确方法? 问题答案: 您可以使用的或方法将其作为函数调用。与所有方法一样,这种恐慌是错误的类型。 http://play.golang.org/p/xGmNLDcLL_

  • 匿名函数也是函数的一种,它的格式和普通函数一模一样,只不过没有名字而已 普通函数的函数名称是固定的, 匿名函数的函数名称是系统随机的 匿名函数可以定义在函数外(全局匿名函数),也可以定义在函数内(局部匿名函数),Go语言中的普通函数不能嵌套定义,但是可以通过匿名函数来实现函数的嵌套定义 全局匿名函数 package main import "fmt" // 方式一 var a = func(