Проверьте наличие COM-указателя

В C++, MFC:

У меня есть CComPointer:

CComPointer<IMyTask> m_pTask;

в моем коде много мест, я вызываю этот ComPointer для запуска методов задачи. Например:

void method1()
 {
    if (FAILED(hRet = m_pTask->MyFunc1()))
                  .....
 }

void method2()
{
    if (FAILED(hRet = m_pTask->MyFunc2()))
                  .....
}

Я пытаюсь решить проблему, чтобы восстановить, когда MyTask не работает. Я написал метод restore (), который повторно запускает CoCreate для MyTask, и он фактически решает проблему.

Я мог видеть, что, если MyTask мертв, я получаю код ошибки HR -2147023174, сервер RPC недоступен. Но указатель com m_pTask содержит полные данные (он не знает, что задача мертва).

Я могу сделать что-то вроде этого:

void method1()
 {
    if (FAILED(hRet = m_pTask->MyFunc1()))
        if (hRet == -2147023174)
           recover();
                  .....
 }

void method2()
{
    if (FAILED(hRet = m_pTask->MyFunc2()))
        if (hRet == -2147023174)
           recover();
                  .....
}

Но, поскольку у меня много вызовов методов через композитор, я хочу сделать что-то более общее. Я хочу, чтобы каждый раз, когда я пытался запустить метод через ComPointer, перед запуском метода, чтобы убедиться, что задача уже существует, а если нет - запустить метод восстановления. Так как даже когда задача мертва, ComPointer все еще хранит все данные времени CoCreate, я не знаю, как я могу это сделать.

Как мне это сделать?

Задача не работает из-за ошибки, которая иногда возникает в системе, и на данный момент моему решению не нужно искать причину сбоя задачи, просто для ее восстановления. Я ищу общее решение - как обертка для ComPointer, но я хочу, чтобы класс-обертка только проверял, существует ли MyTask, и если он есть - он возвращает ComPointer, а если нет, он запускает recovery,

Как мне это сделать?

4 ответа

Решение

Хорошо, это общий ответ на общий вопрос. Я не хочу знать, почему задача на самом деле мертва, а указатель - нет. Напишите обертку для указателя задачи и используйте ее вместо этого. Это будет выглядеть примерно так:

class CMyTaskWrapper
{
     CComPtr<IMyTask> m_ptr;
     ...
     HRESULT myFunc1()
     {
         HRESULT hRes = m_ptr->myFunc1();
         if(hRes == 0x800706BA)
         {
             recover();
         }
         return hRes;
     }
     ... //here you should list all members of IMyTask
 };

Edit1: добавлен пример макроса (см. Комментарий № 2)

MYMACRO_0(HRESULT_GETTER, POINTER, FUNCTION) \
HRESULT_GETTER = POINTER->FUNCTION(); \
if(HRESULT_GETTER == 0x800706BA) recover(); \
HRESULT_GETTER = POINTER->FUNCTION() 

MYMACRO_1(HRESULT_GETTER, POINTER, FUNCTION, PARAM1) \
HRESULT_GETTER = POINTER->FUNCTION(PARAM1); \
if(HRESULT_GETTER == 0x800706BA) recover(); \
HRESULT_GETTER = POINTER->FUNCTION(PARAM1)

//here you should add MYMACRO_2 ... MYMACRO_N

Вы можете использовать его следующим образом:

MYMACRO_0(hRes, m_pTask, MyFunc1);
MYMACRO_1(hRes, m_pTask, MyFunc2, parameter_to_pass);

Это может помочь, и это скроет список функций, но, тем не менее, использование такого кода не очень хорошая идея.

Похоже, вам нужен собственный прокси-сервер DCOM вместо логики по умолчанию, предоставляемой midl и Windows. Это возможно, но это также много работы. Это лучший вариант, если вам нужно пользовательское поведение, предоставляемое стороннему коду, который использует COM для создания объекта.

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

Мастер классов MFC позволяет генерировать класс-оболочку вокруг компонента com. Эта страница описывает как.

После того как класс-оболочка создан, вы можете отредактировать любой из методов, чтобы реализовать в нем свою логику повтора. Вы можете использовать тот же подход для классов- оболочек, сгенерированных директивой #import.

Реализация CComPointer довольно проста. Вы можете легко вырезать и вставлять его, чтобы сформировать основу вашего собственного класса интеллектуальных указателей.

Реализация CComPointer основана на переопределении оператора "->". Это избавляет от необходимости знать что-либо о том, какие методы предлагает интерфейс. Каждый звонок эффективно перехватывается и затем переадресовывается.

В вашем новом классе интеллектуальных указателей вы можете встроить необходимые дополнительные функции в реализацию переопределения оператора "->".

Какую проверку сделать для подтверждения вызова сложнее.

Я думаю, что QueryInterface является допустимым вызовом, который вы могли бы использовать для проверки того, что соединение живо - QueryInterface гарантированно существует, и вам нужно будет обратиться к реальной реализации.

Однако всегда будет условие гонки - соединение может прерваться между вашим контрольным вызовом и вашим реальным вызовом.

Поэтому вам может быть лучше просто сделать реальный вызов, и если он не удастся, попробуйте восстановить и позвонить снова - это сложнее сделать с помощью хорошего шаблона - вероятно, проще всего достичь с помощью макроса, см. Ответ из Forgottn.

Другие вопросы по тегам