Architecture
How DeskDrawer is put together: one process, no services, WinForms over the Windows shell, and the reasoning behind each of those choices.
This page describes how DeskDrawer is actually built. It is here because "lightweight" is a claim, and a claim about software should be checkable.
Shape of the application#
One process. No services, no drivers, no shell extensions, no helper processes, no plugin host.
DeskDrawer.exe (one self-contained executable)
├── tray context — the application; there is no main window
├── board windows — one per board, drawn at desktop level
├── desktop scanner — watches the desktop folder for changes
├── icon cache — background icon resolution, in memory
├── config store — atomic reads and writes of config.json
└── shell interop — context menus, clipboard, info tips, links, share, execute
Platform choices#
| Choice | Reason |
|---|---|
| .NET 9, Windows-targeted | Access to the packaged startup-task API and modern shell projections |
| Windows Forms | Thin over Win32. A board is close to a window with custom painting; a heavier UI framework would add a rendering stack for no benefit |
| Single-file self-contained executable, self-contained | No runtime to install, nothing shared to break |
| Not trimmed | Trimming breaks COM interop and late-bound calls — see below |
| Workstation GC, non-concurrent | A background collector thread costs memory and CPU for an application that allocates very little |
| Per-monitor v2 DPI | Correct rendering on mixed-scaling setups — see Per-monitor DPI awareness |
Why not trimmed#
Trimming would shrink the download considerably. It is deliberately off because DeskDrawer's most important behaviour — showing the real Shell context menu — runs through COM interop, and some shell work is late-bound. A trimmer cannot see those call paths, would remove the types they need, and the failure would appear at runtime in the exact features that matter most, with nothing at build time to catch it. A larger file is the correct trade.
Delegate to the shell#
The design rule that shapes most of the code: where Windows already has behaviour, call Windows rather than reimplementing it.
| Behaviour | Provided by |
|---|---|
| Context menus | The shell — real menus, real extensions |
| Copy, cut, paste, drag payloads | Shell clipboard and data objects |
| Hover info tips | The shell |
| Opening files and shortcuts | The shell |
Resolving .lnk targets | The shell link interface |
| The Windows 11 Share pane | The shell share UI |
| Icon names for system items | The shell, in your Windows display language |
The cost is a lot of interop code and a lot of care about threading. The benefit is that DeskDrawer inherits correct behaviour it did not write, including the parts nobody remembers to implement: Shortcut repair prompts, "how do you want to open this file", per-extension menu entries, and localization. See Languages.
Threading#
The rule is that the interface thread never waits on the file system.
Anything that can be slow — resolving an icon, reading a Cloud placeholder, following a Shortcut to a network share, building an info tip — happens on a background thread and updates the board when it completes. Boards draw a placeholder immediately rather than blocking.
This is the single largest source of past bugs in the product, and the reason for it is worth stating plainly: on Windows, a file-system call against an unreachable location does not fail quickly, it blocks until a network timeout. One such call on the interface thread freezes the whole application — including, memorably, the mouse wheel. See The same bug, five times: offline network locations.
Boards are not ordinary windows#
Board windows sit at desktop level rather than in the normal window stack. That is what produces the behaviours in Boards: Win+D does not hide them, "Minimize all" does not minimize them, Alt+F4 gives the shutdown dialog, and applications launched over them still come to the front.
State#
One file, config.json, written atomically. No database, no cache on disk, no index. The entire persistent state of the application is a layout description small enough to read.
What this buys#
An application with no background services, no network access, no disk cache and one small state file has a small failure surface. It is also why the honest description of most releases since 1.1.4 is "stability release, no new features" — see Eight rounds of code audits on a small app, and what each one found.