0

when I run CreateVritualDisk, I get the error 87 (ERROR_INVALID_PARAMETER). Presumably missing a parameter or is incorrect. The problem is with the version CREATE_VIRTUAL_DISK_VERSION_2, CREATE_VIRTUAL_DISK_VERSION_1 runs successfully.

function TForm3.CreateVHDX(const AFilePath: string; const ASize: ULONG; const AType: integer; out AReturn: DWORD): Boolean;
var
  params: TCreateVirtualDiskParameters;
  mask: TVIRTUAL_DISK_ACCESS_MASK;
  vst: TVirtualStorageType;
  hvhd: THandle;
  begin
  hVhd := INVALID_HANDLE_VALUE;

//  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
//  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT ;
  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;

  params.Version:= CREATE_VIRTUAL_DISK_VERSION_2;
  params.Version2.UniqueId := TGUID.Empty;
  params.Version2.MaximumSize:= ASize * 1024 * 1024;
  params.Version2.BlockSizeInBytes := CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE; //0
  params.Version2.SectorSizeInBytes := $200;
  params.Version2.PhysicalSectorSize := $200;
  params.Version2.ParentPath := nil;
//  params.Version2.OpenFlags := OPEN_VIRTUAL_DISK_FLAG_NONE;
  params.Version2.ResiliencyGuid := TGUID.Empty;
//  params.Version2.ParentVirtualStorageType := ;

  mask := VIRTUAL_DISK_ACCESS_NONE;

  if AType = 0 then //dynamic
  begin
    AReturn := CreateVirtualDisk(
      @vst,
      PWideChar(AFilePath),
      mask,
      nil,
      CREATE_VIRTUAL_DISK_FLAG_NONE,
      0,
      @params,
      nil,
      hvhd);
      Result := AReturn = ERROR_SUCCESS;
  end;

  if AType = 1 then //fixed
  begin
    AReturn := CreateVirtualDisk(
    @vst,
    PWideChar(AFilePath),
    mask,
    nil,
    CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
    0,
    @params,
    nil,
    hvhd);
 Result := AReturn = ERROR_SUCCESS;
 end;

 if hvhd <> INVALID_HANDLE_VALUE then
   CloseHandle( hvhd )
 end;

I have already tried several combinations, but no success.

EDIT: I use Windows 10. In the future, i want to create VHD and VHDX files (fixed, dynamic and differencing) with one method call. At this moment, i want to create VHDX (fixed, dynamic and differencing).

TCreateVirtualDiskParametersVersion2 = record
  UniqueId: TGUID;
  MaximumSize: ULONGLONG;
  BlockSizeInBytes: ULONG;
  SectorSizeInBytes: ULONG;
  PhysicalSectorSize: ULONG;
  ParentPath: LPCWSTR;
  SourcePath: LPCWSTR;
  OpenFlags: TOPEN_VIRTUAL_DISK_FLAG;
  ParentVirtualStorageType: VIRTUAL_STORAGE_TYPE;
  SourceVirtualStorageType: VIRTUAL_STORAGE_TYPE;
  ResiliencyGuid: TGUID;
end;
michl2007
  • 15
  • 1
  • 5
  • What OS are you using? Version 2 isn't supported before Windows 8. – Jonathan Potter Jun 25 '16 at 23:13
  • Just so you know the MSDN documentation for the virtual disk API is horrible. A bunch of things are missing or incorrect. – theB Jun 25 '16 at 23:49
  • What type of device are you actually creating? The values differ depending on whether it's a VHD, VHDX or VHD Set – cogumel0 Jun 26 '16 at 00:34
  • Your code is missing a few things, such as the call to the actual `CreateVirtualDisk()` method. Can you also paste your `CREATE_VIRTUAL_DISK_PARAMETERS` structure? – cogumel0 Jun 26 '16 at 01:07
  • Have you tried setting the `SourcePath` to nil as well? Presumably it currently has a value of empty string. – cogumel0 Jun 26 '16 at 01:10
  • I have edit my question. I tried setting the SourcePath to nil, with no success. – michl2007 Jun 26 '16 at 07:45
  • "In the future, i want to create VHD and VHDX files (fixed, dynamic and differencing) with one method call." The type of virtual disk you want to create (VHD, VHDX, VHD Set) has nothing to do with which struct version you use. You can create VHDX using struct V1, the same way you can create VHD using struct V2. All the newer structs give is newer features. For example, using V1 you cannot specify the `PhysicalSectorSizeInBytes` when you create a virtual disk, nor can you invoke certain methods, like the `ResizeVirtualDisk()` method. – cogumel0 Jun 26 '16 at 14:46

