>
>
>
V1114. Suspicious use of 'dynamic_cast'…


V1114. Suspicious use of 'dynamic_cast' when working with COM interfaces. Consider using the 'QueryInterface' member function.

Анализатор обнаружил подозрительный вызов оператора 'dynamic_cast' при работе с COM-интерфейсами. При такой работе не увеличивается счётчик количества ссылок на объект, что может привести к попыткам работы с разрушенным объектом или другим проблемам.

Рассмотрим синтетический пример. Допустим, в коде есть COM-интерфейсы 'IDraw' и 'IShape', которые отвечают за работу с некой геометрической фигурой:

interface IDraw : public IUnknown
{
  ....
  virtual HRESULT Draw() = 0;
  ....
};

interface IShape : public IUnknown
{
  ....
  virtual HRESULT GetArea(double *area) = 0;
  ....
};

Также у нас есть COM-объект 'Circle', который имплементирует интерфейсы 'IDraw' и 'IShape':

class Circle : public IDraw, public IShape
{
  ....
};

Теперь рассмотрим пример неправильной работы с нашим COM-объектом через интерфейс 'IDraw':

void foo(IDraw *ptrIDraw)
{
  IShape *ptrIShape = dynamic_cast<IShape*>(ptrIDraw);
  ....
  if (ptrIShape) 
    ptrIShape->GetArea(area);
  ....
}

В примере выше не произойдет увеличение счётчика ссылок на объект типа 'Circle'. Для увеличения и уменьшения счётчика должны зваться функции 'AddRef' и 'Release' соответственно.

Правильным способом работы c COM-интерфейсами будет использование функции 'QueryInterface', которая специально предназначена для этого.

Функция 'QueryInterface' должна:

  • проверять, что к запрашиваемому интерфейсу можно получить доступ;
  • возвращать указатель на запрашиваемый интерфейс;
  • увеличивать счётчик ссылок на объект.

Таким образом, корректный код выглядит так:

void foo(IDraw *ptrIDraw)
{
  IShape *ptrIShape = nullptr;
  ....
  if (SUCCEEDED(ptrIDraw->QueryInterface(IID_IShape, &ptrIShape))
  ....
}