Mike Hearn wrote:
Here are some more notes in a convenient to read form. I'll turn these into a documentation patch later. Rob, can you double-check this?
This document assumes you are familiar with the basics of DCOM. If you aren't read this first:
http://winehq.com/site/docs/wine-devel/dcom-1
This is not suitable study material for beginners. Don't say I didn't warn you.
- Apartments
Before a thread can use COM it must enter an apartment. Apartments are an abstraction of a COM objects thread safety level. There are many types of apartment but the only two we care about right now are single threaded apartments (STAs) and the multi-threaded apartment (MTA).
Any given process may contain at most one MTA and potentially many STAs.
You might want to add something like this: This is because all objects in MTAs never care where they are invoked from and hence can all be treated the same. Since objects in STAs do care, they cannot be treated the same.
The apartment system was originally designed to deal with the disparity between the Windows NT/C++ world in which threading was given a strong emphasis, and the Visual Basic world in which threading was barely supported and even if it had been fully supported most developers would not have used it. Visual Basic code is not truly multi-threaded, instead if you start a new thread you get an entirely new VM, with separate sets of global variables. Changes made in one thread do NOT reflect in another, which pretty much violates the expected semantics of multi- threading entirely but this is Visual Basic, so what did you expect?
Remove the "so what did you expect?" as this is a bit too hostile.
If you access a VB object concurrently from multiple threads, behind the scenes each VM runs in a STA and the calls are marshaled between the threads using DCOM.
In the Windows 2000 release of COM, several new types of apartment were added, the most important of which are RTAs (the rental threaded apartment) in which concurrent access are serialised by COM using an apartment-wide lock but thread affinity is not guaranteed.
Do we have any details about how you use RTAs? I have a feeling this was something that was due to be implemented for Windows 2000, but was dropped before it shipped.
...
After the SORF flags comes a count of the references represented by this marshaled interface. Typically this will 1 in the case of a normal marshal, but may be 5 for table-strong marshals and 0 for table-weak marshals (the difference between these is explained below).
This is wrong. It is 5 for normal marshals, and 0 for both table-weak and table-strong. The reasoning is this: In the general case, we want to know exactly when an object is unmarshaled and released, so we can accurately control the lifetime of the stub object. This is what happens when cPublicRefs is zero. However, in many cases, we only want to unmarshal an object once. Therefore, if we strengthen the rules to say when marshaling that we will only unmarshal once, then we no longer have to know when it is unmarshaled. Therefore, we can give out an arbitrary number of references when marshaling and basically say "don't call me, except when you die."
...
Unmarshaling one of these streams therefore means setting up a connection to the object exporter (the apartment holding the marshaled interface pointer) and being able to send RPCs to the right ifstub. Each apartment has its own RPC endpoint and calls can be routed to the correct interface pointer by embedding the IPID into the call using RpcBindingSetObject. IRemUnknown, discussed below, uses a reserved IPID.
Only in the implementation I've written and am currently testing now. The native version generates an IPID as per any other object and simply notifies the SCM of this IPID.
...
There is one IRemUnknown implementation per apartment, not per stub manager as you might expect. This is OK because IPIDs are apartment not object scoped.
In fact, according to the DCOM draft spec, they are machine-scoped, but this implies apartment-scoped.
Other than that, it looks good!
Rob