On Sun, 2004-07-25 at 11:27 +0200, Ove Kaaven wrote:
The answer is of course that COM doesn't assume that objects actually are thread-safe. Most real-world objects aren't, in fact, for various reasons. What these reasons are isn't too important here, though, it's just important to realize that the problem of thread-unsafe objects is what COM tries hard to solve with its apartment model. There are also ways to tell COM that your object is truly thread-safe (namely the free-threaded marshaller). In general, no object is truly thread-safe if it could potentially use another not so thread-safe object, though, so the free-threaded marshaller is less used than you'd think.
Right.
Perhaps you should spell out "QueryInterface-d", instead of saying "QId".
Yeah, I suppose I should be as explicit as possible with this topic.
Actually I found out later that I was wrong anyway. You can't just take a proxy and QueryInterface it to IRpcProxyBuffer as they have two physically separate vtables. If you want to control the proxy you have to use a separate vtable that is only ever returned by the CreateProxy function and cannot be accessed any other way.
It depends on the Windows version, I think. Windows 95 and Windows NT 4 certainly had very different models when I looked. I'm pretty sure the Windows 98 version of RPCRT4 was able to dispatch messages directly to individual apartments. I'd be surprised if some similar functionality was not added to Windows 2000. After all, if an object on machine A wanted to use an object on machine B in an apartment C, wouldn't it be most efficient if the RPC system knew about apartments and could dispatch the message directly to it? And if RPC does know how to efficiently dispatch to apartments, why should COM duplicate this functionality? There were, however, no unified way to tell RPC about them across Windows versions, so in that old patch of mine, I let the COM/OLE dlls do the apartment dispatch, but even then, the RPC runtime was always involved. After all, it could be quite tricky to tell whether the call is merely interthread, without involving the RPC runtime...
Currently OXIDs are just ((PID << 32) | TID) so you could see if it was inter-thread by examining that. In real DCOM though I don't know how they do it - presumably by walking the proesses apartment list looking for that OXID first.
Yes, it's right, but as you mentioned, typelibs cannot encode all the information in the original IDL. InstallShield uses MIDL marshallers for the interfaces which cannot be represented perfectly by a type library. (You could of course ask why not use MIDL-generated marshallers all the way. I believe part of the reason for that is that on appropriate Windows versions, the marshallers generated from typelibs will be in a form that Microsoft claims will run faster than a big MIDL-generated marshaller, due to less RAM usage and CPU cache trashing.)
Right.
And some related hacks in the typelib marshaller to cover up for the fact that the typelibs don't actually represent the IDL perfectly, by guessing at the extra information needed to successfully marshal the interfaces used by InstallShield.
To elaborate, the hack we're talking about is treating VT_VOID as an interface pointer.
All those hacks would no longer be needed after that old patch of mine, of course...
Yes but it's very large and none of us have been able to figure out how to chop it up and submit it in a way that won't cause regressions: really up until recently I didn't understand DCOM well enough to even attempt this, I would just have made a big mess of it.
I don't think you have covered the possibility of manually marshalling an interface from one single-threaded apartment to another, either (CoMarshalInterThreadInterfaceInStream). This is used to great effect in InstallShield to separate the worker thread and the UI thread; DCOM does all the hard work of letting the objects in the threads communicate easily and conveniently, even while the worker threads work and the UI thread remains responsive.
Yes, I did not cover this as I thought the email was long enough as is, though the basic principles are still the same. Just the RPC transport differs.
thanks for the review! -mike