这是我的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()没有被调用”的例外。或者以其他方式避免这种异常?
非常感谢。
答案 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)))
根据需要调整返回类型。再次认为与其他解决方案相比,它被认为是次优解决方案。