1 Answers1

0

I got it. I have this parameters:

//  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
//  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT ;
  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;

  params.Version:= CREATE_VIRTUAL_DISK_VERSION_2;
  params.Version2.UniqueId := TGUID.Empty;
  params.Version2.MaximumSize:= ASize * 1024 * 1024;
  params.Version2.BlockSizeInBytes := CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE; //0
  params.Version2.SectorSizeInBytes := 0;
  params.Version2.PhysicalSectorSize := 0;
  params.Version2.ParentPath := nil;
  params.Version2.SourcePath := nil;
  params.Version2.OpenFlags := OPEN_VIRTUAL_DISK_FLAG_NONE;
  params.Version2.ResiliencyGuid := TGUID.Empty;
//  params.Version2.ParentVirtualStorageType := ;

  mask := VIRTUAL_DISK_ACCESS_NONE;

Two parameters were missing in the TCreateVirtualDiskParametersVersion2 record. I have added: SourceLimitPath: LPCWSTR; BackingStorageType: VIRTUAL_STORAGE_TYPE;

New record:

TCreateVirtualDiskParametersVersion2 = record
  UniqueId: TGUID;
  MaximumSize: ULONGLONG;
  BlockSizeInBytes: UINT;
  SectorSizeInBytes: UINT;
  PhysicalSectorSize: UINT;
  ParentPath: LPCWSTR;
  SourcePath: LPCWSTR;
  OpenFlags: TOPEN_VIRTUAL_DISK_FLAG;
  ParentVirtualStorageType: VIRTUAL_STORAGE_TYPE;
  SourceVirtualStorageType: VIRTUAL_STORAGE_TYPE;
  ResiliencyGuid: TGUID;
  SourceLimitPath: LPCWSTR;
  BackingStorageType: VIRTUAL_STORAGE_TYPE;
end;

My temporary working function:

function TForm3.CreateVHDX(const AFilePath: string; const ASize: ULONG; const AType: integer; out AReturn: DWORD): Boolean;
var
  params: TCreateVirtualDiskParameters;
  mask: TVIRTUAL_DISK_ACCESS_MASK;
  vst: TVirtualStorageType;
  hvhd: THandle;
begin
  hVhd := INVALID_HANDLE_VALUE;

//  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
  vst.DeviceId := VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
//  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT ;
  vst.VendorId := VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;

  params.Version:= CREATE_VIRTUAL_DISK_VERSION_2;
  params.Version2.UniqueId := TGUID.Empty;
  params.Version2.MaximumSize:= ASize * 1024 * 1024;
  params.Version2.BlockSizeInBytes := CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE; //0
  params.Version2.SectorSizeInBytes := 0;
  params.Version2.PhysicalSectorSize := 0;
  params.Version2.ParentPath := nil;
  params.Version1.SourcePath := nil;
  params.Version2.OpenFlags := OPEN_VIRTUAL_DISK_FLAG_NONE;
  params.Version2.ResiliencyGuid := TGUID.Empty;
