2

在 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 关闭时,我尝试解决问题以恢复。我写了一个方法,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 仍然拥有 CoCreate 时间的所有数据,我不知道我该怎么做。

我该怎么做?

任务因为系统中的某些时候发生错误而死掉了,目前我的解决方案不需要找到任务失败的原因,只需将其恢复即可。我正在寻找一个通用的解决方案——比如 ComPointer 的包装器,但我希望包装器类只检查 MyTask 是否仍然存在,如果它存在,它将返回 ComPointer,如果不存在,它将运行恢复.

我该怎么做?

4

4 回答 4

0

听起来您想要一个自定义 DCOM 代理,而不是 midl 和 Windows 提供的默认逻辑。这是可能的,但也需要大量的工作。如果您需要为使用 COM 创建对象的第三方代码提供自定义行为,这是最佳选择。

当您控制客户端代码时,编写一个实现相同 COM 接口的包装类可能会更简单,并通过将每个调用转发到远程服务器来实现。

于 2012-06-06T18:21:09.597 回答
0

CComPointer 的实现相当简单。您可以轻松地剪切和粘贴它以形成您自己的智能指针类的基础。

CComPointer 实现依赖于覆盖“->”运算符。这样就无需了解接口提供的方法。每个呼叫都被有效地拦截然后转发。

在您的新智能指针类中,您可以在“->”运算符覆盖的实现中构建您需要的额外功能。

为验证呼叫而进行的检查更难。

我认为 QueryInterface 是一个有效的调用,您可以使用它来检查连接是否处于活动状态 - QueryInterface 保证存在并且需要调用真正的实现。

然而,总会有一个竞争条件——在你的检查电话和你的真实电话之间的连接可能会失败。

因此,您最好只进行真正的通话,如果失败,请尝试恢复并再次通话 - 这很难以一种好的模式进行 - 可能最容易通过宏来实现,请参阅 Forgottn 的答案。

于 2012-06-06T14:13:06.443 回答
0

MFC 类向导允许您围绕 com 组件生成包装类。这个页面描述了如何。

生成包装类后 - 您可以编辑任何方法以在其中实现重试逻辑。您可以对#import 指令生成的包装类使用相同的方法。

于 2012-06-11T14:52:56.660 回答
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);

这可能会有所帮助,这将隐藏函数列表,但是使用这样的代码并不是一个好主意。

于 2012-06-06T12:15:27.663 回答