You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用OpenVirtualDisk()返回错误码2“文件未找到”的技术求助

踩坑记录:C#调用Virtual Disk API挂载ISO失败的解决过程

刚从Borland Pascal转C#,正在做一个基于Windows Imaging API的恢复套件,要在WinPE(Windows 10 + .NET 5.4.2)环境里挂载ISO文件,结果调用OpenVirtualDisk()的时候一直翻车——明明文件存在,程序也以管理员权限运行,要么返回错误码87(无效参数,GetLastWin32Error返回1008“无效令牌”),要么返回错误码2(文件未找到)。试了FileIOPermission给全权限也没用,差点头大。

先贴下我一开始的错误代码:

原DllImport声明

[DllImport("VirtDisk.dll", EntryPoint = "OpenVirtualDisk", CharSet = CharSet.Ansi, ThrowOnUnmappableChar = true ,SetLastError = true)]
public extern static Int64 OpenVirtualDisk(
[In] ref _VIRTUAL_STORAGE_TYPE PVIRTUAL_STORAGE_TYPE,
string Path,
_VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK,
long OPEN_VIRTUAL_DISK_FLAG,
[In, Optional] ref OPEN_VIRTUAL_DISK_PARAMTERS POPEN_VIRTUAL_DISK_PARAMTERS,
ref IntPtr pHandle);

原调用逻辑

private void button1_Click(object sender, EventArgs e) {
    IntPtr pHandle = IntPtr.Zero;
    Int64 RetVal = 0;
    string VirtualDiskPath = @"F:\Images\Windows10.ISO";
    _VIRTUAL_DISK_ACCESS_MASK VIRTUAL_DISK_ACCESS;
    Int64 VIRTUAL_DISK_FLAG;
    _VIRTUAL_STORAGE_TYPE VIRTUAL_STORAGE_TYPE;

    if (File.Exists(VirtualDiskPath)) {
        VIRTUAL_DISK_ACCESS = _VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_ATTACH_ALL;
        VIRTUAL_DISK_FLAG = OPEN_VIRTUAL_DISK_FLAG_NONE;
        VIRTUAL_STORAGE_TYPE.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
        VIRTUAL_STORAGE_TYPE.VendorId = VENDORMICROSOFT;

        IntPtr VirtualStorPtr = IntPtr.Zero;
        VirtualStorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(VIRTUAL_STORAGE_TYPE));
        Marshal.StructureToPtr(VIRTUAL_STORAGE_TYPE, VirtualStorPtr, true);

        IntPtr VirtualDiskVer = IntPtr.Zero;
        OPEN_VIRTUAL_DISK_PARAMTERS OPEN_VIRTUAL_DISK_PARAM;
        OPEN_VIRTUAL_DISK_PARAM = new OPEN_VIRTUAL_DISK_PARAMTERS {
            version = OPEN_VIRTUAL_DISK_VERSION.OPEN_VIRTUAL_DISK_VERSION_1,
            version1 = new OPEN_VIRTUAL_DISK_PARAMTERS1 { RWDepth = 0 }
        };
        VirtualDiskVer = Marshal.AllocHGlobal(Marshal.SizeOf(OPEN_VIRTUAL_DISK_PARAM));
        Marshal.StructureToPtr(OPEN_VIRTUAL_DISK_PARAM, VirtualDiskVer, true);

        RetVal = OpenVirtualDisk(ref VIRTUAL_STORAGE_TYPE, VirtualDiskPath, VIRTUAL_DISK_ACCESS, VIRTUAL_DISK_FLAG, ref OPEN_VIRTUAL_DISK_PARAM, ref pHandle);

        if ((RetVal == 0)) {
            MessageBox.Show("OpenVirtualDisk() has succeded in opening the file: \r\n" + VirtualDiskPath + "\r\nWith the file Handle: " + pHandle.ToString());
        } else {
            MessageBox.Show("OpenVirtualDisk() failed to open the file: " + VirtualDiskPath + ",\r\nWith Error Code: " + Marshal.GetLastWin32Error().ToString() + "\r\nReturn Value: " + RetVal.ToString());
        }
        Marshal.FreeHGlobal(VirtualStorPtr);
    }
}

最终解决方法

折腾了半天,发现问题出在两个地方:

  1. 权限掩码不对:我一开始用了VIRTUAL_DISK_ACCESS_ATTACH_ALL,但ISO是只读镜像,根本不需要这么高的权限,改成VIRTUAL_DISK_ACCESS_READ(对应FILE_ACCESS_MASK_RO)就解决了参数无效的问题。

  2. DllImport的字符集和参数标记错了:

    • Windows API的路径默认是Unicode的,我之前设了CharSet.Ansi,导致路径解析错误,改成CharSet.Unicode就解决了“文件未找到”的问题。
    • 给几个参数加上[In]特性,明确传递方向,避免封送的时候出问题。
    • 顺便把dll名改成小写的virtdisk.dll(其实大小写不影响,但统一规范点)。

修改后的DllImport如下:

[DllImport("virtdisk.dll", CharSet = CharSet.UNICODE, ThrowOnUnmappableChar = true, SetLastError = true)]
public extern static Int64 OpenVirtualDisk(
[In] ref _VIRTUAL_STORAGE_TYPE PVIRTUAL_STORAGE_TYPE,
string Path,
[In] _VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK,
[In] long OPEN_VIRTUAL_DISK_FLAG,
[In, Optional] ref OPEN_VIRTUAL_DISK_PARAMTERS POPEN_VIRTUAL_DISK_PARAMTERS,
[In] ref IntPtr pHandle);

改完之后再调用就成功挂载ISO了,希望同样转C#的Pascal老鸟或者WinPE开发的朋友能少踩这个坑~

内容的提问来源于stack exchange,提问作者R.McInnes-Piper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:14:20