Skip to content

PickerHost and medium-IL processes with package identity refuse to load preview handlers #6116

@GeeLaw

Description

@GeeLaw

Describe the bug

Common file dialogs in a process with package identity (even if the process is medium IL) and file picker host refuse to load preview handlers (registered under shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}). If the file uses a preview handler, then the preview pane is blank when opened.

(However, if the file uses a thumbnail handler, the thumbnail can be shown. This allows "previewing" picture files.)

Steps to reproduce the bug

First, install a preview handler, e.g., Windows TXT preview handler, Adobe PDF preview handler, Word preview handler. Note that this creates a healthy mix of stuffs:

  • Windows TXT preview handler is hosted by the system surrogate and runs at low IL.
  • Adobe PDF preview handler is hosted by the system surrogate and runs at low IL, but the system-hosted object needs to launch Acrobat Reader at low IL.
  • Word preview handler runs out-of-process at medium IL (it also has an in-process handler).

For each of the following apps:

  • Windows Terminal (installed from Store)
  • Windows Terminal (ZIP version)
  • Notepad (new)
  • PowerPoint (installed by Click-to-Run)

Do the following:

  1. Launch the app, invoke its "open file" dialog, use * to force displaying all files.
  2. Select (give focus to, not clicking "Open" button) a file (.txt or .docx).
  3. Press Alt+P to open/close the preview pane.

For Notepad, PowerPoint, the "open file" dialog is easy to trigger. For Windows Terminal, go to Settings, then Profile, then Defaults, then Icon, and choose File, and close "Browse...".

Expected behavior

Preview handlers should load. There should be no security concern for the aforementioned apps.

  • Preview handlers always run out-of-process, so there's no danger of injecting arbitrary code into pickerhost.exe or the app using common dialogs.
  • Those apps already run at medium IL, so launching a preview handler won't increase IL.

However, only Windows Terminal (ZIP) and PowerPoint (Click-to-Run) are able to load preview handlers. No preview handler (TXT or Word) loads in Windows Terminal (Store) or Notepad (new).

Personally, I agree that pickerhost.exe called by low-IL apps (typical UWP apps) should refrain from loading preview handlers, because the picker host is medium-IL only to help the low-IL process.

Screenshots

In the screenshot below:

  • The active window is Notepad (new)'s own "open file" dialog (not pickerhost.exe, has package identity).
  • The active window has blank preview pane. This means a preview handler is detected (otherwise it will say "No preview available.") and the shell doesn't consider the preview handler to have an error (otherwise it will say "This file can't be previewed." or "This file can't be previewed because of an error in the ... previewer."). It's as if the preview handler suddenly disappeared (e.g., if a preview handler is shown, then you terminate the preview handler's server process without touching File Explorer, this is what happens).
  • The background window is File Explorer, showing that the file can be previewed.
  • The reason the file can't be previewed in Notepad (new) is not because of exclusive access to the file. I just took the screenshot together. Even if you just try one window at a time, Notepad (new) still doesn't work and File Explorer still works.

Image

NuGet package version

None

Packaging type

Packaged (MSIX)

Windows version

Windows 11 version 24H2 (26100, June 2025 Update)

IDE

Other

Additional context

I played with those apps in the debugger and found the following. When the shell preview host is about to run, it calls (the signature is conjured from the mangled name from Microsoft symbol server's shell32.pdb and typical COM paradigm)

// static
HRESULT CRichPreviewBackgroundThreadData::CreateInstance(
  CRichPreviewThreadParams *pParams,
  CRichPreviewBackgroundThreadData **ppData
);

This method will invoke _InitializePreviewWindow on the CRichPreviewBackgroundThreadData it's about to return, and if the initialization fails, it bails out.

The initialization method sets the thread's IL to low and calls CoCreateInstance to create CLSID_PreviewWindowCreator in an out-of-process local server with cloaking enabled. The class is surrogated in the standard system preview host. Regardless of whether CoCreateInstance succeeds, the thread will end its impersonation after the call.

It appears the CoCreateInstance call fails when the process has a package identity or if the process is pickerhost.exe. If there's no package identity and the process is a usual medium-IL process, then the call succeeds and hands back a proxy to low-IL preview window creator object (in prevhost).

If the process has a package identity, CoCreateInstance fails with E_ACCESSDENIED, which later causes the preview handler worker to abandon its operation (so no preview handler is shown).

As far as I remember, the effect has been like this since Windows 10 introduced support of packaged medium-IL apps. Whether that's intended, I have no idea.

The documentation of CoCreateInstance talks about limitations imposed on UWP apps (out-of-process activation often fails with E_ACCESSDENIED). The packaged apps are not always UWP (app container) apps. Together with the documentation of CoCreateInstanceFromApp, it appears the limiting factor should be presence of app container token in thread/process, instead of presence of package identity?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions