Files
fluid-explorer/Services/Shell/KnownFolders.cs
T

117 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Runtime.InteropServices;
using System.Text;
namespace FluidExplorer.Services.Shell;
/// <summary>
/// 用外壳自己的 API(SHGetKnownFolderPath)解析系统文件夹,
/// 保证和资源管理器指向同一批真实位置(含 OneDrive 重定向后的"桌面/文档"等)。
/// </summary>
public static class KnownFolders
{
public static string Profile { get; } = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
public static string Desktop { get; } = Get(FolderId.Desktop);
public static string Documents { get; } = Get(FolderId.Documents);
public static string Downloads { get; } = Get(FolderId.Downloads);
public static string Pictures { get; } = Get(FolderId.Pictures);
public static string Music { get; } = Get(FolderId.Music);
public static string Videos { get; } = Get(FolderId.Videos);
public static string RecycleBin { get; } = @"shell:RecycleBinFolder";
/// <summary>此电脑 / 回收站等虚拟外壳对象的解析名,交给外壳取图标与打开。</summary>
public const string ThisPcParsingName = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
public const string RecycleBinParsingName = "::{645FF040-5081-101B-9F08-00AA002F954E}";
public const string NetworkParsingName = "::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}";
public const string HomeParsingName = "::{F874310E-B6B7-47DC-BC84-B9E6B38F5903}"; // 主页
public const string GalleryParsingName = "::{E88865EA-0E1C-4E20-9AA6-EDCD0212C87C}"; // 图库
private static string Get(Guid id)
{
try
{
var hr = SHGetKnownFolderPath(ref id, 0, IntPtr.Zero, out var ptr);
if (hr != 0 || ptr == IntPtr.Zero) return string.Empty;
try { return Marshal.PtrToStringUni(ptr) ?? string.Empty; }
finally { Marshal.FreeCoTaskMem(ptr); }
}
catch
{
return string.Empty;
}
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int SHGetKnownFolderPath(ref Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);
private static class FolderId
{
public static Guid Desktop = new("B4BFCC3A-DB2C-424C-B029-7FE99A87C641");
public static Guid Documents = new("FDD39AD0-238F-46AF-ADB4-6C85480369C7");
public static Guid Downloads = new("374DE290-123F-4565-9164-39C4925E467B");
public static Guid Pictures = new("33E28130-4E1E-4676-835A-98395C3BC3BB");
public static Guid Music = new("4BD8D571-6D19-48D3-BE97-422220080E43");
public static Guid Videos = new("18989B1D-99B5-455B-841C-AB7C74E4DDFC");
}
}
/// <summary>
/// 卷信息(用于侧边栏"此电脑"和状态栏):显示名、总容量、可用空间、就绪状态。
/// </summary>
public sealed class DriveItem
{
public required string RootPath { get; init; }
public required string DisplayName { get; init; }
public required string VolumeLabel { get; init; }
public required string FileSystem { get; init; }
public long TotalBytes { get; init; }
public long FreeBytes { get; init; }
public int DriveType { get; init; }
public bool IsReady { get; init; }
public double UsedRatio => TotalBytes <= 0 ? 0 : 1.0 - (double)FreeBytes / TotalBytes;
public string CapacityText => !IsReady || TotalBytes <= 0
? "不可用"
: $"{FluidExplorer.Models.FileEntry.FormatSize(FreeBytes)} 可用,共 {FluidExplorer.Models.FileEntry.FormatSize(TotalBytes)}";
public string Glyph => DriveType switch
{
2 => "\uE88E", // 可移动磁盘
3 => "\uEDA2", // 本地磁盘
4 => "\uE8CE", // 网络驱动器
5 => "\uE958", // 光驱
_ => "\uEDA2"
};
public static IReadOnlyList<DriveItem> Enumerate()
{
var list = new List<DriveItem>();
foreach (var drive in DriveInfo.GetDrives())
{
try
{
var label = drive.IsReady ? drive.VolumeLabel : string.Empty;
var display = string.IsNullOrWhiteSpace(label)
? (drive.Name.TrimEnd('\\') is { Length: > 0 } letter ? $"本地磁盘 ({letter})" : drive.Name)
: $"{label} ({drive.Name.TrimEnd('\\')})";
list.Add(new DriveItem
{
RootPath = drive.Name,
DisplayName = display,
VolumeLabel = label,
FileSystem = drive.IsReady ? drive.DriveFormat : string.Empty,
TotalBytes = drive.IsReady ? drive.TotalSize : 0,
FreeBytes = drive.IsReady ? drive.TotalFreeSpace : 0,
DriveType = (int)drive.DriveType,
IsReady = drive.IsReady
});
}
catch
{
// 未就绪的驱动器(空读卡器等)直接跳过
}
}
return list;
}
}