DirMon.exe — feature documentation

Directory Monitor

DirMon v2.0 for Windows

DirMon watches one directory — and everything beneath it — and records file events the moment they happen: additions, removals, modifications, and renames. Changes arrive in real time through the Windows ReadDirectoryChangesW API rather than polling, and a rule-based filter engine shapes what you see in a 50,000-entry log.

  • Windows
  • Win32 + DirectX 11
  • Dear ImGui interface
  • Real-time — no polling

1 watched directory (always recursive) · 4 event types · 6 filter operators · 50,000-entry log

At a glance

The essentials in one place.

Monitoring scope
One directory at a time; subdirectories are always included.
Capture method
ReadDirectoryChangesW, real time — the disk is not polled.
Change mask
File name, directory name, and last write (fixed).
Event types
Added, Removed, Modified, Renamed — plus gray system rows.
Log capacity
50,000 entries in a ring buffer, oldest-first eviction.
Event queue
8,192 entries; overflow coalesces into a single marker row.
Filtering
Include / Exclude / Highlight rules with 6 operators; live re-projection.
Find
Case-insensitive substring over visible rows; wraps around.
Export
UTF-8 text with BOM, CRLF line endings — the visible rows.
Persistence
settings.json beside the executable: rules + UI state.
Startup
Nothing auto-starts; monitoring begins when you press Start.
Predecessor
DirMon v1.1 dialog app, kept in the same solution.
Native stack

DirMon is a native Windows application: a Win32 host with a DirectX 11 renderer and a Dear ImGui interface. It is the modern successor to the legacy DirMon v1.1 dialog app, replacing the old hard-coded “smart filter” with a general rule-based filter engine (see Filter rules and About and legacy).

Main window tour

Everything lives in a single full-viewport window. From top to bottom: toolbar, find strip, banners, allowlist badge, filter editor, log list, status bar.

Schematic — region order matches the app; proportions are approximate. Gray dashed rows are conditional: the find strip appears only while Find is open, the banner only when settings could not be loaded or saved, the allowlist badge only while an Include rule is enabled. Log rows are placeholders — see Event types and colors for a realistic sample.

1 · Toolbar

Icon buttons, 48 px at the default font size — they scale with font zoom. Left to right:

  • Start / Stop monitoring — a green play icon while stopped, a red stop icon while running. Starting opens the folder picker.
  • Export — save the log to a text file (see Working with the log).
  • Clear all logs — clears the log after a confirmation dialog.
  • Added, Removed, Modified, Renamed — event-type toggles. A pushed, blue button means the type is on.
  • Find — opens the find strip.
  • Always on top — keeps the window above other applications; the setting persists.
  • Zoom out · current font size · Zoom in — the base font adjusts from 12 to 28 px in steps of 2; the toolbar scales with it. The zoom level is session-only and is not written to settings.
  • About — opens the About dialog.

2 · Find bar

A modeless strip below the toolbar: a search input (hint “Find in log…”), Next (↓), Previous (↑), and Close (×), plus a “(no match)” hint when the query finds nothing. Details under Working with the log.

3 · Banner area

Yellow, at-most-one-line messages about settings persistence:

  • If settings.json cannot be written: “WARNING: could not write settings.json (read-only media?). Settings will not persist for this session.”
  • If settings.json was corrupt or has an unsupported version: “Notice: settings.json was corrupt — it was renamed to settings.broken.json and defaults were loaded.”, with a Dismiss button.

4 · Allowlist badge

Shown whenever at least one Include rule is enabled: “Allowlist active: N include rules” plus a Disable all includes button that switches every Include rule off in one click — the quickest way out of an accidental allowlist. See Filter rules.

5 · Filter rules editor

A collapsible “Filter rules (N)” header, where N is the total rule count. Add Rule appends a new rule that defaults to Exclude with the is operator. Each rule row has: an enabled checkbox, the Action combo (Include / Exclude / Highlight), the Operator combo, a pattern text box, and a delete button (X). While an allowlist is active, enabled Exclude rules carry a gray “(shadowed)” tag — explained in Filter rules.

6 · Log list

