【问题标题】:Using OpenVirtualDisk() returns error code 2 "File not Found" Windows 10使用 OpenVirtualDisk() 返回错误代码 2“找不到文件”Windows 10
【发布时间】:2018-10-26 19:55:06
【问题描述】:

大家晚上好。我希望社区能够帮助解决我的小 C# 编程问题。在这里我要说的是,我对 C# 编程非常陌生,而且它是 Borland Pascal 的一个非常陡峭的学习曲线!

我目前正在尝试使用虚拟磁盘 API(如 MSDN 网站上的 here 所述),转换为 c#(希望保留在托管上下文中)。

我已经设法让 OpenVirtualDisk() 接受第一个参数,但它在第二个参数上失败(我想打开并附加的所述 ISO 的文件路径。)根据大量研究,我声明了参数“路径”作为字符串,让 CLR 最适合函数签名。

应用程序当前正在提升权限下运行(通过 Visual Studio 2017)

以下是我的 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);

所有其他常量、枚举和结构都被声明为由 VirtDisk.h 提供,如果需要,可以提供。

这是我用来调用 OpenVirtualDisk 的所有代码(如您所见,我使用 File.Exists() 来确保在开始任何工作之前文件存在):

        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);

        }
    }

到目前为止,每次尝试的 RetVal 为 87“Invalid Parameter”,GetLastWin32Error 报告 1008“Invalid Token”,或者 RetVal 为 2“File Not Found”,GetLastWin32Error 报告相同。

谁能发现我哪里出错了?

提前致谢。

里奇

注意,这是我在 c# 中构建的恢复套件的一部分,它基于 Windows Imaging API (Wimgapi.h)。如果需要,这是为了允许安装 Windows(任何版本,只要是 64 位)。它将在 WinPE(Windows 10,.Net 版本 5.4.2)上运行我什至尝试使用 FileIOPermssion 来允许该进程完全访问文件。

故障已排序,如下cmets。 FILE_ACCESS_MASK 需要更改为 FILE_ACCESS_MASK_RO,但也需要修改 DLLimport 声明。 DLLImport 现在显示为:

[DllImport("virtdisk.dll" CharSet = CharSet.UNICODE, ThrowOnUnmappableChar = true ,SetLastError = true)] 公共外部静态 Int64 OpenVirtualDisk( [输入] 参考 _VIRTUAL_STORAGE_TYPE PVIRTUAL_STORAGE_TYPE, 字符串路径, [在]_VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK, [输入] 长 OPEN_VIRTUAL_DISK_FLAG, [在,可选] 参考 OPEN_VIRTUAL_DISK_PARTERS POPEN_VIRTUAL_DISK_PARTERS, [输入] ref IntPtr pHandle);

