AddFontMemResourceEx - c++

The following code should work to load a font from a binary resource stored in my executable to system memory according to all of the examples I have found but it is not working. "myfont" is the name of the ttf associated with IDR_FONT in the resource file.
DWORD Count ;
HRSRC Resource = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_FONT),"BINARY") ;
DWORD Length = SizeofResource(GetModuleHandle(NULL),Resource) ;
HGLOBAL Address = LoadResource(GetModuleHandle(NULL),Resource) ;
HANDLE Handle = AddFontMemResourceEx(Address,Length,0,&Count) ;
if(Handle==0)
{
MessageBox(hWnd,"Font load failed", "Error",NULL);
}
LOGFONT logfont; //set window font
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfEscapement = 0;
memcpy(logfont.lfFaceName, "myfont", LF_FACESIZE);
logfont.lfHeight = 14;
logfont.lfItalic = FALSE;
logfont.lfOrientation = 0;
logfont.lfOutPrecision = OUT_TT_PRECIS;
logfont.lfQuality = PROOF_QUALITY;
logfont.lfStrikeOut = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfWeight = FW_DONTCARE;
hFont = CreateFontIndirect(&logfont);
Any ideas what I am doing incorrectly?

There are two problems with your code.
You are not checking any of the API functions for failure. Most likely, your call to FindResource() is failing because "BINARY" is not a standard resource type. User-defined resources should use RCDATA instead:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_RCDATA);
Or maybe FONT if it is an actual standard FONT resource:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_FONT);
The actual name of the resource type depends on the content of the .RC file you used to add the resource to the executable, though.
The other problem, and more importatly, is that you are not actually accessing the raw data of the resource so you can pass the real font data to AddFontMemResourceEx(). You need to use LockResource() for that.
Try something more like this instead:
HANDLE AddResourceFont(LPCTSTR ResID, DWORD *Installed)
{
if (Installed) *Installed = 0;
HMODULE hMod = GetModuleHandle(NULL);
DWORD Count, ErrorCode;
HRSRC Resource = FindResource(hMod, ResID, RT_RCDATA); // or RT_FONT or whatever your actual resource type is
if (!Resource)
{
ErrorCode = GetLastError();
//...
return NULL;
}
DWORD Length = SizeofResource(hMod, Resource);
if ((Length == 0) && (GetLastError() != 0))
{
ErrorCode = GetLastError();
//...
return NULL;
}
HGLOBAL Address = LoadResource(hMod, Resource);
if (!Address)
{
ErrorCode = GetLastError();
//...
return NULL;
}
PVOID FontData = LockResource(Address);
if (!FontData)
{
ErrorCode = GetLastError();
//...
return NULL;
}
HANDLE Handle = AddFontMemResourceEx(FontData, Length, 0, &Count);
if (!Handle)
{
ErrorCode = GetLastError();
//...
return NULL;
}
if (Installed) *Installed = Count;
return Handle;
}
.
DWORD Count = 0;
HANDLE hFont = AddResourceFont(MAKEINTRESOURCE(IDR_FONT), &Count);
if (hFont)
{
//...
RemoveFontMemResourceEx(hFont);
}

Related

How to validate credentials with CredUIPromptForWindowsCredentials

