I'm using VLD 2.4.0 to search for memory leaks in my MFC x64 app.
When I'm trying to open CFileDialog my application just hangs in the way that it just waiting for the CFileDialog to appear (which never happens).
When I don't include VLD header in my code CFileDialog works as expected.
Here is my code:
void CMainFrame::OnBtnOpen()
{
// TODO: Add your command handler code here
if (theApp.xAM->GetApplicationState() != idle)
{
return;
}
bool isFirst = true; //czy aktualnie wczytana chmura byla pierwsza(potrzebne przy wczytywaniu wielu chmur na raz)
CString csFilter = CMsg(ID_IMPORT_CLOUDS_OPEN_DIALOG_FILTER);
CFileDialog OpenDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, csFilter, this, 0, TRUE);
UINT maxFiles = 50;
UINT buffSize = maxFiles*(MAX_PATH + 1) + 1;
CString buffer;
OpenDialog.GetOFN().lpstrFile = buffer.GetBuffer(buffSize);
OpenDialog.GetOFN().nMaxFile = buffSize;
if (OpenDialog.DoModal() == IDOK) // HANGS ON THIS CALL
{
// set import path in data structure
POSITION POS = OpenDialog.GetStartPosition();
while (POS)
{
CString strPath = OpenDialog.GetNextPathName(POS);
std::wstring v_wsPath(strPath);
theApp.xAM->SetImportPath(v_wsPath);
DWORD thrdExitCode;
WThreadParams_ImportCloud threadParams;
if (isFirst)
{
//tworzy nowa grupe
threadParams.iCloudIndex = -1;
threadParams.iGroupIndex = -1;
isFirst = false;
}
else
{
//dopisuje chmure do ostatniej grupy
threadParams.iCloudIndex = -1;
threadParams.iGroupIndex = theApp.xAM->GetGroupsCount() - 1;
}
theApp.StartWorkerThread(ImportPointCloudsThread, (WThreadParams*)(&threadParams), &thrdExitCode);
reinterpret_cast<CSideDockablePane*>(theApp.GetSideDockablePane())->RepaintTree();
theApp.xAM->FitDataToViewport(true);
theApp.xAM->RenderScene(OpenGLRenderingCtx::eRM_STATIC);
glFinish();
}
}
reinterpret_cast<CSideDockablePane*>(theApp.GetSideDockablePane())->RepaintTree();
}
For me this is pretty big problem because that is how I input data into my app so I can test other algorithms for memory leaks.
Is there any solution so I can use VLD together with CFileDialog?
Related
I have code that executes in InitInstance that checks if my application is already running, and if so brings it to the foreground. Standard code:
if (m_hMutex != nullptr)
{ // indicates running instance
if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
EnumWindows(searcher, (LPARAM)&hOther);
if (hOther != nullptr)
{
::SetForegroundWindow(::GetLastActivePopup(hOther));
if (IsIconic(hOther))
{
::ShowWindow(hOther, SW_RESTORE);
}
}
return FALSE; // terminates the creation
}
}
The above I have no issues with. Recently I added support for double-clicking a file from File Explorer and it open in my software CDialog derived). So I do the following in InitInstance:
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (PathFileExists(cmdInfo.m_strFileName))
{
m_bOpenFileFromFileExplorer = true;
m_strFileToOpenFromFileExplorerPath = cmdInfo.m_strFileName;
}
Then, in my main dialog OnInitDialog I do this:
if (theApp.OpenFileFromFileExplorer())
{
CString strFileToOpen = theApp.GetFileToOpenFromFileExplorerPath();
CString strFileExtension = PathFindExtension(strFileToOpen);
strFileExtension.MakeLower();
if (strFileExtension == _T(".srr"))
PostMessage(WM_COMMAND, ID_FILE_OPENREPORT);
else if (strFileExtension == _T(".mwb"))
PostMessage(WM_COMMAND, ID_FILE_OPEN_CHRISTIAN_LIFE_AND_MINISTRY_REPORT);
}
Finally, each of my respective handlers for each editor does something like this):
void CMeetingScheduleAssistantDlg::OnFileOpenReport()
{
CCreateReportDlg dlgReport(this);
CString strFilePath, strFileName;
if (theApp.OpenFileFromFileExplorer())
{
strFilePath = theApp.GetFileToOpenFromFileExplorerPath();
strFileName = PathFindFileName(strFilePath);
if (strFilePath == _T("") || strFileName == _T(""))
{
// Error!
return;
}
}
else
{
CString strTitle, strFilter;
strTitle.LoadString(IDS_STR_SELECT_SRR_FILE);
strFilter.LoadString(IDS_STR_SRR_FILTER);
CFileDialog dlgOpen(TRUE, _T(".SRR"),
nullptr, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);
dlgOpen.m_ofn.lpstrTitle = strTitle;
// get a file to open from user
if (dlgOpen.DoModal() != IDOK)
return;
strFilePath = dlgOpen.GetPathName();
strFileName = dlgOpen.GetFileName();
}
// AJT V9.1.0 - Most Recent File List support
theApp.AddToRecentFileList(strFilePath);
// tell report we want to open it
dlgReport.SetFileToOpen(strFilePath, strFileName);
// display it
dlgReport.DoModal();
// AJT V9.1.0 Bug Fix
SetDayStates(m_calStart);
SetDayStates(m_calEnd);
}
The other handler works in a similar way. There are no issues with the code implemented and users can double-click a file and it will open in the software with the right editor.
Ofcourse, if my software is already running (but only on the primary dialog) and the user double clicks a file, the duplicate instance will trigger and it will simply bring that window to the foreground.
What I would like to do is this:
Is the duplicate instance on the primary window?
Bring it to the foreground.
Trigger to open this file the user has double in this attempted instance.
Shutdown this instance.
Else
Bring it to the foreground.
Not much else we can do since a modal window is open in the other instance.
So just shut down.
End if
So how do I do that bit:
Is the duplicate instance on the primary window?
Bring it to the foreground.
Trigger to open this file the user has double in this attempted instance.
Shutdown this instance.
Else
?
Update
The problem is that:
HWND hOther = nullptr;
if (DetectRunningInstance(hOther))
{
DetectFileToOpenFromFileExplorer(); // AJT v20.1.6
CString strFile = GetFileToOpenFromFileExplorerPath();
LPCTSTR lpszString = strFile.GetBufferSetLength(_MAX_PATH);
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = _MAX_PATH;
cds.lpData = (LPVOID)lpszString;
DWORD dwResult;
SendMessageTimeout(hOther, WM_COPYDATA,
NULL, (LPARAM)(LPVOID)&cds, SMTO_BLOCK, 2000, &dwResult);
strFile.ReleaseBuffer();
return FALSE; // Terminates the creation
}
...
...
BOOL CMeetingScheduleAssistantDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
if (pCopyDataStruct->dwData == nnn)
{
LPCTSTR lpszString = (LPCTSTR)(pCopyDataStruct->lpData);
AfxMessageBox(lpszString);
}
return TRUE;
}
The above passes the string, even if the other instance of MSA has a modal window up. So SendMessageTimeout never actual times out.
Got!
if (GetLastActivePopup() != this)
This is what I have so far...
Once I have determined that another instance is already running, and that a file was provided on the command line, I then run this method before I cancel the duplicate instance:
void CMeetingScheduleAssistantApp::TryToOpenFileInOtherInstance(HWND hOtherInstance)
{
CString strFile = GetFileToOpenFromFileExplorerPath();
LPCTSTR lpszString = strFile.GetBufferSetLength(_MAX_PATH);
COPYDATASTRUCT cds;
cds.dwData = xxxxx;
cds.cbData = _MAX_PATH;
cds.lpData = (LPVOID)lpszString;
DWORD_PTR dwResult;
if (SendMessageTimeout(hOtherInstance, WM_COPYDATA,
NULL, (LPARAM)(LPVOID)&cds, SMTO_BLOCK, 2000, &dwResult) != 0)
{
// The message was sent and processed
if (dwResult == FALSE)
{
// The other instance returned FALSE. This is probably because it
// has a pop-up window open so can't open the file
::OutputDebugString(_T("InitInstance::SendMessageTimeout [dwResult was FALSE].\n"));
}
}
else
{
DWORD dwError = ::GetLastError();
if (dwError == ERROR_TIMEOUT)
{
// The message timed out for some reason
::OutputDebugString(_T("InitInstance::SendMessageTimeout [ERROR_TIMEOUT].\n"));
}
else
{
// Another unknown error
}
CString strError = _T("");
strError.Format(_T("InitInstance::SendMessageTimeout [%d: %s]\n"), dwError, GetLastErrorAsStringEx(dwError));
::OutputDebugString(strError);
}
strFile.ReleaseBuffer();
}
In the WM_COPYDATA message handler:
BOOL CMeetingScheduleAssistantDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
if (pCopyDataStruct->dwData == xxx)
{
LPCTSTR lpszString = (LPCTSTR)(pCopyDataStruct->lpData);
{
if (GetLastActivePopup() != this) // Popup windows!
{
// TODO: Tell user?
return FALSE;
}
theApp.SetFileToOpenFromFileExplorer(lpszString);
OpenFileFromFileExplorer();
}
}
return TRUE;
}
I was trying to adapt the CopyData approach as described here but could not get it to work — Got it to work and code is shown here.
I am finding that if I navigate to a file and then I try to delete the file the system tells me it is in use.
How can I stopped the files from being "in use" so I can delete it and recreate it to update the html display?
If I create a NEW XML data file every time and navigate to that then I get no problems. This is because there is no file to delete.
But the moment I use the same file I get the file in use issue.
I added code in my dialog OnDestroy method and added an array of temporary files that i create. Then I try to delete them:
for (auto i = 0; i < m_aryStrTempFiles.GetCount(); i++)
{
if (PathFileExists(m_aryStrTempFiles[i]))
{
if (!::DeleteFile(m_aryStrTempFiles[i]))
{
AfxMessageBox(theApp.GetLastErrorAsString(), MB_OK | MB_ICONERROR);
}
}
}
I find that ALL of the files are considered still in use.
The code that creates the temporary file names is not the issue:
CString CMeetingScheduleAssistantApp::GetFolderTempFilenameEx(CString strFolder, CString strToken, CString strSuffix /*_T("htm")*/)
{
CString strFile;
int i;
::GetTempFileName(strFolder, strToken, 0, strFile.GetBuffer(_MAX_PATH));
strFile.ReleaseBuffer();
// Because we will rename to .HTM we must delete old file
::DeleteFile(strFile);
// I can't be sure the suffix is .tmp so I manually
// replace the suffix, whatever it is, with .htm"
i = strFile.ReverseFind(_T('.'));
strFile = strFile.Left(i + 1);
strFile += strSuffix;
return strFile;
}
And this is the code that saves my XML files:
bool CMeetingScheduleAssistantApp::SaveToXML(CString strFileXML, tinyxml2::XMLDocument& rDocXML)
{
FILE *fStream = nullptr;
CString strError, strErrorCode;
errno_t eResult;
bool bDisplayError = false;
int iErrorNo = -1;
using namespace tinyxml2;
// Does the file already exist?
if (PathFileExists(strFileXML))
{
// It does, so try to delete it
if (!::DeleteFile(strFileXML))
{
// Unable to delete!
AfxMessageBox(theApp.GetLastErrorAsString(), MB_OK | MB_ICONINFORMATION);
return false;
}
}
// Now try to create a FILE buffer (allows UNICODE filenames)
eResult = _tfopen_s(&fStream, strFileXML, _T("w"));
if (eResult != 0 || fStream == nullptr) // Error
{
bDisplayError = true;
_tcserror_s(strErrorCode.GetBufferSetLength(_MAX_PATH), _MAX_PATH, errno);
strErrorCode.ReleaseBuffer();
}
else // Success
{
// Now try to save the XML file
XMLError eXML = rDocXML.SaveFile(fStream);
int fileCloseResult = fclose(fStream);
if (eXML != XMLError::XML_SUCCESS)
{
// Error saving
bDisplayError = true;
strErrorCode = rDocXML.ErrorName();
iErrorNo = rDocXML.GetErrorLineNum();
}
if (!bDisplayError)
{
if (fileCloseResult != 0)
{
// There was a problem closing the stream. We should tell the user
bDisplayError = true;
_tcserror_s(strErrorCode.GetBufferSetLength(_MAX_PATH), _MAX_PATH, errno);
strErrorCode.ReleaseBuffer();
}
}
}
if (bDisplayError)
{
if (iErrorNo == -1)
iErrorNo = errno;
strError.Format(IDS_TPL_ERROR_SAVE_XML, strFileXML, strErrorCode, iErrorNo);
AfxMessageBox(strError, MB_OK | MB_ICONINFORMATION);
return false;
}
return true;
}
As you can see, they all close the stream. Yet, even though in OnDestroy I delete the html view first the temporary files still can't be deleted. Why?
The issue was how I was testing for a file still being open:
bool CMeetingScheduleAssistantApp::WaitForFileToBeReady(CString strFile)
{
HANDLE hFile;
int delay = 10;
while ((hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_SHARING_VIOLATION) {
Sleep(delay);
if (delay < 5120) // max delay approx 5.Sec
delay *= 2;
}
else
{
AfxMessageBox(theApp.GetLastErrorAsString(), MB_OK | MB_ICONINFORMATION);
return false; // some other error occurred
}
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return true;
}
I was missing the CloseHandle lines of code.
I used the example from https://github.com/hdeldar/QtCrashDumper and made us of the same in my application. Lately for actual crashes in the application the stack trace has been a little useless.
Another question is the dmp files generated module version does not match. I have double checked the module version and it is the same however the dump file has different versions. File version is 2.8.0.4 and the dmp file has 2.08.0.4
I have looked into a few answers on stackoverflow to not understand what functions I am missing.
CrashDump Info
The KB link does not exist anymore - KB313109
My implementation
#include "CrashDumpDef.h"
#include "version.h"
#ifdef USE_MINI_DUMP
#include "CrashDump.h"
#include "FileSystem.h"
LPCWSTR CrashDump::m_szAppName;
LPWSTR CrashDump::m_szAppVersion;
LPWSTR CrashDump::m_szAppBuildNumber;
WCHAR CrashDump::m_szMessageText[MAX_WARNING_MESSAGE_PATH];
LPWSTR CrashDump::m_szDumpFilePath;
#define DEFAULT_MESSAGE_TEXT L"%s Designer has experienced an issue. \nCrash dump has been saved in %s."
#define MAX_DUMP_FILE_NUMBER 9999
CrashDump::CrashDump(LPCWSTR szAppName, LPCWSTR szVersion, LPCWSTR szBuildNumber)
{
// if this assert fires then you have two instances of CrashDump
// which is not allowed
Q_ASSERT(m_szAppName == NULL);
const char* sz = VER_PRODUCTVERSION_STR;
std::vector<wchar_t> vec;
size_t len = strlen(sz);
vec.resize(len + 1);
mbstowcs(&vec[0], sz, len);
const wchar_t* productVersion = &vec[0];
std::string version = VER_PRODUCTVERSION_STR;
char build = version.back();
const char* buildNum = new char(build);
std::vector<wchar_t> vec1;
size_t lenA = strlen(buildNum);
vec1.resize(lenA + 1);
mbstowcs(&vec1[0], buildNum, lenA);
const wchar_t* buildNumber = &vec1[0];
m_szAppName = szAppName ? wcsdup(szAppName) : wcsdup(L"Designer");
m_szAppVersion = productVersion ? wcsdup(productVersion) : wcsdup(productVersion);
m_szAppBuildNumber = buildNumber ? wcsdup(buildNumber) : wcsdup(buildNumber);
wcscpy(m_szMessageText, DEFAULT_MESSAGE_TEXT);
m_szDumpFilePath = NULL;
::SetUnhandledExceptionFilter(TopLevelFilter);
}
CrashDump::~CrashDump()
{
}
void CrashDump::SetVersion(LPCWSTR szVersion)
{
if (szVersion)
{
free(m_szAppVersion);
m_szAppVersion = wcsdup(szVersion);
}
}
void CrashDump::SetBuildNumber(LPCWSTR szBuildNumber)
{
if (szBuildNumber)
{
free(m_szAppBuildNumber);
m_szAppBuildNumber = wcsdup(szBuildNumber);
}
}
void CrashDump::SetDumpFilePath(LPCWSTR szFilePath)
{
free(m_szDumpFilePath);
{
m_szDumpFilePath = wcsdup(szFilePath);
}
}
LONG CrashDump::TopLevelFilter(struct _EXCEPTION_POINTERS *pExceptionInfo)
{
//::MessageBoxW(NULL, L"debugging", m_szAppName, MB_OK);
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
WCHAR szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"DBGHELP.DLL");
hDll = ::LoadLibrary(szDbgHelpPath);
}
}
if (hDll == NULL)
{
// load any version we can
hDll = ::LoadLibrary(L"DBGHELP.DLL");
}
LPCWSTR szResult = NULL;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
if (pDump)
{
WCHAR szDumpPath[_MAX_PATH];
WCHAR szDumpRootPath[_MAX_PATH];
WCHAR szScratch[_MAX_PATH];
// work out a good place for the dump file - add the path here
if (m_szDumpFilePath == NULL)
{
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"");
wcscpy(szDumpPath, szDbgHelpPath);
}
}
//else if (!GetTempPath(_MAX_PATH, szDumpPath))
std::string dmpFile = filesystem::buildFilename(QStringList()
<< QDir::toNativeSeparators(QDir::homePath()) + "\\AppData\\Roaming\\ABC\\logs\\"
).toStdString();
std::wstring wideDmpFile;
for (int i = 0; i < dmpFile.length(); ++i)
wideDmpFile += wchar_t(dmpFile[i]);
const wchar_t* szName = wideDmpFile.c_str();
wcscpy(szDumpPath, szName);
}
else
{
wcscpy(szDumpPath, m_szDumpFilePath);
}
wcscpy(szDumpRootPath, szDumpPath);
//PrintDebug(L"[CrashDump] Mini Dump file:[%s]",szDumpPath);
// ask the user if they want to save a dump file
//if (::MessageBox( NULL, _T("Crash, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
int i = 1;
WCHAR szFileNumber[_MAX_PATH];
while (hFile == INVALID_HANDLE_VALUE)
{
swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d", i);
wcscpy(szDumpPath, szDumpRootPath);
wcscat(szDumpPath, m_szAppName);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppVersion);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppBuildNumber);
wcscat(szDumpPath, szFileNumber);
wcscat(szDumpPath, L".dmp");
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
i++;
if (i > MAX_DUMP_FILE_NUMBER)
{
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
}
// create the file
if (hFile != INVALID_HANDLE_VALUE)
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionInfo;
ExInfo.ClientPointers = NULL;
// write the dump
BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
if (bOK)
{
swprintf(szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath);
szResult = szScratch;
retval = EXCEPTION_EXECUTE_HANDLER;
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
::CloseHandle(hFile);
WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);
//PrintError(_T("%s"), csOutMessage);
::MessageBoxW(NULL, csOutMessage, m_szAppName, MB_OK);
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
}
}
else
{
szResult = L"DBGHELP.DLL too old";
}
}
else
{
szResult = L"DBGHELP.DLL not found";
}
if (szResult)
{
//PrintDebug(_T("[CrashDump] Mini Dump result:[%s]"),szResult);
}
return retval;
}
#endif
I try to extract the icon of file and return it to GetIconLocation of shell extension.
in general I change the icons of files (te.docx.xx) with the extension of xx and returns the icon of file without the xx. (for this I cretae temp file in temp directory with the original extension e.g te.docx)
my operating system is windows 7 x64.
my code is:
STDMETHODIMP CTxtIconShlExt::GetIconLocation (
UINT uFlags, LPTSTR szIconFile, UINT cchMax,
int* piIndex, UINT* pwFlags )
{
DWORD dwFileSizeLo, dwFileSizeHi;
DWORDLONG qwSize;
HANDLE hFile;
OutputDebugStringW(L"Hello world, from GetIconLocation !");
std::string strFilePath;
std::string tempFolder="c:\\.tmp";
std::string tempFile="tmpfile";
std::string fileWithOutDN;
SHFILEINFO retShFileInfo;
for(int i = 0; m_szFilename[i] != 0; i++)
{
strFilePath += m_szFilename[i];
}
fileWithOutDN= strFilePath.substr(0,strFilePath.size()-3 );
std::string extension = fileWithOutDN.substr(fileWithOutDN.find_last_of("."));
CreateDirectory(tempFolder.c_str(),NULL);
tempFile=tempFolder+"\\"+tempFile+extension;
GetFileAttributes(tempFile.c_str()); // from winbase.h
if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(tempFile.c_str()) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
//File not found
HANDLE h = CreateFile(tempFile.c_str(), // name of the file
GENERIC_WRITE, // open for writing
0, // sharing mode, none in this case
0, // use default security descriptor
CREATE_ALWAYS, // overwrite if exists
FILE_ATTRIBUTE_NORMAL,
0);
if (h)
{
CloseHandle(h);
}else
{
return S_FALSE; //faild to create file
}
}
ZeroMemory(&retShFileInfo, sizeof(SHFILEINFO));
CoInitialize(NULL);
SHGetFileInfo(tempFile.c_str(),256,&retShFileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_LARGEICON);
lstrcpyn ( szIconFile, retShFileInfo.szDisplayName, cchMax );
*piIndex = retShFileInfo.iIcon;
*pwFlags = 0;
return S_OK;
my problem is that the retShFileInfo.szDisplayName return an empty array (all items are zero), it should return full path to icon location.
I try to play with the combination of the flags but nothing was helpful
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,
¶ms,
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,
¶meters,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"