【问题讨论】:

    标签: c# virtual-disk


    【解决方案1】:

    我之前打开过虚拟 ISO,我会为您发布我的代码:

    public static class NativeMethods
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Justification = "Warning is bogus.")]
        [DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
        public static extern Int32 OpenVirtualDisk(ref VIRTUAL_STORAGE_TYPE VirtualStorageType, 
            string Path, 
            VIRTUAL_DISK_ACCESS_MASK VirtualDiskAccessMask, 
            OPEN_VIRTUAL_DISK_FLAG Flags, 
            ref OPEN_VIRTUAL_DISK_PARAMETERS Parameters, 
            ref VirtualDiskSafeHandle Handle);
    
        public static readonly Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47e9-901F-71415A66345B");
        public const int OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT = 1;
    
        public const Int32 ERROR_SUCCESS = 0;
        public const Int32 ERROR_FILE_CORRUPT = 1392;
        public const Int32 ERROR_FILE_NOT_FOUND = 2;
        public const Int32 ERROR_PATH_NOT_FOUND = 3;
        public const Int32 ERROR_ACCESS_DENIED = 5;
    
        /// CD or DVD image file device type. (.iso file)
        /// </summary>
        public const int VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1;
    
        /// <summary>
        /// Device type is unknown or not valid.
        /// </summary>
        public const int VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN = 0;
    
        /// <summary>
        /// Virtual hard disk device type. (.vhd file)
        /// </summary>
        public const int VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2;
    
        /// <summary>
        /// VHDX format virtual hard disk device type. (.vhdx file)
        /// </summary>
        public const int VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3;
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct VIRTUAL_STORAGE_TYPE
        {
            /// <summary>
            /// Device type identifier.
            /// </summary>
            public Int32 DeviceId; //ULONG
    
            /// <summary>
            /// Vendor-unique identifier.
            /// </summary>
            public Guid VendorId; //GUID
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct OPEN_VIRTUAL_DISK_PARAMETERS
        {
            /// <summary>
            /// An OPEN_VIRTUAL_DISK_VERSION enumeration that specifies the version of the OPEN_VIRTUAL_DISK_PARAMETERS structure being passed to or from the VHD functions.
            /// </summary>
            public OPEN_VIRTUAL_DISK_VERSION Version; //OPEN_VIRTUAL_DISK_VERSION
    
            /// <summary>
            /// A structure.
            /// </summary>
            public OPEN_VIRTUAL_DISK_PARAMETERS_Version1 Version1;
        }
    
        public enum OPEN_VIRTUAL_DISK_VERSION : int
        {
            /// <summary>
            /// </summary>
            OPEN_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0,
    
            /// <summary>
            /// </summary>
            OPEN_VIRTUAL_DISK_VERSION_1 = 1
        }
    
        [Flags]
        public enum VirtualDiskAccessMask : int
        {
            /// <summary>
            /// Open the virtual disk for read-only attach access. The caller must have READ access to the virtual disk image file. If used in a request to open a virtual disk that is already open, the other handles must be limited to either VIRTUAL_DISK_ACCESS_DETACH or VIRTUAL_DISK_ACCESS_GET_INFO access, otherwise the open request with this flag will fail.
            /// </summary>
            AttachReadOnly = 0x00010000,
            /// <summary>
            /// Open the virtual disk for read-write attaching access. The caller must have (READ | WRITE) access to the virtual disk image file. If used in a request to open a virtual disk that is already open, the other handles must be limited to either VIRTUAL_DISK_ACCESS_DETACH or VIRTUAL_DISK_ACCESS_GET_INFO access, otherwise the open request with this flag will fail. If the virtual disk is part of a differencing chain, the disk for this request cannot be less than the RWDepth specified during the prior open request for that differencing chain.
            /// </summary>
            AttachReadWrite = 0x00020000,
            /// <summary>
            /// Open the virtual disk to allow detaching of an attached virtual disk. The caller must have (FILE_READ_ATTRIBUTES | FILE_READ_DATA) access to the virtual disk image file.
            /// </summary>
            Detach = 0x00040000,
            /// <summary>
            /// Information retrieval access to the VHD. The caller must have READ access to the virtual disk image file.
            /// </summary>
            GetInfo = 0x00080000,
            /// <summary>
            /// VHD creation access.
            /// </summary>
            Create = 0x00100000,
            /// <summary>
            /// Open the VHD to perform offline meta-operations. The caller must have (READ | WRITE) access to the virtual disk image file, up to RWDepth if working with a differencing chain. If the VHD is part of a differencing chain, the backing store (host volume) is opened in RW exclusive mode up to RWDepth.
            /// </summary>
            MetaOperations = 0x00200000,
            /// <summary>
            /// Allows unrestricted access to the VHD. The caller must have unrestricted access rights to the virtual disk image file.
            /// </summary>
            All = 0x003f0000,
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct OPEN_VIRTUAL_DISK_PARAMETERS_Version1
        {
            /// <summary>
            /// Indicates the number of stores, beginning with the child, of the backing store chain to open as read/write. The remaining stores in the differencing chain will be opened read-only. This is necessary for merge operations to succeed.
            /// </summary>
            public Int32 RWDepth; //ULONG
        }
    
        public enum OPEN_VIRTUAL_DISK_FLAG : int
        {
            /// <summary>
            /// No flag specified.
            /// </summary>
            OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000,
    
            /// <summary>
            /// Open the backing store without opening any differencing-chain parents. Used to correct broken parent links.
            /// </summary>
            OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 0x00000001,
    
            /// <summary>
            /// Reserved.
            /// </summary>
            OPEN_VIRTUAL_DISK_FLAG_BLANK_FILE = 0x00000002,
    
            /// <summary>
            /// Reserved.
            /// </summary>
            OPEN_VIRTUAL_DISK_FLAG_BOOT_DRIVE = 0x00000004
        }
    
        public enum VIRTUAL_DISK_ACCESS_MASK : int
        {
            /// <summary>
            /// Open the virtual disk for read-only attach access. The caller must have READ access to the virtual disk image file. If used in a request to open a virtual disk that is already open, the other handles must be limited to either VIRTUAL_DISK_ACCESS_DETACH or VIRTUAL_DISK_ACCESS_GET_INFO access, otherwise the open request with this flag will fail.
            /// </summary>
            VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x00010000,
    
            /// <summary>
            /// Open the virtual disk for read-write attaching access. The caller must have (READ | WRITE) access to the virtual disk image file. If used in a request to open a virtual disk that is already open, the other handles must be limited to either VIRTUAL_DISK_ACCESS_DETACH or VIRTUAL_DISK_ACCESS_GET_INFO access, otherwise the open request with this flag will fail. If the virtual disk is part of a differencing chain, the disk for this request cannot be less than the RWDepth specified during the prior open request for that differencing chain.
            /// </summary>
            VIRTUAL_DISK_ACCESS_ATTACH_RW = 0x00020000,
    
            /// <summary>
            /// Open the virtual disk to allow detaching of an attached virtual disk. The caller must have (FILE_READ_ATTRIBUTES | FILE_READ_DATA) access to the virtual disk image file.
            /// </summary>
            VIRTUAL_DISK_ACCESS_DETACH = 0x00040000,
    
            /// <summary>
            /// Information retrieval access to the VHD. The caller must have READ access to the virtual disk image file.
            /// </summary>
            VIRTUAL_DISK_ACCESS_GET_INFO = 0x00080000,
    
            /// <summary>
            /// VHD creation access.
            /// </summary>
            VIRTUAL_DISK_ACCESS_CREATE = 0x00100000,
    
            /// <summary>
            /// Open the VHD to perform offline meta-operations. The caller must have (READ | WRITE) access to the virtual disk image file, up to RWDepth if working with a differencing chain. If the VHD is part of a differencing chain, the backing store (host volume) is opened in RW exclusive mode up to RWDepth.
            /// </summary>
            VIRTUAL_DISK_ACCESS_METAOPS = 0x00200000,
    
            /// <summary>
            /// Reserved.
            /// </summary>
            VIRTUAL_DISK_ACCESS_READ = 0x000d0000,
    
            /// <summary>
            /// Allows unrestricted access to the VHD. The caller must have unrestricted access rights to the virtual disk image file.
            /// </summary>
            VIRTUAL_DISK_ACCESS_ALL = 0x003f0000,
    
            /// <summary>
            /// Reserved.
            /// </summary>
            VIRTUAL_DISK_ACCESS_WRITABLE = 0x00320000
        }
    
    }
    
    [SecurityPermission(SecurityAction.Demand)]
    public class VirtualDiskSafeHandle : SafeHandle
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Justification = "Warning is bogus.")]
        [DllImportAttribute("kernel32.dll", SetLastError = true)]
        [return: MarshalAsAttribute(UnmanagedType.Bool)]
        public static extern Boolean CloseHandle(IntPtr hObject);
    
        public VirtualDiskSafeHandle()
            : base(IntPtr.Zero, true)
        {
        }
    
        public override bool IsInvalid
        {
            get { return (this.IsClosed) || (base.handle == IntPtr.Zero); }
        }
    
        public override string ToString()
        {
            return this.handle.ToString();
        }
    
        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    
        public IntPtr Handle
        {
            get { return handle; }
        }
    }
    

    要使用它,请创建如下方法:

    private VirtualDiskSafeHandle OpenIso(string fileName, NativeMethods.VirtualDiskAccessMask fileAccessMask)
    {
        var parameters = new NativeMethods.OPEN_VIRTUAL_DISK_PARAMETERS();
        parameters.Version = NativeMethods.OPEN_VIRTUAL_DISK_VERSION.OPEN_VIRTUAL_DISK_VERSION_1;
        parameters.Version1.RWDepth = NativeMethods.OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT;
    
        var storageType = new NativeMethods.VIRTUAL_STORAGE_TYPE();
        storageType.DeviceId = NativeMethods.VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
        storageType.VendorId = NativeMethods.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;
    
        fileAccessMask = ((fileAccessMask & NativeMethods.VirtualDiskAccessMask.GetInfo) == NativeMethods.VirtualDiskAccessMask.GetInfo) ? NativeMethods.VirtualDiskAccessMask.GetInfo : 0;
        fileAccessMask |= NativeMethods.VirtualDiskAccessMask.AttachReadOnly;
    
        VirtualDiskSafeHandle handle = new VirtualDiskSafeHandle();
    
        int res = NativeMethods.OpenVirtualDisk(ref storageType, fileName,
            (NativeMethods.VIRTUAL_DISK_ACCESS_MASK) fileAccessMask,
            NativeMethods.OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE, ref parameters, ref handle);
    
        if (res == NativeMethods.ERROR_SUCCESS)
        {
            return handle;
        }
        else
        {
            handle.SetHandleAsInvalid();
            if ((res == NativeMethods.ERROR_FILE_NOT_FOUND) || (res == NativeMethods.ERROR_PATH_NOT_FOUND))
            {
                throw new FileNotFoundException("File not found.");
            }
            else if (res == NativeMethods.ERROR_ACCESS_DENIED)
            {
                throw new IOException("Access is denied.");
            }
            else if (res == NativeMethods.ERROR_FILE_CORRUPT)
            {
                throw new InvalidDataException("File type not recognized.");
            }
            else
            {
                throw new Win32Exception(res);
            }
        }
    }
    

    然后在整个程序中,您可以简单地执行以下操作:

    VirtualDiskSafeHandle handle = OpenIso(@"c:\IsoLocation\Isoname.iso", NativeMethods.VirtualDiskAccessMask.All);
    MessageBox.Show($"Handle = {handle.Handle}");
    

    希望这会有所帮助!

    【讨论】:

    • 谢谢 Icemanind,作为第二个按钮实现并在我的测试平台应用程序中发挥作用。我在哪里误入歧途 - 除了没有将所有内容封装在它自己的类中?
    • @R.McInnes-Piper 我在想,因为它是 ISO 并且 ISO 是只读的,您可能不得不将 VIRTUAL_DISK_ACCESS_MASK 设置为只读或其他。否则,它将尝试打开它进行写访问,这对 ISO 无效
    • 找到了!我将 VIRTUAL_DISK_ACCESS_MASK 更改为 RO,它仍然失败。错误似乎在我的 DLLImport 声明中。我删除了 DllImport(..., EntryPoint = "OpenVirtualDisk" 并将 CharSet 更改为 CharSet = CharSet.Unicode,。它起作用了!似乎是 Borland Pascal 时代的宿醉......
    猜你喜欢
    • 2018-09-16
    • 2017-11-28
    • 1970-01-01
    • 2011-04-10
    • 2019-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多