A scrolling table with four columns — type icon, Time, Path, Note. The header row stays frozen while rows scroll, columns can be resized by dragging, and rendering is virtualized, so a full 50,000-entry log stays responsive. When there is nothing to show: “No log entries (toggle a type and Start a watch).” Left-click selects a row; right-click opens its context menu. Hovering a truncated path shows the full text.

7 · Status bar

A legend of the four event types — the same shapes and colors as the log rows — followed by counters. Full reference in Status bar reference.

Dialogs and menus

  • About dialog“DirMon  v2.0”, “Directory Monitor”, “Copyright (C) 2003-2026 epocsoft.com”, and a link to https://www.epocsoft.com that opens in the default browser. OK or Esc closes it.
  • Clear confirmation“Clear all log entries?” with the stored count, “This cannot be undone.”, and a “Don’t show again this session” checkbox. With the checkbox ticked, later clears from the toolbar skip the dialog for the rest of the session.
  • Row context menu (right-click on a file row) — Include <path>, Exclude <path>, Highlight <path>, Clear all logs, Copy this line. Each of the first three items adds an enabled is rule for that row’s full path. Note that the context menu’s Clear all logs clears immediately, without the confirmation dialog.

Monitoring directories

One directory at a time, watched recursively, in real time. Monitoring starts and stops on your command — never on its own.

Starting a watch

  • Press the toolbar Start button or Ctrl+O. Any running watch stops first, a folder picker opens, and the chosen directory is watched immediately.
  • Monitoring never starts automatically on launch. Even with a restored last directory, nothing runs until you press Start.
  • The four event-type toggles do not change what the watcher asks Windows for — everything arrives, and events of a switched-off type are dropped and counted (see By-toggle in Status bar reference).
Picker details

If you cancel the folder picker while a previous directory is remembered, the watch still starts — on that remembered directory. On a first run, with nothing remembered, canceling the picker aborts the start.

What gets watched

  • Exactly one directory at a time. Starting a new watch replaces the old one.
  • Recursion into subdirectories is always on — there is no non-recursive mode.
  • The change mask is fixed: file name, directory name, and last write — in API terms, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE. In practice: files and folders being created, deleted, or renamed, and files being written to.

Stopping

  • Toolbar Stop or Shift+F5.
  • Stopping does not clear the log — entries stay for review and export. Clearing is a separate action.
  • There is no pause or resume; a watch is either running or stopped.

Queue and overflow

Events flow from the watcher thread through an internal queue of 8,192 entries into the log. If the queue saturates — a burst faster than the UI can drain — the incoming event is dropped and counted, the oldest queued item is discarded, and a single gray Queue overflow system row records it. Whenever the dropped count is above zero, the status bar shows “(queue overflow dropped N)” in red.

Event types and colors

Every log row carries a color, a shape, and — in exports and clipboard text — a one-character marker.

Marker Icon Type Color What it means
+ Added #4CD959
rgb(76,217,89)
A file or folder was created under the watched directory.
Removed #F24D4D
rgb(242,77,77)
A file or folder was deleted.
* Modified #FAA61A
rgb(250,166,26)
A file’s contents changed (last-write notification).
! Renamed #33BFE6
rgb(51,191,230)
A file or folder was renamed — Path holds the old name, Note the new one.
# System #A6A6A6
rgb(166,166,166)
Watch started, Watch stopped, Watch error, and Queue overflow rows.
  • Timestamps are local time, in HH:MM:SS.mmm format.
  • System rows — Watch started, Watch stopped, and Watch error show the watched directory in the Path column; a Watch error also carries the Windows error number. System rows are never deduplicated.
  • The highlight effect — a matching Highlight rule tints the entire row a warm yellow, rgba(255,217,26,0.35), with bold text. The event color is preserved; highlight carries no visibility meaning (see Filter rules).

For the source-minded: the renderer stores these as ImGui float colors — Added (0.30, 0.85, 0.35), Removed (0.95, 0.30, 0.30), Modified (0.98, 0.65, 0.10), Renamed (0.20, 0.75, 0.90), System (0.65, 0.65, 0.65).

A realistic sample

