├── README.md ├── libs ├── EntryPoint.c ├── ParseNumber.c ├── ParseNumber.h └── StringIntrinsics.h ├── makevhd.c ├── resizevhd.c └── vhdutils.mak /README.md: -------------------------------------------------------------------------------- 1 | # VHD-Utilities 2 | These are simple utilities to manipulate Virtual Hard Disks (VHD/VHDX) from the command line. 3 | 4 | VHD Utilities 5 | Version 1.0 6 | 7 | 8 | 9 | Introduction 10 | ============ 11 | 12 | These are simple utilities to manipulate Virtual Hard Disks (VHD/VHDX) from the 13 | command line. 14 | 15 | 16 | System Requirements 17 | =================== 18 | 19 | Windows 7 / Server 2008 R2 or newer is required. Windows 8 / Server 2012 or 20 | newer is required for in-place resizing (resizevhd) and VHDX support. 21 | 22 | 23 | Usage 24 | ===== 25 | 26 | Create a VHD: 27 | makevhd [-d] vhd size [source] 28 | 29 | -d Use dynamic allocation for the virtual disk. 30 | vhd Path of the VHD file to be created. 31 | size Maximum size, in bytes, of the VHD; must be a multiple of 512. 32 | Alternatively, DVD or BD can be specified for preset sizes. 33 | If set to 0, the size of the source disk, if available, will be used. 34 | source Path of an optional source whose data will populate the new VHD. 35 | 36 | Create a differencing VHD: 37 | makevhd -f vhd parent 38 | 39 | -f Create a differencing VHD. 40 | vhd Path of the differencing VHD file to be created. 41 | parent Path of an existing disk to be associated as the parent. 42 | 43 | Resize a VHD in-place: 44 | resizevhd [-f] vhd size 45 | 46 | -f Forcibly truncate the data stored within the VHD, if necessary. 47 | vhd Path of the VHD file to be resized. 48 | size Maximum size, in bytes, of the VHD; must be a multiple of 512. 49 | Alternatively, DVD or BD can be specified for preset sizes. 50 | If set to 0, reduce the VHD to the smallest possible size. 51 | 52 | Notes: 53 | In-place resizing of a virtual disk (using resizevhd) can only be used to 54 | enlarge .vhd files; .vhdx files can be either enlarged or shrunken using 55 | resizevhd. To shrink a .vhd file or to resize a disk on Windows 7, use 56 | makevhd instead (see Usage Examples below). 57 | 58 | 59 | Usage Examples 60 | ============== 61 | 62 | Creating a fully-allocated VHD that can be backed-up onto a single Blu-Ray disc: 63 | makevhd example.vhd BD 64 | 65 | Creating a dynamically-allocated VHD 8 GiB (0x200000000 bytes) in size: 66 | makevhd -d example.vhd 0x200000000 67 | 68 | Resizing a dynamically-allocated VHD to 8 GiB (8589934592 bytes): 69 | makevhd -d resized.vhd 8589934592 original.vhd 70 | 71 | Enlarging a VHD to 8 GiB in-place, without creating a copy (requires Windows 8): 72 | resizevhd example.vhd 8589934592 73 | 74 | Converting a dynamically-allocated VHD into a fully-allocated VHD: 75 | makevhd full.vhd 0 dynamic.vhd 76 | 77 | Converting a fully-allocated VHD into a dynamically-allocated VHD: 78 | makevhd -d dynamic.vhd 0 full.vhd 79 | 80 | Creating a differencing VHD from a base VHD: 81 | makevhd -f diff.vhd parent.vhd 82 | 83 | Merging a differencing VHD with its parent into a single combined dynamic VHD: 84 | makevhd -d merged.vhd 0 diff.vhd 85 | 86 | Merging into a fully-allocated VHD that can be backed up onto a DVD-R: 87 | makevhd merged.vhd DVD diff.vhd 88 | -------------------------------------------------------------------------------- /libs/EntryPoint.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | UINT __fastcall EntryMain( UINT argc, PTSTR *argv ); 4 | 5 | #ifdef UNICODE 6 | #define GetArgv(pcArgs) CommandLineToArgvW(GetCommandLineW(), pcArgs) 7 | #else 8 | // GetArgv.c needs to be compiled and linked if Unicode is not used. 9 | PSTR * __fastcall GetArgvA( INT *pcArgs ); 10 | #define GetArgv GetArgvA 11 | #endif 12 | 13 | #pragma comment(linker, "/entry:EntryPoint") 14 | void EntryPoint( ) 15 | { 16 | UINT uRet = ~0; 17 | UINT argc = 0; 18 | PTSTR *argv = GetArgv(&argc); 19 | 20 | if (argv) 21 | { 22 | uRet = EntryMain(argc, argv); 23 | LocalFree(argv); 24 | } 25 | 26 | ExitProcess(uRet); 27 | } 28 | -------------------------------------------------------------------------------- /libs/ParseNumber.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * ParseUnsignedInteger: string to uint64; base 10 or 16 5 | **/ 6 | BOOLEAN __fastcall ParseUnsignedInteger( PCTSTR pszIn, PUINT64 puiOut ) 7 | { 8 | BOOLEAN fHex = FALSE; 9 | 10 | PCTSTR pszHead = NULL, pszTail; 11 | TCHAR ch; 12 | 13 | *puiOut = 0; 14 | 15 | // Strip away leading and trailing whitespace 16 | 17 | while (ch = *pszIn) 18 | { 19 | // After this loop, pszHead will point to the first non-whitespace char 20 | // and pszTail will point to the final non-whitespace char; pszTail is 21 | // guaranteed to be valid if pszHead is non-NULL. 22 | 23 | if (ch > TEXT(' ')) 24 | { 25 | if (!pszHead) 26 | pszHead = pszIn; 27 | 28 | pszTail = pszIn; 29 | } 30 | 31 | ++pszIn; 32 | } 33 | 34 | if (!pszHead) 35 | return(FALSE); 36 | 37 | // Detect the "0x" and "h" affixes for hexadecimal input 38 | 39 | if (pszHead[0] == TEXT('0') && (pszHead[1] | 0x20) == TEXT('x')) 40 | { 41 | fHex = TRUE; 42 | pszHead += 2; 43 | } 44 | else if (*pszTail == TEXT('h')) 45 | { 46 | fHex = TRUE; 47 | --pszTail; 48 | } 49 | 50 | // Fail if, after stripping whitespace and affixes, the input is blank 51 | 52 | if (pszHead > pszTail) 53 | return(FALSE); 54 | 55 | // Convert 56 | 57 | while (pszHead <= pszTail) 58 | { 59 | ch = *pszHead; 60 | 61 | if (ch >= TEXT('0') && ch <= TEXT('9')) 62 | { 63 | *puiOut *= (fHex) ? 0x10 : 10; 64 | *puiOut += ch - TEXT('0'); 65 | } 66 | else if (fHex) 67 | { 68 | ch |= 0x20; 69 | 70 | if (ch >= TEXT('a') && ch <= TEXT('f')) 71 | { 72 | *puiOut *= 0x10; 73 | *puiOut += ch - TEXT('a') + 10; 74 | } 75 | else 76 | return(FALSE); // Illegal character 77 | } 78 | else if (ch > TEXT(' ') && ch != TEXT(',') && ch != TEXT('.')) // Exempt delimiters, for decimal input only 79 | return(FALSE); // Illegal character 80 | 81 | ++pszHead; 82 | } 83 | 84 | return(TRUE); 85 | } 86 | -------------------------------------------------------------------------------- /libs/ParseNumber.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARSENUMBER_H__ 2 | #define __PARSENUMBER_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | /** 11 | * ParseUnsignedInteger: string to uint64; base 10 or 16 12 | **/ 13 | BOOLEAN __fastcall ParseUnsignedInteger( PCTSTR pszIn, PUINT64 puiOut ); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /libs/StringIntrinsics.h: -------------------------------------------------------------------------------- 1 | /** 2 | * String Intrinsics Library 3 | * Last modified: 2009/03/04 4 | * Copyright (C) Kai Liu. All rights reserved. 5 | * 6 | * This library will direct that certain mem*, str*, and wcs* functions use 7 | * intrinsic forms even if /Oi is not specified during compilation. 8 | * 9 | * This library will also force the use of intrinsics in cases where the 10 | * compiler does not support them (wcs* on v12/13 compilers) or where the 11 | * compiler does not honor intrinsic settings (mem* on v14+). 12 | * 13 | * Finally, this library will provide definitions for the movs* and stos* 14 | * functions for cases where the CRT's intrin.h cannot be used. 15 | **/ 16 | 17 | #ifndef __STRINGINTRINSICS_H__ 18 | #define __STRINGINTRINSICS_H__ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | 26 | #if _MSC_VER >= 1200 27 | 28 | #if _MSC_VER >= 1400 29 | #pragma warning(disable: 4996) // do not mother me about so-called "insecure" funcs 30 | #endif 31 | 32 | #if _MSC_VER >= 1500 && _MSC_VER < 1600 33 | #pragma warning(disable: 4985) // appears to be a bug in VC9 34 | #endif 35 | 36 | #pragma warning(push) 37 | #pragma warning(disable: 4035) // returns for inline asm functions 38 | 39 | 40 | /******************************************************************************* 41 | * 42 | * 43 | * movs, stos 44 | * 45 | * 46 | ******************************************************************************/ 47 | 48 | 49 | #if _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) 50 | #define __MOVS_STOS_DEFINED 51 | #ifndef __INTRIN_H_ 52 | void __movsb( unsigned char *, unsigned char const *, size_t ); 53 | void __movsw( unsigned short *, unsigned short const *, size_t ); 54 | void __movsd( unsigned long *, unsigned long const *, size_t ); 55 | void __stosb( unsigned char *, unsigned char, size_t ); 56 | void __stosw( unsigned short *, unsigned short, size_t ); 57 | void __stosd( unsigned long *, unsigned long, size_t ); 58 | #endif 59 | #pragma intrinsic(__movsb, __movsw, __movsd, __stosb, __stosw, __stosd) 60 | #endif 61 | 62 | 63 | /******************************************************************************* 64 | * 65 | * 66 | * memcmp, memcpy, memset 67 | * 68 | * 69 | ******************************************************************************/ 70 | 71 | 72 | #pragma intrinsic(memcmp, memcpy, memset) 73 | 74 | // Compiler versions 14 and higher will often refuse to honor the mem* 75 | // intrinsics, so it may be necessary to override them with movs and stos 76 | #if defined(__MOVS_STOS_DEFINED) && !defined(SI_NO_OVERRIDE_MEM_FUNCS) 77 | 78 | __forceinline void * intrin_memcpy( void *dest, const void *src, size_t count ) 79 | { 80 | __movsb((unsigned char *)dest, (unsigned char const *)src, count); 81 | return(dest); 82 | } 83 | 84 | __forceinline void * intrin_memset( void *dest, int c, size_t count ) 85 | { 86 | __stosb((unsigned char *)dest, (unsigned char)c, count); 87 | return(dest); 88 | } 89 | 90 | #define memcpy intrin_memcpy 91 | #define memset intrin_memset 92 | #endif 93 | 94 | 95 | /******************************************************************************* 96 | * 97 | * 98 | * strlen, wcslen 99 | * 100 | * 101 | ******************************************************************************/ 102 | 103 | 104 | #pragma intrinsic(strlen) 105 | #if _MSC_VER >= 1400 106 | #pragma intrinsic(wcslen) 107 | #elif defined(_M_IX86) 108 | 109 | __forceinline size_t intrin_strlen_w( const wchar_t *string ) 110 | { 111 | __asm 112 | { 113 | xor eax,eax 114 | mov edi,string 115 | or ecx,-1 116 | repnz scasw 117 | not ecx 118 | dec ecx 119 | xchg eax,ecx 120 | } 121 | } 122 | 123 | #define wcslen intrin_strlen_w 124 | #endif 125 | 126 | 127 | /******************************************************************************* 128 | * 129 | * 130 | * strcpy, wcscpy 131 | * 132 | * 133 | ******************************************************************************/ 134 | 135 | 136 | #pragma intrinsic(strcpy) 137 | #if _MSC_VER >= 1400 138 | #pragma intrinsic(wcscpy) 139 | #elif defined(_M_IX86) 140 | 141 | __forceinline wchar_t * intrin_strcpy_w( wchar_t *dest, const wchar_t *src ) 142 | { 143 | __asm 144 | { 145 | xor eax,eax 146 | mov esi,src 147 | mov edi,esi 148 | or ecx,-1 149 | repnz scasw 150 | not ecx 151 | mov edi,dest 152 | rep movsw 153 | } 154 | 155 | return(dest); 156 | } 157 | 158 | #define wcscpy intrin_strcpy_w 159 | #endif 160 | 161 | 162 | /******************************************************************************* 163 | * 164 | * 165 | * strcat, wcscat 166 | * 167 | * 168 | ******************************************************************************/ 169 | 170 | 171 | #pragma intrinsic(strcat) 172 | #if _MSC_VER >= 1400 173 | #pragma intrinsic(wcscat) 174 | #elif defined(_M_IX86) 175 | 176 | __forceinline wchar_t * intrin_strcat_w( wchar_t *dest, const wchar_t *src ) 177 | { 178 | __asm 179 | { 180 | xor eax,eax 181 | mov esi,src 182 | mov edi,esi 183 | or ecx,-1 184 | repnz scasw 185 | not ecx 186 | mov edi,dest 187 | push ecx 188 | or ecx,-1 189 | repnz scasw 190 | pop ecx 191 | dec edi 192 | dec edi 193 | rep movsw 194 | } 195 | 196 | return(dest); 197 | } 198 | 199 | #define wcscat intrin_strcat_w 200 | #endif 201 | 202 | 203 | #pragma warning(pop) 204 | 205 | #endif // _MSC_VER >= 1200 206 | 207 | #ifdef __cplusplus 208 | } 209 | #endif 210 | 211 | #endif 212 | -------------------------------------------------------------------------------- /makevhd.c: -------------------------------------------------------------------------------- 1 | #pragma comment(linker, "/version:1.0") // MUST be in the form of major.minor 2 | 3 | #define INITGUID 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "libs\StringIntrinsics.h" 10 | #include "libs\ParseNumber.h" 11 | 12 | __forceinline BOOLEAN IsFlag( PCTSTR pszArg ); 13 | __forceinline BOOLEAN CheckFlagI( PCTSTR pszArg, TCHAR ch ); 14 | 15 | UINT __fastcall EntryMain( UINT argc, PTSTR *argv ) 16 | { 17 | PTSTR pszTargetPath = NULL; 18 | PTSTR pszTargetSize = NULL; 19 | PTSTR pszSourcePath = NULL; 20 | UINT64 cbTargetSize = 0; 21 | BOOLEAN fDynamic = FALSE; 22 | BOOLEAN fDifferencing = FALSE; 23 | BOOLEAN fShowUsage = FALSE; 24 | 25 | // Parse command line parameters 26 | 27 | UINT i; 28 | 29 | for (i = 1; i < argc; ++i) 30 | { 31 | if (!IsFlag(argv[i])) 32 | { 33 | if (pszTargetPath == NULL) 34 | pszTargetPath = argv[i]; 35 | else if (pszTargetSize == NULL) 36 | pszTargetSize = argv[i]; 37 | else if (pszSourcePath == NULL) 38 | pszSourcePath = argv[i]; 39 | else 40 | fShowUsage = TRUE; 41 | } 42 | else if (!fDynamic && CheckFlagI(argv[i], TEXT('d'))) 43 | fDynamic = TRUE; 44 | else if (!fDifferencing && CheckFlagI(argv[i], TEXT('f'))) 45 | fDifferencing = TRUE; 46 | else 47 | fShowUsage = TRUE; 48 | } 49 | 50 | if (fDifferencing) 51 | { 52 | // It is possible for the -f flag to be specified at the end, in which 53 | // case, the meaning of the second non-flag parameter can only be 54 | // determined after a complete pass of the parameters. 55 | 56 | if (pszTargetSize && !pszSourcePath) 57 | pszSourcePath = pszTargetSize; 58 | else 59 | fShowUsage = TRUE; 60 | } 61 | 62 | // Parse the target size 63 | 64 | else if (!pszTargetSize) 65 | fShowUsage = TRUE; 66 | else if (lstrcmpi(pszTargetSize, TEXT("DVD")) == 0) 67 | cbTargetSize = 0x118200000; // 4,699,717,632 B or 4,482 MiB 68 | else if (lstrcmpi(pszTargetSize, TEXT("BD")) == 0) 69 | cbTargetSize = 0x5D2200000; // 25,000,148,992 B or 23,842 MiB 70 | else if (!ParseUnsignedInteger(pszTargetSize, &cbTargetSize)) 71 | fShowUsage = TRUE; 72 | 73 | // Act according to the command line parameters 74 | 75 | if (fShowUsage) 76 | { 77 | _tprintf(TEXT("Usage: makevhd [-d] vhd size [source]\n\n")); 78 | _tprintf(TEXT(" -d Use dynamic allocation for the virtual disk.\n") 79 | TEXT(" vhd Path of the VHD file to be created.\n") 80 | TEXT(" size Maximum size, in bytes, of the VHD; must be a multiple of 512.\n") 81 | TEXT(" Alternatively, DVD or BD can be specified for preset sizes.\n") 82 | TEXT(" If set to 0, the size of the source disk, if available, will be used.\n") 83 | TEXT(" source Path of an optional source whose data will populate the new VHD.\n\n")); 84 | 85 | _tprintf(TEXT("Usage: makevhd -f vhd parent\n\n")); 86 | _tprintf(TEXT(" -f Create a differencing VHD.\n") 87 | TEXT(" vhd Path of the differencing VHD file to be created.\n") 88 | TEXT(" parent Path of an existing disk to be associated as the parent.\n")); 89 | 90 | return(~1); 91 | } 92 | else 93 | { 94 | VIRTUAL_STORAGE_TYPE vst; 95 | CREATE_VIRTUAL_DISK_PARAMETERS cvdp; 96 | 97 | HANDLE hVhd; 98 | DWORD dwResult; 99 | DWORD cchMessage; 100 | PTSTR pszErrorMessage = NULL; 101 | 102 | PTSTR pszTargetExt = _tcsrchr(pszTargetPath, TEXT('.')); 103 | 104 | vst.DeviceId = (pszTargetExt && lstrcmpi(pszTargetExt + 1, TEXT("vhdx")) == 0) ? 105 | VIRTUAL_STORAGE_TYPE_DEVICE_VHDX : 106 | VIRTUAL_STORAGE_TYPE_DEVICE_VHD; 107 | vst.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; 108 | 109 | ZeroMemory(&cvdp, sizeof(cvdp)); 110 | cvdp.Version = CREATE_VIRTUAL_DISK_VERSION_1; 111 | cvdp.Version1.MaximumSize = cbTargetSize; 112 | cvdp.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE; 113 | 114 | if (fDifferencing) 115 | cvdp.Version1.ParentPath = pszSourcePath; 116 | else 117 | cvdp.Version1.SourcePath = pszSourcePath; 118 | 119 | dwResult = CreateVirtualDisk( 120 | &vst, 121 | pszTargetPath, 122 | VIRTUAL_DISK_ACCESS_CREATE, 123 | NULL, 124 | (fDynamic || fDifferencing) ? 0 : CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION, 125 | 0, 126 | &cvdp, 127 | NULL, 128 | &hVhd 129 | ); 130 | 131 | if (dwResult == ERROR_SUCCESS) 132 | CloseHandle(hVhd); 133 | 134 | cchMessage = FormatMessage( 135 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 136 | NULL, 137 | dwResult, 138 | 0, 139 | (PTSTR)&pszErrorMessage, 140 | 0, 141 | NULL 142 | ); 143 | 144 | if (cchMessage) 145 | _ftprintf(stderr, TEXT("%s"), pszErrorMessage); 146 | else 147 | _ftprintf(stderr, TEXT("Code %08X\n"), dwResult); 148 | 149 | LocalFree(pszErrorMessage); 150 | 151 | return(dwResult); 152 | } 153 | } 154 | 155 | __forceinline BOOLEAN IsFlag( PCTSTR pszArg ) 156 | { 157 | return( 158 | (pszArg[0] | 0x02) == TEXT('/') && 159 | (pszArg[1] ) != 0 && 160 | (pszArg[2] ) == 0 161 | ); 162 | } 163 | 164 | __forceinline BOOLEAN CheckFlagI( PCTSTR pszArg, TCHAR ch ) 165 | { 166 | return( 167 | (pszArg[1] | 0x20) == ch 168 | ); 169 | } 170 | -------------------------------------------------------------------------------- /resizevhd.c: -------------------------------------------------------------------------------- 1 | #pragma comment(linker, "/version:1.0") // MUST be in the form of major.minor 2 | 3 | #define INITGUID 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "libs\StringIntrinsics.h" 10 | #include "libs\ParseNumber.h" 11 | 12 | __forceinline BOOLEAN IsFlag( PCTSTR pszArg ); 13 | __forceinline BOOLEAN CheckFlagI( PCTSTR pszArg, TCHAR ch ); 14 | 15 | UINT __fastcall EntryMain( UINT argc, PTSTR *argv ) 16 | { 17 | PTSTR pszTargetPath = NULL; 18 | PTSTR pszTargetSize = NULL; 19 | UINT64 cbTargetSize = 0; 20 | BOOLEAN fForce = FALSE; 21 | BOOLEAN fShowUsage = FALSE; 22 | 23 | // Parse command line parameters 24 | 25 | UINT i; 26 | 27 | for (i = 1; i < argc; ++i) 28 | { 29 | if (!IsFlag(argv[i])) 30 | { 31 | if (pszTargetPath == NULL) 32 | pszTargetPath = argv[i]; 33 | else if (pszTargetSize == NULL) 34 | pszTargetSize = argv[i]; 35 | else 36 | fShowUsage = TRUE; 37 | } 38 | else if (!fForce && CheckFlagI(argv[i], TEXT('f'))) 39 | fForce = TRUE; 40 | else 41 | fShowUsage = TRUE; 42 | } 43 | 44 | // Parse the target size 45 | 46 | if (!pszTargetSize) 47 | fShowUsage = TRUE; 48 | else if (lstrcmpi(pszTargetSize, TEXT("DVD")) == 0) 49 | cbTargetSize = 0x118200000; // 4,699,717,632 B or 4,482 MiB 50 | else if (lstrcmpi(pszTargetSize, TEXT("BD")) == 0) 51 | cbTargetSize = 0x5D2200000; // 25,000,148,992 B or 23,842 MiB 52 | else if (!ParseUnsignedInteger(pszTargetSize, &cbTargetSize)) 53 | fShowUsage = TRUE; 54 | 55 | // Act according to the command line parameters 56 | 57 | if (fShowUsage) 58 | { 59 | _tprintf(TEXT("Usage: resizevhd [-f] vhd size\n\n")); 60 | _tprintf(TEXT(" -f Forcibly truncate the data stored within the VHD, if necessary.\n") 61 | TEXT(" vhd Path of the VHD file to be resized.\n") 62 | TEXT(" size Maximum size, in bytes, of the VHD; must be a multiple of 512.\n") 63 | TEXT(" Alternatively, DVD or BD can be specified for preset sizes.\n") 64 | TEXT(" If set to 0, reduce the VHD to the smallest possible size.\n")); 65 | 66 | return(~1); 67 | } 68 | else 69 | { 70 | VIRTUAL_STORAGE_TYPE vst; 71 | 72 | HANDLE hVhd; 73 | DWORD dwResult; 74 | DWORD cchMessage; 75 | PTSTR pszErrorMessage = NULL; 76 | 77 | PTSTR pszTargetExt = _tcsrchr(pszTargetPath, TEXT('.')); 78 | 79 | vst.DeviceId = (pszTargetExt && lstrcmpi(pszTargetExt + 1, TEXT("vhdx")) == 0) ? 80 | VIRTUAL_STORAGE_TYPE_DEVICE_VHDX : 81 | VIRTUAL_STORAGE_TYPE_DEVICE_VHD; 82 | vst.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; 83 | 84 | dwResult = OpenVirtualDisk( 85 | &vst, 86 | pszTargetPath, 87 | VIRTUAL_DISK_ACCESS_ALL, 88 | OPEN_VIRTUAL_DISK_FLAG_NONE, 89 | NULL, 90 | &hVhd 91 | ); 92 | 93 | if (dwResult == ERROR_SUCCESS) 94 | { 95 | RESIZE_VIRTUAL_DISK_PARAMETERS rvdp; 96 | rvdp.Version = RESIZE_VIRTUAL_DISK_VERSION_1; 97 | rvdp.Version1.NewSize = cbTargetSize; 98 | 99 | dwResult = ResizeVirtualDisk( 100 | hVhd, 101 | (rvdp.Version1.NewSize == 0) ? 102 | RESIZE_VIRTUAL_DISK_FLAG_RESIZE_TO_SMALLEST_SAFE_VIRTUAL_SIZE : (fForce) ? 103 | RESIZE_VIRTUAL_DISK_FLAG_ALLOW_UNSAFE_VIRTUAL_SIZE : 104 | RESIZE_VIRTUAL_DISK_FLAG_NONE, 105 | &rvdp, 106 | NULL 107 | ); 108 | 109 | CloseHandle(hVhd); 110 | } 111 | 112 | cchMessage = FormatMessage( 113 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 114 | NULL, 115 | dwResult, 116 | 0, 117 | (PTSTR)&pszErrorMessage, 118 | 0, 119 | NULL 120 | ); 121 | 122 | if (cchMessage) 123 | _ftprintf(stderr, TEXT("%s"), pszErrorMessage); 124 | else 125 | _ftprintf(stderr, TEXT("Code %08X\n"), dwResult); 126 | 127 | LocalFree(pszErrorMessage); 128 | 129 | return(dwResult); 130 | } 131 | } 132 | 133 | __forceinline BOOLEAN IsFlag( PCTSTR pszArg ) 134 | { 135 | return( 136 | (pszArg[0] | 0x02) == TEXT('/') && 137 | (pszArg[1] ) != 0 && 138 | (pszArg[2] ) == 0 139 | ); 140 | } 141 | 142 | __forceinline BOOLEAN CheckFlagI( PCTSTR pszArg, TCHAR ch ) 143 | { 144 | return( 145 | (pszArg[1] | 0x20) == ch 146 | ); 147 | } 148 | -------------------------------------------------------------------------------- /vhdutils.mak: -------------------------------------------------------------------------------- 1 | # MAKE_KITVER=5, MAKE_SKIPBIT=0 2 | 3 | 4 | BASE_NAME=vhdutils 5 | 6 | 7 | !IF "$(ARCH)" != "x86-32" && "$(ARCH)" != "x86-64" 8 | !MESSAGE Available build configurations: 9 | !MESSAGE NMAKE /f "$(BASE_NAME).mak" ARCH="x86-32" 10 | !MESSAGE NMAKE /f "$(BASE_NAME).mak" ARCH="x86-64" 11 | !MESSAGE You should also set CPPVER to match your compiler version; e.g., CPPVER=150 12 | !ERROR A valid configuration was not specified. 13 | !ENDIF 14 | 15 | 16 | ################################################################################ 17 | # Adjustable configuration 18 | ################################################################################ 19 | 20 | 21 | # File extension of our desired target 22 | TARGET_EXTENSION=exe 23 | 24 | 25 | # Output and intermediate directories 26 | BINDIR=bin.$(ARCH) 27 | OBJDIR=obj.$(ARCH) 28 | 29 | 30 | # Additional include directories 31 | CPPFLAGS_INC= 32 | # Additional definitions 33 | CPPFLAGS_DEF_EX= 34 | 35 | 36 | # Linker output type: Subsystem 37 | LINKFLAGS_SUB=CONSOLE 38 | 39 | 40 | # Additional library paths 41 | LINK_LIBPATHS= \ 42 | /LIBPATH:libs\$(ARCH) 43 | 44 | 45 | # Import libraries 46 | LINK_LIBS= \ 47 | kernel32.lib \ 48 | shell32.lib \ 49 | virtdisk.lib 50 | 51 | 52 | # Target definitions 53 | TARGET_1="$(BINDIR)\makevhd.$(TARGET_EXTENSION)" 54 | LINK_OBJS_1= \ 55 | "$(OBJDIR)\makevhd.obj" \ 56 | "$(OBJDIR)\EntryPoint.obj" \ 57 | "$(OBJDIR)\ParseNumber.obj" 58 | 59 | TARGET_2="$(BINDIR)\resizevhd.$(TARGET_EXTENSION)" 60 | LINK_OBJS_2= \ 61 | "$(OBJDIR)\resizevhd.obj" \ 62 | "$(OBJDIR)\EntryPoint.obj" \ 63 | "$(OBJDIR)\ParseNumber.obj" 64 | 65 | 66 | !IF "$(ARCH)" == "x86-32" 67 | 68 | CPPVER_DEFAULT=120 69 | ARCH_DEF=_M_IX86 70 | ARCH_LNK=IX86 71 | NTVER_DEF=0x0602 72 | NTVER_LNK_1=6.1 73 | NTVER_LNK_2=6.2 74 | CPPFLAGS_EX= 75 | LINKFLAGS_EX= 76 | 77 | !ELSEIF "$(ARCH)" == "x86-64" 78 | 79 | CPPVER_DEFAULT=140 80 | ARCH_DEF=_M_AMD64 81 | ARCH_LNK=AMD64 82 | NTVER_DEF=0x0602 83 | NTVER_LNK_1=6.1 84 | NTVER_LNK_2=6.2 85 | CPPFLAGS_EX= 86 | LINKFLAGS_EX= 87 | 88 | !ENDIF 89 | 90 | 91 | ################################################################################ 92 | # Standard configuration 93 | ################################################################################ 94 | 95 | 96 | # Standard version-specific compiler options 97 | !IFNDEF CPPVER 98 | CPPVER=$(CPPVER_DEFAULT) 99 | !ENDIF 100 | 101 | !IF $(CPPVER) <= 130 102 | CPPFLAGS_STD_VER=/G6 103 | !ELSEIF $(CPPVER) == 131 104 | CPPFLAGS_STD_VER=/G7 105 | !ELSE 106 | CPPFLAGS_STD_VER=/GS- 107 | !ENDIF 108 | 109 | 110 | # Standard compiler options 111 | CPPFLAGS_STD=/nologo /c /MD /W3 /GF /GR- /EHs-c- /O1 112 | # Standard definitions 113 | CPPFLAGS_DEF_STD=/D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_WIN32_WINNT=$(NTVER_DEF)" 114 | 115 | 116 | # Linker output type: DLL and .def 117 | !IF "$(TARGET_EXTENSION)" == "dll" 118 | LINKFLAGS_DLL=/DLL /DEF:"$(BASE_NAME).def" 119 | MAKE_DOPOST_CLEANDLL=1 120 | !ELSE 121 | LINKFLAGS_DLL= 122 | MAKE_DOPOST_CLEANDLL=0 123 | !ENDIF 124 | 125 | 126 | # Standard linker options (/OPT:NOWIN98 is implied by SUBSYSTEM version >= 5.0) 127 | LINKFLAGS_STD=/NOLOGO /RELEASE /OPT:REF /OPT:ICF /MERGE:.rdata=.text /IGNORE:4078 128 | # Target OS and machine options 129 | LINKFLAGS_TARG_1=/SUBSYSTEM:$(LINKFLAGS_SUB),$(NTVER_LNK_1) /OSVERSION:$(NTVER_LNK_1) /MACHINE:$(ARCH_LNK) 130 | LINKFLAGS_TARG_2=/SUBSYSTEM:$(LINKFLAGS_SUB),$(NTVER_LNK_2) /OSVERSION:$(NTVER_LNK_2) /MACHINE:$(ARCH_LNK) 131 | 132 | 133 | # Code compiler 134 | CPP=@cl.exe 135 | CPPFLAGS=$(CPPFLAGS_STD) $(CPPFLAGS_STD_VER) $(CPPFLAGS_EX) $(CPPFLAGS_INC) $(CPPFLAGS_DEF_STD) $(CPPFLAGS_DEF_EX) 136 | CPPFLAGSOUT=$(CPPFLAGS) /Fo"$(OBJDIR)\\" 137 | 138 | 139 | # Resource compiler 140 | RC=@rc.exe 141 | RFLAGS=/l 0x409 /d "NDEBUG" /d "$(ARCH_DEF)" 142 | 143 | 144 | # Linker 145 | LINK=@link.exe 146 | LINKFLAGS_1=$(LINKFLAGS_STD) $(LINKFLAGS_DLL) $(LINKFLAGS_TARG_1) $(LINKFLAGS_EX) $(LINK_LIBPATHS) $(LINK_LIBS) 147 | LINKFLAGS_2=$(LINKFLAGS_STD) $(LINKFLAGS_DLL) $(LINKFLAGS_TARG_2) $(LINKFLAGS_EX) $(LINK_LIBPATHS) $(LINK_LIBS) 148 | 149 | 150 | # By default, do not post-process unless explicitly told to do so 151 | !IFNDEF MAKE_DOPOST 152 | MAKE_DOPOST=0 153 | !ENDIF 154 | 155 | 156 | ################################################################################ 157 | # Recipes and rules 158 | ################################################################################ 159 | 160 | 161 | DEFAULT : "$(BINDIR)" "$(OBJDIR)" $(TARGET_1) $(TARGET_2) 162 | !IF $(MAKE_DOPOST) > 0 163 | @cd "$(BINDIR)" 164 | -@md5sum *.exe *.dll *.lib 1>"$(BASE_NAME).md5" 165 | @cd .. 166 | !ENDIF 167 | 168 | $(TARGET_1) : $(LINK_OBJS_1) 169 | $(LINK) @<< 170 | $(LINKFLAGS_1) $(LINK_OBJS_1) /OUT:$@ 171 | << 172 | 173 | $(TARGET_2) : $(LINK_OBJS_2) 174 | $(LINK) @<< 175 | $(LINKFLAGS_2) $(LINK_OBJS_2) /OUT:$@ 176 | << 177 | 178 | "$(BINDIR)" : 179 | -@mkdir $@ 180 | 181 | "$(OBJDIR)" : 182 | -@mkdir $@ 183 | 184 | .rc{$(OBJDIR)}.res: 185 | $(RC) $(RFLAGS) /Fo$@ $< 186 | 187 | .c{$(OBJDIR)}.obj:: 188 | $(CPP) @<< 189 | $(CPPFLAGSOUT) $< 190 | << 191 | 192 | .cpp{$(OBJDIR)}.obj:: 193 | $(CPP) @<< 194 | $(CPPFLAGSOUT) $< 195 | << 196 | 197 | {libs}.c{$(OBJDIR)}.obj:: 198 | $(CPP) @<< 199 | $(CPPFLAGSOUT) $< 200 | << 201 | 202 | {libs}.cpp{$(OBJDIR)}.obj:: 203 | $(CPP) @<< 204 | $(CPPFLAGSOUT) $< 205 | << 206 | --------------------------------------------------------------------------------