2

这是我的 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()”的异常。或任何其他方式来避免此异常?

非常感谢。

4

2 回答 2

4

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

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

于 2013-06-14T04:48:00.067 回答
1

我同意那些建议将此类初始化留给 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; }

然后将它与初始化列表一起使用:

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

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

于 2013-06-14T08:11:42.333 回答