CreateVirtualDisk đưa ra lỗi 87 (Tham số không chính xác.)


8

Trên Windows 10, cố gắng sử dụng API CreatVirtualDisk để tạo đĩa ảo, không thành công và trả về mã lỗi 87.

Hoàn thành ví dụ tái sản xuất tối thiểu.

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.

Rõ ràng chạy như quản trị viên không làm cho sự khác biệt.

Đọc thưởng


2
tôi được đề nghị sử dụng VIRTUAL_DISK_ACCESS_ALLthay thế VIRTUAL_DISK_ACCESS_NONE. trong c ++ tôi không thể tái tạo lỗi của bạn (hoặc tôi chuyển đổi sai delphi thành c ++). dễ dàng tìm thấy nơi thất bại hơn nếu bạn đính kèm exe nhị phân, có thể gỡ lỗi
RbMm

đính kèm tệp nhị phân của bạn
RbMm

Câu trả lời:


11

Nhận xét đầu tiên của @ RbMm cho các điểm câu hỏi cần tìm và cách giải quyết vấn đề. Ông nói rằng bản dịch c ++ không tái tạo vấn đề. Sau đó, vấn đề phải là với bản dịch của tiêu đề (virtdisk.h). Nhận xét thậm chí nói rằng bản dịch từ Delphi có thể không chính xác.

Nhanh chóng duyệt mã cho các lỗi dịch thuật phổ biến mà chúng tôi gặp phải. Với các giá trị được gán rõ ràng (lớn nhất là 3 byte), giá trị đầu tiên (VIRTUAL_DISK_ACCESS_MASK) là tốt, trình biên dịch sẽ sử dụng 4 byte ở đây.

Cái tiếp theo là có vấn đề:

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

Thận trọng về kích thước liệt kê, trình biên dịch sẽ sử dụng 1 byte cho loại này. Điều đó sẽ gây ra sự không khớp nhị phân với hàm được xuất ( CreateVirtualDisk), do đó 87 (ERROR_INVALID_PARAMETER).

Bạn có thể sử dụng {$Z4}trước khi khai báo cho phần này.

Thử nghiệm cho thấy bạn cũng cần tính đến lời khuyên khác trong cùng một nhận xét, cụ thể là sử dụng VIRTUAL_DISK_ACCESS_NONE. Điều này gây ra điểm 5 trong thử nghiệm của tôi, đó là ERROR_ACCESS_DENIED. Tôi có thể tạo đĩa với VIRTUAL_DISK_ACCESS_ALL, như lời khuyên bình luận.

Nhiều thử nghiệm cho thấy sử dụng root của ổ đĩa gốc cho đĩa ảo có thể không phải là một ý tưởng hay, được đề cập trong bình luận này . Thử nghiệm của tôi với 'C: \ test.vhd' đã thành công nhưng tôi không thể tìm thấy tệp này. Sử dụng một thư mục có thể ghi khác, tôi không gặp vấn đề gì trong việc định vị tệp.


1
Chuyển đổi để VIRTUAL_DISK_ACCESS_CREATElàm cho nó hoạt động. Rõ ràng khi bạn đang sử dụng "v2", bạn phải chỉ định VIRTUAL_DISK_ACCESS_NONE. Nhưng nếu bạn đang sử dụng "v1", bạn không được chỉ định VIRTUAL_DISK_ACCESS_NONE. Tôi đã tìm thấy CREATEcác tác phẩm - miễn là tệp không tồn tại (xóa nó nếu có). Tôi cũng đã thêm vào {$MINENUMSIZE 4}đầu VirtDisk.pasđơn vị để làm cho nó theo Windows ABI.
Ian Boyd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.