microsoft / microsoft/Windows-classic-samples

Shell does not fall back to the registered per-extension IThumbnailProvider when a cloud sync provider declines

Open
#429 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
No language data
Stars
5.7k
Forks
3.3k
PR merge metrics
No merged PRs in 30d

Description

Filed here because the CloudMirror sample in this repository is what demonstrates the correct
delegation pattern, and the sample is what we used to reproduce the problem. If this belongs
elsewhere, please point us at the right place — we will refile.

Summary

For files that are dehydrated placeholders inside a Cloud Files API sync root, the shell routes
thumbnail generation to the sync root's registered ThumbnailProvider and never falls back to the
per-extension thumbnail handler
, even when the sync provider explicitly returns
WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER (0x8004B207).

The practical result: a third-party file format can never show a thumbnail for a cloud-only file,
regardless of how correctly its IThumbnailProvider is registered — including registration through an
MSIX manifest (com:Extension + desktop2:ThumbnailHandler).

We hit this with .mdp, the native document format of MediBang Paint and FireAlpaca
(MediBang Inc.). MediBang Paint for Desktop is published on the Microsoft Store, so the format is
affected on a product Microsoft itself distributes. Our thumbnail handler is correct and works for
ordinary local files; it is simply never invoked once a file becomes a placeholder.

This is reproducible with Microsoft's own CloudMirror sample, modified by 15 lines (patch at the
end of this issue).

Reported by

MediBang Inc. — publisher of MediBang Paint for Desktop on the Microsoft Store
(MediBangInc.MediBangPaintforDesktop). .mdp is the native format of MediBang Paint and
FireAlpaca, used by a large drawing-app user base that stores work in OneDrive by default.

Environment

OS Windows 11 Pro 10.0.26200, 25H2, UBR 9168
OneDrive 26.150.0804.0011 (Personal)
Windows SDK 10.0.26100.0
Sample microsoft/Windows-classic-samplesSamples/CloudMirror (main)

Reproduction

  1. Register a thumbnail handler for .mdp (MediBang Paint / FireAlpaca documents) via an MSIX package
    (com:Extension / windows.comServer + desktop2:ThumbnailHandler).
    Verified working for ordinary local files.
  2. Build and install the CloudMirror sample, patched so that
    ThumbnailProvider::GetThumbnail() returns a chosen HRESULT (patch at the end of this issue).
  3. Place .mdp files in the "server" folder and let CloudMirror create dehydrated placeholders
    (FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS, attributes 0x401620) in the sync root.
  4. Query thumbnails with IThumbnailCache::GetThumbnail(item, 96, WTS_EXTRACT) and inspect the
    returned HBITMAP. Use a fresh file name for each run — the thumbnail cache survives
    registration changes, dehydration and provider restarts, and will otherwise mask the result.

Results

# What ThumbnailProvider::GetThumbnail() returns Observed
1 Stock sample: delegates via BHID_ThumbnailHandler on the source item Thumbnail rendered. Confirmed in Explorer with the cloud-only badge still present
2 WTS_E_EXTRACTIONPENDING (0x8004B205) No thumbnail. Caller receives 0x8004B205 on every retry; it never resolves
3 WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER (0x8004B207) No thumbnail. 0x8004B207 is returned verbatim to the caller. No fallback occurs

Case 1 proves the shell can display thumbnails for dehydrated placeholders — the limitation is not
inherent to Files On-Demand.

Case 1 — .mdp thumbnails on cloud-only placeholders in the CloudMirror sync root. Note the
cloud-only badge on each item; nothing was hydrated.

Case 1: distinct thumbnails render on cloud-only placeholders, cloud badge still present

Case 3 is the issue: a constant exists that names precisely this situation
("no storage provider thumbnail handler"), yet returning it produces no fallback behaviour.

Why this matters

OneDrive behaves like case 2. For extensions its service cannot render server-side, it returns
WTS_E_EXTRACTIONPENDING rather than a terminal error, and the request never completes.

