Очистка COM-объекта

В чем разница между двумя строками кода ниже:

CComPtr< IInterface > m_interface;

IInterface* m_interface;

Я знаю, что CComPtr помогает устранить утечки памяти, но я получаю противоречивые результаты. При объявлении указателя с помощью CComPtr< IInterface > m_interface; и использовании интерфейса в моем коде C # ошибок нет, однако при использовании интерфейса в VC ++ я получаю ошибку необработанного исключения, даже если я закомментирую создание экземпляра IInterface.

Я почти уверен, что проблема где-то здесь:

STDMETHODIMP CSomeClass::get_IClass(IClass** var)
{ 
      return m_class_var->QueryInterface(var);
}
STDMETHODIMP CSomeClass::putref_IClass(IClass* var)
{ 
     m_class_var = var;
     return S_OK;
}

Когда я объявляю указатель интерфейса с помощью: IInterface* m_interface;, я получаю ошибку RPC_E_SERVERFAULT при тестировании интерфейса на C # и мне приходится явно вызывать GC.Collect (), чтобы избежать появления ошибки после создания нескольких объектов. При тестировании интерфейса в VC ++ ошибка согласуется, однако когда она возникает, она отличается. Если я закомментирую создание экземпляра IInterface, код работает нормально, однако, когда я пытаюсь создать экземпляр, я получаю ту же ошибку, что и раньше, только неопределенную ошибку необработанного исключения. Что я здесь делаю не так?


person Reggie McCray    schedule 25.02.2010    source источник
comment
Вам действительно стоит потратить 15 минут на создание очень короткого фрагмента, который продемонстрирует проблему.   -  person sharptooth    schedule 26.02.2010
comment
Вы говорите, что при использовании интерфейса в VC ++ я получаю необработанную ошибку исключения - можете ли вы показать нам код, используя интерфейс в VC ++?   -  person JoeG    schedule 26.02.2010


Ответы (3)


IInstance* m_instance - простой указатель на объект IInstance. Вы должны сами управлять временем жизни этого указателя. Вы не new и delete COM-объекты, как обычные объекты. Вместо этого операционная система выделяет объект, когда вы вызываете функцию WINAPI `CoCreateInstance ':

// instantiate the CoClass which implements IInstance...
IInstance* instance = 0;
HRESULT hr = CoCreateInstance(__uuidof(mylibrary::MyCoClass), 0, CLSCTX_INPROC_SERVER, __uuidof(mylib::IInstance), &instance);

:   :

// We're done, so release the object...
instance->Release();
instance = 0;

Каждый COM-объект реализует подсчет ссылок. Когда последняя ссылка на объект была Release()ed, COM-объект уничтожает себя.

Использование CComPtr<> упрощает управление сроком службы COM-объектов. Это умный указатель, похожий по своей природе на std :: auto_ptr или shared_ptr Boost, но он работает с COM-объектами. Обычно при использовании CComPtr вы вызываете функцию-член CreateInstance, а не функцию WINAPI, и не вызываете явно Release, когда закончите. Просто позвольте CComPtr выйти за пределы области видимости, и при вызове его деструктора он вызовет для вас Release:

void function()
{
  // instantiate the CoClass which implements IMyInterface...
  CComPtr<IInstance> instance;
  instance.CoCreateInstance(__uuidof(mylibrary::MyCoClass));

  :   :

  // We're done, so release the object...
  // dont have to do anything, it will be released when function() exits
}
person John Dibling    schedule 25.02.2010

CComPtr - это умный указатель, предназначенный для «правильных» действий при использовании с идиомами COM.

Ваш код для get_IClass выглядит неплохо, но putref_IClass должен вызывать AddRef на IClass, когда вы его сохраняете. Если бы вы использовали CComPtr, это произошло бы автоматически.

Вам нужно будет добавить дополнительные сведения о необработанном исключении VC ++.

person JoeG    schedule 25.02.2010
comment
Спасибо. это поможет понять немного лучше. Я бы проголосовал за вас, но у меня недостаточно очков репутации - person Reggie McCray; 25.02.2010

CComPtr ‹IInterface> m_interface - это объект. В то время как IInterface * m_interface - это указатель.

Деструктор первого будет вызван, когда он выйдет из области видимости, и я думаю (давно с тех пор, как я его использовал), он автоматически вызовет m_interface -> Release ().

Последний является указателем на интерфейс, и вам нужно управлять, когда вызывается m_interface-> Release ().

Можете ли вы подтвердить, что COM-объект не освобождается до доступа?

person Preet Sangha    schedule 25.02.2010
comment
Спасибо. Я немного отредактировал свой вопрос, чтобы дать больше информации. Я вызываю Release () в рамках реализации интерфейса тестирования кода VC ++. Это не помогает, я подозреваю, что мне нужно освободить / уничтожить объект в неуправляемом коде даже при использовании CComPtr ‹IInterface›, но я не уверен. - person Reggie McCray; 25.02.2010
comment
@Reggie: иногда вам нужно вызвать AddRef / Release для объекта, даже если он управляется CComPtr. Вам нужно будет показать нам код VC ++, чтобы мы могли убедиться, что вы делаете что-то не так. - person JoeG; 26.02.2010