I don't know why I can't unpack the authentification buffer used in CredUIPromptForWindowsCredentials with CredUnPackAuthenticationBufferW, I always get ERROR_INSUFFICIENT_BUFFER error.
I will appreciate your help.
std::wstring caption = L"Caption";
std::wstring msg= L"Msg";
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0;
LPVOID outCredBuffer = nullptr;
ULONG outCredSize = 0;
BOOL save = false;
LPWSTR pszUserName = nullptr;
DWORD pcchlMaxUserName = 0;
LPWSTR pszDomainName = nullptr;
DWORD pcchMaxDomainName = 0;
LPWSTR pszPassword = nullptr;
DWORD pcchMaxPassword = 0;
DWORD result = CredUIPromptForWindowsCredentialsW(&credui,
0,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS);
std::cout <<CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS
,outCredBuffer
,outCredSize
,pszUserName
,&pcchlMaxUserName
,pszDomainName
,&pcchMaxDomainName
,pszPassword
,&pcchMaxPassword) << std::endl;
std::cout << GetLastError() << std::endl; // out put 122 == ERROR_INSUFFICIENT_BUFFER
this is typical winapi pattern - api must return some information in the memory buffer. but instead allocate buffer yourself - it obligate caller to allocate buffer.
so caller must allocate buffer itself and pass it pointer and size to api.
api check buffer size - if it large enough fill information to buffer, otherwise return ERROR_INSUFFICIENT_BUFFER (assume that no another errors) or sometime ERROR_MORE_DATA. which which concrete error reurned ERROR_INSUFFICIENT_BUFFER or ERROR_MORE_DATA usual direct documented for api call. different between this 2 errors: ERROR_INSUFFICIENT_BUFFER - mean no any info filled to buffer at all, when ERROR_MORE_DATA mean some data is returned, but incomplete.
and api return to user, via some out parameter, required buffer size in this case. frequently this is done via the same inout parameter - pointer to DWORD. in input specifies the size of user allocated buffer, in output - specifies the required size of buffer or size of returned data
frequently which buffer size is required - unknown at begin. so we need or call api with 0 size buffers(s) first, or allocate some, supposedly sufficient buffer size. if buffer will be insuffient - reallocate or extend it and call api again. for some api (like CredUnPackAuthenticationBufferW) the required output buffer does not change with time (if input parameters not changed), but usual output buffer size may change between calls - even second call with buffer size returned by first call can fail with buffer size error (because returned data may grow between calls). in this case need call api in do/while(error == ERROR_INSUFFICIENT_BUFFER/ERROR_MORE_DATA) loop. but even in case output buffer does not change with time we can better do this is loop with single api call inside, instead 2 api calls.
for concrete case code can look like
ULONG cred()
{
CREDUI_INFO ci = { sizeof(ci) };
BOOL bSave = FALSE;
PVOID pvOutAuthBuffer;
ULONG ulOutAuthBufferSize;
ULONG ulAuthPackage = 0;
ULONG dwError = CredUIPromptForWindowsCredentials(
&ci, NOERROR, &ulAuthPackage, 0, 0,
&pvOutAuthBuffer, &ulOutAuthBufferSize,
&bSave, CREDUIWIN_ENUMERATE_ADMINS );
if (dwError == NOERROR)
{
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = 0, szPassword = 0, szDomainName = 0;
ULONG cchNeed, cchAllocated = 0;
do
{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
dwError = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS,
pvOutAuthBuffer, ulOutAuthBufferSize,
szUserName, &cchUserName,
szDomainName, &cchDomain,
szPassword, &cchPassword)
? NOERROR : GetLastError();
if (dwError == NOERROR)
{
DbgPrint("%S#%S %S\n", szDomainName, szUserName, szPassword);
break;
}
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CoTaskMemFree(pvOutAuthBuffer);
}
return dwError;
}
#RbMm - you're right! I tested it with LogonUser, and it works perfectly. Thanks.
And for a ready solution, I got this :
bool Authenticate_ADMIN_User(std::wstring caption, std::wstring msg, int maxReAsks = 0)
{
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0,
outCredSize = 0;
LPVOID outCredBuffer = nullptr;
BOOL save = false;
DWORD err = 0;
int tries = 0;
bool reAsk = false;
do
{
tries++;
if(CredUIPromptForWindowsCredentialsW(&credui,
err,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS)
!= ERROR_SUCCESS)
return false;
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
ULONG cchNeed, cchAllocated = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = nullptr, szPassword = nullptr, szDomainName = nullptr;
BOOL ret;
do{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
ret = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS , outCredBuffer, outCredSize, szUserName, &cchUserName,
szDomainName, &cchDomain, szPassword,
&cchPassword);
}while(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
SecureZeroMemory(outCredBuffer, outCredSize);
CoTaskMemFree(outCredBuffer);
HANDLE handle = nullptr;
if (LogonUser(szUserName,
szDomainName,
szPassword,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&handle))
{
CloseHandle(handle);
return true;
}
else
{
err = ERROR_LOGON_FAILURE;
reAsk = true;
}
}while(reAsk && tries < maxReAsks);
return false;
}

Load .BIN file from resources inside exe

BIN file to resources of my executable file and then load it from resources instead of argv argument like : "loader.exe some.bin" i need a do this inside exe without putting file on disk here is code which i currently use:
LPSTR finalShellcode = NULL, data = NULL;
DWORD finalSize, dataSize;
DWORD dwOldProtect1 = 0;
SYSTEM_INFO sysInfo;
HMODULE test = LoadLibraryA("User32.dll");
if (argc < 2) {
return 0;
}
if (!GetFileContents(argv[1], &data, dataSize)) {
return 0;
}
if (data[0] == 'M' && data[1] == 'Z') {
if (!ConvertToShellcode(data, dataSize, HashFunctionName("SayHello"), "dave", 5, SRDI_CLEARHEADER, finalShellcode, finalSize)) {
return 0;
}
And here is GetFileContents function :
DWORD GetFileContents(LPCSTR filename, LPSTR *data, DWORD &size)
{
std::FILE *fp = std::fopen(filename, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
*data = (LPSTR)malloc(size + 1);
fread(*data, size, 1, fp);
fclose(fp);
return true;
}
return false;
}
Iam try make BIN file like RC data but without solution i dont know how i can embed .bin to resource then load it directly from resources any ideas any help? Thanks a lot
now i ADD test.bin as RCDATA with name IDR_RCDATA1 :
HMODULE hModule = GetModuleHandle(NULL);
HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA); // substitute RESOURCE_ID and RESOURCE_TYPE.
HGLOBAL hMemory = LoadResource(hModule, hResource);
DWORD dwSize = SizeofResource(hModule, hResource);
LPVOID lpAddress = LockResource(hMemory);
char *bytes = new char[dwSize];
but i dont know ho to make it working...
A also read : How to load a custom binary resource in a VC++ static library as part of a dll? but without solution

Enumerating process handles, weird issue

I scan for opened handles to my process and print them in the console.
I start my process
I attach cheat engine
I run the enumeration of opened handles
I see which process has a handle to my process
The weird issue at this point is as follows, check the code:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
PSYSTEM_HANDLE_INFORMATION handleInfo = new SYSTEM_HANDLE_INFORMATION;
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS)16; // SystemHandleInformation
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (!NT_SUCCESS(status))
{
if (needed == 0)
return nullptr;
// The previously supplied buffer wasn't enough.
delete handleInfo;
size = needed + 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION)new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
HANDLE currentProcess = GetCurrentProcess();
DWORD currentProcessId = GetProcessId(currentProcess);
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
//printf(".");
SYSTEM_HANDLE handle = handleInfo->Handles[i];
HANDLE procHandle = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (GetLastError() == ERROR_ACCESS_DENIED)
continue;
HANDLE dupl = 0;
if (!DuplicateHandle(procHandle, (HANDLE)handle.wValue, currentProcess, &dupl, 0, false, DUPLICATE_SAME_ACCESS))
continue;
DWORD procId = GetProcessId(dupl);
if (procId == currentProcessId)
{
printf("accessing us\n");
char processName[MAX_PATH];
GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
CloseHandle(dupl);
}
return accessorList->ToArray();
}
If I uncomment the line with printf(".");, I see 3 opened handles to my process (cheatengine). If it's commented (runs way faster), there is no opened handle. However I don't know why this affects my code. Im surprised, does anyone know why this happens? Or how to find out how to find the handles without my printf("."); line?
Another issue is: each time I call the function, the number of allocated bytes duplicates. And I don't know why.
I see logic problems with your code.
You are not ignoring array items where handle.dwProcessId equals currentProcessId, so you end up opening handles to your own process. Since you are only interested in looking for other processes, you should be ignoring items where handle.dwProcessId is equal to currentProcessId.
You are not checking if OpenProcess() fails for any reason other than ERROR_ACCESS_DENIED. Do not call GetLastError() unless OpenProcess() actually returns NULL first.
You are not closing an opened handle if DuplicateHandle() fails. And why are you duplicating each source handle just to call GetProcessId() on it? You already have their process IDs from the array, so the whole DuplicateHandle()+GetProcessId() is completely unnecessary.
You are taking the wrong approach anyway. Have a look at this discussion:
Enumerating the processes referencing an object
Use NtQuerySystemInformation with SystemInformationClass set to SystemHandleInformation. This fills in an array of SYSTEM_HANDLE_INFORMATION structures, which are defined as:
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION;
Search for the entry corresponding to the handle you opened with ProcessID equal to GetCurrentProcessId(), then find all entries with the same Object pointer.
Although the discussion shows the wrong declaration for SYSTEM_HANDLE_INFORMATION. The following article shows the correct one:
HOWTO: Enumerate handles
#define SystemHandleInformation 16
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
With that said, try something more like this:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
DWORD currentProcessId = GetCurrentProcessId();
HANDLE currentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, currentProcessId);
PVOID currentProcessAddr = nullptr;
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS) 16; // SystemHandleInformation
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
// The previously supplied buffer wasn't enough.
delete[] handleInfo;
size += 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
if (status != 0)
{
delete[] handleInfo;
return nullptr;
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId == currentProcessId) &&
(currentProcess == (HANDLE)handle.wValue))
{
currentProcessAddr = handle.pAddress;
break;
}
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId != currentProcessId) &&
(handle.pAddress == currentProcessAddr))
{
printf("accessing us\n");
HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (procHandle != 0)
{
char processName[MAX_PATH+1];
DWORD len = GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
CloseHandle(procHandle);
processName[len] = '\0';
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
else
accessorList->Add(gcnew Accessor(gcnew String("unknown"), handle.GrantedAccess));
}
}
CloseHandle(currentProcess);
delete[] handleInfo;
return accessorList->ToArray();
}

