获取固定驱动器列表

人气:364 发布:2022-10-16 标签: windows winapi go system-calls ffi

问题描述

如何才能仅获取实体驱动器的所有装入点的列表?我看到这里有类似的答案,但它列出了包括网络共享在内的所有装入点。

How can I get a listing of all drives on Windows using golang?

推荐答案

好了,我已决定重拾Win32API编程技能并准备解决方案。

基于the thread you referred to中的LAME方法的解决方案如下:

package main

import (
    "errors"
    "fmt"
    "log"
    "syscall"
    "unsafe"
)

var (
    kernel32 = syscall.NewLazyDLL("kernel32.dll")

    getDriveTypeWProc = kernel32.NewProc("GetDriveTypeW")
)

func getDriveType(rootPathName []uint16) (int, error) {
    rc, _, _ := getDriveTypeWProc.Call(
        uintptr(unsafe.Pointer(&rootPathName[0])),
    )

    dt := int(rc)

    if dt == driveUnknown || dt == driveNoRootDir {
        return -1, driveTypeErrors[dt]
    }

    return dt, nil
}

var (
    errUnknownDriveType = errors.New("unknown drive type")
    errNoRootDir        = errors.New("invalid root drive path")

    driveTypeErrors = [...]error{
        0: errUnknownDriveType,
        1: errNoRootDir,
    }
)

const (
    driveUnknown = iota
    driveNoRootDir

    driveRemovable
    driveFixed
    driveRemote
    driveCDROM
    driveRamdisk
)

func getFixedDOSDrives() ([]string, error) {
    var drive = [4]uint16{
        1: ':',
        2: '\',
    }

    var drives []string

    for c := 'A'; c <= 'Z'; c++ {
        drive[0] = uint16(c)
        dt, err := getDriveType(drive[:])

        if err != nil {
            if err == errNoRootDir {
                continue
            }
            return nil, fmt.Errorf("error getting type of: %s: %s",
                syscall.UTF16ToString(drive[:]), err)
        }

        if dt != driveFixed {
            continue
        }

        drives = append(drives, syscall.UTF16ToString(drive[:]))
    }

    return drives, nil
}

func main() {
    drives, err := getFixedDOSDrives()
    if err != nil {
        log.Fatal(err)
    }
    for _, drive := range drives {
        log.Println(drive)
    }
}

运行By Box(在Wine 4.0下)我得到:

tmp$ GOOS=windows go build drvs.go 
tmp$ wine64 ./drvs.exe
0009:fixme:process:SetProcessPriorityBoost (0xffffffffffffffff,1): stub
2020/07/06 21:06:02 C:
2020/07/06 21:06:02 D:
2020/07/06 21:06:02 X:
2020/07/06 21:06:02 Z:

(使用winecfg映射所有驱动器。)

此方法的问题是:

即使系统中存在的DOS驱动器数量远远少于ASCII大写字母的数量,它也会执行26个系统调用。

在今天的Windows系统上,驱动器可以映射到常规目录下--这与POSIX系统非常相似,因此它根本没有DOS驱动器号。

Eryk Sun准确地暗示了应该对此做些什么。 我将尝试提出一个适当的(尽管更复杂的)解决方案,将这些考虑因素考虑在内。

以下是gist及其代码。

GetDriveTypeW docs。

希望这将使您对Win32 API的工作原理以及如何在Go中使用它感兴趣。尝试查看Go安装中的syscall包的源代码--再加上MSDN文档,这应该很有启发性。

129