Unter Windows 10 schlägt der Versuch, mithilfe der CreateVirtualDisk-API eine virtuelle Festplatte zu erstellen, fehl und gibt den Fehlercode 87 zurück.
Komplettes minimal reproduzierbares Beispiel.
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Winapi.Windows;
type
// Identifiers for virtual storage types and providers
VIRTUAL_STORAGE_TYPE = record
DeviceId: ULONG; // VIRTUAL_STORAGE_TYPE_DEVICE_xxx
VendorId: TGUID; // VIRTUAL_STORAGE_TYPE_VENDOR_xxx
end;
PVIRTUAL_STORAGE_TYPE = ^VIRTUAL_STORAGE_TYPE;
const
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT: TGUID = '{EC984AEC-A0F9-47e9-901F-71415A66345B}';
VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN: TGUID = '{00000000-0000-0000-0000-000000000000}';
type
// Version definitions
CREATE_VIRTUAL_DISK_VERSION = (
CREATE_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0,
CREATE_VIRTUAL_DISK_VERSION_1 = 1
);
// Versioned CreateVirtualDisk parameter structure
CREATE_VIRTUAL_DISK_PARAMETERS_V1 = record
Version: CREATE_VIRTUAL_DISK_VERSION;
UniqueId: TGUID;
MaximumSize: ULONGLONG;
BlockSizeInBytes: ULONG;
SectorSizeInBytes: ULONG;
ParentPath: LPCWSTR;
SourcePath: LPCWSTR;
end;
PCREATE_VIRTUAL_DISK_PARAMETERS = Pointer;
const
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN = 0; //Device type is unknown or not valid.
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1; //CD or DVD image file device type. (.iso file) Windows 7 and Windows Server 2008 R2: This value is not supported before Windows 8 and Windows Server 2012.
VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2; //Virtual hard disk device type. (.vhd file)
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3; //VHDX format virtual hard disk device type. (.vhdx file) Windows 7 and Windows Server 2008 R2: This value is not supported before Windows 8 and Windows Server 2012.
type
VIRTUAL_DISK_ACCESS_MASK = (
VIRTUAL_DISK_ACCESS_NONE = $00000000,
VIRTUAL_DISK_ACCESS_ATTACH_RO = $00010000,
VIRTUAL_DISK_ACCESS_ATTACH_RW = $00020000,
VIRTUAL_DISK_ACCESS_DETACH = $00040000,
VIRTUAL_DISK_ACCESS_GET_INFO = $00080000,
VIRTUAL_DISK_ACCESS_CREATE = $00100000,
VIRTUAL_DISK_ACCESS_METAOPS = $00200000,
VIRTUAL_DISK_ACCESS_READ = $000d0000,
VIRTUAL_DISK_ACCESS_ALL = $003f0000,
VIRTUAL_DISK_ACCESS_WRITABLE = $00320000
);
// Flags for CreateVirtualDisk
CREATE_VIRTUAL_DISK_FLAG = (
CREATE_VIRTUAL_DISK_FLAG_NONE = $00000000, // i.e. dynamically expanding disk
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION = $00000001 // Pre-allocate all physical space necessary for the virtual size of the disk (e.g. a fixed VHD).
);
function CreateVirtualDisk(
{in} VirtualStorageType: PVIRTUAL_STORAGE_TYPE;
{in} Path: PWideChar;
{in} VirtualDiskAccessMask: VIRTUAL_DISK_ACCESS_MASK;
{in_opt} SecurityDescriptor: PSECURITY_DESCRIPTOR;
{in} Flags: CREATE_VIRTUAL_DISK_FLAG;
{in} ProviderSpecificFlags: ULONG;
{in} Parameters: PCREATE_VIRTUAL_DISK_PARAMETERS;
{in_opt} Overlapped: POverlapped;
out Handle: THandle
): DWORD; stdcall; external 'VirtDisk.dll';
procedure CreateVhd(Path: UnicodeString; FileSizeBytes: Int64);
var
storageType: VIRTUAL_STORAGE_TYPE;
parameters: CREATE_VIRTUAL_DISK_PARAMETERS_V1;
vhdHandle: THandle;
res: DWORD;
begin
// Specify UNKNOWN for both device and vendor so the system will use the file extension to determine the correct VHD format.
storageType.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_VHD; //VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; //VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
parameters := Default(CREATE_VIRTUAL_DISK_PARAMETERS_V1);
parameters.Version := CREATE_VIRTUAL_DISK_VERSION_1;
parameters.UniqueId := TGuid.NewGuid;
parameters.MaximumSize := FileSizeBytes;
parameters.BlockSizeInBytes := 0; //CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;
parameters.SectorSizeInBytes := 512; //CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
parameters.ParentPath := nil;
parameters.SourcePath := nil;
res := CreateVirtualDisk(
@storageType,
PWideChar(Path),
VIRTUAL_DISK_ACCESS_NONE,
nil, // default security descriptor
CREATE_VIRTUAL_DISK_FLAG_NONE, // dynamically expanding disk
0,
@parameters,
nil, //not overlapped
{out}vhdHandle);
if res <> ERROR_SUCCESS then
begin
RaiseLastOSError(res);
Exit;
end;
CloseHandle(vhdHandle);
end;
begin
try
CreateVhd('C:\test.vhd', 15*1024*1024); //15 MB
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
WriteLn('Press enter to close...');
ReadLn;
end.
Offensichtlich macht es keinen Unterschied, als Administrator zu arbeiten.
Bonuslesung
delphi
winapi
virtual-disk
Ian Boyd
quelle
quelle
VIRTUAL_DISK_ACCESS_ALL
stattdessen zu verwendenVIRTUAL_DISK_ACCESS_NONE
. in c ++ kann ich deinen fehler nicht reproduzieren (oder ich konvertiere delphi falsch in c ++).Antworten:
@ RbMms erster Kommentar zu den Fragen zeigt, wo gesucht und wie das Problem gelöst werden muss. Er gibt an, dass die c ++ - Übersetzung das Problem nicht reproduziert. Dann muss das Problem bei der Übersetzung des Headers (virtdisk.h) liegen. Der Kommentar besagt sogar, dass die Übersetzung von Delphi möglicherweise nicht korrekt ist.
Beim schnellen Durchsuchen des Codes nach häufigen Übersetzungsfehlern stoßen wir auf Aufzählungen. Bei explizit zugewiesenen Werten (der größte ist 3 Byte) ist der erste (VIRTUAL_DISK_ACCESS_MASK) gut, der Compiler verwendet hier 4 Byte.
Der nächste ist problematisch:
Aus Gründen der Aufzählungsgröße verwendet der Compiler 1 Byte für diesen Typ.
CreateVirtualDisk
Dies führt zu einer binären Nichtübereinstimmung mit der exportierten Funktion ( ), daher 87 (ERROR_INVALID_PARAMETER).Sie können
{$Z4}
vor der Deklaration für diesen Teil verwenden.Tests zeigen, dass Sie auch die anderen Ratschläge im selben Kommentar berücksichtigen müssen, nämlich die Verwendung
VIRTUAL_DISK_ACCESS_NONE
. Dies verursacht in meinem Test eine 5, die ERROR_ACCESS_DENIED ist. Ich kann die Festplatte mit erstellenVIRTUAL_DISK_ACCESS_ALL
, wie im Kommentar empfohlen.Weitere Tests zeigen, dass die Verwendung des Stammverzeichnisses des Stammlaufwerks für die virtuelle Festplatte möglicherweise keine sehr gute Idee ist, die in diesem Kommentar erwähnt wird . Mein Test mit 'C: \ test.vhd' war erfolgreich, aber ich kann diese Datei nicht finden. Bei Verwendung eines anderen beschreibbaren Verzeichnisses kann ich die Datei problemlos finden.
quelle
VIRTUAL_DISK_ACCESS_CREATE
funktioniert es. Anscheinend müssen Sie angeben, wenn Sie "v2" verwendenVIRTUAL_DISK_ACCESS_NONE
. Wenn Sie jedoch "v1" verwenden , dürfen Sie dies nicht angebenVIRTUAL_DISK_ACCESS_NONE
. Ich habeCREATE
Werke gefunden - solange die Datei noch nicht existiert (löschen Sie sie, wenn dies der Fall ist). Ich habe auch{$MINENUMSIZE 4}
oben amVirtDisk.pas
Gerät hinzugefügt , damit es dem Windows-ABI folgt.