Time Path Note
09:41:02.317 C:\REPO\SRC
09:41:02.331 C:\REPO\SRC\main.cpp
09:41:02.940 C:\REPO\SRC\main.cpp
09:41:05.840 C:\REPO\SRC\old.cpp C:\REPO\SRC\new.cpp
09:41:07.102 C:\REPO\SRC\temp.txt
09:41:12.002 C:\REPO\SRC

Illustrative rows, colors and column meanings exactly as in the app. The first and last rows are Watch started / Watch stopped system rows (the Path column carries the watched directory). The highlighted row shows the effect of a Highlight rule: warm-yellow tint, bold text, event color preserved. A rename shows the old path under Path and the new path under Note.

Filter rules

A rule-based filter engine replaces the legacy “smart filter”. Rules are matched live against the stored log — the view re-projects the moment anything changes, with no watch restart.

Anatomy of a rule

Every rule is one flat object with four parts:

  • Action — Include, Exclude, or Highlight: what happens on a match.
  • Operator — how the pattern is compared to the path.
  • Pattern — the text to match.
  • Enabled — a per-rule switch; disabled rules are ignored entirely.

Add Rule in the editor appends a new rule that defaults to Exclude with the is operator. Rules live in settings.json and persist between sessions (see Settings reference).

How patterns match

  • Patterns are plain text — no wildcards, no regular expressions.
  • Matching is case-insensitive and runs against the entry’s full absolute path.
  • A renamed entry matches if either its old or its new path matches.
  • An empty pattern matches nothing. An empty rule set shows everything.
  • Rule order is irrelevant to the outcome — visibility does not depend on position in the list.

Actions

Action Effect on a matching row
Include Admits the row. While any Include rule is enabled, only rows an Include matches are visible (allowlist mode, below).
Exclude Hides the row — unless an allowlist is active, in which case it has no effect (shadowed).
Highlight Tints the row warm yellow with bold text. Never affects visibility — a Highlight match cannot reveal a hidden row.

Operators

All six compare the pattern against the full absolute path, case-insensitively:

Operator Matches when Example
isThe path equals the pattern exactly.c:\repo\src\main.cpp
is notThe path is anything else.
begins withThe path starts with the pattern.C:\REPO\
ends withThe path ends with the pattern..cpp
containsThe pattern appears somewhere inside the path.\SRC\
excludesThe pattern appears nowhere in the path — the opposite of contains.\\vendor\\

Allowlist semantics

The filter runs in one of two modes, decided by whether any Include rule is enabled:

  • Allowlist off (no enabled Include rules): every row is visible unless an Exclude rule matches it.
  • Allowlist on (at least one enabled Include rule): only rows that an Include matches are visible. Exclude rules then hide nothing at all — they are tagged “(shadowed)” in the rules list, and the allowlist badge appears above the editor with a Disable all includes shortcut. Include wins any direct conflict; the shadow tag records exactly that.
  • Highlight is orthogonal: it tints rows that are already visible and never reveals a hidden one.
Live re-filtering

Any rule edit — add, change, toggle, delete — re-projects the entire stored log instantly (up to 50,000 entries), and incoming events follow the same rules. No watch restart is needed.

Quick rules from a row

Right-click a file row and pick Include <path>, Exclude <path>, or Highlight <path> to add an enabled is rule on that row’s full path — precise, and a noisy path is silenced in two clicks. Rename rows create the rule on the new path.

Worked example

These are the three rules from the settings example. Rule 1 admits anything under the repo’s source folder; rule 2 is a vendor exclusion; rule 3 tints one specific file:

  • Include · contains · C:\REPO\SRC\
  • Exclude · contains · \\vendor\\
  • Highlight · is · c:\repo\src\main.cpp

Rule 1 is enabled, so an allowlist is active. Walking a few events through the engine:

Event Path Result Why
Added C:\REPO\SRC\main.cpp Visible · highlighted Matches Include 1 (contains C:\REPO\SRC\); Highlight 3 matches it exactly (is, case-insensitive).
Added C:\REPO\SRC\vendor\lib.cpp Visible Include 1 admits it. Exclude 2 also matches — but while the allowlist is active, an exclude hides nothing; the rule is tagged (shadowed).
Added C:\REPO\DOC\readme.md Hidden No Include rule matches — the allowlist admits nothing else.
Renamed C:\REPO\TMP\a.txt → C:\REPO\SRC\b.txt Visible The new path matches Include 1 — a rename matches when either path matches.
Modified C:\OTHER\main.cpp Hidden No Include rule matches — and a Highlight match alone could not reveal it.

