golang, call GetVolumeInformation winapi function

huangapple go评论100阅读模式
英文:

golang, call GetVolumeInformation winapi function

问题

尝试从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)
}

... 最后出现错误 golang, call GetVolumeInformation winapi function

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

不理解,并且谷歌无法帮助调用winapi函数并返回字符串结果。

谢谢。

英文:

Tries to call GetVolumeInformation function from golang. Want to get volume name.

Use spec's of 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
);

Use code:

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

... and finally have error golang, call GetVolumeInformation winapi function

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

Don't understand and google cant'd help with calling winapi functions and returng string as result.

Thank's.

答案1

得分: 3

> 不安全包
>
> 不安全包包含绕过Go程序类型安全性的操作。
>
> 类型指针
>
> type Pointer *ArbitraryType
>
> Pointer表示指向任意类型的指针。对于类型Pointer,有四个特殊操作是其他类型不可用的。
>
> 1) 任何类型的指针值都可以转换为Pointer。
>
> 2) Pointer可以转换为任何类型的指针值。
>
> 3) uintptr可以转换为Pointer。
>
> 4) Pointer可以转换为uintptr。
>
> 因此,Pointer允许程序绕过类型系统读取和写入任意内存。应该非常小心地使用它。

你没有注意到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))
}
英文:

> 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.

You failed to heed the warning that unsafe.Pointer "should be used with extreme care."

Try this:

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

答案2

得分: 0

我不知道你遇到的具体问题,但我认为可能是因为你没有使用https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go中与将内核输出的格式转换为Go所需格式相关的函数。查看env_windows.go中的其他调用UTF16ToString的代码,看看它们是如何使用的。

英文:

I don't know the exact problem you are having but I think it is likely because you are not using the functions in https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go related to converting from the format that comes out of the kernel to what Go needs. Look at other callers to UTF16ToString, like in env_windows.go, to see how they are used.

huangapple
  • 本文由 发表于 2016年2月6日 16:23:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/35238933.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定