В любом случае, чтобы вызвать CoInitialize() перед списком инициализации?
Вот мой C++ код конструктора файла ThorDetectorSwitch.cpp:
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 ответа
Сначала я рекомендую вам использовать CoInitializeEx
вместо CoInitialize
, Даже документация MSDN рекомендует это. Во-вторых, я рекомендую вам позвонить CoInitializeEx
в main()
и в начале каждого дополнительного потока, который требует использования объектов COM. Для этого есть очень веские причины. Например, каждый звонок CoInitializeEx
должен иметь соответствующий вызов CoUninitialize
до окончания потока. Это обеспечивает правильное завершение библиотеки COM. Если вы вызываете его из конструктора, вам также нужно управлять количеством инициализаций библиотеки COM, чтобы получить правильное количество вызовов для CoUninitialize
сделаны. Другая проблема, когда последующие звонки сделаны CoInitializeEx
с другой моделью квартиры это не получится. Если это происходит, и ваш конструктор проверяет наличие ошибок, как это должно произойти в случае сбоя во время создания экземпляра. Как вы обрабатываете условие ошибки, подобное этому в конструкторе? Кидая исключение - не очень приятная вещь, которая случается.
Моя последняя рекомендация - прочитать документацию и делать все правильно, в противном случае вы поцарапаете голову, как это было в последние несколько дней.
Я согласен с теми, кто предлагает оставить такой 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; }
затем используйте его со списком инициализации:
ThorDetectorSwitch::ThorDetectorSwitch() : _mcSwitch(ComHelper(__uuidof(MCLControlClass)))
при необходимости измените тип возвращаемого значения. Еще раз, что это считается неоптимальным решением по сравнению с другими.