Disable Include 1 — or click Disable all includes in the badge — and the allowlist lifts: every row becomes visible except matches of Exclude 2, which starts hiding \\vendor\\ paths again.

Working with the log

A scrolling, resizable, virtualized table of everything the watch captured — plus the tools to search, copy, and export it.

Columns

Column Width Contents
(type icon) Fixed, narrow The colored shape marking the event type (see Event types and colors). Hovering it names the type.
Time Fixed Local timestamp, HH:MM:SS.mmm.
Path Stretches 2× The full path — for renames, the old path. Hover shows the full text when clipped.
Note Stretches 1× Empty for most rows; the new path for renames.

The header row stays frozen while rows scroll, columns can be resized by dragging their edges, and rendering is virtualized — only visible rows are drawn, so a full log stays smooth. When empty, the list reads: “No log entries (toggle a type and Start a watch).”

Storage: ring buffer and dedupe

  • The log holds up to 50,000 entries in a ring buffer. When it fills, the oldest entry is evicted first. Evicted entries are counted and cannot be brought back by re-filtering.
  • Consecutive identical file events — same type, same path, same old path — are collapsed into a single row. System rows are never deduplicated.
  • The evicted and deduped counters are lifetime totals: they survive Clear. The per-type counters do not — see Status bar reference.

Find

  • Open with Ctrl+F or the toolbar Find button; close with Esc or the × button. The strip is modeless — it stays open while you work with the log.
  • Case-insensitive substring match over the visible rows’ paths. A rename also matches on its old path.
  • Enter or Next (↓) jumps forward; Previous (↑) jumps back. The search wraps around at the ends.
  • A hit is selected and scrolled to the center of the list. A miss shows “(no match)” beside the input.

Context menu and copy

Right-click a file row for Include <path>, Exclude <path>, Highlight <path> (each adds an enabled is rule on the full path — renames use the new path), Clear all logs, and Copy this line.

Copy this line puts the row on the clipboard as HH:MM:SS.mmm path — a rename copies old -> new.

Export

  • Toolbar Export opens a save dialog with the default name DirMon-Export.txt and a Text files (*.txt) filter.
  • Files are written as UTF-8 with a BOM and CRLF line endings, so non-ASCII paths survive intact.
  • Export writes the currently visible rows — the same rows the log list shows after filter rules and type toggles.
  • Line format: HH:MM:SS.mmm <marker> path. Renames export as old -> new; Watch error rows append the Windows error number as (error N).
09:41:02.331 + C:\REPO\SRC\main.cpp
09:41:02.940 * C:\REPO\SRC\main.cpp
09:41:05.840 ! C:\REPO\SRC\old.cpp -> C:\REPO\SRC\new.cpp
09:41:07.102 - C:\REPO\SRC\temp.txt
09:41:09.550 # C:\REPO\SRC

Example lines; system rows (Watch started / stopped / error, Queue overflow) use the # marker and carry the watched directory as their path.

Status bar reference

The legend at the left repeats the log row icons and colors, one per event type, each followed by its count; the rest of the bar summarizes storage and filtering.

Format

Added N  Removed N  Modified N  Renamed N | Hidden N  By-toggle N | Stored N (capacity 50000, evicted N, deduped N) | Rules N

With data in it, the same bar reads, for example:

Added 12  Removed 3  Modified 47  Renamed 2 | Hidden 5  By-toggle 18 | Stored 64 (capacity 50000, evicted 0, deduped 9) | Rules 3

Whenever the internal queue has overflowed at least once, a red “(queue overflow dropped N)” is appended after the counters.

Counters

