
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 base64 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!
Some of the above features are still under development!
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)
{
bool bRetVal = false;
HRESULT hResult = S_OK;
IFileOperation* pFileOperation = nullptr;
IShellItem* pFolderItem = nullptr;
IShellItem* pShellItem = nullptr;
IShellItemArray* pShellItemArray = nullptr;
CString strDestination = pDestination->GetCurrentFolder();
ASSERT(pDestination != nullptr);
ASSERT(arrSelection != nullptr);
if ((SUCCEEDED(hResult = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation)))) &&
(SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent))) &&
(SUCCEEDED(hResult = pFileOperation->SetOperationFlags(FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOFX_SHOWELEVATIONPROMPT))) &&
(SUCCEEDED(hResult = SHCreateItemFromParsingName(strDestination, nullptr, IID_PPV_ARGS(&pFolderItem)))))
{
if (arrSelection->GetCount() == 1)
{
CFileData* pFileData = arrSelection->GetAt(0);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
if ((SUCCEEDED(hResult = SHCreateItemFromParsingName(strFilePath, nullptr, IID_PPV_ARGS(&pShellItem)))) &&
(SUCCEEDED(hResult = pFileOperation->CopyItem(pShellItem, pFolderItem, nullptr, nullptr))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::CopyFile"), hResult);
}
}
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 = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
if ((SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists(nCount, arrItemIDList, &pShellItemArray))) &&
(SUCCEEDED(hResult = pFileOperation->CopyItems(pShellItemArray, pFolderItem))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::CopyFile"), hResult);
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST)arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = nullptr;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::CopyFile"), hResult);
}
if (pShellItemArray != nullptr)
{
pShellItemArray->Release();
pShellItemArray = nullptr;
}
if (pShellItem != nullptr)
{
pShellItem->Release();
pShellItem = nullptr;
}
if (pFolderItem != nullptr)
{
pFolderItem->Release();
pFolderItem = nullptr;
}
if (pFileOperation != nullptr)
{
pFileOperation->Release();
pFileOperation = nullptr;
}
return bRetVal;
}
How to Move/Rename Files in Windows?
bool CFileSystem::MoveFile(CFileSystem* pDestination, CFileList* arrSelection)
{
bool bRetVal = false;
HRESULT hResult = S_OK;
IFileOperation* pFileOperation = nullptr;
IShellItem* pFolderItem = nullptr;
IShellItem* pShellItem = nullptr;
IShellItemArray* pShellItemArray = nullptr;
CString strDestination = pDestination->GetCurrentFolder();
ASSERT(pDestination != nullptr);
ASSERT(arrSelection != nullptr);
if ((SUCCEEDED(hResult = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation)))) &&
(SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent))) &&
(SUCCEEDED(hResult = pFileOperation->SetOperationFlags(FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOFX_SHOWELEVATIONPROMPT))) &&
(SUCCEEDED(hResult = SHCreateItemFromParsingName(strDestination, nullptr, IID_PPV_ARGS(&pFolderItem)))))
{
if (arrSelection->GetCount() == 1)
{
CFileData* pFileData = arrSelection->GetAt(0);
ASSERT_VALID(pFileData);
CString strFileName = pFileData->GetFileName();
CString strFolder = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
if ((SUCCEEDED(hResult = SHCreateItemFromParsingName(strFilePath, nullptr, IID_PPV_ARGS(&pShellItem)))) &&
(SUCCEEDED(hResult = pFileOperation->MoveItem(pShellItem, pFolderItem, nullptr, nullptr))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::MoveFile"), hResult);
}
}
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 = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
if ((SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists(nCount, arrItemIDList, &pShellItemArray))) &&
(SUCCEEDED(hResult = pFileOperation->MoveItems(pShellItemArray, pFolderItem))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::MoveFile"), hResult);
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST)arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = nullptr;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::MoveFile"), hResult);
}
if (pShellItemArray != nullptr)
{
pShellItemArray->Release();
pShellItemArray = nullptr;
}
if (pShellItem != nullptr)
{
pShellItem->Release();
pShellItem = nullptr;
}
if (pFolderItem != nullptr)
{
pFolderItem->Release();
pFolderItem = nullptr;
}
if (pFileOperation != nullptr)
{
pFileOperation->Release();
pFileOperation = nullptr;
}
return bRetVal;
}
How to Delete Files in Windows?
bool CFileSystem::DeleteFile(CFileSystem* pDestination, CFileList* arrSelection)
{
bool bRetVal = false;
HRESULT hResult = S_OK;
IFileOperation* pFileOperation = nullptr;
IShellItem* pShellItem = nullptr;
IShellItemArray* pShellItemArray = nullptr;
CString strDestination = pDestination->GetCurrentFolder();
ASSERT(pDestination != nullptr);
ASSERT(arrSelection != nullptr);
if ((SUCCEEDED(hResult = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation)))) &&
(SUCCEEDED(hResult = pFileOperation->SetOwnerWindow(m_hWndParent))) &&
(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 = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
if ((SUCCEEDED(hResult = SHCreateItemFromParsingName(strFilePath, nullptr, IID_PPV_ARGS(&pShellItem)))) &&
(SUCCEEDED(hResult = pFileOperation->DeleteItem(pShellItem, nullptr))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::DeleteFile"), hResult);
}
}
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 = GetCurrentFolder();
CString strFilePath = strFolder + strFileName;
arrItemIDList[nIndex] = ILCreateFromPath(strFilePath);
}
if ((SUCCEEDED(hResult = SHCreateShellItemArrayFromIDLists(nCount, arrItemIDList, &pShellItemArray))) &&
(SUCCEEDED(hResult = pFileOperation->DeleteItems(pShellItemArray))) &&
(SUCCEEDED(hResult = pFileOperation->PerformOperations())))
{
bRetVal = true;
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::DeleteFile"), hResult);
}
for (int nIndex = 0; nIndex < nCount; nIndex++)
{
ILFree((LPITEMIDLIST)arrItemIDList[nIndex]);
}
delete arrItemIDList;
arrItemIDList = nullptr;
}
}
else
{
DisplayErrorBox(m_wndCaptionBar, _T("CFileSystem::DeleteFile"), hResult);
}
if (pShellItemArray != nullptr)
{
pShellItemArray->Release();
pShellItemArray = nullptr;
}
if (pShellItem != nullptr)
{
pShellItem->Release();
pShellItem = nullptr;
}
if (pFileOperation != nullptr)
{
pFileOperation->Release();
pFileOperation = nullptr;
}
return bRetVal;
}
Final Words
IntelliFile application uses many components that have been published on CodeProject. Many thanks to:
- My
CMFCListView
form view (see source code) - Armen Hakobyan for his
CFolderDialog
class - Paul DiLascia for his
CHtmlCtrl
class - PJ Naughter for his
CInstanceChecker
class - PJ Naughter for his
CVersionInfo
class - Mizan Rahman for his
CWndResizer
class
History
- Version 1.01 (May 13th, 2022) - Initial release.
- Version 1.02 (May 20th, 2022) - Implemented "New folder" functionality.
- Version 1.03 (May 23rd, 2022) - Implemented "Change drive" functionality.
- Version 1.04 (May 24th, 2022) - Implemented "View text file" functionality.
- Version 1.05 (May 27th, 2022):
- Implemented "View RTF file" functionality;
- Implemented "View XML file" functionality;
- Implemented "Context menu" functionality.
- Version 1.06 (August 21st, 2022) - Added "Change drive..." icon.
- Version 1.07 (September 9th, 2022) - Added Contributors hyperlink to AboutBox dialog.
- Version 1.08 (January 23rd, 2023) - Updated PJ Naughter's
CVersionInfo
library to the latest version available. - Version 1.09 (January 24rd, 2023) - Updated PJ Naughter's
CInstanceChecker
library to the latest version available. - Replaced
NULL
throughout the codebase with nullptr
.
Replaced BOOL
throughout the codebase with bool
.
This means that the minimum requirement for the application is now Microsoft Visual C++ 2010. - Version 1.10 (April 25th, 2023) - Added base64 encode/decode functions.
- Version 1.11 (May 13th, 2023) - Added new changes suggested by Rick Dishman: Reset View, and save last folder.
- Version 1.12 (May 15th, 2023) - Added rename of file name on clicking its label in MFC ListView.
- Version 1.13 (May 18th, 2023) - Fixed an issue regarding editing image files reported by Rick Dishman.
- Version 1.14 (May 19th, 2023) - Fixed an issue regarding statusbar reported by Rick Dishman.
- Version 1.15 (May 21st, 2023) - Changed the double click implementation to open a file in EDIT mode.
- Version 1.16 (May 27th, 2023) - Updated About dialog with GPLv3 notice.
- Version 1.17 (June 17th, 2023) - Added quick access dialog for favorite folders.
- Version 1.18 (June 25th, 2023):
- Implemented "Command prompt" functionality;
- Replaced old
CHyperlinkStatic
class with PJ Naughter's CHLinkCtrl
library.
- Version 1.19 (August 17th, 2023):
- Implemented "Switch views" functionality (Switches source view with target view);
- Added social media links: Twitter, LinkedIn, Facebook, and Instagram;
- Added shortcuts to GitHub repository's Issues, Discussions, and Wiki.
- Version 1.20 (August 26th, 2023):
- Refactored CopyFile, MoveFile and DeleteFile functions.
- Changed article's download link. Updated the About dialog (email & website).
- Version 1.21 (September 22nd, 2023): Switched to Visual Studio Enterprise 2022 (some changes were made in source code of the project).
- Version 1.22 (September 30th, 2023): Added SCINTILLA control to view source code with syntax highlighting.
My professional background includes knowledge of analyst programmer for Microsoft Visual C++, Microsoft Visual C#, Microsoft Visual Basic, Sun Java, assembly for Intel 80x86 microprocessors, assembly for PIC microcontrollers (produced by Microchip Inc.), relational databases (MySQL, Oracle, SQL Server), concurrent version systems, bug tracking systems, web design (HTML5, CSS3, XML, PHP/MySQL, JavaScript).