壹伍柒叁 發表於 2026-1-12 23:50:00

.NET 磁盘管理-技术方案选型

<p>在家庭以及企业场景下的网络磁盘产品,使用Iscsi均需要对磁盘进行管理。不同Windows版本、安装第三方软件,导致每个C端用户的运行环境不同,对磁盘的管理带来一定的使用干扰</p>
<p>本文介绍下磁盘管理的几种方案以及存在的一些问题</p>
<p>对磁盘管理主要有以下操作入口/方式:</p>
<ol>
<li>Powershell</li>
<li>Diskpart</li>
<li>WMI</li>
<li>WIN32(IOCTL)</li>
</ol>
<p>下面介绍下四者之间的关系以及所依赖的windows系统服务</p>
<h1>Windows磁盘管理服务依赖层级</h1>
<p>从操作系统角度看,这几种方式编程/操作入口是围绕同一套内核与服务堆栈的不同“壳”,完成<strong>套娃封装</strong></p>
<p>从高到低,依次列下windows主要的磁盘相关入口和服务</p>
<p>1. GUI/工具层</p>
<p>MMC -&nbsp;Windows系统磁盘管理工具,如果需要快速查看和操作磁盘分区的话,可以用这个</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112154249299-1528163380.png" alt="image" width="529" height="270" loading="lazy"></p>
<p>以及Storage Spaces GUI - Windows系统设置存储管理</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112154850543-1013979831.png" alt="image" width="533" height="306" loading="lazy"><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112155107194-71293024.png" alt="image" width="403" height="305" loading="lazy"></p>
<p>这俩个工具主要是使用WMI相关操作来实现</p>
<p>2. 脚本/命令层</p>
<p>Powershell磁盘管理命令</p>
<p>diskpart磁盘管理命令</p>
<p>CIM磁盘管理命令</p>
<p>3. API/管理接口层</p>
<p>WMI服务:Winmgmt(Windows Management Instrumentation),使用Win32_DiskDrive 等</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112181124821-2050380879.png" alt="image" loading="lazy"></p>
<p>磁盘管理服务:Virtual Disk,VDS进程名称vds.exe</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112180656866-1672546299.png" alt="image" loading="lazy"></p>
<p>磁盘存储服务:Microsoft Storage Spaces SMP</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112163817548-1975243303.png" alt="image" loading="lazy"></p>
<p>4. 内核/驱动/IOCTL层</p>
<p>Storage Management Provider:系统组件,不是单独服务可见<br>IOCTL: Win32API、DevicerIoControl</p>
<p>磁盘类驱动(disk.sys)、卷管理器(volmgr/vdsci)、文件系统驱动(NTFS/ReFS)</p>
<p><strong>而上面说的四种方案,依赖的底层服务:</strong></p>
<p>PowerShell 基于 WMI / Storage Management API封装,依赖的组件最多:Winmgmt、Microsoft Storage Spaces SMP、Storage Service、VDS等<br>WMI/CIM 有部分是走 VDS / Storage API,有部分直接调用底层驱动,主要依赖:Winmgmt服务</p>
<p>diskpart 内部是调用 VDS / Storage API / IOCTL,依赖相对较少:VDS服务等</p>
<p>Win32 IOCTL 是最底层(用户态可达)的接口,不依赖上层框架</p>
<p>比如下方的WMI服务不存在,会导致powershell磁盘查询不到,WMI磁盘查询不到,但diskpart访问正常:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> PS C:\Users\yudong04&gt; G<span style="color: rgba(0, 0, 255, 1)">et-Disk</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> PS C:\Users\yudong04&gt; <span style="color: rgba(0, 0, 255, 1)">Get-CimInstance</span> -Namespace root/Microsoft/Windows/Storage -<span style="color: rgba(0, 0, 0, 1)">ClassName MSFT_Disk
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> PS C:\Users\yudong04&gt;<span style="color: rgba(0, 0, 0, 1)"> diskpart
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> Microsoft DiskPart 版本 10.0.26100.1150
<span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">Copyright (C) Microsoft Corporation.
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> 在计算机上: GIH-D-24762
<span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> DISKPART&gt;<span style="color: rgba(0, 0, 0, 1)"> list disk
</span><span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</span>   磁盘 <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">##状态         大小   可用   DynGpt</span>
<span style="color: rgba(0, 128, 128, 1)">13</span>   -----------------------------------------
<span style="color: rgba(0, 128, 128, 1)">14</span>   磁盘 0    联机             3726 GB1024 KB      *
<span style="color: rgba(0, 128, 128, 1)">15</span>   磁盘 1    联机             3726 GB1024 KB      *
<span style="color: rgba(0, 128, 128, 1)">16</span>   磁盘 2    联机             2794 GB      0 B      *
<span style="color: rgba(0, 128, 128, 1)">17</span>   磁盘 3    联机            931 GB      0 B      *
<span style="color: rgba(0, 128, 128, 1)">18</span>   磁盘 4    联机            465 GB1024 KB      *
<span style="color: rgba(0, 128, 128, 1)">19</span>   磁盘 5    联机             1863 GB      0<span style="color: rgba(0, 0, 0, 1)"> B
</span><span style="color: rgba(0, 128, 128, 1)">20</span>   磁盘 6    联机             7452 GB      0 B      *</pre>
</div>
<p><span style="font-size: 14px">还有Microsoft Storage Spaces SMP服务被第三方软件禁用,导致Powershell Get-Disk获取结果为空:</span></p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112205453476-213941181.png" alt="image" width="1009" height="554" loading="lazy"></p>
<p><span style="font-size: 14px">下面对各个模块展开介绍下</span></p>
<h1>Powershell磁盘管理</h1>
<p>上面说了,PowerShell使用 Storage Management API + 新的 WMI/CIM 类,磁盘命令本质是对这些 WMI 类的包装。层级如下:</p>
<p>PowerShell cmdlet<br>-&gt; MSFT_* WMI 类 (CIM)、WMI服务Winmgmt<br>-&gt; Storage Management Provider<br>-&gt; 内核驱动 (disk.sys, partmgr.sys, volmgr.sys)<br>-&gt; 设备硬件</p>
<p>powershell有以下查找主要命令,</p>
<p>Get-Disk - 查找磁盘</p>
<p>Get-Partition - 查找分区</p>
<p>Get-Volume - 查找卷</p>
<p>Get-Disk | Where-Object -FilterScript {&nbsp; $_.BusType -Eq "iSCSI" -and $_.SerialNumber -Eq "8fa461f8-9436-4260-8191-789b23859757"} - 查找指定Iscsi协议磁盘</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112162810665-890504091.png" alt="image" loading="lazy"></p>
<p>操作磁盘命令,比如初始化GPT磁盘:Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -UseMaximumSize | Format-Volume -FileSystem:NTFS -NewFileSystemLabel:测试盘 -Confirm:$false -Force</p>
<p>Powershell命令因易用性,非常适合脚本自动化、用户级的使用。但非常与用户环境有关,换个用户或换台机器就经常表现不同,比如:卡很久、超时、直接报错、磁盘盘就是查询不到</p>
<p>几个原因:</p>
<p>WMI / CIM 调用超时</p>
<ul>
<li>WMI 服务卡住、存储驱动响应慢</li>
<li>网络/防火墙导致远程调用超时</li>










</ul>
<p>硬件IO超时</p>
<ul>
<li>坏盘 / 坏 U 盘 / USB 扩展坞质量问题</li>
<li>大量重新尝试 I/O 导致操作整体拖得很长</li>