Segment Meaning
Added / Removed / Modified / Renamed Events counted per type since the last Clear. A switched-off type’s events are not counted here — they land in By-toggle.
Hidden Stored entries not currently visible — hidden by filter rules and/or a switched-off type toggle.
By-toggle Events dropped at capture time because their type toggle was switched off.
Stored Entries currently held in the ring buffer.
capacity 50000 The ring buffer’s size.
evicted Entries dropped by oldest-first eviction. Lifetime total — survives Clear.
deduped Consecutive identical file events collapsed. Lifetime total — survives Clear.
Rules Number of filter rules, enabled or not.

Clear resets the per-type counts, Hidden, and Stored — but not evicted or deduped, which are lifetime totals. The type toggles count double duty: they gate newly captured events (By-toggle) and hide already-stored rows of that type when the view is re-projected (Hidden).

Keyboard shortcuts

Everything important is one chord away.

Shortcut Action
Ctrl+FOpen the Find strip and focus the input.
Ctrl+OStart monitoring — opens the folder picker.
Shift+F5Stop monitoring.
EnterIn the find field: jump to the next match.
EscClose the Find strip, the About dialog, or the Clear confirmation.

While the About or Clear-log dialog is open, the shortcuts yield to the dialog. Font zoom is mouse-only: the toolbar buttons adjust the base font from 12 to 28 px in steps of 2, session-only — the size is not written to settings.

Settings reference

One JSON file — settings.json, stored beside DirMon.exe — holds the filter rules and the UI state. Schema version 1.

Example file

{
  "version": 1,
  "rules": [
    { "action": "include",   "op": "contains",   "pattern": "C:\\REPO\\SRC\\", "enabled": true },
    { "action": "exclude",   "op": "contains",   "pattern": "\\\\vendor\\\\",   "enabled": true },
    { "action": "highlight", "op": "is",         "pattern": "c:\\repo\\src\\main.cpp", "enabled": true }
  ],
  "ui": { "alwaysOnTop": false, "lastDir": "", "watchAdded": true, "watchModified": false,
          "watchRemoved": true, "watchRenamed": true, "windowH": 640, "windowW": 1024 }
}

Backslashes are escaped JSON-style — a single \ in the editor is \\ in the file. The three rules above are walked through in the worked example.

Keys

Key Meaning
versionSchema version. Must be 1; anything else and the file is treated as corrupt.
rulesArray of filter rules — one flat object each. Order is irrelevant to outcomes.
rules[].actioninclude, exclude, or highlight.
rules[].opis, is_not, begins_with, ends_with, contains, or excludes — the same six operators the UI shows, spelled with underscores in the file.
rules[].patternPlain text, matched case-insensitively against full absolute paths.
rules[].enabledThe per-rule switch.
ui.alwaysOnTopThe always-on-top toggle.
ui.lastDirThe last watched directory, used when starting a watch.
ui.watchAdded / watchRemoved / watchModified / watchRenamedEvent-type toggle states. They gate newly captured events and hide already-stored rows of that type when the view is re-projected.
ui.windowW / windowHWindow size in pixels, clamped to [200, 32767] on load.

Behavior

  • Loaded at startup. A missing file simply means defaults.
  • A corrupt file — or an unsupported version — is renamed to settings.broken.json, defaults load, and a dismissible banner explains what happened.
  • Unknown keys are ignored.
  • Saves are debounced: about one second after the last change, plus a synchronous flush on exit.
  • If the write fails — read-only media, permissions — the session continues in memory and a yellow banner warns that settings will not persist.

About and legacy

The About dialog (toolbar About) shows the application icon, the “DirMon  v2.0” title, “Directory Monitor”, “Copyright (C) 2003-2026 epocsoft.com”, and a link to https://www.epocsoft.com that opens in the default browser. OK or Esc closes it.

Legacy note

DirMon is the modern successor to the legacy DirMon v1.1 dialog application, which remains in the same solution untouched. The old app’s “smart filter” — a hard-coded ignore list for system files — and its “Ignore file with extensions” checkbox are gone, replaced by the general rule-based filter engine: any path can be included, excluded, or highlighted, and the rules persist in settings.json. Both apps share the same watcher backend, so event behavior is identical.

DirMon v2.0 — Directory Monitor (DirMon.exe) · Copyright (C) 2003-2026 epocsoft.com

This documentation describes DirMon.exe as of v2.0; interface strings and behaviors are taken from the application source.