Files
Stirling-PDF/frontend/editor/src-tauri/thumbnail-handler
0a50e765b7 Restructure/frontend editor (#6404)
## Move editor under `frontend/editor/`

Pure restructure: `frontend/` becomes the workspace, `frontend/editor/`
holds
  the PDF editor. 1775 file renames + 40 wiring edits. No logic changes.

  ### Why

`frontend/` is currently the editor — its `src/`, `public/`,
`src-tauri/`,
  config files all sit at the root. Promoting `frontend/` to a
workspace and putting the editor in a sibling folder leaves room for
future
apps to drop in alongside it, sharing one `package.json` /
`node_modules` /
  lint config / Storybook.

  ### What moves

  frontend/
  ├── editor/                ← NEW: everything editor-specific
  │   ├── src/               ← was frontend/src/
  │   ├── public/            ← was frontend/public/
  │   ├── src-tauri/         ← was frontend/src-tauri/
│ ├── index.html, vite.config.ts, vitest.config.ts, playwright.config.ts
  │   ├── tsconfig*.json, tailwind.config.js, postcss.config.js
  │   ├── scripts/
  │   ├── .env, .env.desktop, .env.saas
  │   └── DeveloperGuide.md
├── package.json, package-lock.json, node_modules/ ← workspace install
  ├── eslint.config.mjs, .prettierrc, .prettierignore ← shared tooling
  ├── .gitignore
  └── README.md

  ### Wiring edits (40 files)

  - `.taskfiles/frontend.yml`, `desktop.yml`, `e2e.yml`
  - `build.gradle`, `app/core/build.gradle`
- `eslint.config.mjs`, `frontend/package.json`, `.gitignore`,
`.prettierignore`
  - `docker/frontend/Dockerfile`
  - 8 `.github/workflows/*.yml`, plus `.github/dependabot.yml`,
    `.github/config/.files.yaml`, `.github/labeler-config-srvaroa.yml`
  - `scripts/translations/**`
- Docs: `AGENTS.md`, `CLAUDE.md`, `ADDING_TOOLS.md`,
`DeveloperGuide.md`,
`WINDOWS_SIGNING.md`, `devGuide/HowToAddNewLanguage.md`,
`frontend/README.md`,
    `frontend/editor/DeveloperGuide.md`

Plus 3 renamed + edited: `editor/vite.config.ts` (env path +
node_modules
  walk-up), `editor/scripts/setup-env.mts` (renamed from `.ts` for
`import.meta.url`), `editor/scripts/build-provisioner.mjs` (resolve
src-tauri
  relative to script).

  ### Verification

  | Check | Result |
  |---|---|
  | `task frontend:typecheck:all` (6 variants) | exit 0 |
  | `task frontend:lint` (eslint + dpdm) | exit 0 |
  | `task frontend:format:check` | exit 0 |
  | `task frontend:test` | 657 tests pass, 50 files |
| `task frontend:build:{core,proprietary,saas,desktop,prototypes}` | all
green |
| `task desktop:build` | full Tauri pipeline →
`Stirling-PDF_2.11.0_x64_en-US.msi` |
  | `playwright test --list --project=stubbed` | 172 tests discovered |

`task desktop:build` exercises the heaviest path — Rust + WiX + MSI
bundle
against the moved `editor/src-tauri/`. If anything in the restructure
was
  wrong it wouldn't have built.

  ### Test plan

  - [ ] `frontend-validation.yml` green
  - [ ] `e2e-stubbed.yml` green
  - [ ] `tauri-build.yml` green on at least one platform
  - [ ] `check_toml.yml` runs on a translation-touching PR

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-22 13:40:34 +01:00
..
2026-05-22 13:40:34 +01:00
2026-05-22 13:40:34 +01:00
2026-05-22 13:40:34 +01:00
2026-05-22 13:40:34 +01:00
2026-05-22 13:40:34 +01:00

Windows PDF Thumbnail Handler

A lightweight COM DLL that provides PDF page-preview thumbnails in Windows Explorer when Stirling-PDF is the default PDF application.

Why this exists

When Stirling-PDF registers as the default PDF handler, Windows associates .pdf files with Stirling's ProgID. Without a thumbnail handler on that ProgID, Explorer falls back to showing the application icon (the big S logo) instead of a page preview. This DLL restores thumbnail previews by implementing the Windows Shell IThumbnailProvider COM interface.

How it works

  1. Explorer requests a thumbnail — when a folder with PDFs is opened in Medium/Large icon view, Explorer loads the DLL via the registered COM CLSID.
  2. Shell calls IInitializeWithStream — passes the PDF file content as an IStream.
  3. Shell calls IThumbnailProvider::GetThumbnail(cx) — requests a bitmap of size cx × cx.
  4. The DLL renders page 1 using the built-in Windows.Data.Pdf WinRT API (the same engine Edge uses), preserving aspect ratio.
  5. WIC decodes the rendered PNG into BGRA pixels, which are copied into an HBITMAP via CreateDIBSection.
  6. Explorer displays the bitmap as the file's thumbnail.

All COM methods are wrapped in catch_unwind so a malformed PDF cannot crash Explorer.

Technical details

Language Rust (cdylib)
DLL size ~156 KB
External deps None — uses only Windows built-in APIs
PDF renderer Windows.Data.Pdf (WinRT, Windows 10+)
Image decode WIC (IWICImagingFactory) with BGRA32 format conversion
COM CLSID {2D2FBE3A-9A88-4308-A52E-7EF63CA7CF48}
Threading model Apartment (STA — standard for shell extensions)
Min Windows Windows 10

Registry entries (managed by MSI)

The WiX installer (provisioning.wxs) registers:

  • CLSID at HKLM\SOFTWARE\Classes\CLSID\{2D2FBE3A-...}\InprocServer32 pointing to the DLL
  • Shellex at HKLM\SOFTWARE\Classes\.pdf\shellex\{E357FCCD-...} linking .pdf thumbnails to our CLSID

Both are automatically removed on uninstall.

Building

The DLL is built automatically as part of the Tauri build pipeline via build-provisioner.mjs:

cd frontend
npm run tauri-build

To build the DLL standalone:

cd frontend/src-tauri/thumbnail-handler
cargo build --release
# Output: target/release/stirling_thumbnail_handler.dll

Linux / macOS

This DLL is Windows-only. Linux and macOS don't need it — their thumbnail systems (thumbnailers on Linux, Quick Look on macOS) are decoupled from the default app association and continue working regardless of which app is set as default.