Microsoft-ui-xaml: Bug: [uwp] RectHelper is the opposite of helping (RPC_E_WRONG_THREAD)

Created on 29 Jun 2020  路  12Comments  路  Source: microsoft/microsoft-ui-xaml

Trust me, this is not the first title I came up with.

RectHelper.Intersect throws an exception: The application called an interface that was marshalled for a different thread.

image

My take is that this is because I'm not calling RectHelper.Intersect on the UI thread (I can't think of any other possibilities).

However, how can this happen, for something that should be so simple?

It's like forcing us to use Math.Sin only on the UI thread. Who in their right mind would do such a thing?

Please, either fix it, or just throw away the whole RectHelper class.

needs-winui-3 team-Framework

Most helpful comment

Sorry you ran into this issue. I moved this to the Xaml repo because that's where this is implemented, and it's something we could address in WinUI3. Much of Xaml depends on running on the UI thread and performs runtime validation checks, but these static members shouldn't need to be restricted.

All 12 comments

Does this also crash when running the function on the UI thread?


Also, while I can see that errors and random exceptions are annoying, please don't use wording such as "how can you design something so stupid" and adhere to the Microsoft Code of Conduct. Such language is neither respectful nor is it helping in having a welcoming and friendly discussion :)

Does this also crash when running the function on the UI thread?

No, it does not crash in that case.

Also, while I can see that errors and random exceptions are annoying, please don't use wording such as "how can you design something so stupid" and adhere to the Microsoft Code of Conduct. Such language is neither respectful nor is it helping in having a welcoming and friendly discussion :)

Trust me, I'm doing my best to keep things civil, but there's so many things wrong with WinRT that I sometimes can't. It's really easy for you, 'cause you don't have deadlines and stuff, there's no pressure. But in my case, there is.

Having said that, I do stand by my words - why would ANYONE design such a simple function to require being in the UI thread?

Trust me, I'm doing my best to keep things civil, but there's so many things wrong with WinRT that I sometimes can't. It's really easy for you, 'cause you don't have deadlines and stuff, there's no pressure. But in my case, there is.

Trust me I also have deadlines, but nice of you to assume that I don't :)
That said, yes if things don't work especially in a stressful environment we all can lose our temper. But I don't think that anyone who worked on winrt thought: "Yes, let's annoy people who use winrt and sprinkle some random crashes in here." After all, we are all humans and make mistakes, some make more, some make less. I hope that things improve for you soon, and the number of bugs you encounter hopefully declines with more and more code going open source and people contributing fixes.

Having said that, I do stand by my words - why would ANYONE design such a simple function to require being in the UI thread?

I'm a bit surprised too that it requires the UI thread, maybe there is a reason for this we don't know, maybe this just an oversight.

Trust me I also have deadlines, but nice of you to assume that I don't :)

Sorry about that.

That said, yes if things don't work especially in a stressful environment we all can lose our temper. But I don't think that anyone who worked on winrt thought: "Yes, let's annoy people who use winrt and sprinkle some random crashes in here." After all, we are all humans and make mistakes, some make more, some make less. I hope that things improve for you soon, and the number of bugs you encounter hopefully declines with more and more code going open source and people contributing fixes.

I'm not saying people at winrt intentionally do that, I'm annoyed that bugs such as this simply shouldn't happen.

I'm sooo tired of dealing with bugs/issues/inconsistencies/whatever coming from WinRT/UWP.