LoadAccelerators for a specific resource language

I want to call LoadAccelerators but for a specific language in the resources. Is there a way to do it?
I did some reverse engineering and here's how to load it from memory for a specific LCID:
#pragma pack(push, 1) // exact fit - no padding
struct ACCEL_MEM{
BYTE fVirt;
BYTE byteReserved;
WORD wKey;
WORD wCmd;
WORD wReserved;
};
#pragma pack(pop)
HACCEL LoadAcceleratorsIndirectWithLCID(UINT nResourceID, LCID lcid)
{
//Open accelerators table with the 'nResourceID'
//'nResourceID' = Resource ID to use
//'lcid' = LCID to load resources for, or NULL to use the one from current thread
//RETURN:
// = HACCEL loaded -- must be removed with DestroyAcceleratorTable(), or
// = NULL if error
ASSERT(nResourceID);
HACCEL hAccel = NULL;
HINSTANCE hInst = ::GetModuleHandle(NULL);
if(hInst)
{
//Do we have a LCID?
if(lcid == NULL)
lcid = ::GetThreadLocale();
//Get language ID
LANGID langid = LANGIDFROMLCID(lcid);
//Try to load for specified resource
HRSRC hResource = ::FindResourceEx(hInst, RT_ACCELERATOR, MAKEINTRESOURCE(nResourceID), langid);
if(hResource == NULL)
{
//If failed, use default lcid
hResource = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_ACCELERATOR);
}
if(hResource)
{
HGLOBAL hglb = LoadResource(hInst, hResource);
if(hglb)
{
LPVOID lpsz = LockResource(hglb);
DWORD dwcbSz = ::SizeofResource(hInst, hResource);
if(lpsz &&
dwcbSz)
{
ACCEL_MEM* pMem = (ACCEL_MEM*)lpsz;
//Count items in the table
int nCnt = 0;
ACCEL_MEM* pTest = pMem;
for(;; pTest++)
{
nCnt++;
if(pTest->fVirt & 0x80)
break;
}
//Reserve mem
ACCEL* pAccels = new ACCEL[nCnt];
//Parse data
for(int i = 0; i < nCnt; i++)
{
pAccels[i].fVirt = pMem[i].fVirt & 0x7f;
pAccels[i].key = pMem[i].wKey;
pAccels[i].cmd = pMem[i].wCmd;
}
//Create accel table
hAccel = ::CreateAcceleratorTable(pAccels, nCnt);
//Free mem
delete[] pAccels;
pAccels = NULL;
}
}
}
}
return hAccel;
}
You put your language-specific resources in a DLL. At run time, you load that DLL and specify the DLL's handle as the hInstance when you call LoadAccelerators.

