CreateVirtualDiskはエラー87を出します(パラメーターが正しくありません)。


8

Windows 10では、CreateVirtualDisk APIを使用して仮想ディスクを作成しようとすると失敗し、エラーコード87を返します。

最小限の再現可能な例を完成させます。

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.

明らかに、管理者として実行しても違いはありません。

ボーナスリーディング


2
VIRTUAL_DISK_ACCESS_ALL代わりに使用することをお勧めしますVIRTUAL_DISK_ACCESS_NONEC ++(++やCに私が間違っ変換デルファイ)私はあなたのエラーを再現することはできません。バイナリexeもアタッチすると失敗する場所をより簡単に見つけることができます。これはデバッグの可能性があります
RbMm

あなたのバイナリファイル添付
RbMm

回答:


11

質問に対する @RbMmの最初のコメントは、問題の検索場所と解決方法を示しています。彼は、c ++変換では問題が再現されないと述べています。次に、問題はヘッダー(virtdisk.h)の変換にあるはずです。コメントには、Delphiからの翻訳が正確ではない可能性があることさえ含まれています。

列挙型に遭遇する一般的な翻訳エラーのコードをすばやく閲覧します。明示的に割り当てられた値(最大値は3バイト)で、最初の値(VIRTUAL_DISK_ACCESS_MASK)は適切であり、コンパイラーはここで4バイトを使用します。

次のものは問題があります:

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).

列挙型のサイズについては保守的であるため、コンパイラーはこのタイプに1バイトを使用します。これにより、エクスポートされた関数(CreateVirtualDisk)とバイナリの不一致が発生するため、87(ERROR_INVALID_PARAMETER)になります。

{$Z4}この部分の宣言の前に使用できます。

テストでは、同じコメント内の他のアドバイス、つまりを使用することも考慮する必要があることが示されていますVIRTUAL_DISK_ACCESS_NONE。これにより、テストで5、つまりERROR_ACCESS_DENIEDが発生します。VIRTUAL_DISK_ACCESS_ALLコメントのアドバイスのように、でディスクを作成できます。

このコメントに記載されているように、仮想ディスクにルートドライブのルートを使用することはあまり良いアイデアではない可能性があることを示すテストが増えています。「C:\ test.vhd」でのテストは成功しましたが、このファイルが見つかりません。別の書き込み可能なディレクトリを使用して、ファイルを見つけるのに問題はありません。


1
に切り替えるVIRTUAL_DISK_ACCESS_CREATEと機能します。どうやら「v2」を使用している場合は、を指定する必要ありますVIRTUAL_DISK_ACCESS_NONE。ただし、「v1」を使用している場合は、を指定しないでくださいVIRTUAL_DISK_ACCESS_NONE。動作することがわかりましたCREATE-ファイルがまだ存在しない場合(存在する場合は削除してください)。また{$MINENUMSIZE 4}VirtDisk.pasユニットの上部に追加して、Windows ABIに準拠するようにしました。
Ian Boyd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.