COM(Component Object Model)是一种用于创建在不同应用程序间通讯的Microsoft的软件复用技术。COM允许开发者通过公共接口(interface)来访问其他程序中的对象(object),这些对象共享在不同程序之间的数据和功能。如果想使用COM,初始化方法Coinitialize将是很重要的一步。
Coinitialize是一组在COM程序员日常编程中引用的内部API函数。它位于COM library中,在使用COM创建对象之前必须调用。Coinitialize是COM 程序的客户端进程和COM 组件使用的COM library之间的接口。在代码中调用Coinitialize将初始化COM library,为调用COM 接口进行准备工作,减少了一些代码开销和切换上下文的操作,提高了程序运行效率。
Coinitialize有以下几种形式。具体用法根据不同的应用场景会有所不同。
HRESULT CoInitialize(LPVOID pvReserved);
HRESULT CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit);
void CoUninitialize(void);
一般来说,如果一个进程没有在新的线程中调用Coinitialize,也没有调用过CoInitializeSecurity(关联安全性),那么调用Co的其他函数将自动初始化COM库(除 COM 服务器 对象外)。 如果你的程序需要在新的线程中创建COM对象,你需要在新线程早期的时候调用Coinitialize。当然除非你在代码中擅自这么做,所以在多线程程序开发中,一般都会在新线程开始时使用CoinitializeEx函数进行初始化。
CoInitialize函数可用于以下情况:
· 初始化当前线程以使用COM库。
· CoInitialize必须在应用程序的其他任何线程和第一个调用CoInitialize的线程之前,因为每个调用线程只能初始化一次。
· 如果并行协作方法需要执行内部初始化,例如用于内部同步的处理程序,则应从调用方法的线程内部调用CoInitialize。
· 如果您使用的是ATL(Active Template Library),则必须在 CWinApp::InitInstance函数内部调用CoInitialize。
CoInitializeEx动态链接库中的一个函数,可以启用多线程应用程序线程模型,以便在同一时刻可以通过多个线程访问对象。 与CoInitializeEx相关联的参数确定了所请求的模型类型。请注意,在调用CoInitializeEx之前必须先使用引用,结构和另一个库函数提供了为用新模型而做的额外初始化。
CoInitializeSecurity函数是一个必选函数,当应用程序希望更严格地控制某些安全特性时才使用。绝大多数应用程序都不需要进行安全控制,因此并不需要调用CoInitializeSecurity函数。仅在在构造ISecurityCallContextinterface时要调用时使用此函数。注意:在Windows Server 2003 或更高版本上的应用程序中,建议使用CoInitializeSecurity函数的参数设置,以确保向前兼容。
CoUninitialize函数可用于以下情况:
· 完全释放当前线程使用的COM库。
· CoUninitialize必须通过可以访问所有线程的全局状态进行调用,因为它调用线程只能同时对一个类的特定成员进行销毁; 如果在未调用CoUninitialize的情况下终止进程,则释放COM库的操作将进行自动清理。
· 在过去到现在使用MSDN(Microsoft Developer Network)查询语句时,当查询CoInitialize函数时会自动生成以下代码段:
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr))
{
return ;
}
// TODO: 使用COM之前一定要先调用CoInitialize函数
// 使用后,调用CoUninitialize函数
CoUninitialize();
使用Coinitialize可以保证COM在使用其它解释器使用类的时候得到正确处理,也可以保证多线程程序中对Call函数的实例化。
然而,Coinitialize也会有一些坑点需要注意:
1.加锁。当调用CoInitialize()期间,在该线程非常务密集的情况下,有时会被调用线程上的某些Windows API函数的调用所阻塞。这可能会导致停滞和性能问题,因此我们必须确保在所有关键代码中使用加锁同步机制。
2.线程安全。在多线程程序中,要确保所有线程都调用CoInitialize函数,对于“单线程单元”来说,CoInitialize会创建单个访问点(apartment)。而对于“多线程单元”来说,CoInitialize会创建一个多线程公寓(MTA,Multithreaded Apartment),这个公寓中的所有对象都可以被任何线程访问。
3.内存泄漏。在使用COM结束后,调用无效或未调用CoUnitialize函数都会导致内存泄漏。因此,在使用CoInitialize后,必须在程序结束前调用CoUninitialize以释放所有COM资源。
实际上,Coinitialize还有很多值得注意的地方。如果我们不清楚这些要点,就可能会导致程序出现一些奇怪的问题。因此,必须尽可能熟悉Coinitialize及其使用方法。