大家晚上好。 我希望社区能够帮助解决我的小 C# 编程问题。 我在这里要说的是,我对C#编程非常陌生,这是Borland Pascal的一个非常陡峭的学习曲线!
我目前正在尝试使用虚拟磁盘 API(如 MSDN 网站上所述),转换为 c#(希望保持在托管上下文中)。
我已经设法让 OpenVirtualDisk() 接受第一个参数,但它在第二个参数(我想打开并附加的所述 ISO 的文件路径)上失败。 根据大量研究,我将参数"Path"声明为字符串,以使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:ImagesWindows10.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: rn" +
VirtualDiskPath + "rnWith the file Handle: " + pHandle.ToString());
}
else
{
MessageBox.Show("OpenVirtualDisk() failed to open the file: " +
VirtualDiskPath + ",rnWith Error Code: " + Marshal.GetLastWin32Error().ToString() +
"rnReturn Value: " + RetVal.ToString());
}
Marshal.FreeHGlobal(VirtualStorPtr);
}
}
到目前为止,每次尝试都有 RetVal 为 87 个"无效参数",GetLastWin32Error 报告1008 个"无效令牌",或者 RetVal 为 2 个"找不到文件",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( [在] 参考文献 _VIRTUAL_STORAGE_TYPE PVIRTUAL_STORAGE_TYPE, 字符串路径, [在] _VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK, [在]长OPEN_VIRTUAL_DISK_FLAG, [输入,可选] 参考OPEN_VIRTUAL_DISK_PARAMTERS POPEN_VIRTUAL_DISK_PARAMTERS, [In] ref IntPtr pHandle);
我以前打开过虚拟 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:IsoLocationIsoname.iso", NativeMethods.VirtualDiskAccessMask.All);
MessageBox.Show($"Handle = {handle.Handle}");
希望这有帮助!!