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がダウンしたときに回復する問題を解決しようとしています。CoCreateをMyTaskに再実行するメソッドrecover()を作成しましたが、実際に問題を解決します。

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を介してメソッドを実行しようとするたびに、メソッドを実行する前に、タスクがすでに存在することを確認し、存在しない場合は、recoverメソッドを実行する必要があります。タスクが停止している場合でも、ComPointerにはCoCreate時のすべてのデータが残っているため、どうすればよいかわかりません。

どうすればいいですか?

システムでエラーが発生したためにタスクが停止しました。今のところ、私のソリューションでは、タスクを回復するためだけに、タスクの失敗の理由を見つける必要はありません。ComPointerのラッパーのような一般的な解決策を探していますが、ラッパークラスがMyTaskがまだ存在するかどうかだけをチェックし、存在する場合はComPointerを返し、存在しない場合はrecoverを実行するようにします。 。

どうすればいいですか?

4

4 に答える 4

0

midlとWindowsが提供するデフォルトロジックではなく、カスタムDCOMプロキシが必要なようです。それは可能ですが、それは多くの作業でもあります。これは、COMを使用してオブジェクトを作成するサードパーティのコードに提供されるカスタム動作が必要な場合に最適なオプションです。

クライアントコードを制御する場合、同じCOMインターフェイスを実装するラッパークラスを作成する方がおそらく簡単であり、すべての呼び出しをリモートサーバーに転送します。

于 2012-06-06T18:21:09.597 に答える
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
 };

編集1:マクロサンプルを追加しました(コメント#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 に答える
0

CComPointerの実装はかなり簡単です。簡単にカットアンドペーストして、独自のスマートポインタクラスの基礎を形成できます。

CComPointerの実装は、「->」演算子のオーバーライドに依存しています。これにより、インターフェイスが提供するメソッドについて何も知る必要がなくなります。すべての呼び出しは効果的に傍受されてから転送されます。

新しいスマートポインタクラスでは、「->」演算子のオーバーライドの実装に必要な追加機能を組み込むことができます。

呼び出しを検証するために行うチェックはより困難です。

QueryInterfaceは、接続が有効であることを確認するために使用できる有効な呼び出しだと思います。QueryInterfaceは存在することが保証されており、実際の実装を呼び出す必要があります。

ただし、常に競合状態が発生します。チェックコールと実際のコールの間に接続が失敗する可能性があります。

したがって、実際の呼び出しを行うだけの方がよい場合があります。失敗した場合は、回復して再度呼び出してみてください。これは、適切なパターンで行うのは困難です。おそらく、マクロを使用して達成するのが最も簡単です。Forgottnの回答を参照してください。

于 2012-06-06T14:13:06.443 に答える