Apartment Model
在该模型中,一个对象和一个特定的线程有关联,只有在该线程的context之中才能够调用该对象。 COM的“apartment”是一个对象产生,运作和毁灭的地方。当client要求一个指向interface的指针,它是从一个特定的线程(也就是apartment)中发出请求。这个client可能只在该apartment中使用该interface指针。当然也有可能产生一个interface指针给其他的apartment使用,这种情况你必须使用COM函数 CoMarshalInterThreadInterfaceInStream() 和CoGetInterfaceAndReleaseStream()。
Apartment model的内部运作系使用消息队列 。COM为每个在apartment model中登记在案的线程产生一个不可见的窗口。而我们知道,一个窗口的消息只能被产生该窗口的线程处理。所以,使用消息队列可以自动强迫适当的线程处理对COM对象的调用。副作用是使用apartment model的线程必须有一个消息循环,否则调用COM对象时消息将不会被派送。
Free-Threaded Model
在这个模型中,对于out-of-proc COM server(是个exe而不是dll) 中的对象的调用动作,是由属于COM的线程发出。换句话说,即使你的程序只有一个线程,COM自己也有一缸子线程,用来调用你的COM对象。
如果server是in-proc(也就是dll形式 ),那么调用通常直接来自client,送往server,其间没有COM的介入。
在in-proc server和out-of-proc server之间,存在一个基本差异,那就是由谁产生线程。在in-proc server 中,线程的产生与否完全被client程序中的线程个数所控制。一旦in-proc server开始执行,其典型行为类似于一个正常的多线程dll与应用程序之间的互动。但在一个out-of-proc server中,线程是由COM产生的。
free-Threaded不依赖使用W'indows消息,所以没有必要拥有一个消息循环。避过消息循环,可以使得对free-threaded对象的调用能够比apartment model对象的调用更显著的快速处理。付出的代价是应用程序必须负起保护对象的完全责任。确定对象受到保护非常重要。在apartmodel中,由于外界请求总是一个个被处理,所以同步化控制根本不需要。
client程序也可以声明为free-threaded。一个free-threaded client可以完全地把一个interface 指针传递给另外一个线程,并且可以在任何时间对任何线程中的interface发出调用。这个意思是client可以对着同一个对象同时发出多个请求,也因此一个free client可能在同一个时间使用5个不同线程中的同一个interface指针。
声明一个线程模型
一个COM client或者server必须声明其所支持的线程模型。对于exe文件,每个即将使用COM的线程都必须在调用任何COM函数之前先调用CoInitialize或者CoInitializeEX。线程模型即在那个时候选定。
HRESULT CoInitialize(
LPVOID pvReserved //must NULL
);
HRESULT CoInitializeEx(
void * pvReserved,
DWORD dwCoInit //COINIT enum中的一个栏位 COINIT_APARTMENTTHREADED and COINIT_MULTITHREADED flags cannot both be set.
);
返回值:如果成功,传回S_OK,如果参数不合法,传回E_INVALIDARG.如果线程先前调用过CoInitializeEx,并且给予不同的dwCoInit 值,传回RPC_E_CHANGED_MODEL.
Dll server的运作又不同了,他不是在启动时注册其线程模型,而是将模型种类存储在注册表中。在CLSID/InprocServer32项目之下,DLL放置一个键,名为ThreadingModel。
混合模型
一个应用程序在某些线程中使用apartment model而在另外一些线程中使用free-threaded model是可能的。所有被注册为free-threaded的线程被说是生活在他们自己的apartment中。因此会有一个free-threaded apartment和多个线程,以及一个或多个标准的apartment,每个有用单一线程。
interoperability
一个client和server声明为不同的线程模型也是可能的。
如果client和server都是outofproc,那么COM就可以负责让2个人安全地沟通。如果free-threaded client调用一个apartment model server,那么COM就会将那些请求一个个排好,使server一次处理一个。如果一个apartment model client调用一个free-threaded sderver,那么server被允许正规地处理那些请求。
如果server是in-proc,那么com还是可以负责让通讯的两边交互。但是付出额外的代价。server通常被设计为in-proc,为的是让client发出的请求能直接到达server端,不必透过Com的协助。如果一个free-threaded client尝试使用一个apartment model 的in -proc server,那么CoM必须介入,做法是把请求掉往main apartment(也就是第一个调用CoInitializeEx的线程) ,并将每个请求一次送到in -proc server手上。