// create_vhd.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <Shlwapi.h>
#include <initguid.h>
#include <virtdisk.h>
#include <sddl.h>
DWORD
SampleCreateVirtualDisk(
_In_ LPCWSTR VirtualDiskPath,
_In_opt_ LPCWSTR ParentPath,
_In_ CREATE_VIRTUAL_DISK_FLAG Flags,
_In_ ULONGLONG FileSize,
_In_ DWORD BlockSize,
_In_ DWORD LogicalSectorSize,
_In_ DWORD PhysicalSectorSize)
{
VIRTUAL_STORAGE_TYPE storageType;
CREATE_VIRTUAL_DISK_PARAMETERS parameters;
HANDLE vhdHandle = INVALID_HANDLE_VALUE;
DWORD opStatus;
GUID uniqueId;
if (RPC_S_OK != UuidCreate((UUID*)&uniqueId))
{
opStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// 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_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
memset(¶meters, 0, sizeof(parameters));
//
// CREATE_VIRTUAL_DISK_VERSION_2 allows specifying a richer set a values and returns
// a V2 handle.
//
// VIRTUAL_DISK_ACCESS_NONE is the only acceptable access mask for V2 handle opens.
//
// Valid BlockSize values are as follows (use 0 to indicate default value):
// Fixed VHD: 0
// Dynamic VHD: 512kb, 2mb (default)
// Differencing VHD: 512kb, 2mb (if parent is fixed, default is 2mb; if parent is dynamic or differencing, default is parent blocksize)
// Fixed VHDX: 0
// Dynamic VHDX: 1mb, 2mb, 4mb, 8mb, 16mb, 32mb (default), 64mb, 128mb, 256mb
// Differencing VHDX: 1mb, 2mb (default), 4mb, 8mb, 16mb, 32mb, 64mb, 128mb, 256mb
//
// Valid LogicalSectorSize values are as follows (use 0 to indicate default value):
// VHD: 512 (default)
// VHDX: 512 (for fixed or dynamic, default is 512; for differencing, default is parent logicalsectorsize), 4096
//
// Valid PhysicalSectorSize values are as follows (use 0 to indicate default value):
// VHD: 512 (default)
// VHDX: 512, 4096 (for fixed or dynamic, default is 4096; for differencing, default is parent physicalsectorsize)
//
parameters.Version = CREATE_VIRTUAL_DISK_VERSION_2;
parameters.Version2.UniqueId = uniqueId;
parameters.Version2.MaximumSize = FileSize;
parameters.Version2.BlockSizeInBytes = BlockSize;
parameters.Version2.SectorSizeInBytes = LogicalSectorSize;
parameters.Version2.PhysicalSectorSizeInBytes = PhysicalSectorSize;
parameters.Version2.ParentPath = ParentPath;
opStatus = CreateVirtualDisk(
&storageType,
VirtualDiskPath,
VIRTUAL_DISK_ACCESS_NONE,
NULL,
Flags,
0,
¶meters,
NULL,
&vhdHandle);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
Cleanup:
if (opStatus == ERROR_SUCCESS)
{
wprintf(L"Create success\n");
}
else
{
wprintf(L"Create error = %u\n", opStatus);
}
if (vhdHandle != INVALID_HANDLE_VALUE)
{
printf("%s: Handle closed.\n", __func__);
CloseHandle(vhdHandle);
}
return opStatus;
}
int make_vhd()
{
GUID myGUID;
HRESULT h = CoCreateGuid(&myGUID);
if (h != S_OK)
printf("Failed to generate GUID.\n");
OLECHAR* guidString;
StringFromCLSID(myGUID, &guidString);
printf("%ls\n", guidString);
VIRTUAL_STORAGE_TYPE VirtualStorageType;
VirtualStorageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
VirtualStorageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
PCWSTR Path = L"c:\\vhd_test.vhd";
VIRTUAL_DISK_ACCESS_MASK VirtualDiskAccessMask = VIRTUAL_DISK_ACCESS_NONE;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
CREATE_VIRTUAL_DISK_FLAG Flags = CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION;
//CREATE_VIRTUAL_DISK_FLAG Flags = CREATE_VIRTUAL_DISK_FLAG_NONE;
ULONG ProviderSpecificFlags = 0;
printf("sizeof(PCREATE_VIRTUAL_DISK_PARAMETERS) %zd\n", sizeof(_CREATE_VIRTUAL_DISK_PARAMETERS));
PCREATE_VIRTUAL_DISK_PARAMETERS Parameters = (PCREATE_VIRTUAL_DISK_PARAMETERS)malloc(sizeof(_CREATE_VIRTUAL_DISK_PARAMETERS));
memset(Parameters, 0, sizeof(_CREATE_VIRTUAL_DISK_PARAMETERS));
Parameters->Version = CREATE_VIRTUAL_DISK_VERSION_2;
Parameters->Version2.UniqueId = myGUID;
StringFromCLSID(Parameters->Version2.UniqueId, &guidString);
printf("Parameters->Version2.UniqueId %ls\n", guidString);
Parameters->Version2.MaximumSize = 0x200000000;
Parameters->Version2.BlockSizeInBytes = 0;
Parameters->Version2.SectorSizeInBytes = 0;
Parameters->Version2.PhysicalSectorSizeInBytes = 0;
Parameters->Version2.OpenFlags = OPEN_VIRTUAL_DISK_FLAG_NONE;
Parameters->Version2.ParentPath = NULL;
Parameters->Version2.SourcePath = NULL;
LPOVERLAPPED Overlapped = NULL;
PHANDLE Handle = NULL;
DWORD ret = CreateVirtualDisk(
&VirtualStorageType,
Path,
VirtualDiskAccessMask,
SecurityDescriptor,
Flags,
ProviderSpecificFlags,
Parameters,
Overlapped,
Handle
);
if(ret != ERROR_SUCCESS)
{
printf("%s: CreateVirtualDisk failed (%d)\n", __func__, ret);
}
return 0;
}
DWORD
SampleAttachVirtualDisk(
_In_ LPCWSTR VirtualDiskPath,
_In_ BOOLEAN ReadOnly)
{
OPEN_VIRTUAL_DISK_PARAMETERS openParameters;
VIRTUAL_DISK_ACCESS_MASK accessMask;
ATTACH_VIRTUAL_DISK_PARAMETERS attachParameters;
PSECURITY_DESCRIPTOR sd;
VIRTUAL_STORAGE_TYPE storageType;
LPCTSTR extension;
HANDLE vhdHandle;
ATTACH_VIRTUAL_DISK_FLAG attachFlags;
DWORD opStatus;
vhdHandle = INVALID_HANDLE_VALUE;
sd = NULL;
//
// 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_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
memset(&openParameters, 0, sizeof(openParameters));
extension = ::PathFindExtension(VirtualDiskPath);
if (extension != NULL && _wcsicmp(extension, L".iso") == 0)
{
//
// ISO files can only be mounted read-only and using the V1 API.
//
if (ReadOnly != TRUE)
{
opStatus = ERROR_NOT_SUPPORTED;
goto Cleanup;
}
openParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1;
accessMask = VIRTUAL_DISK_ACCESS_READ;
}
else
{
//
// VIRTUAL_DISK_ACCESS_NONE is the only acceptable access mask for V2 handle opens.
//
openParameters.Version = OPEN_VIRTUAL_DISK_VERSION_2;
openParameters.Version2.GetInfoOnly = FALSE;
accessMask = VIRTUAL_DISK_ACCESS_NONE;
}
//
// Open the VHD or ISO.
//
// OPEN_VIRTUAL_DISK_FLAG_NONE bypasses any special handling of the open.
//
opStatus = OpenVirtualDisk(
&storageType,
VirtualDiskPath,
accessMask,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&openParameters,
&vhdHandle);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
//
// Create the world-RW SD.
//
if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
L"O:BAG:BAD:(A;;GA;;;WD)",
SDDL_REVISION_1,
&sd,
NULL))
{
opStatus = ::GetLastError();
goto Cleanup;
}
//
// Attach the VHD/VHDX or ISO.
//
memset(&attachParameters, 0, sizeof(attachParameters));
attachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
//
// A "Permanent" surface persists even when the handle is closed.
//
attachFlags = ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME;
if (ReadOnly)
{
// ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY specifies a read-only mount.
attachFlags |= ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY;
}
opStatus = AttachVirtualDisk(
vhdHandle,
sd,
attachFlags,
0,
&attachParameters,
NULL);
if (opStatus != ERROR_SUCCESS)
{
goto Cleanup;
}
Cleanup:
if (opStatus == ERROR_SUCCESS)
{
wprintf(L"Attach success\n");
}
else
{
wprintf(L"Attach error = %u\n", opStatus);
}
if (sd != NULL)
{
LocalFree(sd);
sd = NULL;
}
if (vhdHandle != INVALID_HANDLE_VALUE)
{
printf("%s: Handle closed.\n", __func__);
CloseHandle(vhdHandle);
}
return opStatus;
}
HANDLE DoOpenVHD(LPCWSTR VirtualDiskPath, BOOL GetInfoOnly)
{
HANDLE vhdHandle;
OPEN_VIRTUAL_DISK_PARAMETERS openParameters;
openParameters.Version = OPEN_VIRTUAL_DISK_VERSION_2;
openParameters.Version2.GetInfoOnly = GetInfoOnly;
VIRTUAL_STORAGE_TYPE storageType;
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
int ret = OpenVirtualDisk(&storageType, VirtualDiskPath,
VIRTUAL_DISK_ACCESS_NONE, OPEN_VIRTUAL_DISK_FLAG_NONE,
&openParameters, &vhdHandle);
if (ret != ERROR_SUCCESS) {
// If return value of OpenVirtualDisk isn't ERROR_SUCCESS, there was a problem opening the VHD
printf("Failed to open VHD %ls. (%d)\n", VirtualDiskPath, ret);
return NULL;
}
return vhdHandle;
}
int getPhyDrive(HANDLE vhdHandle)
{
wchar_t physicalDrive[MAX_PATH];
ULONG bufferSize = sizeof(physicalDrive);
GetVirtualDiskPhysicalPath(vhdHandle, &bufferSize, physicalDrive);
printf("physicalDrive %ls\n", physicalDrive);
if (vhdHandle != INVALID_HANDLE_VALUE)
{
printf("%s: Handle closed.\n", __func__);
CloseHandle(vhdHandle);
}
char name[1024];
memset(name, 0, 1024);
snprintf(name, 1024, "%ls", physicalDrive);
DWORD driveNumber = name[strlen(name) - 1] - '0';
printf("Drive idx %d\n", driveNumber);
return driveNumber;
}
int __cdecl wmain(_In_ int argc, _In_reads_(argc) WCHAR *argv[])
{
int rc = 0;
LPCWSTR virtualDiskPath = argv[1];
LPCWSTR parentPath = NULL;
ULONGLONG fileSize = _wtoi64(argv[2]);
DWORD blockSize = _wtoi(argv[3]);
DWORD logicalSectorSize = _wtoi(argv[4]);
DWORD physicalSectorSize = _wtoi(argv[5]);
/*rc = SampleCreateVirtualDisk(
virtualDiskPath,
parentPath,
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
fileSize,
blockSize,
logicalSectorSize,
physicalSectorSize);
printf("SampleCreateVirtualDisk %d\n", rc);
rc = SampleAttachVirtualDisk(virtualDiskPath, FALSE);
printf("SampleAttachVirtualDisk %d\n", rc);*/
//wchar_t physicalDrive[MAX_PATH];
//ULONG bufferSize = sizeof(physicalDrive);
HANDLE vhdHandle = DoOpenVHD(virtualDiskPath, TRUE);
int drive_idx = getPhyDrive(vhdHandle);
/*char name[1024];
memset(name, 0, 1024);
snprintf(name, 1024, "%ls", physicalDrive);
DWORD driveNumber = name[strlen(name) - 1] - '0';
printf("Drive idx %d\n", driveNumber);*/
//MountVol(drive_idx);
getchar();
return 0;
}