microsoft / microsoft/microsoft-ui-xaml

Structured Exception Handling in WinUI apps

Open
#10,635 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-triage
Dominant language
C++
Stars
8.4k
Forks
942
Avg merge
2d 7h
Merged PRs (30d)
105

Description

Describe the bug

The main WinUI thread interferes with Structured Exception Handling.

A top-level unhandled exception filter doesn't get called, no matter whether it's set as early as possible (on startup in App constructor or DllMain), or as late as possible (immediately before triggering a test crash).

LONG WINAPI HandleGlobalException(EXCEPTION_POINTERS* exceptionInfo) {
    OutputDebugString(L"HandleGlobalException\n");
    return EXCEPTION_CONTINUE_SEARCH;
}

void TriggerCrash()
{
    volatile int* pInt = 0x00000000;
    *pInt = 20;
}

void winrt::BlankApp::implementation::MainWindow::OnButtonClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    LPTOP_LEVEL_EXCEPTION_FILTER lpOldFilter = SetUnhandledExceptionFilter(&HandleGlobalException);

    TriggerCrash(); // HandleGlobalException does not get called

    SetUnhandledExceptionFilter(lpOldFilter);
}
Steps to reproduce the bug
  1. Create a new Visual Studio C++ project: WinUI Blank App
  2. Install a top-level Unhandled Exception Filter
  3. Start without debugging
  4. Trigger a crash
Expected behavior

The Unhandled Exception Filter gets called.

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.7.3: 1.7.250606001

Windows version

Windows 11 (24H2): Build 26100

Additional context

Originates from:

Additional notes:

  • Manually wrapping TriggerCrash() with __try and __except does work, but does not help a generic crash handler much :)
    __try {
        TriggerCrash(); // HandleLocalException does get called
    }
    __except (HandleLocalException(GetExceptionInformation())) {
    }
    
  • The filter does get called if a crash is triggered from a worker thread:
    std::thread([]() {
        LPTOP_LEVEL_EXCEPTION_FILTER lpOldFilter = SetUnhandledExceptionFilter(&HandleGlobalException);
    
        TriggerCrash(); // HandleGlobalException does get called
    
        SetUnhandledExceptionFilter(lpOldFilter);
    }).join();
    

Contributor guide

Open the contributing guide

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

Reproduce the issue in a new Visual Studio C++ WinUI Blank App using the startup and button-click locations described, then compare the main UI thread with the worker-thread example. Check how WinUI 3 handles the top-level unhandled exception filter and confirm that the expected filter callback occurs for a main-thread crash without requiring a local __try/__except wrapper.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
desktop, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.