golang, вызов функции GetVolumeInformation winapi
Пытается вызвать функцию GetVolumeInformation из golang. Хотите получить имя Тома.
Используйте спецификации 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 и возвращением строки в результате.
Спасибо.
2 ответов:
Пакет unsafe содержит операции, которые обходят безопасность типа Идут программы.
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)) }
Я не знаю точной проблемы, которая у вас есть, но я думаю, что это вероятно, потому что вы не используете функции в https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go связано с преобразованием из формата, который выходит из ядра, в то, что нужно Go. Посмотрите на других абонентов UTF16ToString, как в env_windows.идите, посмотрите, как они используются.
Comments