</ul>
<p>具体场景,发现公司内部某个部门发生powershell命令超时概率很多,因为这些设备都在跑软件压力测试。。。导致磁盘获取命令,很容易超时</p>
<p>还有些特殊情况,服务异常出现的情况比较多。如WMI服务,以下是修复成功案例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> PS C:\Users\yudong04&gt; <span style="color: rgba(0, 0, 255, 1)">Get-WmiObject</span><span style="color: rgba(0, 0, 0, 1)"> Win32_OperatingSystem
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">Get-WmiObject</span><span style="color: rgba(0, 0, 0, 1)"> : 无效类 “Win32_OperatingSystem”
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> 所在位置 行:1 字符: 1
<span style="color: rgba(0, 128, 128, 1)"> 4</span> + <span style="color: rgba(0, 0, 255, 1)">Get-WmiObject</span><span style="color: rgba(0, 0, 0, 1)"> Win32_OperatingSystem
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> +<span style="color: rgba(0, 0, 0, 1)"> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>   + CategoryInfo          : InvalidType: (:) [<span style="color: rgba(0, 0, 255, 1)">Get-WmiObject</span><span style="color: rgba(0, 0, 0, 1)">], ManagementException
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>   +<span style="color: rgba(0, 0, 0, 1)"> FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> PS C:\Users\yudong04&gt; net stop winmgmt /<span style="color: rgba(0, 0, 0, 1)">y
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">Windows Management Instrumentation 服务正在停止.
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">Windows Management Instrumentation 服务已成功停止。
</span><span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> PS C:\Users\yudong04&gt; winmgmt /<span style="color: rgba(0, 0, 0, 1)">resetrepository
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">WMI 存储库已重置
</span><span style="color: rgba(0, 128, 128, 1)">15</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> PS C:\Users\yudong04&gt; <span style="color: rgba(0, 0, 255, 1)">Get-WmiObject</span><span style="color: rgba(0, 0, 0, 1)"> Win32_OperatingSystem
</span><span style="color: rgba(0, 128, 128, 1)">17</span>
<span style="color: rgba(0, 128, 128, 1)">18</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">SystemDirectory : C:\WINDOWS\system32
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">Organization    : Online Game Dept
</span><span style="color: rgba(0, 128, 128, 1)">21</span> BuildNumber   : 26100
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">RegisteredUser: Windows 用户
</span><span style="color: rgba(0, 128, 128, 1)">23</span> SerialNumber    : 00329-00000-00003-<span style="color: rgba(0, 0, 0, 1)">AA238
</span><span style="color: rgba(0, 128, 128, 1)">24</span> Version         : 10.0.26100</pre>
</div>
<p>还有Microsoft Storage Spaces SMP服务,如果Get-Disk拿不到磁盘,定位客户问题发现很大可能是这个服务异常了。重启一下即可</p>
<h1>WMI/CIM磁盘管理</h1>
<p>WMI相关命令,需要拆分为俩部分:WIN32_*经典类,以及MSFT_*新的StorageWMI类</p>
<p><strong>经典类:</strong></p>
<ul>
<li>Win32_DiskDrive</li>
<li>Win32_DiskPartition</li>
<li>Win32_LogicalDisk</li>
<li>Win32_Volume</li>
</ul>
<p>早期设计,很多是通过内核 API + IOCTL 和 VDS 实现。主要用于查询,修改操作有限</p>
<p>依赖服务:Winmgmt、RPCSS(RPC服务)、以及少量依赖VDS</p>
<p><strong>StorageWmi类</strong></p>
<ul>
<li>MSFT_Disk</li>
<li>MSFT_Partition</li>
<li>MSFT_Volume</li>
<li>MSFT_StoragePool</li>
<li>MSFT_VirtualDisk</li>
</ul>
<p>这是Windows8之后的新存储管理WMI接口,详见官网文档:Storage Management API Classes - Windows drivers | Microsoft Learn, 依赖层级:</p>
<p>WMI (MSFT_* 类)<br>-&gt; Storage Management Provider<br>   -&gt; IOCTL -&gt; disk.sys / partmgr.sys / ...</p>
<p>具体依赖的服务:Winmgmt(WMI 服务)</p>
<p>WMI 是“管理数据模型 + 接口”,本身不是一个磁盘管理“方案”,而是很多方案的基础接口。相对Powershell Storage管理,算是比较稳定和依赖较少的了</p>
<p>直接使用.NET通过WMI获取详细的磁盘列表数据,代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> GetDisks()
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> disks = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>         <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Win32_DiskDrive: 物理磁盘</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span>             <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> searcher = <span style="color: rgba(0, 0, 255, 1)">new</span> ManagementObjectSearcher(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SELECT * FROM Win32_DiskDrive</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>             <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> driveCollection =<span style="color: rgba(0, 0, 0, 1)"> searcher.Get())
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">10</span>               <span style="color: rgba(0, 0, 255, 1)">foreach</span> (ManagementObject drive <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> driveCollection)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">12</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> diskInfo = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> LocalDisk();
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1. 磁盘编号 PhysicalDriveN
</span><span style="color: rgba(0, 128, 128, 1)">15</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Win32_DiskDrive.DeviceID 一般为 "\\.\PHYSICALDRIVE0"</span>
<span style="color: rgba(0, 128, 128, 1)">16</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> deviceId = (drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceID</span><span style="color: rgba(128, 0, 0, 1)">"</span>] <span style="color: rgba(0, 0, 255, 1)">as</span> <span style="color: rgba(0, 0, 255, 1)">string</span>) ?? <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 128, 128, 1)">17</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> diskNumber =<span style="color: rgba(0, 0, 0, 1)"> ParsePhysicalDriveNumber(deviceId);
</span><span style="color: rgba(0, 128, 128, 1)">18</span>                     diskInfo.Number =<span style="color: rgba(0, 0, 0, 1)"> diskNumber;
</span><span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. 序列号 (不同厂商格式不统一;有时需要 Win32_PhysicalMedia)</span>
<span style="color: rgba(0, 128, 128, 1)">21</span>                     diskInfo.SerialNumber = (drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SerialNumber</span><span style="color: rgba(128, 0, 0, 1)">"</span>] <span style="color: rgba(0, 0, 255, 1)">as</span> <span style="color: rgba(0, 0, 255, 1)">string</span>)?.Trim() ?? <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 128, 128, 1)">22</span>
<span style="color: rgba(0, 128, 128, 1)">23</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3. DeviceName</span>
<span style="color: rgba(0, 128, 128, 1)">24</span>                     diskInfo.DeviceName = (drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Model</span><span style="color: rgba(128, 0, 0, 1)">"</span>] <span style="color: rgba(0, 0, 255, 1)">as</span> <span style="color: rgba(0, 0, 255, 1)">string</span>)?.Trim() ?? <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 128, 128, 1)">25</span>
<span style="color: rgba(0, 128, 128, 1)">26</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 4. 只读/在线状态(WMI 并没有非常标准的字段,这里用粗略映射)
</span><span style="color: rgba(0, 128, 128, 1)">27</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">   Win32_DiskDrive.Status: "OK" / "Error" / "Degraded" ...</span>
<span style="color: rgba(0, 128, 128, 1)">28</span>                     diskInfo.IsOffline =<span style="color: rgba(0, 0, 0, 1)"> GetOffline(diskNumber);
</span><span style="color: rgba(0, 128, 128, 1)">29</span>
<span style="color: rgba(0, 128, 128, 1)">30</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 没有直接 readonly 标记,先默认为 false,
</span><span style="color: rgba(0, 128, 128, 1)">31</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如需更精确可以通过 Win32_Volume 或 DeviceIoControl 获取。</span>
<span style="color: rgba(0, 128, 128, 1)">32</span>                     diskInfo.IsReadOnly =<span style="color: rgba(0, 0, 0, 1)"> GetReadonly(diskNumber);
</span><span style="color: rgba(0, 128, 128, 1)">33</span>
<span style="color: rgba(0, 128, 128, 1)">34</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 5. 总线类型(没有 STORAGE_BUS_TYPE 枚举,使用 InterfaceType 粗略映射)</span>
<span style="color: rgba(0, 128, 128, 1)">35</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> interfaceType = (drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">InterfaceType</span><span style="color: rgba(128, 0, 0, 1)">"</span>] <span style="color: rgba(0, 0, 255, 1)">as</span> <span style="color: rgba(0, 0, 255, 1)">string</span>)?<span style="color: rgba(0, 0, 0, 1)">.Trim();
</span><span style="color: rgba(0, 128, 128, 1)">36</span>                     diskInfo.BusType =<span style="color: rgba(0, 0, 0, 1)"> MapBusType(interfaceType, diskInfo.DeviceName);
</span><span style="color: rgba(0, 128, 128, 1)">37</span>
<span style="color: rgba(0, 128, 128, 1)">38</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 6. 磁盘容量 (字节 -&gt; GB)
</span><span style="color: rgba(0, 128, 128, 1)">39</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Win32_DiskDrive.Size 为字节数(string)</span>
<span style="color: rgba(0, 128, 128, 1)">40</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Size</span><span style="color: rgba(128, 0, 0, 1)">"</span>] != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; <span style="color: rgba(0, 0, 255, 1)">long</span>.TryParse(drive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Size</span><span style="color: rgba(128, 0, 0, 1)">"</span>].ToString(), <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> sizeBytes))
</span><span style="color: rgba(0, 128, 128, 1)">41</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">42</span>                         diskInfo.DiskSize =<span style="color: rgba(0, 0, 0, 1)"> sizeBytes;
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">44</span>
<span style="color: rgba(0, 128, 128, 1)">45</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 7. 获取挂载点及已用容量,通过 3 张 WMI 关联表:
</span><span style="color: rgba(0, 128, 128, 1)">46</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Win32_DiskDrive -&gt; Win32_DiskDriveToDiskPartition -&gt; Win32_DiskPartition -&gt;
</span><span style="color: rgba(0, 128, 128, 1)">47</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Win32_LogicalDiskToPartition -&gt; Win32_LogicalDisk</span>
<span style="color: rgba(0, 128, 128, 1)">48</span> <span style="color: rgba(0, 0, 0, 1)">                  FillMountPathsAndUsedSize(diskInfo, drive);
</span><span style="color: rgba(0, 128, 128, 1)">49</span> <span style="color: rgba(0, 0, 0, 1)">                  disks.Add(diskInfo);
</span><span style="color: rgba(0, 128, 128, 1)">50</span>
<span style="color: rgba(0, 128, 128, 1)">51</span>                     diskInfo.Tag =<span style="color: rgba(0, 0, 0, 1)"> GetVolumeLabel(diskInfo.MountPaths.FirstOrDefault());
</span><span style="color: rgba(0, 128, 128, 1)">52</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">54</span>
<span style="color: rgba(0, 128, 128, 1)">55</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;.ToSuccess(disks.OrderBy(i =&gt;<span style="color: rgba(0, 0, 0, 1)"> i.Number).ToList());
</span><span style="color: rgba(0, 128, 128, 1)">56</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">57</span>         <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
</span><span style="color: rgba(0, 128, 128, 1)">58</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">59</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">.ToError(ex.Message);
</span><span style="color: rgba(0, 128, 128, 1)">60</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">61</span>   }</pre>
</div>
<p>附带的一些属性获取函数:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_ac2201cc-0955-4850-bc5f-4794df011a32" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_ac2201cc-0955-4850-bc5f-4794df011a32" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_ac2201cc-0955-4850-bc5f-4794df011a32" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span>   <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ParsePhysicalDriveNumber(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> deviceId)
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">3</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> "\\.\PHYSICALDRIVE0" -&gt; 0</span>
<span style="color: rgba(0, 128, 128, 1)">4</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(deviceId))
</span><span style="color: rgba(0, 128, 128, 1)">5</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">6</span>
<span style="color: rgba(0, 128, 128, 1)">7</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> upper =<span style="color: rgba(0, 0, 0, 1)"> deviceId.ToUpperInvariant();
</span><span style="color: rgba(0, 128, 128, 1)">8</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> idx = upper.LastIndexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PHYSICALDRIVE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, StringComparison.Ordinal);
</span><span style="color: rgba(0, 128, 128, 1)">9</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (idx &lt; <span style="color: rgba(128, 0, 128, 1)">0</span>) <span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 10</span>
<span style="color: rgba(0, 128, 128, 1)"> 11</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> numPart = upper.Substring(idx + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PHYSICALDRIVE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">.Length);
</span><span style="color: rgba(0, 128, 128, 1)"> 12</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">int</span>.TryParse(numPart, NumberStyles.Integer, CultureInfo.InvariantCulture, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> num))
</span><span style="color: rgba(0, 128, 128, 1)"> 13</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> num;
</span><span style="color: rgba(0, 128, 128, 1)"> 14</span>
<span style="color: rgba(0, 128, 128, 1)"> 15</span>         <span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 16</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 17</span>
<span style="color: rgba(0, 128, 128, 1)"> 18</span>   <span style="color: rgba(0, 0, 255, 1)">private</span> StorageBusType MapBusType(<span style="color: rgba(0, 0, 255, 1)">string</span> interfaceType, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> deviceName)
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 20</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrEmpty(interfaceType))
</span><span style="color: rgba(0, 128, 128, 1)"> 21</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Unknown;
</span><span style="color: rgba(0, 128, 128, 1)"> 22</span>
<span style="color: rgba(0, 128, 128, 1)"> 23</span>         <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (interfaceType.ToUpperInvariant())
</span><span style="color: rgba(0, 128, 128, 1)"> 24</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 25</span>             <span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SCSI</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)"> 26</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (deviceName.Contains(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SCSI</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 27</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 28</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Iscsi;
</span><span style="color: rgba(0, 128, 128, 1)"> 29</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 30</span>               <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Scsi;
</span><span style="color: rgba(0, 128, 128, 1)"> 31</span>             <span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IDE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)"> 32</span>             <span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ATA</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)"> 33</span>               <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Ata;
</span><span style="color: rgba(0, 128, 128, 1)"> 34</span>             <span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">USB</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span>               <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Usb;
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 可根据需要扩展映射</span>
<span style="color: rgba(0, 128, 128, 1)"> 37</span>             <span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)"> 38</span>               <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> StorageBusType.Unknown;
</span><span style="color: rgba(0, 128, 128, 1)"> 39</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 40</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span>
<span style="color: rgba(0, 128, 128, 1)"> 42</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 43</span>   <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 填充 MountPaths(盘符)和 DiskUsedSize(GB)
</span><span style="color: rgba(0, 128, 128, 1)"> 44</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 45</span>   <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> OperateResult FillMountPathsAndUsedSize(LocalDisk diskInfo, ManagementObject diskDrive)
</span><span style="color: rgba(0, 128, 128, 1)"> 46</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 47</span>         <span style="color: rgba(0, 0, 255, 1)">long</span> totalUsedBytes = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 48</span>
<span style="color: rgba(0, 128, 128, 1)"> 49</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过 Win32_DiskDriveToDiskPartition 关联到分区</span>
<span style="color: rgba(0, 128, 128, 1)"> 50</span>         <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> partitionRel = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ManagementObjectSearcher(
</span><span style="color: rgba(0, 128, 128, 1)"> 51</span>                  <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ASSOCIATORS OF {Win32_DiskDrive.DeviceID='</span><span style="color: rgba(128, 0, 0, 1)">"</span> + diskDrive[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceID</span><span style="color: rgba(128, 0, 0, 1)">"</span>] +
<span style="color: rgba(0, 128, 128, 1)"> 52</span>                  <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">'} WHERE AssocClass = Win32_DiskDriveToDiskPartition</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 53</span>         <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> partitions =<span style="color: rgba(0, 0, 0, 1)"> partitionRel.Get())
</span><span style="color: rgba(0, 128, 128, 1)"> 54</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 55</span>             <span style="color: rgba(0, 0, 255, 1)">foreach</span> (ManagementObject partition <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> partitions)
</span><span style="color: rgba(0, 128, 128, 1)"> 56</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过 Win32_LogicalDiskToPartition 关联到逻辑磁盘(盘符)</span>
<span style="color: rgba(0, 128, 128, 1)"> 58</span>               <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> logicalRel = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ManagementObjectSearcher(
</span><span style="color: rgba(0, 128, 128, 1)"> 59</span>                            <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ASSOCIATORS OF {Win32_DiskPartition.DeviceID='</span><span style="color: rgba(128, 0, 0, 1)">"</span> + partition[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceID</span><span style="color: rgba(128, 0, 0, 1)">"</span>] +
<span style="color: rgba(0, 128, 128, 1)"> 60</span>                            <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">'} WHERE AssocClass = Win32_LogicalDiskToPartition</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 61</span>               <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> logicalDisks =<span style="color: rgba(0, 0, 0, 1)"> logicalRel.Get())
</span><span style="color: rgba(0, 128, 128, 1)"> 62</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 63</span>                     <span style="color: rgba(0, 0, 255, 1)">foreach</span> (ManagementObject logicalDisk <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> logicalDisks)
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)"> 65</span>                         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算已用空间</span>
<span style="color: rgba(0, 128, 128, 1)"> 66</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (logicalDisk[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Size</span><span style="color: rgba(128, 0, 0, 1)">"</span>] != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp;
<span style="color: rgba(0, 128, 128, 1)"> 67</span>                           logicalDisk[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FreeSpace</span><span style="color: rgba(128, 0, 0, 1)">"</span>] != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp;
<span style="color: rgba(0, 128, 128, 1)"> 68</span>                           <span style="color: rgba(0, 0, 255, 1)">long</span>.TryParse(logicalDisk[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Size</span><span style="color: rgba(128, 0, 0, 1)">"</span>].ToString(), <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">long</span> volSize) &amp;&amp;
<span style="color: rgba(0, 128, 128, 1)"> 69</span>                           <span style="color: rgba(0, 0, 255, 1)">long</span>.TryParse(logicalDisk[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FreeSpace</span><span style="color: rgba(128, 0, 0, 1)">"</span>].ToString(), <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> free))
</span><span style="color: rgba(0, 128, 128, 1)"> 70</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)"> 71</span>                           totalUsedBytes += (volSize -<span style="color: rgba(0, 0, 0, 1)"> free);
</span><span style="color: rgba(0, 128, 128, 1)"> 72</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)"> 73</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 76</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 77</span>
<span style="color: rgba(0, 128, 128, 1)"> 78</span>         diskInfo.DiskUsedSize =<span style="color: rgba(0, 0, 0, 1)">totalUsedBytes;
</span><span style="color: rgba(0, 128, 128, 1)"> 79</span>
<span style="color: rgba(0, 128, 128, 1)"> 80</span>         <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)"> 81</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 82</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> paths =<span style="color: rgba(0, 0, 0, 1)"> GetAccessPaths(diskInfo.Number);
</span><span style="color: rgba(0, 128, 128, 1)"> 83</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> filtedPaths = paths.Where(i =&gt; !i.StartsWith(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">\\?\Volume</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)).ToList();
</span><span style="color: rgba(0, 128, 128, 1)"> 84</span>             diskInfo.MountPaths =<span style="color: rgba(0, 0, 0, 1)"> filtedPaths;
</span><span style="color: rgba(0, 128, 128, 1)"> 85</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> OperateResult.ToSuccess();
</span><span style="color: rgba(0, 128, 128, 1)"> 86</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 87</span>         <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 89</span>            <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> OperateResult.ToError(e);
</span><span style="color: rgba(0, 128, 128, 1)"> 90</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 92</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 93</span>   <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取磁盘的所有访问路径
</span><span style="color: rgba(0, 128, 128, 1)"> 94</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 95</span>   <span style="color: rgba(0, 0, 255, 1)">private</span> List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt; GetAccessPaths(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> diskNumber)
</span><span style="color: rgba(0, 128, 128, 1)"> 96</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 97</span>         ManagementScope scope = <span style="color: rgba(0, 0, 255, 1)">new</span> ManagementScope(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">\\.\root\Microsoft\Windows\Storage</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 98</span> <span style="color: rgba(0, 0, 0, 1)">      scope.Connect();
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span>         <span style="color: rgba(0, 0, 255, 1)">string</span> query = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SELECT * FROM MSFT_Partition WHERE DiskNumber = {diskNumber}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">100</span>         <span style="color: rgba(0, 0, 255, 1)">using</span> ManagementObjectSearcher searcher = <span style="color: rgba(0, 0, 255, 1)">new</span> ManagementObjectSearcher(scope, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectQuery(query));
</span><span style="color: rgba(0, 128, 128, 1)">101</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> pathList = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">102</span>         <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> partition <span style="color: rgba(0, 0, 255, 1)">in</span> searcher.Get().Cast&lt;ManagementObject&gt;<span style="color: rgba(0, 0, 0, 1)">())
</span><span style="color: rgba(0, 128, 128, 1)">103</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">104</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取 AccessPaths 属性(数组)</span>
<span style="color: rgba(0, 128, 128, 1)">105</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> accessPaths = partition[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AccessPaths</span><span style="color: rgba(128, 0, 0, 1)">"</span>] <span style="color: rgba(0, 0, 255, 1)">as</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[];
</span><span style="color: rgba(0, 128, 128, 1)">106</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (accessPaths == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">107</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">108</span>               <span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">110</span> <span style="color: rgba(0, 0, 0, 1)">            pathList.AddRange(accessPaths);
</span><span style="color: rgba(0, 128, 128, 1)">111</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">112</span>         <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pathList;
</span><span style="color: rgba(0, 128, 128, 1)">113</span>   }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>遍历磁盘列表,4块盘耗时接近1s:</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112202253746-677311477.png" alt="image" loading="lazy"></p>
<h1>DiskPart磁盘管理</h1>
<p>diskpart 是 原生 Win32 命令行工具,内部大致通过:</p>
<ul>
<li>VDS / Storage Management API(老系统)</li>
<li>新系统上,一部分功能由新的 Storage API 接管</li>
<li>再往下还是 IOCTL 调用内核驱动</li>
</ul>
<p>调用层级如下,diskpart.exe<br>-&gt; VDS / Storage Management API<br>   -&gt; 内核驱动 (disk.sys, partmgr.sys, volmgr.sys)<br>      -&gt; 设备硬件</p>
<p>diskpart常用命令列表:</p>
<ul>
<li>list disk</li>
<li>select disk 1</li>
<li>detail disk</li>
<li>list partition</li>
<li>list volume</li>









</ul>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112202413306-148039174.png" alt="image" loading="lazy"></p>
<p>DiskPart对WMI并不强依赖,基本上依赖服务就一个Virtual Disk了,操作也比较简单。但缺点也比较明显,访问性能比较差、磁盘操作使用Powersehell调用diskpart命令基本也在s级以上</p>
<h1>Win32 IOCTL磁盘管理</h1>
<p>IOCTL是指通过直接调用 Windows API DeviceIoControl 对磁盘、卷、文件句柄发送控制码:</p>
<ul>
<li>IOCTL_DISK_*</li>
<li>IOCTL_STORAGE_*</li>
<li>FSCTL_*(针对文件系统)</li>









</ul>
<p>IOCTL文档:deviceIoControl 函数 (ioapiset.h) - Win32 apps | Microsoft Learn、Winioctl.h 标头 - Win32 apps | Microsoft Learn</p>
<p>磁盘管理详细文档:磁盘管理 - Win32 apps | Microsoft Learn</p>
<p>WIN32方案,不依赖 VDS / WMI 等上层框架</p>
<p>仅依赖:</p>
<ul>
<li>Win32 子系统 + 内核 I/O 栈</li>
<li>对应的设备驱动(disk.sys, storport.sys, nvme.sys 等)</li>









</ul>
<p>需要基于WIN32API一层层处理细节,比如获取磁盘列表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 通过磁盘编号获取序列号SerialNumber
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="diskNumber"&gt;</span><span style="color: rgba(0, 128, 0, 1)">磁盘编号</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="volumeMaps"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span>   <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;LocalDisk&gt; GetDiskInfoByDiskNumber(<span style="color: rgba(0, 0, 255, 1)">int</span> diskNumber, Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> volumeMaps)
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">逐个尝试 PhysicalDrive0..N</span>
<span style="color: rgba(0, 128, 128, 1)">10</span>         <span style="color: rgba(0, 0, 255, 1)">string</span> physicalDrive = <span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">\\.\PhysicalDrive</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> diskNumber;
</span><span style="color: rgba(0, 128, 128, 1)">11</span>         IntPtr hDisk =<span style="color: rgba(0, 0, 0, 1)"> CreateFile(
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">            physicalDrive,
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">            GENERIC_READ,
</span><span style="color: rgba(0, 128, 128, 1)">14</span>             FILE_SHARE_READ | FILE_SHARE_WRITE |<span style="color: rgba(0, 0, 0, 1)"> FILE_SHARE_DELETE,
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">            IntPtr.Zero,
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">            OPEN_EXISTING,
</span><span style="color: rgba(0, 128, 128, 1)">17</span>             <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">            IntPtr.Zero);
</span><span style="color: rgba(0, 128, 128, 1)">19</span>         <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">21</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 不存在这个物理盘(或者无权限),忽略此异常</span>
<span style="color: rgba(0, 128, 128, 1)">22</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (hDisk ==<span style="color: rgba(0, 0, 0, 1)"> INVALID_HANDLE_VALUE)
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">24</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess();
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">26</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskInfo = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> LocalDisk();
</span><span style="color: rgba(0, 128, 128, 1)">27</span>             diskInfo.Number =<span style="color: rgba(0, 0, 0, 1)"> diskNumber;
</span><span style="color: rgba(0, 128, 128, 1)">28</span>
<span style="color: rgba(0, 128, 128, 1)">29</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取磁盘基础信息</span>
<span style="color: rgba(0, 128, 128, 1)">30</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> getDiskPropertiesResult =<span style="color: rgba(0, 0, 0, 1)"> GetDiskProperties(hDisk);
</span><span style="color: rgba(0, 128, 128, 1)">31</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">getDiskPropertiesResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">33</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Get disk {physicalDrive} properties failed, {getDiskPropertiesResult.Message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, getDiskPropertiesResult.Exception, getDiskPropertiesResult.Code);
</span><span style="color: rgba(0, 128, 128, 1)">34</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">35</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskProperties =<span style="color: rgba(0, 0, 0, 1)"> getDiskPropertiesResult.Data;
</span><span style="color: rgba(0, 128, 128, 1)">36</span>             diskInfo.SerialNumber =<span style="color: rgba(0, 0, 0, 1)"> diskProperties.SerialNumber;
</span><span style="color: rgba(0, 128, 128, 1)">37</span>             diskInfo.DeviceName =<span style="color: rgba(0, 0, 0, 1)"> diskProperties.DeviceName;
</span><span style="color: rgba(0, 128, 128, 1)">38</span>             diskInfo.BusType =<span style="color: rgba(0, 0, 0, 1)"> diskProperties.BusType;
</span><span style="color: rgba(0, 128, 128, 1)">39</span>
<span style="color: rgba(0, 128, 128, 1)">40</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否只读/联机</span>
<span style="color: rgba(0, 128, 128, 1)">41</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskAttributesResult =<span style="color: rgba(0, 0, 0, 1)"> GetDiskAttributes(hDisk);
</span><span style="color: rgba(0, 128, 128, 1)">42</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">diskAttributesResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">44</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Get disk {diskProperties.DeviceName} attributes failed, {diskAttributesResult.Message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, diskAttributesResult.Exception, diskAttributesResult.Code);
</span><span style="color: rgba(0, 128, 128, 1)">45</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">46</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskStorageAttributes =<span style="color: rgba(0, 0, 0, 1)"> diskAttributesResult.Data;
</span><span style="color: rgba(0, 128, 128, 1)">47</span>             diskInfo.IsReadOnly =<span style="color: rgba(0, 0, 0, 1)"> diskStorageAttributes.IsReadOnly;
</span><span style="color: rgba(0, 128, 128, 1)">48</span>             diskInfo.IsOffline =<span style="color: rgba(0, 0, 0, 1)"> diskStorageAttributes.IsOffline;
</span><span style="color: rgba(0, 128, 128, 1)">49</span>
<span style="color: rgba(0, 128, 128, 1)">50</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">磁盘容量</span>
<span style="color: rgba(0, 128, 128, 1)">51</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> getDiskSizeResult =<span style="color: rgba(0, 0, 0, 1)"> GetDiskSize(hDisk);
</span><span style="color: rgba(0, 128, 128, 1)">52</span>             diskInfo.DiskSize =<span style="color: rgba(0, 0, 0, 1)"> getDiskSizeResult.Data;
</span><span style="color: rgba(0, 128, 128, 1)">53</span>
<span style="color: rgba(0, 128, 128, 1)">54</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取分区信息</span>
<span style="color: rgba(0, 128, 128, 1)">55</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> partitionInfoResult =<span style="color: rgba(0, 0, 0, 1)"> GetPartitionInfo(hDisk);
</span><span style="color: rgba(0, 128, 128, 1)">56</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">partitionInfoResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)">57</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">58</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Get disk {diskProperties.DeviceName} partition failed, {partitionInfoResult.Message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, partitionInfoResult.Exception, partitionInfoResult.Code);
</span><span style="color: rgba(0, 128, 128, 1)">59</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">60</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskPartitionInfo =<span style="color: rgba(0, 0, 0, 1)"> partitionInfoResult.Data;
</span><span style="color: rgba(0, 128, 128, 1)">61</span>             diskInfo.PartitionStyle =<span style="color: rgba(0, 0, 0, 1)"> (DiskPartitionStyle)diskPartitionInfo.PartitionStyle;
</span><span style="color: rgba(0, 128, 128, 1)">62</span>             diskInfo.PartitionCount =<span style="color: rgba(0, 0, 0, 1)"> diskPartitionInfo.PartitionCount;
</span><span style="color: rgba(0, 128, 128, 1)">63</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">基础数据区分大小</span>
<span style="color: rgba(0, 128, 128, 1)">64</span>             diskInfo.DiskAllocateSize = diskPartitionInfo.Partitions.FirstOrDefault(i =&gt; i.PartitionType.ToUpper() == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">EBD0A0A2-B9E5-4433-87C0-68B6B72699C7</span><span style="color: rgba(128, 0, 0, 1)">"</span>)?.PartitionLength ?? <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">65</span>
<span style="color: rgba(0, 128, 128, 1)">66</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">挂载路径</span>
<span style="color: rgba(0, 128, 128, 1)">67</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (volumeMaps.TryGetValue(diskNumber, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span> mounts) &amp;&amp; mounts != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">68</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">69</span>               diskInfo.MountPaths =<span style="color: rgba(0, 0, 0, 1)"> mounts;
</span><span style="color: rgba(0, 128, 128, 1)">70</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">71</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取卷标名称</span>
<span style="color: rgba(0, 128, 128, 1)">72</span>             <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (diskInfo.MountPaths.Any())
</span><span style="color: rgba(0, 128, 128, 1)">73</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">74</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过任意一个mountPath获取</span>
<span style="color: rgba(0, 128, 128, 1)">75</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> mountPath =<span style="color: rgba(0, 0, 0, 1)"> diskInfo.MountPaths.First();
</span><span style="color: rgba(0, 128, 128, 1)">76</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> getVolumeInfoResult =<span style="color: rgba(0, 0, 0, 1)"> GetVolumeInfo(mountPath);
</span><span style="color: rgba(0, 128, 128, 1)">77</span>               diskInfo.Tag = getVolumeInfoResult.Data?.VolumeLabel ?? <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 128, 128, 1)">78</span>               diskInfo.FileSystemType = getVolumeInfoResult.Data?.FileSystemType ?? <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 128, 128, 1)">79</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">80</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">磁盘已使用大小</span>
<span style="color: rgba(0, 128, 128, 1)">81</span>             <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (diskInfo.MountPaths.Any())
</span><span style="color: rgba(0, 128, 128, 1)">82</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">83</span>               <span style="color: rgba(0, 0, 255, 1)">long</span> diskUsedSize = <span style="color: rgba(128, 0, 128, 1)">0L</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">84</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过所有mountPath相加,获取磁盘已使用大小</span>
<span style="color: rgba(0, 128, 128, 1)">85</span>               <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> mountPath <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> diskInfo.MountPaths)
</span><span style="color: rgba(0, 128, 128, 1)">86</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">87</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> usageByMountPathResult =<span style="color: rgba(0, 0, 0, 1)"> GetDiskSizeUsageByMountPath(mountPath);
</span><span style="color: rgba(0, 128, 128, 1)">88</span>                     diskUsedSize += usageByMountPathResult.Data?.UsedBytes ?? <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">89</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">90</span>               diskInfo.DiskUsedSize =<span style="color: rgba(0, 0, 0, 1)"> diskUsedSize;
</span><span style="color: rgba(0, 128, 128, 1)">91</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">92</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(diskInfo);
</span><span style="color: rgba(0, 128, 128, 1)">93</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">94</span>         <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">95</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">96</span> <span style="color: rgba(0, 0, 0, 1)">            CloseHandle(hDisk);
</span><span style="color: rgba(0, 128, 128, 1)">97</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">98</span>   }</pre>
</div>
<p>其中磁盘属性获取细节,就不展示了:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_ed064c18-3858-41af-a354-0d53b9fb10bf" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_ed064c18-3858-41af-a354-0d53b9fb10bf" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_ed064c18-3858-41af-a354-0d53b9fb10bf" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">2</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取所有磁盘
</span><span style="color: rgba(0, 128, 128, 1)">3</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">4</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">5</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> GetDisks()
</span><span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">7</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1. 先拿卷 -&gt; 卷所属的物理磁盘号 + 盘符/挂载点</span>
<span style="color: rgba(0, 128, 128, 1)">8</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> getVolumesResult =<span style="color: rgba(0, 0, 0, 1)"> GetAllVolumeMountPaths();
</span><span style="color: rgba(0, 128, 128, 1)">9</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">getVolumesResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)"> 10</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 11</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">.ToError(getVolumesResult.Message, getVolumesResult.Exception, getVolumesResult.Code);
</span><span style="color: rgba(0, 128, 128, 1)"> 12</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 13</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> volumeMaps =<span style="color: rgba(0, 0, 0, 1)"> getVolumesResult.Data;
</span><span style="color: rgba(0, 128, 128, 1)"> 14</span>
<span style="color: rgba(0, 128, 128, 1)"> 15</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. 获取磁盘列表</span>
<span style="color: rgba(0, 128, 128, 1)"> 16</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskList = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 17</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 根据卷信息推一个最大磁盘号,同时至少查询16 个</span>
<span style="color: rgba(0, 128, 128, 1)"> 18</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> maxDiskNumberCount = Math.Max(volumeMaps.Max(i =&gt; i.Key), <span style="color: rgba(128, 0, 128, 1)">16</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span>             <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> diskNumber = <span style="color: rgba(128, 0, 128, 1)">0</span>; diskNumber &lt;= maxDiskNumberCount; diskNumber++<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 20</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 21</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> getDiskResult =<span style="color: rgba(0, 0, 0, 1)"> GetDiskInfoByDiskNumber(diskNumber, volumeMaps);
</span><span style="color: rgba(0, 128, 128, 1)"> 22</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">getDiskResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)"> 23</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 24</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">结束查询</span>
<span style="color: rgba(0, 128, 128, 1)"> 25</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (diskNumber == maxDiskNumberCount - <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 26</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)"> 27</span>                         <span style="color: rgba(0, 0, 255, 1)">return</span> getDiskResult.ToResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 28</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)"> 29</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">继续查询其它</span>
<span style="color: rgba(0, 128, 128, 1)"> 30</span>                     <span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 31</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 32</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可能为空</span>
<span style="color: rgba(0, 128, 128, 1)"> 33</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (getDiskResult.Data == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 34</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span>                     <span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 37</span> <span style="color: rgba(0, 0, 0, 1)">                diskList.Add(getDiskResult.Data);
</span><span style="color: rgba(0, 128, 128, 1)"> 38</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 39</span>
<span style="color: rgba(0, 128, 128, 1)"> 40</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;List&lt;LocalDisk&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(diskList);
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 42</span>
<span style="color: rgba(0, 128, 128, 1)"> 43</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 44</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取所有磁盘卷的挂载路径信息
</span><span style="color: rgba(0, 128, 128, 1)"> 45</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;remarks&gt;</span><span style="color: rgba(0, 128, 0, 1)">通过枚举卷,并使用 IOCTL_STORAGE_GET_DEVICE_NUMBER 映射到设备号。</span><span style="color: rgba(128, 128, 128, 1)">&lt;/remarks&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 46</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 47</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;</span><span style="color: rgba(0, 128, 0, 1)">PhysicalDiskNumber -&gt; 对应的所有挂载路径(盘符、挂载点)</span><span style="color: rgba(128, 128, 128, 1)">&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 48</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> GetAllVolumeMountPaths()
</span><span style="color: rgba(0, 128, 128, 1)"> 49</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 50</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> diskDict = <span style="color: rgba(0, 0, 255, 1)">new</span> Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 51</span>
<span style="color: rgba(0, 128, 128, 1)"> 52</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> maxPath = <span style="color: rgba(128, 0, 128, 1)">1024</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 53</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> volNameSb = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuilder(maxPath);
</span><span style="color: rgba(0, 128, 128, 1)"> 54</span>             IntPtr findVolumeHandle = FindFirstVolumeW(volNameSb, (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)volNameSb.Capacity);
</span><span style="color: rgba(0, 128, 128, 1)"> 55</span>             <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)"> 56</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (findVolumeHandle == (IntPtr)(-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 58</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 59</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(diskDict);
</span><span style="color: rgba(0, 128, 128, 1)"> 60</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 61</span>               <span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 62</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 63</span>                     <span style="color: rgba(0, 0, 255, 1)">string</span> volumeName =<span style="color: rgba(0, 0, 0, 1)"> volNameSb.ToString();
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> volumeName: \\?\Volume{GUID}\
</span><span style="color: rgba(0, 128, 128, 1)"> 65</span>
<span style="color: rgba(0, 128, 128, 1)"> 66</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 打开卷设备</span>
<span style="color: rgba(0, 128, 128, 1)"> 67</span>                     <span style="color: rgba(0, 0, 255, 1)">string</span> volumePathForDevice = volumeName.TrimEnd(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\\</span><span style="color: rgba(128, 0, 0, 1)">'</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> \\?\Volume{GUID}</span>
<span style="color: rgba(0, 128, 128, 1)"> 68</span>                     IntPtr hVolume =<span style="color: rgba(0, 0, 0, 1)"> CreateFile(
</span><span style="color: rgba(0, 128, 128, 1)"> 69</span> <span style="color: rgba(0, 0, 0, 1)">                        volumePathForDevice,
</span><span style="color: rgba(0, 128, 128, 1)"> 70</span>                         <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 只需要 IOCTL,不读写</span>
<span style="color: rgba(0, 128, 128, 1)"> 71</span>                         FILE_SHARE_READ |<span style="color: rgba(0, 0, 0, 1)"> FILE_SHARE_WRITE,
</span><span style="color: rgba(0, 128, 128, 1)"> 72</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero,
</span><span style="color: rgba(0, 128, 128, 1)"> 73</span> <span style="color: rgba(0, 0, 0, 1)">                        OPEN_EXISTING,
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span>                         <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero);
</span><span style="color: rgba(0, 128, 128, 1)"> 76</span>
<span style="color: rgba(0, 128, 128, 1)"> 77</span>                     <span style="color: rgba(0, 0, 255, 1)">uint</span>? diskNumber = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 78</span>
<span style="color: rgba(0, 128, 128, 1)"> 79</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (hVolume != (IntPtr)(-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 80</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)"> 81</span>                         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 取 STORAGE_DEVICE_NUMBER</span>
<span style="color: rgba(0, 128, 128, 1)"> 82</span>                         <span style="color: rgba(0, 0, 255, 1)">uint</span> size = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.SizeOf&lt;STORAGE_DEVICE_NUMBER&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 83</span>                         IntPtr outBuf = Marshal.AllocHGlobal((<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)size);
</span><span style="color: rgba(0, 128, 128, 1)"> 84</span>                         <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)"> 85</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)"> 86</span>                           <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (DeviceIoControl(
</span><span style="color: rgba(0, 128, 128, 1)"> 87</span> <span style="color: rgba(0, 0, 0, 1)">                                    hVolume,
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span> <span style="color: rgba(0, 0, 0, 1)">                                    IOCTL_STORAGE_GET_DEVICE_NUMBER,
</span><span style="color: rgba(0, 128, 128, 1)"> 89</span> <span style="color: rgba(0, 0, 0, 1)">                                    IntPtr.Zero,
</span><span style="color: rgba(0, 128, 128, 1)"> 90</span>                                     <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span> <span style="color: rgba(0, 0, 0, 1)">                                    outBuf,
</span><span style="color: rgba(0, 128, 128, 1)"> 92</span> <span style="color: rgba(0, 0, 0, 1)">                                    size,
</span><span style="color: rgba(0, 128, 128, 1)"> 93</span>                                     <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)"> bytesReturned,
</span><span style="color: rgba(0, 128, 128, 1)"> 94</span> <span style="color: rgba(0, 0, 0, 1)">                                    IntPtr.Zero))
</span><span style="color: rgba(0, 128, 128, 1)"> 95</span> <span style="color: rgba(0, 0, 0, 1)">                            {
</span><span style="color: rgba(0, 128, 128, 1)"> 96</span>                                 STORAGE_DEVICE_NUMBER devNum = Marshal.PtrToStructure&lt;STORAGE_DEVICE_NUMBER&gt;<span style="color: rgba(0, 0, 0, 1)">(outBuf);
</span><span style="color: rgba(0, 128, 128, 1)"> 97</span>                                 <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> DeviceType 为 FILE_DEVICE_DISK(0x07) 一般表示物理磁盘</span>
<span style="color: rgba(0, 128, 128, 1)"> 98</span>                                 diskNumber =<span style="color: rgba(0, 0, 0, 1)"> devNum.DeviceNumber;
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span> <span style="color: rgba(0, 0, 0, 1)">                            }
</span><span style="color: rgba(0, 128, 128, 1)">100</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">101</span>                         <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">102</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)">103</span> <span style="color: rgba(0, 0, 0, 1)">                            Marshal.FreeHGlobal(outBuf);
</span><span style="color: rgba(0, 128, 128, 1)">104</span> <span style="color: rgba(0, 0, 0, 1)">                            CloseHandle(hVolume);
</span><span style="color: rgba(0, 128, 128, 1)">105</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">106</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">107</span>
<span style="color: rgba(0, 128, 128, 1)">108</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (diskNumber.HasValue)
</span><span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">110</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (!diskDict.TryGetValue((<span style="color: rgba(0, 0, 255, 1)">int</span>)diskNumber.Value, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> list))
</span><span style="color: rgba(0, 128, 128, 1)">111</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)">112</span>                           list = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">113</span>                           diskDict[(<span style="color: rgba(0, 0, 255, 1)">int</span>)diskNumber.Value] =<span style="color: rgba(0, 0, 0, 1)"> list;
</span><span style="color: rgba(0, 128, 128, 1)">114</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">115</span>                         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取卷的挂载路径列表(可能有多个)</span>
<span style="color: rgba(0, 128, 128, 1)">116</span>                         <span style="color: rgba(0, 0, 255, 1)">var</span> getMountPathsResult =<span style="color: rgba(0, 0, 0, 1)"> GetMountPathsForVolume(volumeName);
</span><span style="color: rgba(0, 128, 128, 1)">117</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">getMountPathsResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)">118</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)">119</span>                           <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">磁盘{diskNumber}卷挂载路径获取失败, {getMountPathsResult.Message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, getMountPathsResult.Exception, getMountPathsResult.Code);
</span><span style="color: rgba(0, 128, 128, 1)">120</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">121</span>                         <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> mp <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> getMountPathsResult.Data)
</span><span style="color: rgba(0, 128, 128, 1)">122</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)">123</span>                           <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">list.Contains(mp))
</span><span style="color: rgba(0, 128, 128, 1)">124</span> <span style="color: rgba(0, 0, 0, 1)">                              list.Add(mp);
</span><span style="color: rgba(0, 128, 128, 1)">125</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">126</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">127</span>
<span style="color: rgba(0, 128, 128, 1)">128</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 下一卷</span>
<span style="color: rgba(0, 128, 128, 1)">129</span> <span style="color: rgba(0, 0, 0, 1)">                  volNameSb.Clear();
</span><span style="color: rgba(0, 128, 128, 1)">130</span> <span style="color: rgba(0, 0, 0, 1)">                  volNameSb.EnsureCapacity(maxPath);
</span><span style="color: rgba(0, 128, 128, 1)">131</span>
<span style="color: rgba(0, 128, 128, 1)">132</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (!FindNextVolumeW(findVolumeHandle, volNameSb, (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)volNameSb.Capacity))
</span><span style="color: rgba(0, 128, 128, 1)">133</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">134</span>                         <span style="color: rgba(0, 0, 255, 1)">int</span> err =<span style="color: rgba(0, 0, 0, 1)"> Marshal.GetLastWin32Error();
</span><span style="color: rgba(0, 128, 128, 1)">135</span>                         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ERROR_NO_MORE_FILES</span>
<span style="color: rgba(0, 128, 128, 1)">136</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (err == <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">137</span>                           <span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">138</span>
<span style="color: rgba(0, 128, 128, 1)">139</span>                         <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;.ToWin32Error(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query disk volumes failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err);
</span><span style="color: rgba(0, 128, 128, 1)">140</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">141</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">142</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">143</span>             <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
</span><span style="color: rgba(0, 128, 128, 1)">144</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">145</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;.ToError(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query disk volumes error</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, ex);
</span><span style="color: rgba(0, 128, 128, 1)">146</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">147</span>             <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">148</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">149</span> <span style="color: rgba(0, 0, 0, 1)">                FindVolumeClose(findVolumeHandle);
</span><span style="color: rgba(0, 128, 128, 1)">150</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">151</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>, List&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(diskDict);
</span><span style="color: rgba(0, 128, 128, 1)">152</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">153</span>
<span style="color: rgba(0, 128, 128, 1)">154</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">155</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取分区信息
</span><span style="color: rgba(0, 128, 128, 1)">156</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">157</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="hDisk"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">158</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">159</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;DiskPartitionInfo&gt;<span style="color: rgba(0, 0, 0, 1)"> GetPartitionInfo(IntPtr hDisk)
</span><span style="color: rgba(0, 128, 128, 1)">160</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">161</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> outSize = Marshal.SizeOf&lt;DRIVE_LAYOUT_INFORMATION_EX&gt;() + <span style="color: rgba(128, 0, 128, 1)">128</span> * <span style="color: rgba(128, 0, 128, 1)">64</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 给多一点空间</span>
<span style="color: rgba(0, 128, 128, 1)">162</span>             IntPtr outBuffer =<span style="color: rgba(0, 0, 0, 1)"> Marshal.AllocHGlobal(outSize);
</span><span style="color: rgba(0, 128, 128, 1)">163</span>
<span style="color: rgba(0, 128, 128, 1)">164</span>             <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)">165</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">166</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">DeviceIoControl(
</span><span style="color: rgba(0, 128, 128, 1)">167</span> <span style="color: rgba(0, 0, 0, 1)">                        hDisk,
</span><span style="color: rgba(0, 128, 128, 1)">168</span> <span style="color: rgba(0, 0, 0, 1)">                        IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
</span><span style="color: rgba(0, 128, 128, 1)">169</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero,
</span><span style="color: rgba(0, 128, 128, 1)">170</span>                         <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">171</span> <span style="color: rgba(0, 0, 0, 1)">                        outBuffer,
</span><span style="color: rgba(0, 128, 128, 1)">172</span>                         (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)outSize,
</span><span style="color: rgba(0, 128, 128, 1)">173</span>                         <span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> _,
</span><span style="color: rgba(0, 128, 128, 1)">174</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero))
</span><span style="color: rgba(0, 128, 128, 1)">175</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">176</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskPartitionInfo&gt;.ToWin32Error(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceIoControl.IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Marshal.GetLastWin32Error());
</span><span style="color: rgba(0, 128, 128, 1)">177</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">178</span>
<span style="color: rgba(0, 128, 128, 1)">179</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 只取结构开头</span>
<span style="color: rgba(0, 128, 128, 1)">180</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> layout = Marshal.PtrToStructure&lt;DRIVE_LAYOUT_INFORMATION_EX_HEADER&gt;<span style="color: rgba(0, 0, 0, 1)">(outBuffer);
</span><span style="color: rgba(0, 128, 128, 1)">181</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> partitionInfo = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DiskPartitionInfo()
</span><span style="color: rgba(0, 128, 128, 1)">182</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">183</span>                     PartitionCount = (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)layout.PartitionCount,
</span><span style="color: rgba(0, 128, 128, 1)">184</span>                     PartitionStyle =<span style="color: rgba(0, 0, 0, 1)"> layout.PartitionStyle,
</span><span style="color: rgba(0, 128, 128, 1)">185</span>                     DiskId =<span style="color: rgba(0, 0, 0, 1)"> layout.Gpt.DiskId,
</span><span style="color: rgba(0, 128, 128, 1)">186</span>                     StartingUsableOffset =<span style="color: rgba(0, 0, 0, 1)"> layout.Gpt.StartingUsableOffset,
</span><span style="color: rgba(0, 128, 128, 1)">187</span>                     UsableLength =<span style="color: rgba(0, 0, 0, 1)"> layout.Gpt.UsableLength,
</span><span style="color: rgba(0, 128, 128, 1)">188</span>                     MaxPartitionCount =<span style="color: rgba(0, 0, 0, 1)"> layout.Gpt.MaxPartitionCount
</span><span style="color: rgba(0, 128, 128, 1)">189</span> <span style="color: rgba(0, 0, 0, 1)">                };
</span><span style="color: rgba(0, 128, 128, 1)">190</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 指向第一个 PARTITION_INFORMATION_EX 的指针:</span>
<span style="color: rgba(0, 128, 128, 1)">191</span>
<span style="color: rgba(0, 128, 128, 1)">192</span>               IntPtr pCurrent = IntPtr.Add(outBuffer, Marshal.SizeOf&lt;DRIVE_LAYOUT_INFORMATION_EX&gt;<span style="color: rgba(0, 0, 0, 1)">());
</span><span style="color: rgba(0, 128, 128, 1)">193</span>               <span style="color: rgba(0, 0, 255, 1)">int</span> partSize = Marshal.SizeOf&lt;PARTITION_INFORMATION_EX&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">194</span>               <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; layout.PartitionCount; i++<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">195</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">196</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> part = Marshal.PtrToStructure&lt;PARTITION_INFORMATION_EX&gt;<span style="color: rgba(0, 0, 0, 1)">(pCurrent);
</span><span style="color: rgba(0, 128, 128, 1)">197</span>                     <span style="color: rgba(0, 0, 255, 1)">var</span> item = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> PartitionEntryInfo
</span><span style="color: rgba(0, 128, 128, 1)">198</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">199</span>                         PartitionNumber = (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)part.PartitionNumber,
</span><span style="color: rgba(0, 128, 128, 1)">200</span>                         StartingOffset =<span style="color: rgba(0, 0, 0, 1)"> part.StartingOffset,
</span><span style="color: rgba(0, 128, 128, 1)">201</span>                         PartitionLength =<span style="color: rgba(0, 0, 0, 1)"> part.PartitionLength,
</span><span style="color: rgba(0, 128, 128, 1)">202</span>                         PartitionType =<span style="color: rgba(0, 0, 0, 1)"> part.Gpt.PartitionType.ToString(),
</span><span style="color: rgba(0, 128, 128, 1)">203</span>                         PartitionName =<span style="color: rgba(0, 0, 0, 1)"> part.Gpt.Name
</span><span style="color: rgba(0, 128, 128, 1)">204</span> <span style="color: rgba(0, 0, 0, 1)">                  };
</span><span style="color: rgba(0, 128, 128, 1)">205</span>
<span style="color: rgba(0, 128, 128, 1)">206</span> <span style="color: rgba(0, 0, 0, 1)">                  partitionInfo.Partitions.Add(item);
</span><span style="color: rgba(0, 128, 128, 1)">207</span>                     pCurrent =<span style="color: rgba(0, 0, 0, 1)"> IntPtr.Add(pCurrent, partSize);
</span><span style="color: rgba(0, 128, 128, 1)">208</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">209</span>
<span style="color: rgba(0, 128, 128, 1)">210</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskPartitionInfo&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(partitionInfo);
</span><span style="color: rgba(0, 128, 128, 1)">211</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">212</span>             <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">213</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">214</span> <span style="color: rgba(0, 0, 0, 1)">                Marshal.FreeHGlobal(outBuffer);
</span><span style="color: rgba(0, 128, 128, 1)">215</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">216</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">217</span>
<span style="color: rgba(0, 128, 128, 1)">218</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">219</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取磁盘静态属性
</span><span style="color: rgba(0, 128, 128, 1)">220</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">221</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="hDisk"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">222</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">223</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;DiskStorageProperty&gt;<span style="color: rgba(0, 0, 0, 1)"> GetDiskProperties(IntPtr hDisk)
</span><span style="color: rgba(0, 128, 128, 1)">224</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">225</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> storageProperties = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DiskStorageProperty();
</span><span style="color: rgba(0, 128, 128, 1)">226</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> query = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> STORAGE_PROPERTY_QUERY
</span><span style="color: rgba(0, 128, 128, 1)">227</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">228</span>               PropertyId =<span style="color: rgba(0, 0, 0, 1)"> STORAGE_PROPERTY_ID.StorageDeviceProperty,
</span><span style="color: rgba(0, 128, 128, 1)">229</span>               QueryType =<span style="color: rgba(0, 0, 0, 1)"> STORAGE_QUERY_TYPE.PropertyStandardQuery,
</span><span style="color: rgba(0, 128, 128, 1)">230</span>               AdditionalParameters = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">]
</span><span style="color: rgba(0, 128, 128, 1)">231</span> <span style="color: rgba(0, 0, 0, 1)">            };
</span><span style="color: rgba(0, 128, 128, 1)">232</span>             <span style="color: rgba(0, 0, 255, 1)">uint</span> allocSize = <span style="color: rgba(128, 0, 128, 1)">1024</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">233</span>             IntPtr buffer = Marshal.AllocHGlobal((<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)allocSize);
</span><span style="color: rgba(0, 128, 128, 1)">234</span>             <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)">235</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">236</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">DeviceIoControl(
</span><span style="color: rgba(0, 128, 128, 1)">237</span> <span style="color: rgba(0, 0, 0, 1)">                        hDisk,
</span><span style="color: rgba(0, 128, 128, 1)">238</span> <span style="color: rgba(0, 0, 0, 1)">                        IOCTL_STORAGE_QUERY_PROPERTY,
</span><span style="color: rgba(0, 128, 128, 1)">239</span>                         <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> query,
</span><span style="color: rgba(0, 128, 128, 1)">240</span>                         (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.SizeOf&lt;STORAGE_PROPERTY_QUERY&gt;<span style="color: rgba(0, 0, 0, 1)">(),
</span><span style="color: rgba(0, 128, 128, 1)">241</span> <span style="color: rgba(0, 0, 0, 1)">                        buffer,
</span><span style="color: rgba(0, 128, 128, 1)">242</span> <span style="color: rgba(0, 0, 0, 1)">                        allocSize,
</span><span style="color: rgba(0, 128, 128, 1)">243</span>                         <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> bytesReturned,
</span><span style="color: rgba(0, 128, 128, 1)">244</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero))
</span><span style="color: rgba(0, 128, 128, 1)">245</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">246</span>                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取失败</span>
<span style="color: rgba(0, 128, 128, 1)">247</span>                     <span style="color: rgba(0, 0, 255, 1)">int</span> err =<span style="color: rgba(0, 0, 0, 1)"> Marshal.GetLastWin32Error();
</span><span style="color: rgba(0, 128, 128, 1)">248</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (err == ERROR_INSUFFICIENT_BUFFER &amp;&amp; bytesReturned &gt;<span style="color: rgba(0, 0, 0, 1)"> allocSize)
</span><span style="color: rgba(0, 128, 128, 1)">249</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">250</span>                         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重新分配更大缓冲区</span>
<span style="color: rgba(0, 128, 128, 1)">251</span> <span style="color: rgba(0, 0, 0, 1)">                        Marshal.FreeHGlobal(buffer);
</span><span style="color: rgba(0, 128, 128, 1)">252</span>                         allocSize =<span style="color: rgba(0, 0, 0, 1)"> bytesReturned;
</span><span style="color: rgba(0, 128, 128, 1)">253</span>                         buffer = Marshal.AllocHGlobal((<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)allocSize);
</span><span style="color: rgba(0, 128, 128, 1)">254</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">DeviceIoControl(
</span><span style="color: rgba(0, 128, 128, 1)">255</span> <span style="color: rgba(0, 0, 0, 1)">                              hDisk,
</span><span style="color: rgba(0, 128, 128, 1)">256</span> <span style="color: rgba(0, 0, 0, 1)">                              IOCTL_STORAGE_QUERY_PROPERTY,
</span><span style="color: rgba(0, 128, 128, 1)">257</span>                                 <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> query,
</span><span style="color: rgba(0, 128, 128, 1)">258</span>                                 (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.SizeOf&lt;STORAGE_PROPERTY_QUERY&gt;<span style="color: rgba(0, 0, 0, 1)">(),
</span><span style="color: rgba(0, 128, 128, 1)">259</span> <span style="color: rgba(0, 0, 0, 1)">                              buffer,
</span><span style="color: rgba(0, 128, 128, 1)">260</span> <span style="color: rgba(0, 0, 0, 1)">                              allocSize,
</span><span style="color: rgba(0, 128, 128, 1)">261</span>                                 <span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> bytesReturned,
</span><span style="color: rgba(0, 128, 128, 1)">262</span> <span style="color: rgba(0, 0, 0, 1)">                              IntPtr.Zero))
</span><span style="color: rgba(0, 128, 128, 1)">263</span> <span style="color: rgba(0, 0, 0, 1)">                        {
</span><span style="color: rgba(0, 128, 128, 1)">264</span>                           <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">重新分配缓冲区,读取失败</span>
<span style="color: rgba(0, 128, 128, 1)">265</span>                           <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageProperty&gt;.ToWin32Error(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceIoControl.IOCTL_STORAGE_QUERY_PROPERTY execute failed after adjust buffer size</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Marshal.GetLastWin32Error());
</span><span style="color: rgba(0, 128, 128, 1)">266</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">267</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">268</span>                     <span style="color: rgba(0, 0, 255, 1)">else</span>
<span style="color: rgba(0, 128, 128, 1)">269</span> <span style="color: rgba(0, 0, 0, 1)">                  {
</span><span style="color: rgba(0, 128, 128, 1)">270</span>                         <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageProperty&gt;.ToWin32Error(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceIoControl.IOCTL_STORAGE_QUERY_PROPERTY execute failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err);
</span><span style="color: rgba(0, 128, 128, 1)">271</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">272</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">273</span>
<span style="color: rgba(0, 128, 128, 1)">274</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 至少要包含 Version/Size/几个 offset</span>
<span style="color: rgba(0, 128, 128, 1)">275</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (bytesReturned &lt; <span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">276</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageProperty&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceIoControl.IOCTL_STORAGE_QUERY_PROPERTY execute success but bytesReturned {bytesReturned} is lower than 24</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">277</span>
<span style="color: rgba(0, 128, 128, 1)">278</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> --- 读取头部固定字段(按官方 C 结构手工偏移)---
</span><span style="color: rgba(0, 128, 128, 1)">279</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Size    (ULONG) at offset 0x04</span>
<span style="color: rgba(0, 128, 128, 1)">280</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> size = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">281</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (size &gt; bytesReturned) size =<span style="color: rgba(0, 0, 0, 1)"> bytesReturned;
</span><span style="color: rgba(0, 128, 128, 1)">282</span>
<span style="color: rgba(0, 128, 128, 1)">283</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 磁盘序列号,同 Get-Disk 的 SerialNumber</span>
<span style="color: rgba(0, 128, 128, 1)">284</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> serialOffset = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">0x18</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">285</span>               <span style="color: rgba(0, 0, 255, 1)">string</span> serialRaw =<span style="color: rgba(0, 0, 0, 1)"> ReadAnsiStringSafe(buffer, size, serialOffset);
</span><span style="color: rgba(0, 128, 128, 1)">286</span>               <span style="color: rgba(0, 0, 255, 1)">string</span> serialClean =<span style="color: rgba(0, 0, 0, 1)"> CleanSerialString(serialRaw);
</span><span style="color: rgba(0, 128, 128, 1)">287</span>               storageProperties.SerialNumber =<span style="color: rgba(0, 0, 0, 1)"> serialClean;
</span><span style="color: rgba(0, 128, 128, 1)">288</span>
<span style="color: rgba(0, 128, 128, 1)">289</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 磁盘厂商/名称相关</span>
<span style="color: rgba(0, 128, 128, 1)">290</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> vendorOffset = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">0x0C</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">291</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> productOffset = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">0x10</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">292</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> revisionOffset = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">0x14</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">293</span>               storageProperties.Vendor =<span style="color: rgba(0, 0, 0, 1)"> ReadAnsiStringSafe(buffer, size, vendorOffset);
</span><span style="color: rgba(0, 128, 128, 1)">294</span>               storageProperties.Product =<span style="color: rgba(0, 0, 0, 1)"> ReadAnsiStringSafe(buffer, size, productOffset);
</span><span style="color: rgba(0, 128, 128, 1)">295</span>               storageProperties.Version =<span style="color: rgba(0, 0, 0, 1)"> ReadAnsiStringSafe(buffer, size, revisionOffset);
</span><span style="color: rgba(0, 128, 128, 1)">296</span>               storageProperties.DeviceName = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{storageProperties.Vendor} {storageProperties.Product}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">297</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> BusType</span>
<span style="color: rgba(0, 128, 128, 1)">298</span>               <span style="color: rgba(0, 0, 255, 1)">uint</span> busTypeOffset = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)Marshal.ReadInt32(buffer, <span style="color: rgba(128, 0, 128, 1)">0x1C</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">299</span>               storageProperties.BusType = Enum.IsDefined(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(StorageBusType), (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)busTypeOffset)
</span><span style="color: rgba(0, 128, 128, 1)">300</span>                     ?<span style="color: rgba(0, 0, 0, 1)"> (StorageBusType)busTypeOffset
</span><span style="color: rgba(0, 128, 128, 1)">301</span> <span style="color: rgba(0, 0, 0, 1)">                  : StorageBusType.Unknown;
</span><span style="color: rgba(0, 128, 128, 1)">302</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageProperty&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(storageProperties);
</span><span style="color: rgba(0, 128, 128, 1)">303</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">304</span>             <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
</span><span style="color: rgba(0, 128, 128, 1)">305</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">306</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageProperty&gt;<span style="color: rgba(0, 0, 0, 1)">.ToError(ex);
</span><span style="color: rgba(0, 128, 128, 1)">307</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">308</span>             <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">309</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">310</span> <span style="color: rgba(0, 0, 0, 1)">                Marshal.FreeHGlobal(buffer);
</span><span style="color: rgba(0, 128, 128, 1)">311</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">312</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">313</span>
<span style="color: rgba(0, 128, 128, 1)">314</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">315</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取磁盘大小(Bytes)
</span><span style="color: rgba(0, 128, 128, 1)">316</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">317</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="hDisk"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">318</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">319</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult&lt;<span style="color: rgba(0, 0, 255, 1)">long</span>&gt;<span style="color: rgba(0, 0, 0, 1)"> GetDiskSize(IntPtr hDisk)
</span><span style="color: rgba(0, 128, 128, 1)">320</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">321</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用一个足够大的缓冲区,一般 1024 字节足够</span>
<span style="color: rgba(0, 128, 128, 1)">322</span>             <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">int</span> bufferSize = <span style="color: rgba(128, 0, 128, 1)">1024</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">323</span>             IntPtr buffer =<span style="color: rgba(0, 0, 0, 1)"> Marshal.AllocHGlobal(bufferSize);
</span><span style="color: rgba(0, 128, 128, 1)">324</span>             <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)">325</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">326</span>               <span style="color: rgba(0, 0, 255, 1)">bool</span> ok =<span style="color: rgba(0, 0, 0, 1)"> DeviceIoControl(
</span><span style="color: rgba(0, 128, 128, 1)">327</span> <span style="color: rgba(0, 0, 0, 1)">                  hDisk,
</span><span style="color: rgba(0, 128, 128, 1)">328</span> <span style="color: rgba(0, 0, 0, 1)">                  IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
</span><span style="color: rgba(0, 128, 128, 1)">329</span> <span style="color: rgba(0, 0, 0, 1)">                  IntPtr.Zero,
</span><span style="color: rgba(0, 128, 128, 1)">330</span>                     <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">331</span> <span style="color: rgba(0, 0, 0, 1)">                  buffer,
</span><span style="color: rgba(0, 128, 128, 1)">332</span>                     (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)bufferSize,
</span><span style="color: rgba(0, 128, 128, 1)">333</span>                     <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> bytesReturned,
</span><span style="color: rgba(0, 128, 128, 1)">334</span> <span style="color: rgba(0, 0, 0, 1)">                  IntPtr.Zero);
</span><span style="color: rgba(0, 128, 128, 1)">335</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">ok)
</span><span style="color: rgba(0, 128, 128, 1)">336</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;<span style="color: rgba(0, 0, 255, 1)">long</span>&gt;.ToError(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">DeviceIoControl.IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Marshal.GetLastWin32Error());
</span><span style="color: rgba(0, 128, 128, 1)">337</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (bytesReturned &lt; Marshal.SizeOf&lt;DISK_GEOMETRY_EX&gt;<span style="color: rgba(0, 0, 0, 1)">())
</span><span style="color: rgba(0, 128, 128, 1)">338</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;<span style="color: rgba(0, 0, 255, 1)">long</span>&gt;.ToSuccess(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">339</span>
<span style="color: rgba(0, 128, 128, 1)">340</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> geomEx = Marshal.PtrToStructure&lt;DISK_GEOMETRY_EX&gt;<span style="color: rgba(0, 0, 0, 1)">(buffer);
</span><span style="color: rgba(0, 128, 128, 1)">341</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;<span style="color: rgba(0, 0, 255, 1)">long</span>&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(geomEx.DiskSize);
</span><span style="color: rgba(0, 128, 128, 1)">342</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">343</span>             <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
</span><span style="color: rgba(0, 128, 128, 1)">344</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">345</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;<span style="color: rgba(0, 0, 255, 1)">long</span>&gt;<span style="color: rgba(0, 0, 0, 1)">.ToError(e);
</span><span style="color: rgba(0, 128, 128, 1)">346</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">347</span>             <span style="color: rgba(0, 0, 255, 1)">finally</span>
<span style="color: rgba(0, 128, 128, 1)">348</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">349</span> <span style="color: rgba(0, 0, 0, 1)">                Marshal.FreeHGlobal(buffer);
</span><span style="color: rgba(0, 128, 128, 1)">350</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">351</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">352</span>
<span style="color: rgba(0, 128, 128, 1)">353</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">354</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取磁盘扩展属性
</span><span style="color: rgba(0, 128, 128, 1)">355</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">356</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="hDisk"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">357</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">358</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;DiskStorageAttribues&gt;<span style="color: rgba(0, 0, 0, 1)"> GetDiskAttributes(IntPtr hDisk)
</span><span style="color: rgba(0, 128, 128, 1)">359</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">360</span>             <span style="color: rgba(0, 0, 255, 1)">try</span>
<span style="color: rgba(0, 128, 128, 1)">361</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">362</span>               <span style="color: rgba(0, 0, 255, 1)">int</span> getSize = Marshal.SizeOf&lt;GET_DISK_ATTRIBUTES&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">363</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> getAttr = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GET_DISK_ATTRIBUTES
</span><span style="color: rgba(0, 128, 128, 1)">364</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">365</span>                     Version = (<span style="color: rgba(0, 0, 255, 1)">uint</span>)getSize, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 关键:Version = sizeof(GET_DISK_ATTRIBUTES)</span>
<span style="color: rgba(0, 128, 128, 1)">366</span>                     Reserved1 = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">367</span>                     Attributes = <span style="color: rgba(128, 0, 128, 1)">0</span>
<span style="color: rgba(0, 128, 128, 1)">368</span> <span style="color: rgba(0, 0, 0, 1)">                };
</span><span style="color: rgba(0, 128, 128, 1)">369</span>
<span style="color: rgba(0, 128, 128, 1)">370</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">DeviceIoControl_DiskAttributes(
</span><span style="color: rgba(0, 128, 128, 1)">371</span> <span style="color: rgba(0, 0, 0, 1)">                        hDisk,
</span><span style="color: rgba(0, 128, 128, 1)">372</span> <span style="color: rgba(0, 0, 0, 1)">                        IOCTL_DISK_GET_DISK_ATTRIBUTES,
</span><span style="color: rgba(0, 128, 128, 1)">373</span>                         <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> getAttr,
</span><span style="color: rgba(0, 128, 128, 1)">374</span>                         (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)getSize,
</span><span style="color: rgba(0, 128, 128, 1)">375</span>                         <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> getAttr,
</span><span style="color: rgba(0, 128, 128, 1)">376</span>                         (<span style="color: rgba(0, 0, 255, 1)">uint</span><span style="color: rgba(0, 0, 0, 1)">)getSize,
</span><span style="color: rgba(0, 128, 128, 1)">377</span>                         <span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> _,
</span><span style="color: rgba(0, 128, 128, 1)">378</span> <span style="color: rgba(0, 0, 0, 1)">                        IntPtr.Zero))
</span><span style="color: rgba(0, 128, 128, 1)">379</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">380</span>                     <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageAttribues&gt;.ToWin32Error(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">IOCTL_DISK_GET_DISK_ATTRIBUTES 失败</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Marshal.GetLastWin32Error());
</span><span style="color: rgba(0, 128, 128, 1)">381</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">382</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">磁盘扩展属性</span>
<span style="color: rgba(0, 128, 128, 1)">383</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> diskStorageAttributes = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DiskStorageAttribues();
</span><span style="color: rgba(0, 128, 128, 1)">384</span>               diskStorageAttributes.IsOffline = (getAttr.Attributes &amp; DISK_ATTRIBUTE_OFFLINE) != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">385</span>               diskStorageAttributes.IsReadOnly = (getAttr.Attributes &amp; DISK_ATTRIBUTE_READ_ONLY) != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">386</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageAttribues&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(diskStorageAttributes);
</span><span style="color: rgba(0, 128, 128, 1)">387</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">388</span>             <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
</span><span style="color: rgba(0, 128, 128, 1)">389</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">390</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskStorageAttribues&gt;<span style="color: rgba(0, 0, 0, 1)">.ToError(ex);
</span><span style="color: rgba(0, 128, 128, 1)">391</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">392</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">393</span>
<span style="color: rgba(0, 128, 128, 1)">394</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">395</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 通过任意挂载路径(盘符、目录挂载点、Volume GUID)获取卷大小与使用量
</span><span style="color: rgba(0, 128, 128, 1)">396</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">397</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;DiskSizeUsage&gt; GetDiskSizeUsageByMountPath(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> mountPath)
</span><span style="color: rgba(0, 128, 128, 1)">398</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">399</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(mountPath))
</span><span style="color: rgba(0, 128, 128, 1)">400</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">401</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskSizeUsage&gt;.ToError($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">parameter {nameof(mountPath)} is empty</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">402</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">403</span>
<span style="color: rgba(0, 128, 128, 1)">404</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 确保路径末尾有反斜杠对某些场景更稳妥</span>
<span style="color: rgba(0, 128, 128, 1)">405</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!mountPath.EndsWith(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\\</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)">406</span>               mountPath += <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\\</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">407</span>
<span style="color: rgba(0, 128, 128, 1)">408</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">GetDiskFreeSpaceExW(mountPath,
</span><span style="color: rgba(0, 128, 128, 1)">409</span>                     <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> freeAvailable,
</span><span style="color: rgba(0, 128, 128, 1)">410</span>                     <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> totalBytes,
</span><span style="color: rgba(0, 128, 128, 1)">411</span>                     <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> totalFreeBytes))
</span><span style="color: rgba(0, 128, 128, 1)">412</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">413</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskSizeUsage&gt;.ToError(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">GetDiskFreeSpaceExW failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Marshal.GetLastWin32Error());
</span><span style="color: rgba(0, 128, 128, 1)">414</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">415</span>
<span style="color: rgba(0, 128, 128, 1)">416</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;DiskSizeUsage&gt;.ToSuccess(<span style="color: rgba(0, 0, 255, 1)">new</span> DiskSizeUsage((<span style="color: rgba(0, 0, 255, 1)">long</span>)totalBytes, (<span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)">)totalFreeBytes));
</span><span style="color: rgba(0, 128, 128, 1)">417</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">418</span>
<span style="color: rgba(0, 128, 128, 1)">419</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">420</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 通过挂载路径获取卷信息
</span><span style="color: rgba(0, 128, 128, 1)">421</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">422</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="mountPath"&gt;</span><span style="color: rgba(0, 128, 0, 1)">盘符, e.g. "E:\\"</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">423</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">424</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult&lt;VolumeInfo&gt; GetVolumeInfo(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> mountPath)
</span><span style="color: rgba(0, 128, 128, 1)">425</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">426</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> volumeName = <span style="color: rgba(0, 0, 255, 1)">new</span> StringBuilder(<span style="color: rgba(128, 0, 128, 1)">256</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">427</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> fileSystemType = <span style="color: rgba(0, 0, 255, 1)">new</span> StringBuilder(<span style="color: rgba(128, 0, 128, 1)">256</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">428</span>
<span style="color: rgba(0, 128, 128, 1)">429</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!mountPath.EndsWith(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\\</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)">430</span>               mountPath += <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\\</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">431</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> success =<span style="color: rgba(0, 0, 0, 1)"> GetVolumeInformationW(
</span><span style="color: rgba(0, 128, 128, 1)">432</span> <span style="color: rgba(0, 0, 0, 1)">                mountPath,
</span><span style="color: rgba(0, 128, 128, 1)">433</span> <span style="color: rgba(0, 0, 0, 1)">                volumeName, volumeName.Capacity,
</span><span style="color: rgba(0, 128, 128, 1)">434</span>               <span style="color: rgba(0, 0, 255, 1)">out</span> _, <span style="color: rgba(0, 0, 255, 1)">out</span> _, <span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> _,
</span><span style="color: rgba(0, 128, 128, 1)">435</span> <span style="color: rgba(0, 0, 0, 1)">                fileSystemType, fileSystemType.Capacity);
</span><span style="color: rgba(0, 128, 128, 1)">436</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">success)
</span><span style="color: rgba(0, 128, 128, 1)">437</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">438</span>               <span style="color: rgba(0, 0, 255, 1)">int</span> err =<span style="color: rgba(0, 0, 0, 1)"> Marshal.GetLastWin32Error();
</span><span style="color: rgba(0, 128, 128, 1)">439</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;VolumeInfo&gt;.ToWin32Error($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">GetVolumeInformationW get {mountPath} volume info failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err);
</span><span style="color: rgba(0, 128, 128, 1)">440</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">441</span>
<span style="color: rgba(0, 128, 128, 1)">442</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> volumeInfo = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> VolumeInfo()
</span><span style="color: rgba(0, 128, 128, 1)">443</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">444</span>               VolumeLabel =<span style="color: rgba(0, 0, 0, 1)"> volumeName.ToString(),
</span><span style="color: rgba(0, 128, 128, 1)">445</span>               FileSystemType =<span style="color: rgba(0, 0, 0, 1)"> fileSystemType.ToString()
</span><span style="color: rgba(0, 128, 128, 1)">446</span> <span style="color: rgba(0, 0, 0, 1)">            };
</span><span style="color: rgba(0, 128, 128, 1)">447</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;VolumeInfo&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(volumeInfo);
</span><span style="color: rgba(0, 128, 128, 1)">448</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">449</span>
<span style="color: rgba(0, 128, 128, 1)">450</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">451</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 通过挂载路径获取磁盘信息
</span><span style="color: rgba(0, 128, 128, 1)">452</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;para&gt;</span><span style="color: rgba(0, 128, 0, 1)">先获取磁盘列表,再筛选</span><span style="color: rgba(128, 128, 128, 1)">&lt;/para&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">453</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">454</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="mountPath"&gt;&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">455</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">456</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult&lt;LocalDisk&gt; GetDiskByMountPath(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> mountPath)
</span><span style="color: rgba(0, 128, 128, 1)">457</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">458</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> getDisksResult =<span style="color: rgba(0, 0, 0, 1)"> GetDisks();
</span><span style="color: rgba(0, 128, 128, 1)">459</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">getDisksResult.Success)
</span><span style="color: rgba(0, 128, 128, 1)">460</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">461</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> getDisksResult.ToResult&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">462</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">463</span>
<span style="color: rgba(0, 128, 128, 1)">464</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> iscsiDisks = getDisksResult.Data.FirstOrDefault(i =&gt;<span style="color: rgba(0, 0, 0, 1)"> i.MountPaths.Contains(mountPath));
</span><span style="color: rgba(0, 128, 128, 1)">465</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> OperateResult&lt;LocalDisk&gt;<span style="color: rgba(0, 0, 0, 1)">.ToSuccess(iscsiDisks);
</span><span style="color: rgba(0, 128, 128, 1)">466</span>         }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>同样的遍历磁盘列表(4块),首次耗时20ms,二次查询仅7ms:</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202601/685541-20260112203649643-1418202473.png" alt="image" loading="lazy"></p>
<p>封装WIN32,异常码只有基础的Win32Exception异常码,不像Powershell Storage有相对上层更多的业务异常码和异常描述那么好理解。</p>
<p>比如句柄CreateFile失败,GetLastError异常码是&nbsp;0x00000002,转换Win32Exception描述:“系统找不到指定的文件”。鬼知道是啥问题。。。结合上下文,才知道原来磁盘IsOffline状态是无法查找卷、也无法创建分区访问句柄</p>
<p>&nbsp;</p>
<p><strong>回到.NET磁盘管理方案选型,</strong></p>
<p>没有复杂的C端环境的话、仅运维等固定场景,磁盘管理操作可以使用Powersshell</p>
<p>对磁盘操作要求稳定、但又想快速实现功能,较少的磁盘功能调用,推荐WMI</p>
<p>对磁盘操作要求稳定、性能要求高,做产品级的存储软件,推荐WIN32</p>
<p>&nbsp;</p>
<p>磁盘相关的其它文章:</p>
<p>Windows 本地虚拟磁盘 - 唐宋元明清2188 - 博客园</p>
Windows 网络存储ISCSI介绍 - 唐宋元明清2188 - 博客园<br>
<p>网络虚拟存储 Iscsi实现方案 - 唐宋元明清2188 - 博客园</p>

</div>
<div id="MySignature" role="contentinfo">
    <div>作者:唐宋元明清2188</div>
<div>出处:http://www.cnblogs.com/kybs0/</div>
<div>让学习成为习惯,假设明天就有重大机遇等着你,你准备好了么</div>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。 </div><br><br>
来源:https://www.cnblogs.com/kybs0/p/19473484
頁: [1]
查看完整版本: .NET 磁盘管理-技术方案选型