作用: 设置本线程的线程模式

1 CoInitialize

CoInitialize是在当前线程初始化Com组件的函数,并且初始化为STA模式(单线程模式)

  1. CoInitialize(
  2. LPVOID pvReserved // 系统 保留的参数,必须传入 NULL.
  3. );

特点:

  • 设置后, 线程就进入了单线程单元, 在这个单元里只能住一个线程. 该线程上创建的Com对象方法被另一个线程调用时, Com运行库会把这个方法编到一个队列里, windows消息会被放进线程消息队列
  • 所有Com方法调用的执行过程 都被放到 创建Com对象的那个线程

    2 CoInitializeEx

    CoInitializeEx初始化当前线程Com组件, 并且初始化为MTA模式(多线程模式)

    1. CoInitialize(
    2. LPVOID pvReserved, // 系统 保留的参数,必须传入 NULL.
    3. DWORD dwCoInit // 指明基于当前线程的并发模式, 一般传0, 即COINIT_MULTITHREADED
    4. );

    dwCoInit:

  • COINIT_MULTITHREADED = 0, // 允许多线程调用, 但每个Com方法调用的执行过程 被放到 各自的调用线程中

  • COINIT_APARTMENTTHREADED = 2, // 允许多线程调用,但所有Com方法调用的执行过程 都被放到 创建Com对象的那个线程

上面这两种最常用, 但两者不能组合使用

  • COINIT_DISABLE_OLE1DDE = 4, // 禁用DDE对OLE1的支持
  • COINIT_SPEED_OVER_MEMORY = 8, // 增加内存使用来使性能上升

    3 两个函数返回值的说明

    1. HRESULT hr = CoInitialize(NULL);
    2. // hr == S_OK COM库初始化成功
    3. // hr == S_FALSE 当前线程上,COM库已经被初始化
    4. // hr == RPC_E_CHANGED_MODE COM库已经被初始化且传入参数设置的并发模式和本次不同

    4 注意事项

    (1) 要在一个线程上合理关闭com库,在线程函数尾部还要有CoUninitialize()

    1. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    2. // ...
    3. CoUninitialize();

    (2) 在MFC程序中初始化Com库, 有两种方法

  • CoInitialize(0);

  • CoInitializeEx(0, COINIT_APARTMENTTHREADED);

原因: MFC使用TLS来维护一些进程线程状态信息,这会和自由线程模型的组件发生冲突。
image.png

(3) Qt主线程不用执行COM初始化,因为已经自动初始化为STA
image.png