2012-06-06 3 views
2

В C++, MFC:Проверить наличие COM указатель

У меня есть CComPointer:

CComPointer<IMyTask> m_pTask; 

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

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

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

Я пытаюсь решить проблему, когда восстанавливается MyTask. Я написал метод, recover(), который перезапускает 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, перед запуском метода, чтобы проверить, что задача уже существует, а если нет - запустите метод восстановления. Поскольку даже когда задача мертва, ComPointer все еще имеет все данные из времени CoCreate, я не знаю, как это сделать.

Как я могу это сделать?

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

Как я могу это сделать?

+0

Это не MFC это ATL. –

+0

Плохая идея, ИМХО. Поездки в сети не дешевы; вы фактически удваиваете их количество. Время выполнения DCOM проверяет мертвые серверы в любом случае - периодический пинг. –

+0

@Seva Alekseyev: Нет, он не удваивает их сумму, ему не понадобится восстановление, если сервер в порядке, что обычно бывает. И если сервер не в порядке, перезапуск его требует много времени. – sharptooth

ответ

0

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

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); 

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

+0

Спасибо за ваш ответ. Задача мертва из-за ошибки, которая возникает в системе, и на данный момент мне не нужно искать причину сбоя задачи, просто восстановите ее. В вашем решении проект с ComPointer должен знать все методы IMyTask, и если есть изменение в IMyTask, поэтому CMyTaskWrapper также должен быть изменен. Я ищу более общее решение - обертка, как вы говорите, хорошая идея, но я хочу, чтобы класс-оболочка проверял только, существует ли MyTask, и если это - он вернет ComPointer, а если нет, он запустит recover.ideas? – user1439691

+0

Нет более общего способа, если вы не используете некоторые специальные генераторы кода, например, например, Visual C++ с ключевым словом '# import'. Мой ответ может быть да только для определенного подмножества случаев. Например, вы можете написать набор макросов (см. Запись редактирования для деталей, комментарии не для кода). – Forgottn

+0

Что касается вашего последнего предложения. Вы можете попробовать, если можете, добавить фиктивный метод, который можно безопасно вызывать из вашей обертки, и проверить, хорошо ли сервис. Но я не уверен, что это будет лучше. – Forgottn

0

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

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

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

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

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

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

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

+0

Это все равно потребуется выполнить проверку перед возвратом указателя. Если эта проверка не может быть выполнена путем вызова некоторой специальной функции, которая проверяет, жив ли соединение с сервером RPC, ваша идея не будет работать. – Forgottn

+0

см. Обновление выше – morechilli

+0

К сожалению, оператор '->' фактически не выполняет вызов, он возвращает только указатель на вызов, который должен быть сделан против. Один из причуд C++. –

0

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

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

0

Мастер классов MFC позволяет создавать класс-оболочку вокруг ком-компонента. This page describes how.

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

Смежные вопросы