首頁  >  文章  >  後端開發  >  如何在Go中正確呼叫GetVolumeInformation WinAPI函數,並避免意外錯誤?

如何在Go中正確呼叫GetVolumeInformation WinAPI函數,並避免意外錯誤?

Susan Sarandon
Susan Sarandon原創
2024-10-25 08:17:28386瀏覽

How to correctly invoke the GetVolumeInformation WinAPI function in Go, and avoid unexpected errors?

在 Go 中呼叫 GetVolumeInformation WinAPI 函數

本文詳細介紹了使用 Go 中的 GetVolumeInformation WinAPI 函數檢索磁碟區名稱的嘗試。然而,最初的努力卻遇到了意外的錯誤。

問題陳述

嘗試將字串緩衝區作為 lpVolumeNameBuffer 參數傳遞時出現問題。程式碼失敗,錯誤「意外的錯誤位址0xffffffffffffffff。」

分析

使用unsafe.Pointer 將Go 字串轉換為指向uint16 陣列的指標被確定為錯誤的指標的原因。在 Go 中,在沒有很好地理解後果的情況下,通常不應直接操作指標。

解決方案

為了解決此問題,重寫了程式碼以建立一個固定的-uint16 字元的緩衝區大小,並將指向緩衝區第一個元素的指標會以lpVolumeNameBuffer 參數傳遞。這種方法可確保緩衝區正確對齊,並避免使用 unsafe.Pointer。

這裡是修正後的程式碼:

<code class="go">package main

import (
    "fmt"
    "syscall"
)

func main() {
    const 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, err := syscall.LoadLibrary("kernel32.dll")
    if err != nil {
        fmt.Println("Error loading kernel32: ", err)
        return
    }

    getVolume, err := syscall.GetProcAddress(kernel32, "GetVolumeInformationW")
    if err != nil {
        fmt.Println("Error getting GetVolumeInformation address: ", err)
        return
    }

    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)

    if ret != 0 {
        fmt.Println("Call succeeded: ", syscall.UTF16ToString(VolumeNameBuffer))
    } else {
        fmt.Println("Call failed: ", callErr)
    }
}</code>

此修改後的程式碼應該會成功擷取並列印名稱指定體積。

以上是如何在Go中正確呼叫GetVolumeInformation WinAPI函數,並避免意外錯誤?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn