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
Updated the code to use C++ uniform initialization for all variable declarations
- Version 1.09 (January 24rd, 2023): Updated PJ Naughter's
CInstanceChecker
library to the latest version available
Updated the code to use C++ uniform initialization for all variable declarations
- 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 the source code of the project)
- Version 1.22 (September 30th, 2023): Added SCINTILLA control to view source code with syntax highlighting
- Version 1.23 (December 10th, 2023): Updated PJ Naughter's
CScintillaCtrl
library to the latest version available
Removed the SetCallDirect
& GetCallDirect
methods. Instead, now the CScintillaCtrl
class will call the m_DirectStatusFunction
if the calling thread is the same as the thread on which the Scintilla control was created. Thanks to Markus Nissl for this update.
- Version 1.24 (December 29th, 2023): Updated PJ Naughter's
CScintillaCtrl
library to the latest version available
Updated class to work with Scintilla v5.4.1. New messages wrapped include: SCI_CHANGESELECTIONMODE
, SCI_SETMOVEEXTENDSSELECTION
& SCI_SELECTIONFROMPOINT
. Also updated the signatures of the following methods: GetDocPointer
, SetDocPointer
, CreateDocument
, AddRefDocument
and ReleaseDocument
.
- Version 1.25 (January 28th, 2024):
- Added ReleaseNotes.html and SoftwareContentRegister.html to GitHub repo
- Replaced old
CFileDialogST
class with Armen Hakobyan's CFolderDialog
library
- Version 1.26 (February 21st, 2024): Switched MFC application' theme back to native Windows.
- Version 1.27.1 (March 31st, 2024):
- Updated
LEXILLA
library to version 5.3.1 and SCINTILLA
library to version 5.4.3. - Updated PJ Naughter's
CScintillaCtrl
library to the latest version available.
Updated class to work with Scintilla v5.4.3. New messages wrapped include: SCI_GETUNDOACTIONS
, SCI_GETUNDOSAVEPOINT
, SCI_SETUNDODETACH
, SCI_SETUNDOTENTATIVE
, SCI_SETUNDOCURRENT
, SCI_PUSHUNDOACTIONTYPE
, SCI_CHANGELASTUNDOACTIONTEXT
, SCI_GETUNDOACTIONTYPE
, SCI_GETUNDOACTIONPOSITION
& SCI_GETUNDOACTIONTEXT
.
- Version 1.28 (April 26th, 2024):
- Updated
LEXILLA
library to version 5.3.2 and SCINTILLA
library to version 5.5.0. - Updated PJ Naughter's
CScintillaCtrl
library to the latest version available.
- Version 1.29 (July 21st, 2024):
- Implemented "View text file" functionality for C/C++ programming language.
- Implemented selection of files with specific search pattern, size, date or contents.
- Implemented enhanced search function with full text search & replace.
- Version 1.30 (July 26th, 2024):
- Implemented "View text file" functionality for HTML / CSS / XML / JavaScript.
- Implemented "View text file" functionality for Java programming language.
- Implemented "View text file" functionality for Python programming language.
- Updated
LEXILLA
library to version 5.3.3 and SCINTILLA
library to version 5.5.1. - Updated PJ Naughter's
CScintillaCtrl
library to the latest version available.
Updated class to work with Scintilla v5.5.1. New messages wrapped include: SCI_AUTOCSETSTYLE
, SCI_AUTOCGETSTYLE
& SCI_CUTALLOWLINE
.
- Version 1.31 (August 24th, 2024):
- Updated
LEXILLA
library to version 5.4.0 and SCINTILLA
library to version 5.5.2. - Updated PJ Naughter's
CScintillaCtrl
library to the latest version available.
Updated class to work with Scintilla v5.5.2. New messages wrapped include: SCI_STYLESETSTRETCH
, SCI_STYLEGETSTRETCH
, SCI_GETUNDOSEQUENCE
, SCI_LINEINDENT
, SCI_LINEDEDENT
, SCI_SETCOPYSEPARATOR
& SCI_GETCOPYSEPARATOR
.
- Version 1.32 (September 3rd, 2024):
- Enabled syntax highlighting for the following Programming Languages:
- Bash
- Batch
- CMake
- Groovy
- JavaScript
- JSON
- Makefile
- MATLAB
- R
- Rust
- Implemented User Manual option into Help menu.
- Implemented Check for updates... option into Help menu.
- Version 1.33 (September 14th, 2024): Implemented "View binary file" functionality using Jovibor's HexCtrl library.
- Version 1.34 (October 11th, 2024):
- Fixed access to Google Drive (bug reported by simon mago).
- Fixed access to Favorite Folders (bug reported by markjuggles).
- Fixed a situation when viewing a text file would result in a crash.
- Enabled syntax highlighting for TCL/TK Programming Language.