2011-09-20 8 views
1

次のコードはすべてを正しくリリースしていますが、ひどいです。参照を漏らさず、読み込み可能なCOMコードを書くにはどうすればよいですか?正しいCOMコードを書くにはどうしたらいいですか?

C++ \ CLIビットを無視してください。

IBaseFilter* leftFilter; 
if (graph->FindFilterByName(L"Left", &leftFilter) == S_OK) 
{ 
    IPin* leftIn; 
    if (leftFilter->FindPin(L"Audio Input pin (rendered)", &leftIn) == S_OK) 
    { 
     IBaseFilter* meterFilter; 
     if (graph->FindFilterByName(L"Meter", &meterFilter) == S_OK) 
     { 
      IPin* meterIn; 
      if (meterFilter->FindPin(L"Input", &meterIn) == S_OK) 
      { 
       IPin* meterOut; 
       if (meterFilter->FindPin(L"Output", &meterOut) == S_OK) 
       { 
        try 
        { 
         IntPtr fileName = Marshal::StringToCoTaskMemUni(source->OriginalString); 
         IBaseFilter* sourceFilter; 
         if (graph->AddSourceFilter((LPCWSTR)(void*)fileName, L"Source", &sourceFilter) == S_OK) 
         { 
          IPin* sourceOut; 
          if (sourceFilter->FindPin(L"Output", &sourceOut) == S_OK) 
          { 
           if (graph->Connect(sourceOut, meterIn) == S_OK) 
           { 
            IBaseFilter* rightFilter; 
            if (graph->FindFilterByName(L"Right", &rightFilter) == S_OK) 
            { 
             IPin* rightIn; 
             if (rightFilter->FindPin(L"Audio Input pin (rendered)", &rightIn) == S_OK) 
             { 
              IBaseFilter* splitFilter; 
              if (graph->FindFilterByName(L"Split", &splitFilter) == S_OK) 
              { 
               IPin* splitIn; 
               if (splitFilter->FindPin(L"Input", &splitIn) == S_OK) 
               { 
                IPin* splitLeft; 
                if (splitFilter->FindPin(L"Left", &splitLeft) == S_OK) 
                { 
                 IPin* splitRight; 
                 if (splitFilter->FindPin(L"Right", &splitRight) == S_OK) 
                 { 
                  if (graph->ConnectDirect(meterOut, splitIn, NULL) == S_OK 
                   && graph->ConnectDirect(splitLeft, leftIn, NULL) == S_OK 
                   && graph->ConnectDirect(splitRight, rightIn, NULL) == S_OK) 
                  { 
                   this->source = source; 
                   OnMediaOpened(EventArgs::Empty); 
                  } 
                  splitRight->Release(); 
                 } 
                 splitLeft->Release(); 
                } 
                splitIn->Release(); 
               } 
               splitFilter->Release(); 
              } 
              rightIn->Release(); 
             } 
             rightFilter->Release(); 
            } 
            else 
            { 
             if (graph->ConnectDirect(meterOut, leftIn, NULL) == S_OK) 
             { 
              this->source = source; 
              OnMediaOpened(EventArgs::Empty); 
             } 
            } 
           } 
           sourceOut->Release(); 
          } 
          sourceFilter->Release(); 
         } 
         Marshal::FreeCoTaskMem(fileName); 
        } 
        catch (Exception^) { } 
        meterOut->Release(); 
       } 
       meterIn->Release(); 
      } 
      meterFilter->Release(); 
     } 
     leftIn->Release(); 
    } 
    leftFilter->Release(); 
} 
+1

うわー!!非常に多くのネストされた 'ifs'。可能であれば、論理および/または設計を再考することができます。 – Mahesh

+0

'if(possible)reconsider_design();';)を意味しますか? – Dan

答えて

2

スマートポインタ(CComPtrなど)を使用します。 MSDN documentation on CComPtrには、CComPtrがマニュアルライフタイム管理と比較してより簡単になる方法を示す例があります。

0

boost::intrusive_ptrを使用すると、Releaseのすべての呼び出しに乗ることになります。私はifを入れ子にしたものをすべて削除する別の方法を考えることはできませんが、例外をスローする関数を持つことによって考えています。あなたの関数呼び出しを、S_OKまたはそれ以外の場合はthrowと照合するもので囲むことを検討してください。

1

デストラクタであなたのためにReleaseを呼び出すスマートポインタを使用できます。たとえば、CComPtr、またはBoostのintrusive pointerです。

2

スマートポインタを使用してRelease()をすべてチャッキングし、成功ではなく失敗を条件として使用します。

if (graph->FindFilterByName(L"Left", &leftFilter) != S_OK) 
    throw ...; 

もちろん、これをお気に入りのインライン関数またはマクロにリファクタリングすることができます。

関連する問題