晚上好。我希望社区可以帮助我的小C#编程问题。我会在这里说我对C#编程很陌生,而且这是Borland Pascal的一个非常陡峭的学习曲线!
我目前正在尝试使用虚拟磁盘API(如MSDN网站上的here所述),转换为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:\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“无效参数”,GetLastWin32Error报告1008“无效令牌”,或RetVal为2“文件未找到”,GetLastWin32Error报告相同。
有人能找到我错的地方吗?
提前致谢。
里奇
N.B这是我基于Windows Imaging API(Wimgapi.h)在c#中构建的恢复套件的一部分。这是为了允许安装Windows(任何版本,只要它是64位),如果需要的话。它将在WinPE上运行(Windows 10,.Net Version 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, string Path, [In] _VIRTUAL_DISK_ACCESS_MASK LVIRTUAL_DISK_ACCESS_MASK, [In]长OPEN_VIRTUAL_DISK_FLAG, [在,可选]参考OPEN_VIRTUAL_DISK_PARAMTERS POPEN_VIRTUAL_DISK_PARAMTERS, [In] ref IntPtr pHandle);
答案 0 :(得分:1)
之前我已经打开了虚拟ISO,我将为您发布我的代码:
-Wl
要使用它,请创建如下方法:
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);
}
}
}
希望这会有所帮助!!