This article is about the IntelliFile application which is a free alternative Windows version to Total Commander and uses many components that have been published on CodeProject.

Feature List
The application is free as in free speech/free beer, and the final version will have the following features:
- File handling
- Extended copying, moving, renaming and deleting of entire trees
- Compare files by content, with built-in text editor
- Encode/Decode files in UUE, XXE and MIME format
- Show/select files with specific search pattern, size, date or contents
- Enhanced search function with full text search in any files across multiple drives, even inside archives
- Supports Drag & Drop with Explorer/the Desktop
- FTP client
- Built-in FTP client supports most public FTP servers
- Secure FTP over SSL/TLS, enter the URL as follows: ftps://ftp.servername.com
- Download in the background (separate thread)
- Archive handling
- Archives are handled like subdirectories. You can easily copy files to and from archives.
- Built-in ZIP-compatible packer, supports long filenames! This packer is based on ZLIB by Info-Zip.
- Pack archives in the background (separate thread).
For now, only the basic file operations are implemented: edit, copy, move, rename, and delete!
The Architecture
Each file definition is contained in a CFileData
class, with the following interface:
DWORD GetFileAttributes();
- returns file's attributes void SetFileAttributes(DWORD dwFileAttributes);
- sets file's attributes COleDateTime GetCreationTime();
- return file's creation date/time void SetCreationTime(COleDateTime ftCreationTime);
- sets file's creation date/time COleDateTime GetLastAccessTime();
- return file's last read date/time void SetLastAccessTime(COleDateTime ftLastAccessTime);
- sets file's last read date/time COleDateTime GetLastWriteTime();
- returns file's last write date/time void SetLastWriteTime(COleDateTime ftLastWriteTime);
- sets file's last write date/time ULONGLONG GetFileSize();
- returns file's size void SetFileSize(ULONGLONG nFileSize);
- sets file's size CString GetFileName();
- returns file's name void SetFileName(CString strFileName);
- sets file's name CString GetAlternate();
- returns file's alternate name void SetAlternate(CString strAlternateFileName);
- sets file's alternate name
Then, we define CFileList
as typedef CArray<cfiledata*> CFileList;
This list is managed inside the CFileSystem
class, with the following interface:
BOOL RemoveAll();
- removes all files from list int GetSize();
- returns the count of files in list CFileData* GetAt(int nIndex);
- returns a file definition from list int GetSystemType();
- returns file system type (FAT, FTP, ZIP) void SetSystemType(int nSystemType);
- sets file system type (FAT, FTP, ZIP) CString GetFolder();
- returns current folder path BOOL SetFolder(CString strFolder);
- sets current folder path BOOL Refresh();
- updates the file definitions from list BOOL ViewFile(CString strFilePath);
- allows viewing the selected file BOOL EditFile(CString strFilePath);
- allows editing the selected file BOOL CopyFile(CFileSystem* pDestination, CFileList* arrSelection);
- copies the selected files and folders BOOL MoveFile(CFileSystem* pDestination, CFileList* arrSelection);
- moves the selected files and folders BOOL NewFolder(CFileSystem* pDestination, CFileList* arrSelection);
- creates a new folder BOOL DeleteFile(CFileSystem* pDestination, CFileList* arrSelection);
- deletes the selected files and folders
How to Edit Files in Windows?
BOOL CFileSystem::EditFile(CString strFilePath)
{
const int nDot = strFilePath.ReverseFind(_T('.'));
if ((nDot != -1) && !IsApplication(strFilePath))
{
CString strExtension = strFilePath.Mid(nDot);
CString strApplication;
TCHAR lpszBuffer[0x1000] = { 0 };
DWORD cbLength = sizeof(lpszBuffer);
if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_COMMAND,
strExtension, _T("open"), lpszBuffer, &cbLength)))
{
lpszBuffer[cbLength] = 0;
strApplication = lpszBuffer;
}
if (strApplication.IsEmpty())
{
MessageBox(m_hWndParent, _T("There is no application associated with
this type of file."), _T("IntelliFile"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (strApplication.Find(_T("%1")) != -1)
{
strApplication.Replace(_T("\"%1\""), (_T("\"") + strFilePath + _T("\"")));
strApplication.Replace(_T("%1"), (_T("\"") + strFilePath + _T("\"")));
}
else
{
strApplication += _T(" ") + (_T("\"") + strFilePath + _T("\""));
}
CString strExe;
CString strParam;
if (strApplication.Find(_T("rundll32.exe")) != -1)
{
if ((int) ShellExecute(m_hWndParent, _T("open"),
strFilePath, NULL, NULL, SW_SHOWNORMAL) <= 32)
{
DisplayErrorBox(m_wndCaptionBar, _T("ShellExecute"), GetLastError());
return FALSE;
}
}
else
{
if (strApplication[0] == _T('"'))
{
int nPos = strApplication.Find('"', 1);
if (nPos != -1)
{
strExe = strApplication.Left(nPos+1);
strParam = strApplication.Mid(nPos+1);
}
else
{
ASSERT(0);
}
}
else
{
int nPos = strApplication.Find(' ', 1);
if (nPos != -1)
{
strExe = strApplication.Left(nPos+1);
strParam = strApplication.Mid(nPos+1);
}
else
{
ASSERT(0);
}
}
strExe.Trim(_T(" \r\n\t"));
strParam.Trim(_T(" \r\n\t"));
SHELLEXECUTEINFO pShellExecuteInfo;
pShellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
pShellExecuteInfo.fMask = SEE_MASK_FLAG_DDEWAIT |
SEE_MASK_NOCLOSEPROCESS | SEE_MASK_DOENVSUBST;
pShellExecuteInfo.hwnd = m_hWndParent;
pShellExecuteInfo.lpVerb = NULL;
pShellExecuteInfo.lpFile = (LPCWSTR)(strExe);
pShellExecuteInfo.lpParameters = (LPCWSTR)(strParam);
pShellExecuteInfo.lpDirectory = NULL;
pShellExecuteInfo.nShow = SW_SHOWNORMAL;
if (!ShellExecuteEx(&pShellExecuteInfo))
{
DisplayErrorBox(m_wndCaptionBar, _T("ShellExecute"), GetLastError());
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
How to Copy Files in Windows?
BOOL CFileSystem::CopyFile(CFileSystem* pDestination, CFileList* arrSelection)
{
HRESULT hResult = S_OK;
if ((pDestination != NULL) && (arrSelection != NULL))
{
IFileOperation* pFileOperation = NULL;
if (SUCCEEDED(hResult = CoCreateInstance(CLSID_FileOperation,
NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation))))
{
if (SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent)))
{
if (SUCCEEDED(hResult = pFileOperation->SetOperationFlags(
FOF_NOCONFIRMMKDIR |
FOF_NOERRORUI |
FOFX_SHOWELEVATIONPROMPT)))
{
CString strDestination = pDestination->GetFolder();
IShellItem* pFolderItem = NULL;
if (SUCCEEDED(hResult = SHCreateItemFromParsingName
(strDestination, NULL, IID_PPV_ARGS(&pFolderItem))))
{
if (arrSelection->GetCount() == 1)
{
CFileData* pFileData = arrSelection->GetAt(0);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
IShellItem* pShellItem = NULL;
if (SUCCEEDED(hResult = SHCreateItemFromParsingName
(strFilePath, NULL, IID_PPV_ARGS(&pShellItem))))
{
if (SUCCEEDED(hResult = pFileOperation->CopyItem
(pShellItem, pFolderItem, NULL, NULL)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->CopyItem"), hResult);
pShellItem->Release();
pFolderItem->Release();
pFileOperation->Release();
return FALSE;
}
pShellItem->Release();
pShellItem = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateItemFromParsingName"), hResult);
pFolderItem->Release();
pFileOperation->Release();
return FALSE;
}
}
else
{
const int nCount = (int)arrSelection->GetCount();
LPCITEMIDLIST* arrItemIDList = new LPCITEMIDLIST[nCount];
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
CFileData* pFileData = arrSelection->GetAt(nIndex);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
IShellItemArray* pShellItemArray = NULL;
if (SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists
(nCount, arrItemIDList, &pShellItemArray)))
{
if (SUCCEEDED(hResult = pFileOperation->CopyItems
(pShellItemArray, pFolderItem)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->CopyItems"), hResult);
pShellItemArray->Release();
pFolderItem->Release();
pFileOperation->Release();
delete arrItemIDList;
return FALSE;
}
pShellItemArray->Release();
pShellItemArray = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateShellItemArrayFromIDLists"), hResult);
pFileOperation->Release();
pFolderItem->Release();
delete arrItemIDList;
return FALSE;
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST) arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = NULL;
}
pFolderItem->Release();
pFolderItem = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateItemFromParsingName"), hResult);
pFileOperation->Release();
return FALSE;
}
if (SUCCEEDED(hResult = pFileOperation->PerformOperations()))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->PerformOperations"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOperationFlags"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOwnerWindow"), hResult);
pFileOperation->Release();
return FALSE;
}
pFileOperation->Release();
pFileOperation = NULL;
return TRUE;
}
else
{
OutputDebugString(_T("CoCreateInstance(IFileOperation) failed!\n"));
}
}
return FALSE;
}
How to Move/Rename Files in Windows?
BOOL CFileSystem::MoveFile(CFileSystem* pDestination, CFileList* arrSelection)
{
HRESULT hResult = S_OK;
if ((pDestination != NULL) && (arrSelection != NULL))
{
IFileOperation* pFileOperation = NULL;
if (SUCCEEDED(hResult = CoCreateInstance
(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation))))
{
if (SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent)))
{
if (SUCCEEDED(hResult = pFileOperation->SetOperationFlags(
FOF_NOCONFIRMMKDIR |
FOF_NOERRORUI |
FOFX_SHOWELEVATIONPROMPT)))
{
CString strDestination = pDestination->GetFolder();
IShellItem* pFolderItem = NULL;
if (SUCCEEDED(hResult = SHCreateItemFromParsingName
(strDestination, NULL, IID_PPV_ARGS(&pFolderItem))))
{
if (arrSelection->GetCount() == 1)
{
CFileData* pFileData = arrSelection->GetAt(0);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
IShellItem* pShellItem = NULL;
if (SUCCEEDED(hResult = SHCreateItemFromParsingName
(strFilePath, NULL, IID_PPV_ARGS(&pShellItem))))
{
if (SUCCEEDED(hResult = pFileOperation->MoveItem
(pShellItem, pFolderItem, NULL, NULL)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->MoveItem"), hResult);
pShellItem->Release();
pFolderItem->Release();
pFileOperation->Release();
return FALSE;
}
pShellItem->Release();
pShellItem = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateItemFromParsingName"), hResult);
pFolderItem->Release();
pFileOperation->Release();
return FALSE;
}
}
else
{
const int nCount = (int)arrSelection->GetCount();
LPCITEMIDLIST* arrItemIDList = new LPCITEMIDLIST[nCount];
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
CFileData* pFileData = arrSelection->GetAt(nIndex);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
IShellItemArray* pShellItemArray = NULL;
if (SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists
(nCount, arrItemIDList, &pShellItemArray)))
{
if (SUCCEEDED(hResult = pFileOperation->MoveItems
(pShellItemArray, pFolderItem)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->MoveItems"), hResult);
pShellItemArray->Release();
pFolderItem->Release();
pFileOperation->Release();
delete arrItemIDList;
return FALSE;
}
pShellItemArray->Release();
pShellItemArray = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateShellItemArrayFromIDLists"), hResult);
pFileOperation->Release();
pFolderItem->Release();
delete arrItemIDList;
return FALSE;
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST) arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = NULL;
}
pFolderItem->Release();
pFolderItem = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateItemFromParsingName"), hResult);
pFileOperation->Release();
return FALSE;
}
if (SUCCEEDED(hResult = pFileOperation->PerformOperations()))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->PerformOperations"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOperationFlags"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOwnerWindow"), hResult);
pFileOperation->Release();
return FALSE;
}
pFileOperation->Release();
pFileOperation = NULL;
return TRUE;
}
else
{
OutputDebugString(_T("CoCreateInstance(IFileOperation) failed!\n"));
}
}
return FALSE;
}
How to Delete Files in Windows?
BOOL CFileSystem::DeleteFile(CFileSystem* pDestination, CFileList* arrSelection)
{
HRESULT hResult = S_OK;
if ((pDestination != NULL) && (arrSelection != NULL))
{
IFileOperation* pFileOperation = NULL;
if (SUCCEEDED(hResult = CoCreateInstance
(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation))))
{
if (SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent)))
{
if (SUCCEEDED(hResult = pFileOperation->SetOperationFlags(
FOF_NOCONFIRMMKDIR |
FOF_NOERRORUI |
FOFX_SHOWELEVATIONPROMPT)))
{
if (arrSelection->GetCount() == 1)
{
CFileData* pFileData = arrSelection->GetAt(0);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
IShellItem* pShellItem = NULL;
if (SUCCEEDED(hResult = SHCreateItemFromParsingName
(strFilePath, NULL, IID_PPV_ARGS(&pShellItem))))
{
if (SUCCEEDED(hResult = pFileOperation->DeleteItem
(pShellItem, NULL)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->DeleteItem"), hResult);
pShellItem->Release();
pFileOperation->Release();
return FALSE;
}
pShellItem->Release();
pShellItem = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateItemFromParsingName"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
const int nCount = (int)arrSelection->GetCount();
LPCITEMIDLIST* arrItemIDList = new LPCITEMIDLIST[nCount];
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
CFileData* pFileData = arrSelection->GetAt(nIndex);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
IShellItemArray* pShellItemArray = NULL;
if (SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists
(nCount, arrItemIDList, &pShellItemArray)))
{
if (SUCCEEDED(hResult = pFileOperation->DeleteItems
(pShellItemArray)))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->DeleteItems"), hResult);
pShellItemArray->Release();
pFileOperation->Release();
delete arrItemIDList;
return FALSE;
}
pShellItemArray->Release();
pShellItemArray = NULL;
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("SHCreateShellItemArrayFromIDLists"), hResult);
pFileOperation->Release();
delete arrItemIDList;
return FALSE;
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST) arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = NULL;
}
if (SUCCEEDED(hResult = pFileOperation->PerformOperations()))
{
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->PerformOperations"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOperationFlags"), hResult);
pFileOperation->Release();
return FALSE;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar,
_T("pFileOperation->SetOwnerWindow"), hResult);
pFileOperation->Release();
return FALSE;
}
pFileOperation->Release();
pFileOperation = NULL;
return TRUE;
}
else
{
OutputDebugString(_T("CoCreateInstance(IFileOperation) failed!\n"));
}
}
return FALSE;
}
Final Words
IntelliFile application uses many components that have been published on CodeProject. Many thanks to:
- My
CMFCListView
form view (see source code) - Mizan Rahman for his
CWndResizer
class - PJ Naughter for his
CInstanceChecker
class - PJ Naughter for his
CVersionInfo
class
History
- Version 1.01 (13th May, 2022) - Initial release.
- Version 1.02 (20th May, 2022) - Implemented "New folder" functionality.
- Version 1.03 (23rd May, 2022) - Implemented "Change drive" functionality.
- Version 1.04 (24th May, 2022) - Implemented "View text file" functionality.