Open a file or folder in Windows File Explorer using C++/MFC



We are using ShellExecuteEx Windows API here to open a file or folder in Windows File Explorer using C++/MFC.

It has additional option whether to select the file, show the folder tree by the side and whether to use existing instance of Windows File Explorer if open, or not. These are all frequently required options in many apps.

 
BOOL OpenInWindowsExplorer(CString strFileOrFolderPath, BOOL bSelectFile, BOOL bShowFolderTree, BOOL bUseExistingIfAlreadyOpen)
{
 
	TCHAR szPath[MAX_PATH];
	CString strCommandLine, strAppPath;
	SHELLEXECUTEINFO stSEI = {0};
 
	stSEI.cbSize = sizeof(SHELLEXECUTEINFO);
	stSEI.hwnd = NULL;
	stSEI.lpVerb = _T("open");
	stSEI.nShow = SW_SHOW;
 
	// if this function fails that the OS needs to be reinstalled :)
	GetWindowsDirectory(szPath,MAX_PATH);
	PathAddBackslash(szPath);
	StrCat(szPath,_T("explorer.exe"));
 
	strAppPath = szPath;
 
	if (!bUseExistingIfAlreadyOpen)
	{
		strCommandLine += _T("/n,");
	}
 
	if (bShowFolderTree)
	{
		strCommandLine += _T("/e,");
	}
 
	if (bSelectFile)
	{	
		strCommandLine += _T("/select,");
	}
 
	PathQuoteSpaces(strFileOrFolderPath.GetBufferSetLength(MEDIUM_TEXT_LENGTH));
	strFileOrFolderPath.ReleaseBuffer();
	strCommandLine += strFileOrFolderPath;
 
	stSEI.lpFile = LPCTSTR(strAppPath);
	stSEI.lpParameters = LPCTSTR(strCommandLine);
	stSEI.lpDirectory = NULL;
	stSEI.nShow = SW_SHOW;
 
	BOOL bRet = ShellExecuteEx(&stSEI);
	if (bRet == FALSE)
	{
		DWORD dwErr = GetLastError();
		return FALSE;
	}
	return TRUE;
}


Format a number with comma in Windows (C++/MFC)



Following is the code to format a number with commas using C++/MFC in Windows.

 
 
// nFracDigits = -1 : use no. of frac. digits from string
CString FormatNumberWithCommas(LPCTSTR lpszNumber, int nFracDigits)
{
 
 
	CString str = lpszNumber;
 
	int nSize = (int(_tcslen(lpszNumber)) * 3) + 100;
	_TCHAR *pszFormattedNumber = new _TCHAR [nSize];
 
 
	int dp = nFracDigits;
	if (dp == -1)
	{
		// set number of fractional digits from input string
		CString strDecSep = m_nf.lpDecimalSep;
		dp = str.Find(m_nf.lpDecimalSep);
		dp = (dp == -1) ? 0 : str.GetLength() - dp - strDecSep.GetLength();
	}
	//updated every time depending on nFracDigits
	m_nf.NumDigits = dp;
 
	if (GetNumberFormat(LOCALE_USER_DEFAULT, 
						0, 
						lpszNumber, 
						&m_nf, 
						pszFormattedNumber, 
						nSize-1))
	{
		str = pszFormattedNumber;
	}
 
	if (pszFormattedNumber)
		delete [] pszFormattedNumber;
 
	return str;
}


Launch website link url asynchronously in Windows using C++/MFC



Almost all programs require to launch a website url. One way to do this is using ShellExecute Windows API. But this method hangs the current GUI thread for few seconds, causing annoyance. So another better way is to launch the url is separate thread.

Here is the code to launch the web page asynchronously using C++/MFC in Windows.

 
 
	UINT GotoURLThread( LPVOID pData)
	{
		CWaitCursor curWait;
 
		if (pData == NULL) return 0;
 
		if ( long(ShellExecute(NULL, _T("open"), LPCTSTR(pData), NULL,NULL, SW_SHOWNORMAL)) <= 32) 
		{
			//do nothing
			//mostly it will succeed
 
		}
 
		//we allocated it in GotoURL
		delete pData;
 
		return 0;
	}
 
 
	//why do we create a thread
	//shell execute many times is slow
	//it takes few seconds. So the UI
	//hangs for some time. To avoid
	//this we create a thread
	BOOL GotoURL(LPCTSTR url, BOOL bAsync /*= TRUE*/)
	{
		CWaitCursor curWait;
 
		//if we are dealing with FILE:// URL then we must launch
		//directly since we we launch it from a thread, we see some crash
		//and first chance exception (infinitely).
		//If it is not FILE:// then we launch it from notes browser
 
		//If we are lunching it synchronously then we must use ShellExecute
		//otherwise we will launch it in a separate thread
 
		//Why would we want to launch it synchronously?
		//Sometimes we might want to launch a url while
		//exiting a program, at that time, spawning another
		//thread will not work
 
		CString strUrl = url;
		if ( (!bAsync) || 
			(strUrl.Left(5).CompareNoCase(_T("FILE:")) == 0) )
		{
			if ( long(ShellExecute(NULL, _T("open"), LPCTSTR(url), NULL,NULL, SW_SHOWNORMAL)) <= 32)
			{
				return FALSE;
			}
 
		}else
		{
			LPTSTR pAllocatedURL = NULL;
 
			if (_tcslen(url) == 0) return FALSE;
 
			INT_PTR iLen = _tcslen(url)+1;
 
			pAllocatedURL = new TCHAR[iLen];
			ZeroMemory(pAllocatedURL, iLen*sizeof(TCHAR));
			_tcscpy_s(pAllocatedURL,iLen, url);
 
			//pAllocatedURL will be dellocated in the thread
			AfxBeginThread(GotoURLThread, pAllocatedURL);
 
		}
		return TRUE;
	}
 
 
	BOOL GotoURL(UINT iStringId, BOOL bAsync /*= TRUE*/)
	{
		CString strUrl;
		strUrl.LoadString(iStringId);
		return GotoURL(strUrl, bAsync);
	}


Create HDROP from list of file paths in Windows using C++/MFC/ATL



When dragging and dropping files in Windows, you need the HDROP object with list of files. Also, when copying files to clipboard, you would need HDROP object.

The following code lets you quickly create HDROP from list of file paths in Windows using C++/MFC/ATL.

 
//Creates a HDROP memory block as HGLOBAL
HGLOBAL CreateHDROPFromPaths(CAtlArray<CString> & arrPaths)
{
	DROPFILES *pDropFiles = NULL;
	INT_PTR i, iSize;
	CString strUrl;
	TCHAR*  pszBuff;
	DWORD dwSize = 0;
	HGLOBAL hGlobalDrop = NULL;
 
	try
	{
 
		iSize = arrPaths.GetCount();
		for(i=0;i<iSize;i++)
		{			
			// including the NULL character
			dwSize += arrPaths[i].GetLength()+sizeof(TCHAR);
		}
 
		// for the last NULL character
		dwSize = sizeof(DROPFILES) + sizeof(TCHAR) * (dwSize + 1);;
 
 
		// Allocate memory from the heap for the DROPFILES struct.
		hGlobalDrop = GlobalAlloc ( GHND | GMEM_SHARE, dwSize );
 
		if ( NULL == hGlobalDrop )
			return FALSE;
 
		pDropFiles = (DROPFILES*) GlobalLock ( hGlobalDrop );
 
		if ( NULL == pDropFiles )
		{
			GlobalFree ( hGlobalDrop );
			return FALSE;
		}
 
		// Fill in the DROPFILES struct.
 
		pDropFiles->pFiles = sizeof(DROPFILES);
		#ifdef _UNICODE
			// If we're compiling for Unicode, set the Unicode flag in the struct to
			// indicate it contains Unicode strings.
			pDropFiles->fWide = TRUE;
		#endif
 
		pszBuff = (TCHAR*) (LPBYTE(pDropFiles) + sizeof(DROPFILES));
 
		for(i=0;i<iSize;i++)
		{
			lstrcpy ( pszBuff, (LPCTSTR) arrPaths[i] );
			pszBuff = 1 + _tcschr ( pszBuff, '\0' );
		}
 
		GlobalUnlock ( hGlobalDrop );
 
 
	}catch(int iErr)
	{
		iErr = -1;
		return NULL;
	}
 
	return hGlobalDrop;
}


Check if the current operation system is 64 bit in Windows (C++/MFC)



Following is the code to determine if the current OS is 64 bit or not, in Windows using C++/MFC.

 
BOOL IsRunning64BitOperatingSystem()
{
        SYSTEM_INFO systemInfo;
        GetNativeSystemInfo(&systemInfo);
 
	return ( (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
		|| (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) ) ? TRUE : FALSE;
}


Get Hotkey display string from hotkey in Windows using C++/MFC



If you program allows configuring system level hotkeys for different features, then you may have discovered the need to display the string for the exact hotkey configured. Example: If the user configures Ctrl+Shift+B for a feature then you may want to show the text Ctrl+Shift+B in your popup menu or any other UI of your program.

A hotkey is configured using 2 parts. Modifier and Virtual Key. Modifier tells whether it is Ctrl, Shift, Alt etc key. Virtual key tells exactly which key (A..Z, 0..9 etc) is pressed along with the modifier.

In the below code, we use the CHotkeyCtrl MFC control to get the hotkey display string.

 
	CString GetHotkeyStringFromHotkey( CWnd *pParent, WORD wModifiers,  WORD wVirtualKey)
	{
		CString strHotkeyString;
		CString strWindowsKeyText;
 
		strWindowsKeyText.LoadString(IDS_HOTKEY_WINKEY);
 
		// dummy control
		CHotKeyCtrl objHotKeyCtrl;
		WORD wModifiersTemp = 0;
 
		objHotKeyCtrl.Create(0,CRect(0,0,0,0),pParent,100);
 
		//we remove the Extended key modifier otherwise
		//SetHotKey will not work properly
		wModifiersTemp = wModifiers;
		if (wModifiers & HOTKEYF_EXT)
		{
			wModifiersTemp &= ~HOTKEYF_EXT;
		}
		objHotKeyCtrl.SetHotKey(wVirtualKey,wModifiersTemp);
		strHotkeyString = objHotKeyCtrl.GetHotKeyName();
 
		if (strHotkeyString.IsEmpty())
		{
			//do nothing, return empty string
		}else
		{
			if (wModifiers & HOTKEYF_EXT)
			{
				strHotkeyString = _T("+") + strHotkeyString;
				strHotkeyString = strWindowsKeyText + strHotkeyString;
			}
		}
 
		objHotKeyCtrl.DestroyWindow();
 
		//finally remove any spaces because hotkey control adds spaces in between like Ctrl + Shift. We want to make it Ctrl+Shift
		strHotkeyString.Remove(_T(' '));
 
		return strHotkeyString;
 
	}


Generate new file name when a file with same name already exists in Windows (C++/MFC)



Sometimes, when you wish you create a new file or copy another file to a folder, a file with the same name may already exists. At this time, you wish to decide whether to replace existing file with duplicate name or save it in a new name.

The following code generates a new name adding (1), (2), (3) number just like how Windows OS does. We use C++/MFC for this purpose.

 
//example if we are copying New Text Document.txt to the same folder
//then the new file will become New Text Document (1).txt
//try for 50 times
CString GenerateDuplicateFileName(CString & strFilePath)
{
	const int iMaxTrial = 50;
	int i = 0;
	CString strNewFilePath;
	CString strNumber;
	CString strExtension;
	BOOL bFolder = FALSE;
 
	//since strFilePath can be folder path also
	//with backslash, we will check if there is any trailing
	//backslash. if so we will consider that as extension
	//so that backslash is again suffixed at the end
 
	if (strFilePath.Right(1) == _T("\\"))
	{
		strFilePath.TrimRight(_T('\\'));
		strExtension = _T("\\");
		bFolder = TRUE;
	}else
	{
		//save the extension
		strExtension = PathFindExtension(strFilePath);
	}
 
	for(i=0;i<iMaxTrial;i++)
	{
		strNumber.Format(_T(" (%d)"), i+1);
		strNewFilePath = strFilePath;
 
		if (!bFolder)
		{
			//remove the extension
			PathRemoveExtension(strNewFilePath.GetBufferSetLength(MEDIUM_TEXT_LENGTH));
			strNewFilePath.ReleaseBuffer();
		}
 
		strNewFilePath += strNumber;
		strNewFilePath += strExtension;
 
		if (!PathFileExists(strNewFilePath))
		{
			break;
		}
	}
 
	return strNewFilePath;
 
}


Get current logged in user display name in Windows using C++/MFC



As the title says, the following code gets logged in user display name in Windows using C++/MFC.

 
//eg: John Smith
CString GetCurrentUserDisplayName()
{
	ULONG size = 1024;
	TCHAR tszUserName[1024];
 
	GetUserNameEx(NameDisplay, tszUserName, &size);
 
	return CString(tszUserName);
 
}


Register a file extension with the current program (process) in Windows using C++/MFC



Here is how to associate a file extension with the current program (process) in Windows using C++/MFC. In addition, you can provide additional command line parameters so that the program receives it when the related file is opened.

 
void SaveStringToRegistry(HKEY hKey, CString szSubkey,CString szValueName,CString szData)
{
	HKEY retKey;
 
	CString szFull = szSubkey;
 
    LONG retval = RegCreateKey(hKey,szFull, &retKey);
 
	if (retval == ERROR_SUCCESS) 
	{
		RegSetValueEx(retKey,szValueName,0, REG_SZ,(const BYTE *)LPCTSTR(szData),(szData.GetLength()+1)*sizeof(TCHAR));
		RegCloseKey(retKey);
	}	 
}
 
void RegisterFileExtension(CString name, CString description, CString extension, CString additionalCommandLineParameters)
{
	CString strAppExe = GetAppExePath();
 
	CString strCommandLine;
	CString strSubKey;
 
	SaveStringToRegistry(HKEY_CLASSES_ROOT, extension, _T(""), name);
 
	SaveStringToRegistry(HKEY_CLASSES_ROOT, name, _T(""), description);
 
	strCommandLine.Format(_T("\"%s\" %s \"%%1\""), strAppExe, additionalCommandLineParameters);
 
	strSubKey.Format(_T("%s\\shell\\Open\\Command"), name);
 
	SaveStringToRegistry(HKEY_CLASSES_ROOT, strSubKey, _T(""), strCommandLine);
 
}