PresentationFramework.TextStore.GrantLock hangs application on Windows 11
- Dominant language
- C#
- Stars
- 7.7k
- Forks
- 1.3k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 61
Description
### Description
We have a AutoCompleter in our project which uses a RichTextBox internally. When the user writes text we search, and return an object which matches the entered text. In that case we delete the text and replace it with an InlineUIContainer which then displays the found item. The items are interactive and the user might use their contextmenu or copy them to another place.
Currently when users try to perform either of these actions the client hangs, and finally is killed of by the OS.
I have created a MVP which displays the problem which can be seen in the following gif:

If you take a dump of the file, or pauses the Application with a debugger attached the stalling seems to originate from the following stacktrace where the 3 highlighted lines always are present:
`
PresentationFramework.dll!System.Windows.Documents.TextSchema.IsNonMergeableInline(System.Type elementType) Unknown
PresentationFramework.dll!System.Windows.Documents.TextSchema.IsMergeableInline(System.Type elementType) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointerBase.GetBorderingElementCategory(System.Windows.Documents.ITextPointer position, System.Windows.Documents.LogicalDirection direction) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointerBase.IsAtNormalizedPosition(System.Windows.Documents.ITextPointer position, bool respectCaretUnitBoundaries) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointerBase.NormalizePosition(System.Windows.Documents.ITextPointer thisNavigator, System.Windows.Documents.LogicalDirection direction, bool respectCaretUnitBoundaries) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointer.MoveToInsertionPosition(System.Windows.Documents.LogicalDirection direction) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointer.System.Windows.Documents.ITextPointer.MoveToInsertionPosition(System.Windows.Documents.LogicalDirection direction) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointerBase.MoveToLineBoundary(System.Windows.Documents.ITextPointer thisPointer, System.Windows.Documents.ITextView textView, int count, bool respectNonMeargeableInlineStart) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointer.MoveToLineBoundary(int count) Unknown
PresentationFramework.dll!System.Windows.Documents.TextPointer.System.Windows.Documents.ITextPointer.MoveToLineBoundary(int count) Unknown
PresentationFramework.dll!System.Windows.Documents.TextStore.MS.Win32.UnsafeNativeMethods.ITextStoreACP.GetTextExt(int viewCookie, int startIndex, int endIndex, out MS.Win32.UnsafeNativeMethods.RECT rect, out bool clipped) Unknown
[Native to Managed Transition]
[Managed to Native Transition]
`
***`
PresentationFramework.dll!System.Windows.Documents.TextStore.GrantLock() Unknown
PresentationFramework.dll!System.Windows.Documents.TextStore.GrantLockWorker(MS.Win32.UnsafeNativeMethods.LockFlags flags) Unknown
PresentationFramework.dll!System.Windows.Documents.TextStore.RequestLock(MS.Win32.UnsafeNativeMethods.LockFlags flags, out int hrSession) Unknown
`***
`
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.GetMessage(ref System.Windows.Interop.MSG msg, System.IntPtr hwnd, int minMessage, int maxMessage) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) Unknown
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) Unknown
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) Unknown
PresentationFramework.dll!System.Windows.Application.Run() Unknown
Win11TextPointerHang.exe!Win11TextPointerHang.App.Main() Unknown
`
Inspecting it in the Windows Event Log it seems to be a 4-step cycle:
**Problem signature**
Problem Event Name: AppHangB1
Application Name: Win11TextPointerHang.exe
Application Version: 1.0.0.0
Application Timestamp: 6720fc2b
Hang Signature: bec4
Hang Type: 134217728
OS Version: 10.0.22631.2.0.0.768.101
Locale ID: 1030
Additional Hang Signature 1: bec4eacce45c87d222cf0c1d657a150a
Additional Hang Signature 2: c247
Additional Hang Signature 3: c24739b36124a85c61b2550e90c2503b
Additional Hang Signature 4: bec4
Additional Hang Signature 5: bec4eacce45c87d222cf0c1d657a150a
Additional Hang Signature 6: c247
Additional Hang Signature 7: c24739b36124a85c61b2550e90c2503b
### Reproduction Steps
Can be repoduced as follows.
0. Build the below as a WPF Framework 4.8 App.
1. Then start the application and write text in the textbox such that the next line in the textbox is activated f.ex. 'testing' will do the trick.
2. Then press the button to convert the text to delete the old text and convert it to an InlineUIContainer.
3. Then try to either select all the text in the textbox or spawn a contextmenu for the new item.
4. Hang.
```c#
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace Win11TextPointerHang
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitializeTextBox();
}
private void Button_Click(object sender, RoutedEventArgs e)
=> ReplaceCurrentTextWithItem();
private void ReplaceCurrentTextWithItem()
{
if (!GetCurrentText(out TextPointer pos, out string text))
return;
// This line seems to be the trigger point for the error.
pos.DeleteTextInRun(-text.Length);
TextBoxInlines.Add(BuildItem(text));
}
private bool GetCurrentText(out TextPointer pos, out string beforeText)
{
pos = ItemsTextBox.CaretPosition;
if (pos == null)
{
beforeText = null;
return false;
}
beforeText = pos.GetTextInRun(LogicalDirection.Backward) ?? "";
return true;
}
#region Helpers
private InlineCollection TextBoxInlines { get; set; }
private void InitializeTextBox()
{
var paragraph = new Paragraph();
ItemsTextBox.Document.Blocks.Add(paragraph);
TextBoxInlines = paragraph.Inlines;
TextBoxInlines.Add(BuildItem("A really long line that takes most of the space"));
}
private InlineUIContainer BuildItem(string text)
=> new InlineUIContainer(new Label
{
Content = text,
Background = Brushes.Yellow,
Margin = new Thickness(0, 0, 6, 0)
});
#endregion
}
}
```
```html
```
### Expected behavior
You can delete text in a textrun via the TextPointer.DeleteTextInRun.
### Actual behavior
Deleting text with TextPointer.DeleteTextInRun hangs the applicaiton.
### Regression?
Works in Windows 10 - seems isolated to Windows 11
### Known Workarounds
_No response_
### Impact
The bug impacts all users on Windows 11 which try to interact (selection or context menu) with an item which has just been created in a RichTextBox.
### Configuration
**.Net:**
Framework 4.8
**OS:**
Windows 11 Pro for Workstations
23H2 - 22631.4391
**Architecture **
x64
**Configuration**
Observed across multiple different computers which all runs Windows 11. Windows 10 cannot reproduce the problem.
First observed around mid June this year, but we have few customers on Windows 11 so might have existed for longer.
### Other information
OBS: There seems to be some limitations to the problem.
- It cannot be the first item
- You can still select/spawn contextmenu for the first item after the problem is in an active state.
- The problem only arises if you interact with the new elements.
- The problem only arises if the TextPointer.DeleteTextInRun is called, just creating InlineUIContainers cannot reproduce the problem.
- The problem only arises if the new InlineUIContainer spawns on a new line in the RichTextBox
Contributor guide
Assessment
This issue has not been assessed yet.