Maison >développement back-end >Golang >Comment appeler correctement la fonction GetVolumeInformation WinAPI dans Go et éviter les erreurs inattendues ?

Comment appeler correctement la fonction GetVolumeInformation WinAPI dans Go et éviter les erreurs inattendues ?

Susan Sarandon
Susan Sarandonoriginal
2024-10-25 08:17:28484parcourir

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

Appel de la fonction GetVolumeInformation WinAPI dans Go

Cet article détaille une tentative de récupération du nom d'un volume à l'aide de la fonction GetVolumeInformation WinAPI depuis Go. Cependant, les efforts initiaux ont rencontré une erreur inattendue.

Énoncé du problème

Le problème est survenu lors de la tentative de transmission d'un tampon de chaîne en tant que paramètre lpVolumeNameBuffer. Le code a échoué avec l'erreur "adresse de défaut inattendue 0xffffffffffffffff."

Analyse

L'utilisation de unsafe.Pointer pour convertir la chaîne Go en pointeur vers un tableau uint16 a été identifié comme la cause de l'erreur. Dans Go, les pointeurs ne doivent généralement pas être manipulés directement sans une bonne compréhension des conséquences.

Solution

Pour résoudre ce problème, le code a été réécrit pour créer un correctif -size buffer de uint16 caractères et passer un pointeur vers le premier élément du buffer en tant que paramètre lpVolumeNameBuffer. Cette approche garantit que le tampon est correctement aligné et évite d'avoir à utiliser unsafe.Pointer.

Voici le code corrigé :

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

Ce code modifié devrait réussir à récupérer et imprimer le nom du volume spécifié.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn