Почему QueryInterface ищет два разных COM-проекта для одной и той же строки кода?

Позвольте мне начать с того, что я ОЧЕНЬ неопытен с работой COM, но мне было поручено отладить проблему для кого-то другого.

У меня есть два COM-проекта с именами pvTaskCOM и pvFormsCOM, и у каждого есть много интерфейсов, но я обеспокоен следующими двумя:

ITaskActPtr, который находится в pvTaskCOM

IChartingObjectPtr, который находится в pvFormsCOM

Строка кода, вызывающая мою проблему:

ITaskActPtr pTaskAct = m_pChartObj;

Где m_pChartObj — это IChartingObjectPtr. Проблема, с которой я столкнулся, состояла в том, что pTaskAct был НЕДЕЙСТВИТЕЛЕН после этого назначения в одном рабочем процессе, но хорошо в большинстве других рабочих процессов. Я погрузился в то, что здесь происходит, используя отладчик, и обнаружил, что он просматривает неправильные записи COM во время QueryInterface. В рабочих процессах, которые работают нормально, QueryInterface извлекает записи из pvTaskCOM / pvTaskAct.h:

BEGIN_COM_MAP(CTaskAct)
COM_INTERFACE_ENTRY(ITaskAct)
.
.
.
END_COM_MAP()

Который содержит интерфейс, который я пытаюсь привести, и QueryInterface возвращает S_OK.

Но в этом другом рабочем процессе m_pChartObj создается таким же образом, но QueryInterface по какой-то странной причине заглядывает внутрь pvFormsCOM / ChartingObject.h

BEGIN_COM_MAP(CChartingObject)
COM_INTERFACE_ENTRY(IChartingObject)
.
.
.
END_COM_MAP()

который НЕ содержит ITaskAct, к которому мы пытаемся привести, и поэтому QueryInterface возвращает E_NOINTERFACE.

Вопрос, который у меня возник, заключается в том, что может заставить его искать два разных COM-кода для одной и той же строки кода? Это какая-то проблема наследования? Мне просто нужен шаг в правильном направлении.

1

Решение

В рабочих процессах, которые работают нормально, QueryInterface получает записи из pvTaskCOM / pvTaskAct.h

Так не должно быть.

Эта строка:

ITaskActPtr pTaskAct = m_pChartObj;

Делает это под капотом:

ITaskAct *pTaskAct = NULL;
m_pChartObj->QueryInterface(IID_ITaskAct, (void*)&pTaskAct);

Это спрашивает IChartingObjectреализует объект, если он поддерживает ITaskAct интерфейс, и если так, чтобы вернуть указатель на эту реализацию. Так что этот код должен смотреть только на записи COM_MAP для CChartingObject учебный класс. Не стоит смотреть на CTaskAct класс вообще.

Но в этом другом рабочем процессе m_pChartObj создается таким же образом, но QueryInterface по какой-то странной причине заглядывает внутрь pvFormsCOM / ChartingObject.h

Это правильное поведение, так как именно здесь CChartingObject на самом деле реализовано. Если нет записи для ITaskAct в COM_MAP из CChartingObjectтогда правильное поведение CChartingObject::QueryInterface() потерпеть неудачу с E_NOINTERFACE ошибка.

Итак, настоящая проблема заключается в том, что ваши «рабочие» рабочие процессы на самом деле несовершенны, а ваш «неработающий» рабочий процесс делает правильные вещи.

что может заставить его искать два разных COM-кода для одной и той же строки кода? Это какая-то проблема наследования?

Нет. «Рабочие» рабочие процессы повреждены, просты и понятны. призвание QueryInterface() на IChartingObject интерфейс должен вызывать CChartingObject::QueryInterface(), но это явно зовет CTaskAct::QueryInterface() вместо. Так что либо

  • IChartingObject* указатель на самом деле указывает на CTaskAct объект вместо CChartingObject объект

  • что-то испортило память и IChartingObjectvtable является ничего не подозревающей жертвой.

Я бы заподозрил первое. Итак, в «рабочих» рабочих процессах убедитесь, что IChartingObject* указатель на самом деле указывает на правильный объект. Похоже, кто-то взял ITaskAct* и набрал его на IChartingObject* без использования QueryInterface(), Или они позвонили QueryInterface() на каком-то объекте и попросил его IID_ITaskAct вместо IID_IChartingObject но затем сохранил возвращенный указатель в IChartingObject* указатель вместо ITaskAct* указатель.

2

Другие решения

Вы, вероятно, немного заблудились в сантехнике. Это код C ++, который должен был сделать COM немного менее драконовским. Важным аспектом COM является то, что клиентский код работает только с интерфейсы. Он ничего не знает о объекты. Интерфейс — это простой контракт, список функций, которые вы можете вызвать. Например, IChartingObject будет иметь функцию Paint (). У ITaskAct не было бы никакой реальной идеи, что-то «тасккое», функция Schedule ().

Обратите внимание, что m_pChartObj — довольно обманчивое имя. Он хранит указатель интерфейса, а не объект. Но нередко, указатель интерфейса легко представить как указатель объекта, если объект реализует только один интерфейс или имеет «доминирующий» интерфейс, который вы будете использовать все время. Сокрытие объекта внутри серверного кода является очень важной целью в COM, вы можете только когда-либо делать вызовы интерфейса.

Так что ITaskActPtr pTaskAct = m_pChartObj; в основном объявляет: «У меня есть график, я хочу сделать вызов функции задач дальше». Нравится Расписание (). Для этого COM должен спросить реализацию объекта диаграммы «знаете ли вы что-нибудь о контракте интерфейса задачи?». Неизбежно он должен обратиться обратно к серверу, в карте интерфейса для CChartingObject, откуда появился IChartingObject, чтобы увидеть, реализует ли он также ITaskAct.

То, что вы видите, происходит совершенно нормально. Ответ — нет».

2

По вопросам рекламы [email protected]