The same .mdp files under OneDrive. The MSIX-registered thumbnail handler is never invoked, so
only the static file-type icon is shown. The .psd and .png files in the same folder do get
thumbnails — those are formats the OneDrive service renders on its own.

Image

Because there is no fallback path, every third-party format owner is blocked:

Vendor Format Status
Krita .kra KDE Bug 479726 — open; maintainer: "I don't think we can fix this"
Blender .blend blender#115282 — open
MediBang Inc. .mdp (MediBang Paint / FireAlpaca) This report

Note that .one (OneNote) is also affected on the machine used here — Microsoft's own format
shows no thumbnail while cloud-only. This is a plain observation on our test machine, not a claim
about OneNote's design.

Related, though not the same report: WindowsAppSDK #1874
("StorageFile.GetThumbnailAsync does not generate thumbnails for OneDrive files", 2021) covers a
different symptom — thumbnails not being generated on demand for formats OneDrive can render. It
carried the transfer-to-platform label for over two years and was closed in March 2024 with:

Super interesting, but not a WASDK issue. I've filed http://task.ms/49323440 for @RobertStPierre or @luedersj to look into.

We mention it only to note that thumbnail behaviour on placeholders has been raised before and
routed to an internal task with no public outcome. The problem described here — no fallback to the
per-extension handler — is distinct and, as far as we can find, has not been reported with a
reproduction.

Requests

1. (Defect) Do not leave WTS_E_EXTRACTIONPENDING outstanding for work that will never complete.
When the service is known not to support an extension, return a terminal error so callers stop
retrying. This alone does not restore thumbnails, but it removes wasted work.

2. (The actual fix) Let the shell fall back to the registered per-extension handler when the sync
provider declines.
WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER already names this case. Honouring it
would unblock every format owner at once, with no change required from any third party.

As an alternative to (2), a documented opt-in whereby the sync provider hydrates a single file on
demand and delegates — the pattern the CloudMirror sample itself demonstrates — would also resolve it.

Patch

The full change to Samples/CloudMirror/CloudMirror/ThumbnailProvider.cpp. Nothing else in the
sample affects the result; a second small patch only replaces the folder-picker dialogs with
environment variables so the run is non-interactive.

@@ -55,6 +55,21 @@ IFACEMETHODIMP ThumbnailProvider::GetThumbnail(_In_ UINT width, _Out_ HBITMAP* bitmap, _Out_ WTS_ALPHATYPE* alphaType)
     *bitmap = nullptr;
     *alphaType = WTSAT_UNKNOWN;

+    // [EXPERIMENT] Override the return value via MBP_THUMB_MODE. Unset = stock sample behaviour.
+    //   nostorage = return WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER (0x8004B207)
+    //   pending   = return WTS_E_EXTRACTIONPENDING (0x8004B205)  (what OneDrive is observed to do)
+    //   notimpl   = return E_NOTIMPL
+    {
+        wchar_t mode[64] = {};
+        if (GetEnvironmentVariable(L"MBP_THUMB_MODE", mode, ARRAYSIZE(mode)) > 0)
+        {
+            if (_wcsicmp(mode, L"nostorage") == 0) { return HRESULT(0x8004B207L); }
+            if (_wcsicmp(mode, L"pending") == 0)   { return HRESULT(0x8004B205L); }
+            if (_wcsicmp(mode, L"notimpl") == 0)   { return E_NOTIMPL; }
+        }
+    }
+
     try
     {
         winrt::com_ptr<IThumbnailProvider> thumbnailProviderSource;

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Samples/CloudMirror/CloudMirror/ThumbnailProvider.cpp and the reproduction steps using MBP_THUMB_MODE, then query thumbnails through IThumbnailCache with fresh file names. Compare the three HRESULT cases and confirm whether the shell invokes the registered per-extension handler after WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER; done means the fallback works for dehydrated placeholders without changing the sample's delegation pattern.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.