//  params.Version2.ParentVirtualStorageType := ;

  mask := VIRTUAL_DISK_ACCESS_NONE;

  if AType = 0 then //dynamic
  begin
    AReturn := CreateVirtualDisk(
      @vst,
      PWideChar(AFilePath),
      mask,
      nil,
      CREATE_VIRTUAL_DISK_FLAG_NONE,
      0,
      @params,
      nil,
      hvhd);
    Result := AReturn = ERROR_SUCCESS;
  end;

  if AType = 1 then //fixed
  begin
    AReturn := CreateVirtualDisk(
      @vst,
      PWideChar(AFilePath),
      mask,
      nil,
      CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
      0,
      @params,
      nil,
      hvhd);
    Result := AReturn = ERROR_SUCCESS;
  end;

  if hvhd <> INVALID_HANDLE_VALUE then
    CloseHandle( hvhd );
end;
michl2007
  • 15
  • 1
  • 5
  • 1
    While this may have fixed your problem, I am afraid it is *not* the correct answer. `CREATE_VIRTUAL_DISK_PARAMETERS.Version2` struct does not contain either a `SourceLimitPath` or a `BackingStorageType` member, `CREATE_VIRTUAL_DISK_PARAMETERS.Version3` does... So, it might be that your `CREATE_VIRTUAL_DISK_VERSION_2` is set to 3 rather than 2 on your internal struct. I can provide you a copy of the entire struct from the headers of the Windows 10 SDK if you require it. The problem is neither in your struct nor which values you're specifying, so provide *all* required code. – cogumel0 Jun 26 '16 at 13:06
  • Here is a Bug: params.Version1.SourcePath := nil; -> params.Version2.SourcePath := nil; @cogumel0: You are right, i have deleted this two parameters and it works. – michl2007 Jun 26 '16 at 14:29
  • So, the problem was always that the SourcePath was set to an empty string rather than `nil` then? – cogumel0 Jun 26 '16 at 14:39
  • your code above still contains `params.Version1.SourcePath := nil;`. – cogumel0 Jun 26 '16 at 14:49
  • If one compares the code before and after , this is the difference. However, it should be called version 2 and not Version1 . – michl2007 Jun 26 '16 at 21:38
  • I still don't understand why you're using V1 for VHDs and V2 for VHDX. Just use one of the two for everything. – cogumel0 Jun 26 '16 at 21:57
  • V2 is not for win7/2008R2. In newer systems i use V2 – michl2007 Jun 28 '16 at 10:51
  • My point is, the newer systems also support the V1 structure. Unless you *really* need the extra features that the V2 structure offers, which, let's be honest, almost no one does, then you should just use one structure for everything... What does the V2 structure give you that you *need* to have that's not available on V1 structure? – cogumel0 Jul 01 '16 at 09:22
  • We have customers and they use Server 2008R2 and they will not update to a newer version. So i need the v1 structure – michl2007 Jul 10 '16 at 14:33
  • You *still* don't understand what I'm trying to say. The V1 structure allows you to create both VHD and VHDX files. So why not just use the V1 structure to create VHD, VHDX, VHD Set on Windows 2008, Windows 2008 R2, Windows 2012, Windows 2012 R2 and Windows 2016? The V1 structure will work on *all* OSs starting with Windows 2008 and work on *all* VHD types. Period. You do lose some functionality, but the question is exactly what you're after. If you *just* want to create a disk the easiest way is to use V1 for everything. Keep it simple. – cogumel0 Jul 12 '16 at 21:20
  • OK, now i understand you. My Problem: When I create a vhdx with V1, it fail to open the Disk with the Windows 10 Explorer (The disk ist corrupt). If I use attach function from V1, the Disk is mounted and ready. – michl2007 Jul 19 '16 at 18:50
  • That sounds like a bug to me. – cogumel0 Jul 19 '16 at 20:46
  • INVALID_HANDLE_VALUE is not correct. CreateVirtualDisk doc states the value of disk handle returned is undefined if the API call returns different than ERROR_SUCCESS. Caller should set hvhd value to INVALID_HANDLE_VALUE if the call fails. – Cristian Amarie Jan 17 '19 at 09:33