Open Salamander is a fast and reliable two-panel file manager for Windows.
The original version of Servant Salamander was developed by Petr Šolín during his studies at the Czech Technical University. He released it as freeware in 1997. After graduation, Petr Šolín founded the company Altap in cooperation with Jan Ryšavý. In 2001 they released the first shareware version of the program. In 2007 a new version was renamed to Altap Salamander 2.5. Many other programmers and translators contributed to the project. In 2019, Altap was acquired by Fine. After this acquisition, Altap Salamander 4.0 was released as freeware. In 2023, the project was open sourced under the GPLv2 license as Open Salamander 5.0.
The name Servant Salamander came about when Petr Šolín and his friend Pavel Schreib were brainstorming name for this project. At that time, the well-known file managers were the aging Norton Commander and the rising Windows Commander. They questioned why a file manager should be named Commander, which implied that it commanded instead of served. This thought led to the birth of the name Servant Salamander.
Please bear with us as Salamander was our first major project where we learned to program in C++. From a technology standpoint, it does not use C++ Core Guidelines, smart pointers, RAII, STL, or WIL, all of which were just beginning to evolve during the time Salamander was created. Historically, many comments were written in Czech. However, an active community effort is translating the codebase to English to improve accessibility for international contributors. Salamander is a pure WinAPI application and does not use any frameworks, such as MFC.
We would like to thank Fine company for making the open sourced Salamander release possible.
The 5.0 release marks a transition to open development with several key enhancements:
- UI Modernization: Introduced high-quality SVG icons for toolbars, replacing legacy bitmaps for better scaling on modern displays.
- Performance Breakthroughs:
- Asynchronous Loading: File icons are now loaded using a dedicated thread pool, significantly speeding up directory browsing.
- Optimized I/O: Local-to-local file operations now use a 1MB buffer to minimize system calls and improve throughput.
- Memory Management: Refined memory allocation strategies specifically for Unicode string handling.
- Enhanced Unicode Support: Comprehensive fixes for Unicode handling in window titles, file execution, and viewer outputs, ensuring full compatibility with international filenames.
- Codebase Internationalization: We are systematically translating legacy Czech comments into English (
// CommentsTranslationProject: TRANSLATED) to foster a global contributor community. - Reliability: Addressed critical threading issues, fixed "Access Denied" errors in worker threads, and resolved stability bugs in directory refreshing.
- Windows 11 or newer
- Visual Studio 2022
- Desktop development with C++ workload installed in VS2022
- Windows 11 (10.0.26100.4654) SDK optional component installed in VS2022
-
PowerShell 7.4 or newer
-
Set the
OPENSAL_BUILD_DIRenvironment variable to specify the build directory. Make sure the path has a trailing backslah, e.q.D:\Build\OpenSal\
Solution \src\vcxproj\salamand.sln may be built from within Visual Studio or from the command-line using \src\vcxproj\rebuild.cmd.
Use \src\vcxproj\!populate_build_dir.cmd to populate build directory with files required to run Open Salamander.
Open Salamander uses Inno Setup to create the installer. The installer script is located at Installer\setup.iss.
- Install Inno Setup 6 or later
- Build the solution in Release|x64 configuration
- Stage the files and compile the installer:
# Stage files for the installer
.\tools\prepare_installer.ps1 -BuildDir "build_stage" -StagingDir "Installer_Staging"
# Compile the installer
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "Installer\setup.iss"The installer will be created in Installer\Output\.
The repository includes a GitHub Actions workflow (.github\workflows\build-installer.yml) that automatically:
- Builds the solution using MSBuild
- Stages all required files (executables, plugins, language files, toolbars)
- Installs Inno Setup via Chocolatey
- Compiles the installer with build number versioning
- Creates a GitHub release with the installer attached
The workflow is triggered on pushes to main and produces versioned installers named OpenSalamander_5.0.{build_number}.exe.
Open Salamander uses scalable SVG icons for its toolbars.
- Location:
src\res\toolbars - Format: Standard SVG
- Dimensions: The standard viewbox is 16x16 pixels.
- Process: To add or update an icon, simply place the
.svgfile in thesrc\res\toolbarsdirectory. The build scripts (!populate_build_dir.cmdfor local dev andCreate-Sfx.ps1for installer) will automatically include them.
The execution logging system runs only in DEBUG builds. It records major application execution paths (startup, plugin loading, directory listing, file operations, and key UI features) through the Trace system. The logs are emitted as TRACE messages, so they appear in the Trace Server when it is connected. In release builds, the logging calls are compiled out and produce no output.
This project welcomes contributions to build and enhance Open Salamander!
\convert Conversion tables for the Convert command
\doc Documentation
\help User manual source files
\src Open Salamander core source code
\src\common Shared libraries
\src\common\dep Shared third-party libraries
\src\lang English resources
\src\plugins Plugins source code
\src\reglib Access to Windows Registry files
\src\res Image resources
\src\salmon Crash detecting and reporting
\src\salopen Open files helper
\src\salspawn Process spawning helper
\src\setup Installer and uinstaller
\src\sfx7zip Self-extractor based on 7-Zip
\src\shellext Shell extension DLL
\src\translator Translate Salamander UI to other languages
\src\tserver Trace Server to display info and error messages
\src\vcxproj Visual Studio project files
\tools Minor utilities
\translations Translations into other languagesA few Open Salamander 5.0 plugins are either not included or cannot be compiled. For instance, the PictView engine pvw32cnv.dll is not open-sourced, so we should consider switching to WIC or another library. The Encrypt plugin is incompatible with modern SSD disks and has been deprecated. The UnRAR plugin lacks unrar.dll, and the FTP plugin is missing OpenSSL libraries. Both issues are solvable as both projects are open source. To build WinSCP plugin you need Embarcadero C++ Builder.
All the source code uses UTF-8-BOM encoding and is formatted with clang-format. Refer to the \normalize.ps1 script for more information.
Open Salamander is a pure WinAPI C++ application with no external UI frameworks (no MFC, ATL, or Qt). The architecture follows a layered design with a plugin-based extensibility model. The codebase targets Windows Vista+ (WINVER=0x0601) and supports both x86 and x64 builds.
┌─────────────────────────────────────────────────────────┐
│ UI Layer │
│ Main Window · File Panels · Menus · Toolbars │
├─────────────────────────────────────────────────────────┤
│ Business Logic Layer │
│ File Operations · Plugin Manager · Configuration │
├─────────────────────────────────────────────────────────┤
│ Service Layer │
│ Worker Threads · Icon Cache · File System Access │
├─────────────────────────────────────────────────────────┤
│ Data Layer │
│ Registry Storage · WinAPI File System · Plugin Data │
└─────────────────────────────────────────────────────────┘
The codebase is organised into focused file groups. Each group uses a common prefix so related files sort together:
| Prefix | Files | What it contains |
|---|---|---|
mainwnd_* |
7 | Main window: init, config, messages, commands, panels, shutdown, HTML help |
fileswindow_* |
12 | File panel implementation: navigation, display, operations, archiving, etc. |
filesbox_* |
2 | Virtual list-box rendering and keyboard/mouse input |
dialogs_* |
8 | All dialog boxes: file ops, rename, attributes, configuration pages |
plugins_* |
4 | Plugin loader, interface layer, archiver and file-system adapters |
toolbar_* |
8 | Toolbar core, rendering, drag-and-drop, drive bar, hot-paths, user menu |
menu_* |
4 | Popup menus, shared resources, templates, window queue |
gui_* |
3 | Reusable GUI controls: progress bar, static text, buttons and animations |
zip_* |
4 | ZIP/archive API: progress, general API, utilities, directory management |
find_* |
3 | Find dialog: result data structures, dialog UI, toolbar |
app_* |
2 | Application entry point and global variable definitions |
transfer_speed, async_copy, operations_core, worker |
4 | File-copy engine: speed meters, async copy, operation dispatch |
Rule of thumb adopted for new code: one logical component or feature per file; aim for files under 1 500 lines.
CMainWindow is the top-level window that hosts the entire application. Its implementation is split across seven focused files:
| File | Contents |
|---|---|
mainwnd_init.cpp |
Constructor, window creation, destruction, toolbar/panel layout |
mainwnd_config.cpp |
Configuration load/save, registry persistence |
mainwnd_messages.cpp |
WindowProc switch — delegates to the two extracted handlers below |
mainwnd_commands.cpp |
HandleWmCommand — all WM_COMMAND menu and toolbar dispatch (~2 500 cases) |
mainwnd_shutdown.cpp |
HandleShutdown — WM_CLOSE, WM_ENDSESSION, WM_QUERYENDSESSION |
mainwnd_help.cpp |
CSalamanderHelp, OpenHtmlHelp, MessageBoxHelpCallback |
mainwnd_panels.cpp |
Panel layout helpers, splitter, focus management |
Key hosted objects:
- Two
CFilesWindowinstances (left and right panels) - Drive bars, toolbars (
CMainToolBar,CPluginsBar,CBottomToolBar,CUserMenuBar,CHotPathsBar) - Menu system (
CMenuBar,CMenuPopup,CMenuNew) CPanelStatusBar(status bar below each panel) andCToolTipWindow
CMainWindowLock (declared in mainwnd.h) serialises access to the main window during shutdown; extern CMainWindowLock MainWindowCS is defined in app_globals.cpp.
CFilesWindow implements a single file panel. Its implementation is split across twelve focused files:
| File | Contents |
|---|---|
fileswindow_init.cpp |
Constructor, creation, destruction |
fileswindow_navigation.cpp |
ReadDirectory, ChangeDir, path history |
fileswindow_display.cpp |
Painting: SetFontAndColors, DrawIcon, DrawItem |
fileswindow_operations.cpp |
MakeFileList, MoveFiles, BuildScriptMain — copy/move scripting |
fileswindow_archiving.cpp |
Pack, unpack, panel enumeration data |
fileswindow_file_actions.cpp |
Convert, ChangeAttr, FindFile, ViewFile |
fileswindow_execute.cpp |
Open/execute files, view-template selection |
fileswindow_quicksearch.cpp |
Find-as-you-type quick search |
fileswindow_columns.cpp |
Column configuration and management |
fileswindow_delete.cpp |
DeleteThroughRecycleBin, FilesAction |
fileswindow_dir_reading.cpp |
CVisibleFileItemsArray, directory reading |
fileswindow_wndproc.cpp |
WindowProc, LockUI, OpenDirHistory |
The virtual list-box rendering lives in filesbox_rendering.cpp (CFileListBox) and keyboard/mouse input in filesbox_input.cpp (CFileListHeader).
Each panel operates in one of three modes driven by the path type: ptDisk (local/network drive), ptZIPArchive (archive root), or ptPluginFS (virtual file system provided by a plugin).
File Copy Engine (src/worker.h, src/worker.cpp, src/async_copy.cpp, src/operations_core.cpp, src/transfer_speed.cpp)
Long-running operations (copy, move, delete, rename) execute on dedicated worker threads. The implementation is split across four files:
| File | Contents |
|---|---|
transfer_speed.cpp |
CTransferSpeedMeter, CProgressSpeedMeter — real-time throughput measurement |
async_copy.cpp |
CCopy_Context, DoCopyFile, DoMoveFile, DoDeleteFile, DoCreateDir — the core async copy engine with overlapped I/O |
operations_core.cpp |
DoConvert, DoChangeAttrs, ThreadWorker, StartWorker, COperationsQueue |
worker.cpp |
COperations methods, UTF-8 file helpers, buffer-size heuristics |
The operation pipeline:
- User triggers a command →
CCriteriaDatais built with masks, attributes, and speed limits. - A
COperationsobject is created and a worker thread is started viaStartWorker. - The worker processes each file, updates
CProgressData, and communicates back via Windows messages. - On completion or cancellation, both source and target panels are refreshed.
CAsyncCopyParams (declared in worker.h) manages overlapped-I/O buffers for the async path. CWorkerData and CProgressDlgData (also in worker.h) carry per-operation state across the four translation units.
The plugin-facing archive API (CSalamanderGeneral, CSalamanderDirectory, etc.) is split into four files:
| File | Contents |
|---|---|
zip_progress.cpp |
CZIPUnpackProgress — progress dialog integration |
zip_general_api.cpp |
CSalamanderGeneral — the main archive API surface (~3 000 lines) |
zip_utilities.cpp |
CSalamanderBMSearchDataImp, CSalamanderMD5Imp, CSalamanderPNG, CSalamanderCrypt |
zip_directory.cpp |
CSalamanderDirectory, CSalamanderForOperations, TestFreeSpace |
All dialogs are grouped by function:
| File | Contents |
|---|---|
dialogs_file_ops.cpp |
Copy, move, delete confirmation dialogs |
dialogs_rename.cpp |
Rename and batch-rename dialogs |
dialogs_attributes.cpp |
File-attribute dialogs, CZipSizeResultsDialog, CPasswordDialog |
dialogs_config_general.cpp |
Configuration pages: CConfigPageGeneral, CConfigPageRegional, CConfigPageView |
dialogs_config_viewers.cpp |
Configuration pages: Viewers, Associations |
dialogs_config_panels.cpp |
Configuration pages: Panels, Colors |
dialogs_config_environment.cpp |
Environment/paths configuration page |
dialogs_config_packing.cpp |
Packing/archiving configuration page |
| File | Contents |
|---|---|
find_results.cpp |
CFindOptions, CFoundFilesData, CFoundFilesListView — data model and list control |
find_dialog_ui.cpp |
CFindDialog — search dialog UI and logic (~3 300 lines) |
finddlg2.cpp |
CFindDialog continuation methods, CFindTBHeader toolbar |
Reusable custom controls shared across all dialogs and the main window:
| File | Contents |
|---|---|
gui_progressbar.cpp |
CProgressBar — animated, self-moving progress bar |
gui_statictext.cpp |
CStaticText — text control with ellipsis, path compaction, tooltips |
gui_controls.cpp |
CButton, CColorArrowButton, CToolbarHeader, CAnimate, layout helpers |
CGuiBitmap (a memory-DC helper for flicker-free button drawing) is declared in gui_bitmap.h and shared by gui_progressbar.cpp and gui_controls.cpp.
| File | Contents |
|---|---|
plugins_loading.cpp |
Discovery, LoadLibraryUtf8, version check, activation |
plugins_interface.cpp |
CPluginInterfaceEncapsulation — thread-safety guards |
plugins_archiver.cpp |
Archiver plugin adapter |
plugins_filesystem.cpp |
Virtual file-system plugin adapter |
Plugins implement abstract interface classes:
| Interface | Purpose |
|---|---|
CPluginInterfaceAbstract |
Base; version negotiation |
CPluginInterfaceForArchiverAbstract |
List/pack/unpack archives |
CPluginInterfaceForViewerAbstract |
File preview/viewer |
CPluginInterfaceForFileSystemAbstract |
Virtual file systems (e.g. FTP) |
CPluginInterfaceForThumbLoaderAbstract |
Thumbnail generation |
Every call is wrapped with EnterPlugin() / LeavePlugin() guards for thread safety and call-stack tracking.
| File | Contents |
|---|---|
app_globals.cpp |
All global variable definitions — runtime flags, GDI handles, colour tables, enabler arrays, CMainWindowLock MainWindowCS |
app_entry.cpp |
MyEntryPoint, WinMain, WinMainBody, locale init, graphics init, CRC-32 helpers |
Shared infrastructure used by both the core and all plugins:
| File | Purpose |
|---|---|
array.h |
TIndirectArray<T> — typed dynamic array template |
strutils.h/cpp |
UTF-8 ↔ wide string conversion, CreateFileUtf8, DeleteFileUtf8, etc. |
handles.h/cpp |
Handle tracking and leak detection in debug builds |
messages.h/cpp |
Typed message-box helpers |
allochan.h/cpp |
Allocation tracking wrappers |
heap.h/cpp |
Custom heap management |
crc32.h/cpp |
CRC-32 checksum |
moore.h/cpp |
Boyer-Moore string search |
multimon.cpp |
Multi-monitor layout support |
SalmonInit() is called before WinMain via MyEntryPoint() in app_entry.cpp. It installs an unhandled-exception filter that captures a minidump and call-stack trace, enabling post-mortem analysis of field crashes.
| Type | Description |
|---|---|
CFileData |
Metadata for one file or directory (name, size, time, attributes, plugin-specific data) |
CSalamanderDirectory |
Full directory listing exposed to plugins via the archive API |
CCriteriaData |
Parameters for a copy/move: masks, date range, size limits, speed cap |
CAsyncCopyParams |
Overlapped-I/O buffer block for the async copy path (declared in worker.h) |
CWorkerData / CProgressDlgData |
Per-operation worker state shared across the copy-engine translation units |
CDirectorySizeCache |
Cached directory-size results (avoids redundant recursive scans) |
CVisibleFileItemsArray |
Tracks which file items are currently visible in the panel for incremental refresh |
CChangeCaseData |
Options for a batch rename-case operation |
CAttrsData |
Parameters for changing file attributes in bulk |
All UI objects derive from a thin CWindow base that wraps a WinAPI HWND and routes messages through a virtual WindowProc(). There are no MFC CWnd semantics; message handling is done with explicit WM_* comparisons.
CWindow
├── CMainWindow
│ ├── CFilesWindow (×2, left/right panels)
│ │ ├── CFileListBox (virtual list-box rendering)
│ │ └── CFileListHeader (column headers with drag-to-resize)
│ ├── CMenuBar
│ ├── CMainToolBar / CPluginsBar / CBottomToolBar / ...
│ ├── CDriveBar
│ └── CPanelStatusBar (status bar below each panel)
└── CDialog (modal/modeless dialogs)
├── CFindDialog (find dialog with CFoundFilesListView)
├── CConfigPageGeneral / CConfigPageRegional / CConfigPageView / ...
├── CPasswordDialog
├── CZipSizeResultsDialog
└── CInlineRenameEdit (in-place rename edit control)
The codebase follows these conventions for new and refactored code:
| Category | Convention | Example |
|---|---|---|
| Dialog classes | C*Dialog |
CPasswordDialog, CZipSizeResultsDialog |
| Window classes | C*Window |
CMainWindow, CFilesWindow |
| Data-holder structs | C*Data or C*Info |
CFileData, CCriteriaData |
| Manager / cache classes | C*Manager or C*Cache |
CDirectorySizeCache, CIconCache |
| Locks / critical sections | C*Lock |
CMainWindowLock, CStringResourceLock |
The solution (src/vcxproj/salamand.sln) targets MSVC v143 (VS 2022). MSBuild property sheets layer the configuration:
sal_base.props— common defines, include paths, warning levelsal_debug.props/sal_release.props— optimization and debug flagsx86.props/x64.props— platform-specific settings
The OPENSAL_BUILD_DIR environment variable controls where build artifacts are placed. !populate_build_dir.cmd stages executables, plugins, language files, and resources into a runnable layout.
Each plugin is its own .vcxproj linked into the solution and produces a DLL placed alongside the main executable.
CALL_STACK_MESSAGE*macros maintain a lightweight call-stack log available in crash reports without requiring full debug symbols.HANDLES_ENABLE(debug-only) activateshandles.htracking that asserts on leaked or double-closed WinAPI handles.- The Trace Server (
src/tserver/) receivesTRACE_*messages emitted throughout the codebase and displays them in a separate window; all trace calls are compiled out in release builds.
Open Salamander is open source software licensed GPLv2 and later. Individual files and libraries have a different, but compatible license.