Pergunta

In c++, MFC:

I have a CComPointer:

CComPointer<IMyTask> m_pTask;

there are a lot of places in my code, I call to this ComPointer to run the task's methods. For example:

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

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

I try to solve a problem to recover when MyTask is down. I wrote a method, recover(), that rerun the CoCreate to MyTask, and it actually solves the problem.

I could see that if MyTask is dead, i get an HR fail code of -2147023174, RPC server is unavailable. But, the com pointer m_pTask has the full data (it doesn't know the task is dead).

I can do something like this:

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

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

But, because I have alot of calling to methods via the compointer, I want to make something more general. I want that everytime I try to run a method via the ComPointer, before the runnuing of the method, to check that the task is already exists, and if not - run the recover method. Since even when the task is dead, ComPointer still has all the data from the CoCreate time, I don't know how can I do it.

How can I do it?

The task is dead due to an error that occurs sometiems in the system, and for now my solution does not need to find the reason for the task failure, just to recover it. I am looking for a general solution - like a wrapper to the ComPointer, but I want that the wrapper class will only check if MyTask is still exists, and if it is -it will return the ComPointer, and if not, it will run recover.

How can I do it?

Foi útil?

Solução

Okay, it's a general answer to a general question. I don't want to know, why the task is actually dead, when the pointer is not. Write a wrapper for the task pointer and use it instead. It will look something like this:

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: added a macros sample (see comment #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

You can use it in following way:

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

This could help, and this will hide the function list, but nevertheless it's not very good idea to use such code.

Outras dicas

The implementation of CComPointer is fairly simple. You can easily cut and paste it to form the basis of your own smart pointer class.

The CComPointer implementation relies on overriding the "->" operator. This avoids the need to know anything about what methods an interface offers. Every call is effectively intercepted and then forwarded.

In your new smart pointer class you could build you're required extra functionality into the implementation of the "->" operator override.

What check to make to validate the call is harder.

I think QueryInterface is a valid call that you could use to check that the connection is alive - QueryInterface is guaranteed to exist and will need to call through to the real implementation.

However there will always be a race condition - the connection may fail in between your checking call and your real call.

Therefore you may be better just to make the real call and if it fails try to recover and call again - this harder to do in a nice pattern - probably easiest to achieve with a macro see answer from Forgottn.

It sounds like you want a custom DCOM proxy, instead of the default logic provided by midl and Windows. That's possible, but it's also a lot of work. This is the best option if you need the custom behavior provided to third-party code that uses COM to create the object.

When you control the client code, it would probably be simpler to just write a wrapper class that implements the same COM interface, and does so by forwarding every call to the remote server.

The MFC class wizard allows you to generate a wrapper class around a com component. This page describes how.

Once the wrapper class has been generated - you can edit any of the methods to implement your retry logic in it. You can use the same approach for wrapper classes generated by the #import directive.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top