无论如何在初始化列表之前调用CoInitialize()?

时间:2013-06-14 02:35:21

标签: c++ com constructor initialization-list

这是我的ThorDetectorSwitch.cpp文件构造函数的C ++代码:

ThorDetectorSwitch::ThorDetectorSwitch() : _mcSwitch(__uuidof(MCLControlClass))
{
    _A  = WstringToBSTR(L"A"); 
    _B  = WstringToBSTR(L"B");
    _C  = WstringToBSTR(L"C");
    _D  = WstringToBSTR(L"D");

    _deviceDetected = FALSE;
}

如您所见,初始化列表_mcSwitch(__uuidof(MCLControlClass))用于初始化COM对象(MCLControlClass,它是从COM dll注册的)。

我想知道无论如何我可以在这个初始化列表之前调用CoInitialize()吗?因为我得到了“CoInitialize()没有被调用”的例外。或者以其他方式避免这种异常?

非常感谢。

2 个答案:

答案 0 :(得分:3)

首先,我建议您使用CoInitializeEx代替CoInitialize。甚至MSDN文档也建议这样做。其次,我建议您在CoInitializeEx中以及需要使用COM对象的每个附加线程的开头调用main()。这有很好的理由。例如,在线程结束之前,对CoInitializeEx的每次调用都应该对CoUninitialize进行相应的调用。这可确保正确终止COM库。如果从构造函数中调用它,则还必须管理COM库初始化的次数,以便对CoUninitialize进行正确的调用次数。另一个问题是,当使用不同的公寓模型对CoInitializeEx进行后续调用时,它将失败。如果发生这种情况并且您的构造函数正在检查 之类的错误,则在实例化期间最终会出现故障情况。你如何处理构造函数中的错误条件?抛出异常 - 不是一件非常令人愉快的事情。

我最后的建议是阅读文档并以正确的方式做事情,否则你最后会像过去几天一样摸不着头脑。

答案 1 :(得分:1)

我同意那些建议将这样的init留给main()或InitInstance以及其他改进的人,但让我展示原始问题的一个解决方案。

当调用函数创建责任时,您可以从RAII包装器开始,例如:

class ComIniter
{
public:
    ComIniter() { CoInitialize(); } // or use ex, add params, etc
    ~ComIniter() { CoUnInitialize(); } // adjust to match
private:
    ComIniter(const ComIniter&);  // =delete with C++11
    ComIniter& opeartor=(const ComIniter&); // =delete with C++11
};

您可以在main(),线程函数和/或命名空间范围的开头删除一个实例,然后再移动另一个需要COM的静态对象。

如果您决定反对这些并想要最初的想法,请在ThorDetectorSwitch中添加:

private: static const char* ComHelper(const char* arg) { static ComIniter c; return arg; }

然后将其与init列表一起使用:

ThorDetectorSwitch::ThorDetectorSwitch() : _mcSwitch(ComHelper(__uuidof(MCLControlClass)))

根据需要调整返回类型。再次认为与其他解决方案相比,它被认为是次优解决方案。