microsoft / microsoft/microsoft-ui-xaml

TitleBar reading AppWindow.Title during layout can fail-fast the process (windowing GetTitle E_INVALIDARG on empty title)

Open
#11,214 0 comments 0 reactions 0 assignees View on GitHub
area-AppWindow area-TitleBar needs-triage team-Core
Dominant language
C++
Stars
8.4k
Forks
942
Avg merge
2d 7h
Merged PRs (30d)
105

Description

### Description

An app that uses the `TitleBar` control (with `ExtendsContentIntoTitleBar`) can **fail-fast during startup** with `E_INVALIDARG (0x80070057)` originating from the windowing layer while resolving `AppWindow.Title`, triggered from `TitleBar::UpdateTitle` during a deferred layout pass.

Representative stack (top frames):

```
Microsoft.UI.Windowing!...RaiseFailFastException
Microsoft.UI.Windowing!CFlat::Abandonment::FailWithHR
Microsoft.UI.Windowing!...Marshal::ThrowExceptionForHR
Microsoft.UI.Windowing!Core::YieldAndCall::GetTitle // AppWindow.Title getter
Microsoft.UI.Windowing!Api::IAppWindow::get_Title
Microsoft.UI.Xaml.Controls!TitleBar::UpdateTitle
Microsoft.UI.Xaml.Controls!TitleBar::OnApplyTemplate
...deferred layout / measure pass...
```

### Root cause

`AppWindow.Title`'s getter is a wrapper over `GetWindowTextLengthW` / `GetWindowTextW`. `GetWindowTextLengthW` returns **0 for a window with an empty title**, which is a *valid* result — not an error — and (per Win32 docs) it does **not** reset the thread's last-error on that path.

The getter treats length `0` as failure and converts whatever value `GetLastError()` currently holds. When a previous, unrelated call on the UI thread left `ERROR_INVALID_PARAMETER (0x57)` behind, the getter produces `HRESULT_FROM_WIN32(0x57) = 0x80070057 (E_INVALIDARG)`, and the windowing layer escalates that failed HRESULT to a **fail-fast**.

This is intermittent by nature: it requires the native window title to be **empty** at the instant of the read **and** a stale `0x57` on the thread at the same time. `TitleBar::UpdateTitle` reads `AppWindow.Title` during a deferred layout pass (`OnApplyTemplate` → `UpdateTitle`, and again from `ResetTitle`), which is exactly when a window's native title can still be momentarily empty during startup.

### Where it comes from in TitleBar

`TitleBar::UpdateTitle` reads the window title twice:

```cpp
// capture default (fires on first UpdateTitle, e.g. during OnApplyTemplate)
m_defaultAppWindowTitle = appWindow.Title();
...
// redundant-set optimization
const auto currentTitle = appWindow.Title();
if (currentTitle != titleText) { appWindow.Title(titleText); }
```

and `TitleBar::ResetTitle` reads it a third time. Each of these getter reads can trip the windowing fail-fast above.

### Suggested fixes

Two independent layers:

1. **Windowing (the true fix):** `AppWindow.Title`'s getter should treat a length of `0` as a valid empty title. Concretely: `SetLastError(ERROR_SUCCESS)` before `GetWindowTextLengthW`/`GetWindowTextW`, and only treat a *nonzero* last-error as a real failure (return an empty string with `S_OK` otherwise). This is the classic `GetWindowTextLength`-returns-0-for-empty-title pattern documented on MSDN.

2. **WinUI `TitleBar` (mitigation / hardening):** avoid reading `AppWindow.Title()` back in `UpdateTitle`/`ResetTitle`. A `try/catch` in the control does **not** help, because the failure is a fail-fast *inside* the windowing callee, not a returnable HRESULT — so the only WinUI-side mitigation is to not perform the getter reads (set the title unconditionally; track state internally rather than reading back). Tradeoff: the automatic "restore the window's original title when `TitleBar.Title` is cleared" behavior would need to be reworked or dropped. I'll open a draft PR with this approach for discussion.

### Workaround (app side)

Ensure the window's native title is never empty when the `TitleBar` is present (e.g., set a non-empty `Window.Title`/`AppWindow.Title` before the title bar's first layout, and guard against empty title strings from resource lookups). Example: microsoft/PowerToys#49069.

### Version

- Windows App SDK 2.0.x (`TitleBar` control), reproduced on in-market Windows 11.

Contributor guide

Open the contributing guide

Research direction

Start at TitleBar::UpdateTitle and ResetTitle, including the path from OnApplyTemplate, and trace each AppWindow.Title read into the windowing getter. Compare the two suggested fix layers and determine which code is available in this repository. Done means an empty native title no longer causes startup fail-fast while TitleBar title behavior remains correct.

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
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.