Skip to content

Fixing the argument type definition of Marshal.GetNativeVariantForObject method in EnumVariantObject#4168

Merged
RussKie merged 1 commit intodotnet:masterfrom
vladimir-krestov:Issue_4121_FixingCheckedListBox_AccessibilityTree
Nov 10, 2020
Merged

Fixing the argument type definition of Marshal.GetNativeVariantForObject method in EnumVariantObject#4168
RussKie merged 1 commit intodotnet:masterfrom
vladimir-krestov:Issue_4121_FixingCheckedListBox_AccessibilityTree

Conversation

@vladimir-krestov
Copy link
Contributor

@vladimir-krestov vladimir-krestov commented Oct 28, 2020

Fixes #4120 (LinkLabel accessiblity tree)
Fixes #4121 (CheckedListBox accessiblity tree)
Fixes #4130 (MSAA UpDown controls)
Fixes #4172 (MSAA CheckedListBox)

Regression from 0c4d3cb

Proposed changes

  • Cast currentChild from uint to int before using in Marshal.GetNativeVariantForObject

Customer Impact

  • A user can see a correct accessibility tree for controls that don't support the UIA provider using Inspect tool

Regression?

Risk

  • Minimal

Screenshots

Before

  • CheckedListBox doesn't have internal items AccessibleObjects in the accessibility tree
    image

After

  • CheckedListBox has the correct accessibility tree with the internal items
    image

Test methodology

  • Manual testing
  • CTI

Accessibility testing

  • Using Inspect tool

Test environment(s)

  • .Net Version: 6.0.0-alpha.1.20513.9
  • Microsoft Windows [Version 10.0.19042.572]
Microsoft Reviewers: Open in CodeFlow

@vladimir-krestov vladimir-krestov requested a review from a team as a code owner October 28, 2020 18:52
Copy link
Contributor

@weltkante weltkante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you identify what causes the erorr? You are changing the signature of a ComImport IUnknown interface, and of private implementation methods, neither of which are relevant (or visible) to external users

  • ComImport means the definition is external (you don't generate the definition)
  • IUnknown means you are implementing the definition without "reflection" support that comes with IDispatch/Dual interfaces (i.e. COM will not be aware of how you implemented it)

I don't see any point in this changeset which could have an effect to external users of the interface. In particular since the official headers also use unsigned numbers there should never be any negative numbers appear anywhere.

If this fixes the problem I'm obviously missing something, and I'd like to know what :-)

@weltkante
Copy link
Contributor

weltkante commented Oct 28, 2020

I think I see it now, you are not actually touching the line which was broken, which is why I missed it. You are changing a lot more than necessary to fix the bug.

The bug probably comes from NextFromChildCollection calling Marshal.GetNativeVariantForObject and being passed an uint instead of an int - by changing all the types to int (even those that shouldn't be according to native spec) you silently fixed the bug without touching the line causing the issue.

The "minmal" (and IMHO correct) fix would be just adding a typecast to Marshal.GetNativeVariantForObject argument instead of changing unrelated signatures from uint to int. The IEnumVariant method signatures don't need to be changed. Perhaps the currentChild should remain changed to int, can't evaluate that since I don't know too much context of its meaning.

TLDR: while the PR fixes the bug I'd argue the signature changes to IEnumVariant are wrong and should be reverted. They are not wrong enough to break anything, but they deviate from the usual guideline to keep signedness when transcribing native APIs.

@RussKie
Copy link
Contributor

RussKie commented Oct 29, 2020

I had a brief chat with @JeremyKuhne, and whilst our definitions match those in oaidl.h (uint == ULONG), there's probably a contraction/expansion of the underlying value somewhere in the flow that leads to the loss/incorrect signedness...

The "minmal" (and IMHO correct) fix would be just adding a typecast to Marshal.GetNativeVariantForObject argument

👍

@vladimir-krestov vladimir-krestov force-pushed the Issue_4121_FixingCheckedListBox_AccessibilityTree branch from efb3a4e to 063108a Compare October 29, 2020 04:18
@codecov
Copy link

codecov bot commented Oct 29, 2020

Codecov Report

Merging #4168 (ad70d15) into master (8dccbc0) will decrease coverage by 0.00774%.
The diff coverage is n/a.

@@                 Coverage Diff                 @@
##              master       #4168         +/-   ##
===================================================
- Coverage   98.12512%   98.11738%   -0.00774%     
===================================================
  Files            497         497                 
  Lines         258523      258523                 
  Branches        4492        4492                 
===================================================
- Hits          253676      253656         -20     
- Misses          4089        4105         +16     
- Partials         758         762          +4     
Flag Coverage Δ
Debug 98.11738% <ø> (-0.00774%) ⬇️
production ?
test 98.11738% <ø> (-0.00774%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@vladimir-krestov
Copy link
Contributor Author

@weltkante, you are cool as always! You are right.
The typecasting inside Marshal.GetNativeVariantForObject method is a sufficient change for the accessiblity tree to work correctly.

I really agree that changing IEnumVariant methods signature looks confusing because IEnumVARIANT.Next method has ULONG arguments (A ULONG is a 32-bit unsigned integer (range: 0 through 4294967295 decimal)) and it means (uint == ULONG). So it seems using uint for IEnumVARIANT is more correct.

Maybe @hughbe could say should we change currentChild type from uint to int in EnumVariantObject? Or can we keep it as is now?

@vladimir-krestov vladimir-krestov changed the title Fixing arguments types definitions of IEnumVariant methods Fixing the argument type definition of Marshal.GetNativeVariantForObject method in EnumVariantObject Oct 29, 2020
@vladimir-krestov vladimir-krestov added the waiting-review This item is waiting on review by one or more members of team label Oct 29, 2020
@weltkante
Copy link
Contributor

weltkante commented Oct 29, 2020

there's probably a contraction/expansion of the underlying value somewhere in the flow that leads to the loss/incorrect signedness

I didn't see anything of that sort, but Marshal.GetNativeVariantForObject will chose the type of the variant based on the type of the argument you pass in, so if the native code wants an "enumerator of signed integers" you need to pass a signed integer to get a I4 variant.

The signedness of the IEnumVARIANT method arguments has nothing to do with the signedness of the values you are enumerating. Thats why it may be more correct to use int for currentChild (if it represents the enumerated values), but if you are confident that it never becomes negative its just as fine to keep it unsigned and only cast when handing it out through the native API. Especially if that saves you from a lot of typecasts in the implementation.

weltkante
weltkante previously approved these changes Oct 29, 2020
@vladimir-krestov vladimir-krestov added the waiting-for-testing The PR is awaiting manual testing by the primary team; no action is yet required from the author(s) label Oct 29, 2020
@RussKie RussKie added waiting-author-feedback The team requires more information from the author and removed waiting-review This item is waiting on review by one or more members of team labels Oct 29, 2020
@vladimir-krestov vladimir-krestov force-pushed the Issue_4121_FixingCheckedListBox_AccessibilityTree branch from 063108a to 3cc6ddc Compare November 4, 2020 07:34
@ghost ghost removed the waiting-author-feedback The team requires more information from the author label Nov 4, 2020
RussKie
RussKie previously approved these changes Nov 9, 2020
weltkante
weltkante previously approved these changes Nov 9, 2020
for EnumVariantObject

The fix allows users to see the correct accessibility tree of controls that don't support UIA using Inspect tool
Fixes dotnet#4120 (LinkLabel accessiblity tree)
Fixes dotnet#4121 (CheckedListBox accessiblity tree)
The regression from 0c4d3cb
@vladimir-krestov vladimir-krestov dismissed stale reviews from weltkante and RussKie via ad70d15 November 10, 2020 06:54
@vladimir-krestov vladimir-krestov force-pushed the Issue_4121_FixingCheckedListBox_AccessibilityTree branch from 3cc6ddc to ad70d15 Compare November 10, 2020 06:54
@vladimir-krestov vladimir-krestov added waiting-review This item is waiting on review by one or more members of team and removed waiting-for-testing The PR is awaiting manual testing by the primary team; no action is yet required from the author(s) labels Nov 10, 2020
@vladimir-krestov
Copy link
Contributor Author

Testers approved the fix ✔️

@RussKie RussKie removed the waiting-review This item is waiting on review by one or more members of team label Nov 10, 2020
@RussKie RussKie merged commit 5af42bf into dotnet:master Nov 10, 2020
@ghost ghost added this to the 6.0 Preview1 milestone Nov 10, 2020
@vladimir-krestov vladimir-krestov deleted the Issue_4121_FixingCheckedListBox_AccessibilityTree branch December 8, 2020 17:07
@ghost ghost locked as resolved and limited conversation to collaborators Jan 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.