1

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

我目前正在尝试使用虚拟磁盘 API(如 MSDN 网站上的此处所述),转换为 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);

        }
    }

到目前为止,每次尝试要么有一个 87“无效参数”的 RetVal,GetLastWin32Error 报告 1008“无效令牌”,要么有 2 个“未找到文件”的 RetVal,GetLastWin32Error 报告相同。

谁能发现我哪里出错了?

提前致谢。

里奇

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

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

[DllImport("virtdisk.dll" CharSet = CharSet.UNICODE, ThrowOnUnmappableChar = true ,SetLastError = true)] public extern static Int64 OpenVirtualDisk( [In] ref _VIRTUAL_STORAGE_TYPE PVIRTUAL_STORAGE_TYPE, 字符串路径, [In] _VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK, [In] long OPEN , [输入, 可选​​] ref OPEN_VIRTUAL_DISK_PARMTERS POPEN_VIRTUAL_DISK_PARTERS, [输入] ref IntPtr pHandle);

4

1 回答 1

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

希望这可以帮助!!

于 2018-05-16T20:08:05.613 回答