Creating VHD files with the VirtualDisk API

I'm trying to use a VSS snapshot as the source for CreateVirtualDisk(). Environment/tools are C++ VS2008SP1 and 7.1 SDK on W7x64Ultimate
[Edited]
This works on Windows 7 x64
BOOL CreateVHD_Fixed(PCWSTR pszVhdPath, ULONG sizeInMB)
{
BOOL bRet = FALSE;
HANDLE hvhd;
CREATE_VIRTUAL_DISK_PARAMETERS params;
VIRTUAL_DISK_ACCESS_MASK mask;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT
};
wprintf(L"CreateVHD_Fixed %s, size (MB) %d\n", pszVhdPath, sizeInMB);
params.Version1.UniqueId = GUID_NULL;
params.Version1.BlockSizeInBytes = 0;
params.Version1.MaximumSize = sizeInMB * 1024 * 1024;
params.Version1.ParentPath = NULL;
params.Version1.SourcePath = NULL;
params.Version1.SectorSizeInBytes = 512;
params.Version = CREATE_VIRTUAL_DISK_VERSION_1;
mask = VIRTUAL_DISK_ACCESS_CREATE;
DWORD ret = CreateVirtualDisk(&vst,
pszVhdPath,
mask,
NULL,
// To create a dynamic disk, use CREATE_VIRTUAL_DISK_FLAG_NONE instead.
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
0,
&params,
NULL,
&hvhd);
if (ret == ERROR_SUCCESS)
{
bRet = TRUE;
}
else
{
bRet = FALSE;
printf("failed to create vdisk...err 0x%x\n", ret);
PrintErrorMessage(GetLastError());
}
if (INVALID_HANDLE_VALUE != hvhd)
{
CloseHandle(hvhd);
}
return bRet;
}
[Edited] - now failing in a different way with ERROR_INVALID_PARAMETER. Parameters are below with a root path of "\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy64"
VIRTUAL_STORAGE_TYPE storageType =
{
VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
// do not use any other GUID else you get an unknown provider error
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT // **critical!**
};
VIRTUAL_DISK_ACCESS_MASK vdam = (VIRTUAL_DISK_ACCESS_MASK)(VIRTUAL_DISK_ACCESS_CREATE); // |VIRTUAL_DISK_ACCESS_WRITABLE|VIRTUAL_DISK_ACCESS_READ|VIRTUAL_DISK_ACCESS_GET_INFO);
CREATE_VIRTUAL_DISK_FLAG flags = CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION; // CREATE_VIRTUAL_DISK_FLAG_NONE;
CREATE_VIRTUAL_DISK_PARAMETERS parameters;
//
parameters.Version = CREATE_VIRTUAL_DISK_VERSION_1;
parameters.Version1.UniqueId = GUID_NULL;
parameters.Version1.MaximumSize = 0;
parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;
parameters.Version1.ParentPath = 0;
parameters.Version1.SourcePath = root.c_str();
parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
ULONG ProviderSpecificFlags = 0;
HANDLE handle = 0;
dwRet = CreateVirtualDisk(&storageType,
_T("t:\\test.vhd"),
vdam,
NULL,
flags,
ProviderSpecificFlags,
&parameters,0,&handle);
Any ideas? The virtual disk API does not seem to have much example code.
Thx++
Jerry.
Jerry,
Use CreateVirtualDisk API to create a VHD or a differential VHD, make sure u send the right parameters. You have to specify the parent hard disk but not the source hard disk. Care must also be taken while using the flags.
Refer the links below:
"http://code.msdn.microsoft.com/windowshardware/CppVhdAPI-4412d182"
and
"http://code.msdn.microsoft.com/windowsdesktop/Virtual-hard-disk-03108ed3"