Repository navigation
Support decimal in automation ComVariant (fixes NumericUpDown crash under UIA) - #21634
Merged
MrJul merged 1 commit intoJun 24, 2026
Merged
Conversation
NumericUpDown.Value is a decimal?, so changing it while a UI Automation client is attached raised an automation property-changed event whose boxed decimal hit no case in ComVariant.Create and threw an unhandled ArgumentException that crashed the process. The event only fires when a UIA client is listening, so it reproduced only on "some machines". Mirror the BCL System.Runtime.InteropServices.Marshalling.ComVariant (which this type is based on): overlay a decimal field on the variant, write it before setting the VT_DECIMAL discriminator in Create (the discriminator overlaps the decimal's unused leading bytes), and clear that discriminator on a copy before reading the value back in AsObject. Fixes AvaloniaUI#21491
|
You can test this PR using the following package version. |
Collaborator
|
Contributor
Author
|
@cla-avalonia agree |
MrJul
approved these changes
Jun 24, 2026
MrJul
left a comment
Member
There was a problem hiding this comment.
The change matches .NET's own ComVariant.
LGTM!
MrJul
added this pull request to the merge queue
Jun 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does the pull request do?
ComVariant.Createhas no case fordecimal, so it throwsArgumentExceptionfor anydecimalautomation value.NumericUpDown.Valueis adecimal?, so changing it while a UI Automation client is connected crashes the app. This addsVT_DECIMALsupport toComVariant.This is the root-cause
ComVariantfix that @maxkatz6 identified in #21515 (which was closed with the CLA unsigned). I've scoped it to justComVariant. There are noNumericUpDownAutomationPeerchanges.Fixes #21491.
What is the current behavior?
Setup: Windows, with any UI Automation client connected so Narrator, Magnifier, Voice Access, the touch keyboard (TabTip) that Steam opens, the "Show pointer location" setting, etc. Then spinning, typing, or setting a
NumericUpDownvalue crashes the process:The event is only raised when a UIA client is listening, which is why it looks like it only happens on some machines.
What is the updated/expected behavior with this PR?
decimalmarshals toVT_DECIMALand round-trips back, so the property-changed event is raised without throwing and the app keeps running.To check:
dotnet new avalonia.app, add a<NumericUpDown/>, run with Narrator on (Ctrl+Win+Enter), and change the value. It crashes onmasterand works with this change.I've created a minimal demo Project to replicate and prove the issue. When running it, attach Narrator (or the included
trigger-uia.ps1, which subscribes a programmatic UIA client so no screen reader is needed), then try to change the value.UiaDecimalCrashPoc.zip
How was the solution implemented (if it's not obvious)?
Same approach as the BCL
System.Runtime.InteropServices.Marshalling.ComVariant, which this type is based on:decimalfield that overlaps the whole variant. Adecimaldoesn't use its first two bytes, so_vtstill encodes the type; the existingTypeUnionlayout already lines up withDecimal._flags. Automation here is Windows-only (little-endian), so there's no big-endian case to handle.Create, set the value beforeVarType = VT_DECIMAL, since the type discriminator overlaps the decimal's unused leading bytes.AsObject, clear the discriminator on a copy (VarType = VT_EMPTY) before returning, so theVT_DECIMALflag doesn't leak into the value.Checklist
Avalonia.Win32.Automationexposes its internals only toAvalonia.Win32and has no unit-test project yetBreaking changes
None.
Obsoletions / Deprecations
None.
Fixed issues
Fixes #21491