├── 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 |
--------------------------------------------------------------------------------