Another example from yesterday, where I pretty much wasted about 6 hours: An exception thrown when trying to add a control to a panel ("No installed components detected. Element is already a child of another element" - even though control.Parent returns null, and so does VisualTreeHelper.GetParent(). Turns out, when an ascendant is removed from screen, the control.Parent returns null, even though it's still attached to a parent.

Whenever I say, "Oh finally, it's working", some weird issue comes up that makes me waste another 2-3 days. It's beyond exhausting.

I'm a bit surprised too that it requires the UI thread, maybe there is a reason for this we don't know, maybe this just an oversight.

I don't mind some issues, where I can believe - it could be an oversight. This specific case feels like carelessness.

I'm not saying people at winrt intentionally do that, I'm annoyed that bugs such as this simply shouldn't happen.
I'm sooo tired of dealing with bugs/issues/inconsistencies/whatever coming from WinRT/UWP.

Yes I feel you. Though looking back at early android development, WinRT/UWP is definitely better. After all you have a decent documentation, places where you can ask questions and file bug issues. When I tried android development, documentation wasn't a thing, API's threw around null left and right and finding something on StackOverflow wasn't easy either.

But yes, WinRT and UWP definitely have things to improve on!

Another example from yesterday, where I pretty much wasted about 6 hours: An exception thrown when trying to add a control to a panel ("No installed components detected. Element is already a child of another element" - even though control.Parent returns null, and so does VisualTreeHelper.GetParent(). Turns out, when an ascendant is removed from screen, the control.Parent returns null, even though it's still attached to a parent.

The Parent property is only in relation to the VisualTree. If you have controls that are not in the visual tree but render children, those childrens Parent property would return null as they don't have a VisualTree parent since they are not in the visual tree. That's at least how I would interpret the documentation on that. But maybe the documentation should be more clear on that.

I don't mind some issues, where I can believe - it could be an oversight. This specific case feels like carelessness.

Maybe someone from the team can knows why the behavior is the way it is.

@jtorjo - I'm surprised at the error you're seeing, as RectHelper is attributed for "agile" marshalling and "both" threading. As you suggest, there could be a basic oversight in its implementation. A repro would be much appreciated. That said, WinRT helper classes like RectHelper are not necessary in C#. Types like Rect, Size, and Point have custom projections to structs with those helper methods (e.g., Rect.Intersects ), and these are defined in C#, avoiding inefficient calls across the ABI. Can you use that instead?

@Scottj1s Thanks for the reply!

@jtorjo - I'm surprised at the error you're seeing, as RectHelper is attributed for "agile" marshalling and "both" threading. As you suggest, there could be a basic oversight in its implementation. A repro would be much appreciated.

I'll look into it - but it's simply a RectHelper.Intersect call on a non-UI thread.

That said, WinRT helper classes like RectHelper are not necessary in C#. Types like Rect, Size, and Point have custom projections to structs with those helper methods (e.g., Rect.Intersects ), and these are defined in C#, avoiding inefficient calls across the ABI. Can you use that instead?

I would definitely not used this, had the default Rect.Intersect not been in-place. In my mind, RectHelper.Intersect should have been an exact same implementation of Rect.Intersect, only that it would not have been in place.

When I saw the error, after getting extremely annoyed, I tested the simple Rect.Intersect, and it does not throw any exception. So, I basically I created a simple wrapper

    public static Rect intersect(this Rect r, Rect other) {
        var copy = r;
        copy.Intersect(other);
        return copy;
    }

But the point is, this is extremely confusing: you can have code that works correctly, and then get a crash at the customer site, when your code gets executed on another thread. People simply don't expect that - it's a simple class, it should not have any unintended side effects. Even had it been written in the docs (which is not), I shouldn't have to read the docs for a function that is supposed to be trivial to implement.

Yes I feel you. Though looking back at early android development, WinRT/UWP is definitely better. After all you have a decent documentation, places where you can ask questions and file bug issues. When I tried android development, documentation wasn't a thing, API's threw around null left and right and finding something on StackOverflow wasn't easy either.

I do understand that. I'm talking about someone coming from WPF, being used to having pretty much no issues whatsoever, to WinRT/UWP and having to deal with them, and losing countless days that could be spent developing useful features, all the while MS is touting that "UWP is the next big thing". All the while, I haven't seen a decently complex UWP app from MS (I would call a decently complex app, something in the 50K LOC range)

The Parent property is only in relation to the VisualTree. If you have controls that are not in the visual tree but render children, those childrens Parent property would return null as they don't have a VisualTree parent since they are not in the visual tree. That's at least how I would interpret the documentation on that. But maybe the documentation should be more clear on that.

I honestly don't mind the exception, had it had a clear and understandable message. And more to the point, what's the culprit. Googling for the error ended up being pretty much useless. So my point is - if you throw an error, if it's a logical error, I should be able to understand how to fix it.

Sorry you ran into this issue. I moved this to the Xaml repo because that's where this is implemented, and it's something we could address in WinUI3. Much of Xaml depends on running on the UI thread and performs runtime validation checks, but these static members shouldn't need to be restricted.

but these static members shouldn't need to be restricted.

Thanks, agreed 100%

@jtorjo - if it helps lessen the pain, the C#/WinRT projection support in .Net 5 actively excludes these helper types from the projection, so that developers who happen to not see the docs won't fall into that pit (even with the thread affinity fix, there's still the inefficiency of these calls). Thanks a lot for reporting the issue.

@Scottj1s Thanks! As I said, I would never have originally used this, if Rect.Intersect would have returned a copy, instead of being in-place.

Was this page helpful?
0 / 5 - 0 ratings