我该如何编写正确的COM代码?

时间:2011-09-20 15:37:23

标签: c++ 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();
}

4 个答案:

答案 0 :(得分:2)

使用智能指针,例如CComPtrMSDN documentation on CComPtr有一个示例,说明与手动生命周期管理相比,CComPtr如何使事情变得更容易。

答案 1 :(得分:2)

使用智能指针查看所有Release(),然后使用失败,而不是成功,作为条件。

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

当然,这可以重构为您最喜欢的内联函数或宏。

答案 2 :(得分:1)

您可以使用某种智能指针,它将在析构函数中为您调用Release。例如,CComPtr或Boost的intrusive pointer

答案 3 :(得分:0)

使用boost::intrusive_ptr可以将所有这些来电转移到Release。我想不出另一种方法来删除所有嵌套的if,但是让函数抛出异常。考虑使用检查S_OKthrow s。

的内容来围绕您的函数调用