On 09/04/18 21:15, Zebediah Figura wrote:
Signed-off-by: Zebediah Figura z.figura12@gmail.com
dlls/ole32/compobj.c | 2 +- dlls/ole32/compobj_private.h | 3 +- dlls/ole32/marshal.c | 32 ++++++++---- dlls/ole32/rpc.c | 12 +++-- dlls/ole32/tests/marshal.c | 114 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 15 deletions(-)
Repasting my earlier note here since I forgot to edit the patch:
----
This patch results in some good news and some bad news for bug 18070.
The good news is that we can unmarshal into literally any thread—uninitialized, STA, or MTA—as long as there's an MTA somewhere else in the process. This means we can use a COM proxy on any thread. The bad news is that we can't change threading models (i.e. initialize or uninitialize COM on a thread) while we're doing this, or ole32 will throw up RPC_E_WRONG_THREAD when we try to make a proxy call.
The symptoms of bug 18070 show that there has to exist an MTA in the process, but that COM can't be initialized on the thread itself: "It is up to the custom action to initialize COM to its liking." This fits the MTA condition quite nicely, but then runs into the separate problem that the custom action can change the threading model on us.
What this means is that we can't keep proxies around on the custom action's thread and then just run all calls to MSI functions through them, since they might go bad at any point. I see at least two solutions to this:
(1) Keep the COM objects on a different thread (probably just the thread that the MTA is initialized on). Then use a dedicated 'pipe' thread to thunk callbacks to the MTA thread, whence they will then be converted into proxy calls.
(2) Instead of keeping COM objects around during the entire custom action, create and then release one generic 'server' object every time an MSI function is called. This will, of course, work regardless of what threading model the custom action's thread is actively using, since it won't change during the course of the call.
(3) Along the same lines as (2), but potentially even simpler: use the RPC APIs directly. That is, replace our IWineMsiRemotePackage_GetProperty(...) with a simpler remote_GetProperty(...) that does about the same thing, but without the overhead of going through ole32. (And for all the work I did to make ole32 work right! But it is for the best.)
I'm most inclined towards (3)—I think it'll be the solution with the least overhead, and it won't take too much work to convert from what we have.
Therefore: if anyone has any alternate preferences, reasons why one or more of the above won't work, or general feedback, please speak now. Alternatively, wait until I've done all the work to convert everything to RPC server stubs, and then tell me why it all won't work ;-)