.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 - 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> 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> <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><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><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>-> MSFT_* WMI 类 (CIM)、WMI服务Winmgmt<br>-> Storage Management Provider<br>-> 内核驱动 (disk.sys, partmgr.sys, volmgr.sys)<br>-> 设备硬件</p>
<p>powershell有以下查找主要命令,</p>
<p>Get-Disk - 查找磁盘</p>
<p>Get-Partition - 查找分区</p>
<p>Get-Volume - 查找卷</p>
<p>Get-Disk | Where-Object -FilterScript { $_.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> <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> 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> 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> <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>-> Storage Management Provider<br> -> IOCTL -> 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<List<LocalDisk>><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<LocalDisk><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. 磁盘容量 (字节 -> 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> && <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 -> Win32_DiskDriveToDiskPartition -> Win32_DiskPartition ->
</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 -> 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<List<LocalDisk>>.ToSuccess(disks.OrderBy(i =><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<List<LocalDisk>><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" -> 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 < <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)"><summary></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)"></summary></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> &&
<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> &&
<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) &&
<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 => !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)"><summary></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)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)"> 95</span> <span style="color: rgba(0, 0, 255, 1)">private</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>> 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<<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)">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<ManagementObject><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>-> VDS / Storage Management API<br> -> 内核驱动 (disk.sys, partmgr.sys, volmgr.sys)<br> -> 设备硬件</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)"><summary></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)"></summary></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)"><param name="diskNumber"></span><span style="color: rgba(0, 128, 0, 1)">磁盘编号</span><span style="color: rgba(128, 128, 128, 1)"></param></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)"><param name="volumeMaps"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<LocalDisk> GetDiskInfoByDiskNumber(<span style="color: rgba(0, 0, 255, 1)">int</span> diskNumber, Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>><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<LocalDisk><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<LocalDisk>.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<LocalDisk>.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<LocalDisk>.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 => 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) && 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<LocalDisk><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)"><summary></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)"></summary></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult<List<LocalDisk>><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. 先拿卷 -> 卷所属的物理磁盘号 + 盘符/挂载点</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<List<LocalDisk>><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<LocalDisk><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 => 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 <= 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<List<LocalDisk>><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<List<LocalDisk>><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)"><summary></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)"><remarks></span><span style="color: rgba(0, 128, 0, 1)">通过枚举卷,并使用 IOCTL_STORAGE_GET_DEVICE_NUMBER 映射到设备号。</span><span style="color: rgba(128, 128, 128, 1)"></remarks></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)"></summary></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)"><returns></span><span style="color: rgba(0, 128, 0, 1)">PhysicalDiskNumber -> 对应的所有挂载路径(盘符、挂载点)</span><span style="color: rgba(128, 128, 128, 1)"></returns></span>
<span style="color: rgba(0, 128, 128, 1)"> 48</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>><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<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<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)"> 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<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>><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<STORAGE_DEVICE_NUMBER><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<STORAGE_DEVICE_NUMBER><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<<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)">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<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>>.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<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>>.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<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>>.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<Dictionary<<span style="color: rgba(0, 0, 255, 1)">int</span>, List<<span style="color: rgba(0, 0, 255, 1)">string</span>>>><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)"><summary></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)"></summary></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)"><param name="hDisk"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">159</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<DiskPartitionInfo><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<DRIVE_LAYOUT_INFORMATION_EX>() + <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<DiskPartitionInfo>.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<DRIVE_LAYOUT_INFORMATION_EX_HEADER><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<DRIVE_LAYOUT_INFORMATION_EX><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<PARTITION_INFORMATION_EX><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 < 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<PARTITION_INFORMATION_EX><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<DiskPartitionInfo><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)"><summary></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)"></summary></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)"><param name="hDisk"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">223</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<DiskStorageProperty><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<STORAGE_PROPERTY_QUERY><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 && bytesReturned ><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<STORAGE_PROPERTY_QUERY><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<DiskStorageProperty>.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<DiskStorageProperty>.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 < <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<DiskStorageProperty>.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 > 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<DiskStorageProperty><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<DiskStorageProperty><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)"><summary></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)"></summary></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)"><param name="hDisk"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">319</span> <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult<<span style="color: rgba(0, 0, 255, 1)">long</span>><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<<span style="color: rgba(0, 0, 255, 1)">long</span>>.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 < Marshal.SizeOf<DISK_GEOMETRY_EX><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<<span style="color: rgba(0, 0, 255, 1)">long</span>>.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<DISK_GEOMETRY_EX><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<<span style="color: rgba(0, 0, 255, 1)">long</span>><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<<span style="color: rgba(0, 0, 255, 1)">long</span>><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)"><summary></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)"></summary></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)"><param name="hDisk"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">358</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<DiskStorageAttribues><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<GET_DISK_ATTRIBUTES><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<DiskStorageAttribues>.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 & 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 & 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<DiskStorageAttribues><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<DiskStorageAttribues><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)"><summary></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)"></summary></span>
<span style="color: rgba(0, 128, 128, 1)">397</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<DiskSizeUsage> 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<DiskSizeUsage>.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<DiskSizeUsage>.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<DiskSizeUsage>.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)"><summary></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)"></summary></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)"><param name="mountPath"></span><span style="color: rgba(0, 128, 0, 1)">盘符, e.g. "E:\\"</span><span style="color: rgba(128, 128, 128, 1)"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">424</span> <span style="color: rgba(0, 0, 255, 1)">private</span> OperateResult<VolumeInfo> 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<VolumeInfo>.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<VolumeInfo><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)"><summary></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)"><para></span><span style="color: rgba(0, 128, 0, 1)">先获取磁盘列表,再筛选</span><span style="color: rgba(128, 128, 128, 1)"></para></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)"></summary></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)"><param name="mountPath"></param></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)"><returns></returns></span>
<span style="color: rgba(0, 128, 128, 1)">456</span> <span style="color: rgba(0, 0, 255, 1)">public</span> OperateResult<LocalDisk> 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<LocalDisk><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 =><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<LocalDisk><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异常码是 0x00000002,转换Win32Exception描述:“系统找不到指定的文件”。鬼知道是啥问题。。。结合上下文,才知道原来磁盘IsOffline状态是无法查找卷、也无法创建分区访问句柄</p>
<p> </p>
<p><strong>回到.NET磁盘管理方案选型,</strong></p>
<p>没有复杂的C端环境的话、仅运维等固定场景,磁盘管理操作可以使用Powersshell</p>
<p>对磁盘操作要求稳定、但又想快速实现功能,较少的磁盘功能调用,推荐WMI</p>
<p>对磁盘操作要求稳定、性能要求高,做产品级的存储软件,推荐WIN32</p>
<p> </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]