Deeper into COM
Apartment models and Marshalling are two more interesting areas of COM internals. It is not necessary to understand these details to use the EiffelCOM wizard, but the knowledge could improve decision making when designing new EiffelCOM components.
The first interesting subject that warrants more in-depth coverage is the execution context of a component. Components can run in the same process as the client, but can also run in a separate process, even on a different machine. But this only takes processes into account. What happens if a component uses multithreading to achieve it tasks? In the case of remote servers, this is a very real possibility. The problem is that a server does not (and should not) know in advance the nature of its clients. It cannot assume that the client will be able to take advantage of its multithreading capabilities. Conversely a multithreaded client should not rely on the server's ability to handle concurrent access.
The solution chosen in the COM specification is to define an additional execution context called an apartment. When COM loads a component it creates the apartment in which the component will run. Multiple instances of a multithreaded component will coexist in the same apartment since asynchronous calls will be handled correctly and there is no need to add any synchronization layer. On the other hand, single threaded components will be alone in their apartments and any concurrent calls coming from clients will be first synchronized before entering the apartment. These two behaviors define two different kinds of apartments: Multi Threaded Apartments (MTA) and Single Threaded Apartments (STA).
Apartments solve the problem of concurrency by removing the necessity of knowing the multithreaded capability of a component and its clients. Multithreaded clients can always make asynchronous calls and depending on whether the component handles concurrent access or not, they will be forwarded directly or synchronized first. There can be multiple instances of an STA running in one process, while there can be at most one MTA.
COM calls can "cross" apartment boundaries. Components from an STA can make calls to components running in an MTA and vice versa. These apartments might be running in different processes or even on different machines. The approach chosen in the COM specification for cross-apartment calls involves a pattern of proxies and stubs.
The idea is to "trick" the client of an interface by providing an interface proxy in its apartment. The proxy includes exactly the same functions as the interface itself but the implementations will merely forward the call to the actual interface. The client's behavior is the same whether it is dealing the actual interface or just a proxy. A point of interest in this approach is that the client implementation is independent from the location of the component.
But this is not quite the whole story. The call that goes to a proxy will not be forwarded to the actual interface but to its stub. The stub is the counterpart of the proxy—it represents the client for the interface. The interface's behavior is the same whether it is communicating with the actual client or a stub. Although it is not totally true that the component implementation is independent from the location of the client, the stub pattern still helps keep code identical for the implementation of the interface themselves. The implementation of a component will still be different between an in-process or out-of-process component, since it will have to be a DLL in one case and a executable in the other. The design of the interfaces might also differ since out-of-process servers will tend to avoid too many round trips.
There is one proxy/stub pair per interface. The proxy or the stub is loaded dynamically only when needed. This proxy/stub pair constitute the marshaller. The reason for having a single name for two different things comes from how MIDL generates its code. MIDL will produce files for one DLL in which both the proxy and the stub will be included. This DLL is the marshaller.
This brief introduction to the Component Object Model should be enough to get started with the EiffelCOM wizard. It specifies the main characteristics that define the type of a component and that need to be given to the wizard along with the definition file.
- Parent <COM and Eiffel>