-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RO_INIT_MULTITHREADED doesn’t work for everything #62
Comments
Unfortunately, I wouldn't call myself an expert in WinRT threading, and I'm
not sure what's causing the issue you're seeing.
That said, it probably makes sense to expose the threading model setting
for the library -- presumably the various settings exist for a reason.
…On Thu, Jan 24, 2019, 5:38 AM Chris Morgan ***@***.*** wrote:
I have not taken the time to grasp the difference between the different
RO_INIT_*THREADED values (I have done literally *no* research, and I
won’t have a chance to until next week), but what I *observe* is that
this code:
use winrt::{RtActivatable};
use winrt::windows::web::ui::interop::{WebViewControlProcess, WebViewControlProcessOptions};
let options = WebViewControlProcessOptions::get_activation_factory()
.activate_instance()
.query_interface()
.unwrap();
WebViewControlProcess::create_with_options(&options);
(Ugh, is that activation factory business *really* how to do it? It took
me a while to get that far, but I think it’s about right, which is very
icky! But that’s by the bye.)
… failed with code 0x8000001D, which is RO_E_UNSUPPORTED_FROM_MTA,
“Activating a single-threaded class from MTA is not supported.”
As soon as I replaced RuntimeContext::init() with
RoInitialize(RO_INIT_SINGLETHREADED), it started working fine.
I do not know how all of this works with reference to #60
<#60>—as I said, I know
*nothing* at present about the different apartment models beyond the
names and very vague intuitions. @rbtying <https://github.com/rbtying>,
are you perchance an expert?
I know not whether it should switch to single-threaded, or take an
argument to choose.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#62>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA4FwT9jicxenNj1jHyPFyVsXk12T-Wbks5vGbc5gaJpZM4aQ4qF>
.
|
I can try to help out a bit here. WinRT borrows / shares a simplified apartment model with COM. There are two types of apartments, a multithreaded apartment (MTA), which is a singleton, and single-threaded apartments (STA). Single-threaded apartments are strongly associated 1:1 with a single thread. There can be any number of STAs. Any thread which hasn't explicitly opted into an apartment is assumed to be associated with the MTA. Apartments are the unit of dispatch of COM / WinRT marshalled calls (cross-thread or cross-process). A call into an object created from a thread bound to an STA is guaranteed to be delivered to a specific thread, which is often important for UI code correctness and performance. Marshalling and moving objects across threads is a more complex topic, but if you can ensure that the object is only used on the thread you created it on, you can avoid the more complex bits. WebView is an example of a class that enforces that it be used from a thread associated with an STA. Most non-UI related WinRT objects can be used without issue from either an MTA or STA, so it's unlikely this will cause impact to other use of WinRT types within your code. I'm not a rust expert by a long shot, but initializing an STA on the thread that's using the WebView is the correct fix for this issue. Let me know if there's something you'd like me to clarify further. Thanks, Ben Kuhn (msft) |
@chris-morgan I cannot say much about MTA/STA yet, because I need to read up on that first, but here's a quick comment about the activation factory business: let options = WebViewControlProcessOptions::new(); which is provided by the |
About MTA/STA: I think we need to have something like |
The vast majority of APIs work on both multithreaded and singlethreaded / apartmentthreaded. It's not clear to me that it is worthwhile to have RuntimeContext::as_singlethreaded_context() -> Result<&SingleThreadedRuntimeContext>, since the programmer is just going to |
What happens when an application initializes with STA, and uses a library (I'm thinking about something like https://github.com/allenbenz/winrt-notification) which initializes with MTA (because that's the "default") ... that's going to be a problem, right? So the library either needs to know how the application initialized its WinRT context, or it should not do any initialization at all and expect everything to be initialized already ... |
Each thread initializes separately, and initialization can return Changing the default here is probably a breaking change anyways? |
I wouldn't worry too much about breaking changes ... the second sentence in this project's README is:
|
In general, in Windows, we leave that to the application level. If a library needs a specific threading model, it does so only on threads that it owns. There's an additional potential option: The MTA exists as long as it has been requested at least once. You can default to the implicit MTA by incrementing the MTA reference count without binding the current thread to the MTA (see https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-coincrementmtausage). If an app wants to use STA instead, they should initialize STA before creating any winrt objects, but a thread that is implicitly MTA can still be initialized explicitly to STA. This approach could limit the need to use explicit initialization to only those that want STA behavior. Ben |
@BenJKuhn Thank you for that valuable information! However, I don't quite understand this yet: |
Useful knowledge, thanks. Especially RtDefaultConstructible! That definitely makes the code nicer. Documentation is a tricky thing with this kind of library in the context of rustdoc. Now if anyone happened to want to help me, I wouldn’t mind: chris-morgan/webviewcontrol-rs#1, the WebViewControlProcess.create_web_view_control_async async operation is never completing and I can’t figure out why. I’ll make no further mention in this issue here of the concrete case. |
Sorry, I'm going to be a little less helpful there. If there's some notion of module initialization, that's where I'd put it. I don't know what options rust gives you in this context. Ben |
Now according to https://www.youtube.com/watch?v=X41j_gzSwOY#t=26m38s it's (usually) no longer necessary in cppwinrt to call This is quite clever and I think we can do the same thing. According to https://kennykerr.ca/2018/03/24/cppwinrt-hosting-the-windows-runtime/ it's also basically unnecessary to uninitialize the runtime, so we could get rid of the (@rbtying What do you think about this, because you submitted #61, and the change there would now become obsolete?) Additionally we have to add a multithreaded/singlethreaded parameter to |
... and allow STA initialization (fixes contextfree#62).
... and allow STA initialization (fixes #62).
It seems that this is not needed. It could be that cppwinrt calls CoIncrementMTAUsage implicitly (as in idea suggested in contextfree/winrt-rust#62 (comment)). Fixes: microsoft#690
@BenJKuhn, a question that arises here and I couldn't find documentation about is this: In COM, that WinRT "borrows" from, a caller in any apartment can call an object if any threading model, given that there's a marshaller registered for it. (I'm ignoring "Main STA" and NT/NTA in the following.)
Suddenly in WinRT the first 3 items are still true but the 4th one isn't. Could you provide some information on this and rationale for this behavior? |
I have not taken the time to grasp the difference between the different RO_INIT_*THREADED values (I have done literally no research, and I won’t have a chance to until next week), but what I observe is that this code:
(Ugh, is that activation factory business really how to do it? It took me a while to get that far, but I think it’s about right, which is very icky! But that’s by the bye.)
… failed with code 0x8000001D, which is RO_E_UNSUPPORTED_FROM_MTA, “Activating a single-threaded class from MTA is not supported.”
As soon as I replaced
RuntimeContext::init()
withRoInitialize(RO_INIT_SINGLETHREADED)
, it started working fine.I do not know how all of this works with reference to #60—as I said, I know nothing at present about the different apartment models beyond the names and very vague intuitions. @rbtying, are you perchance an expert?
I know not whether it should switch to single-threaded, or take an argument to choose.
The text was updated successfully, but these errors were encountered: