未释放筛选器com对象导致崩溃

Not releasing filter com object causing a crash

本文关键字:崩溃 对象 com 释放 筛选      更新时间:2023-10-16

我正在使用带有vlc的Viveks捕获过滤器(http://tmhare.mvps.org/downloads/vcam.zip)以模拟捕获源。当过滤器打开,我关闭vlc时,我会崩溃。堆栈跟踪指示2个COM对象仍然存在(我猜是过滤器和引脚),应该在CoUninitialize调用之前释放。我的问题是,我不确定在哪里释放filter和pin COM对象,我有一个fitler和pin的析构函数,但当vlc关闭时,它们永远不会被调用。有人遇到了类似的问题(未发布的DirectShow CSource筛选器使程序在进程关闭时崩溃)。

这是dll的重要注册部分。

STDAPI RegisterFilters( BOOL bRegister )
{
    HRESULT hr = NOERROR;
    WCHAR achFileName[MAX_PATH];
    char achTemp[MAX_PATH];
    ASSERT(g_hInst != 0);
    if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp))) 
        return AmHresultFromWin32(GetLastError());
    MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1, 
                   achFileName, NUMELMS(achFileName));
    hr = CoInitialize(0);
    if(bRegister)
    {
        hr = AMovieSetupRegisterServer(CLSID_VirtualCam, L"Virtual Cam", achFileName, L"Both", L"InprocServer32");
    }
    if( SUCCEEDED(hr) )
    {
        IFilterMapper2 *fm = 0;
        hr = CreateComObject( CLSID_FilterMapper2, IID_IFilterMapper2, fm );
        if( SUCCEEDED(hr) )
        {
            if(bRegister)
            {
                IMoniker *pMoniker = 0;
                REGFILTER2 rf2;
                rf2.dwVersion = 1;
                rf2.dwMerit = MERIT_DO_NOT_USE;
                rf2.cPins = 1;
                rf2.rgPins = &AMSPinVCam;
                hr = fm->RegisterFilter(CLSID_VirtualCam, L"Virtual Cam", &pMoniker, &CLSID_VideoInputDeviceCategory, NULL, &rf2);
            }
            else
            {
                hr = fm->UnregisterFilter(&CLSID_VideoInputDeviceCategory, 0, CLSID_VirtualCam);
            }
        }  
      // release interface
      //
      if(fm)
          fm->Release();
    }
    if( SUCCEEDED(hr) && !bRegister )
         hr = AMovieSetupUnregisterServer( CLSID_VirtualCam );
    CoFreeUnusedLibraries();
    CoUninitialize();
    return hr;
}
STDAPI DllRegisterServer()
{
    return RegisterFilters(TRUE);
}
STDAPI DllUnregisterServer()
{
    return RegisterFilters(FALSE);
}
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{
    return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

的重要过滤部分

CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
CSourceStream(NAME("Virtual Cam"),phr, pParent, pPinName), m_pParent(pParent)
{
    // Set the default media type as 320x240x24@15
    GetMediaType(4, &m_mt);
}
CVCamStream::~CVCamStream()
{
    m_pParent->Release();
} 

泄漏的COM引用有点难以确定。假设COM客户端(在您的案例中是VLC)做得很好(可能不是这样,但可以从这个假设开始),问题就出在您的代码上。它通常是以下两种之一:

  1. 您正在处理原始指针,并且在某些地方没有与前面所做的AddRef相匹配的Release
  2. 有循环引用和对象使彼此保持活力

正如您已经看到的,您有两个浮动的对象,一个好的策略是确定它们到底是什么类,并跟踪引用计数器的更改,以查看丢失的IUnknown::Release在哪里。