简体   繁体   English

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

[英]How am I supposed to write correct COM code?

The following code releases everything correctly, but it looks awful. 以下代码可以正确释放所有内容,但看起来很糟糕。 How am I supposed to write COM code that doesn't leak references and is readable? 我应该如何编写不泄漏引用且可读的COM代码?

Ignore the C++\\CLI bits. 忽略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();
}

Use a smart pointer, such as CComPtr . 使用智能指针,例如CComPtr The MSDN documentation on CComPtr has an example that shows how CComPtr makes things easier compared to manual lifetime management. 有关CComPtrMSDN文档提供了一个示例,该示例显示了与手动生命周期管理相比,CComPtr如何使事情变得更容易。

Use a smart pointer to chuck all the Release() s, and then use failure, not success, as the condition. 使用智能指针删除所有Release() ,然后使用失败(而非成功)作为条件。

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

Of course, this can be refactored into your favourite inline function or macro. 当然,可以将其重构为您喜欢的内联函数或宏。

You can use some sort of smart pointer that will call Release for you in the destructor. 您可以使用某种智能指针,该指针将在析构函数中为您调用Release。 For instance, CComPtr , or Boost's intrusive pointer . 例如, CComPtr或Boost的侵入式指针

Using boost::intrusive_ptr would get ride of all those calls to Release . 使用boost::intrusive_ptr将获得对Release的所有调用。 I can't think of another way to remove all those nested if s but by having functions throw exceptions. 我想不出另一种方法来删除所有嵌套的if而是让函数抛出异常。 Consider surrounding your function calls with something that checks against S_OK or else throw s. 考虑在函数调用中使用可以检查S_OKthrow s的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM