Search code examples
c++windowscomatlwindows-shell

Why is this COM code leaking?


I'm maintaining an application which uses Windows Explorer overlay icons. Occasionally some operations require me to forcibly refresh explorers view for a particular folder. I do so using the following function which uses COM:

void RefreshExplorerView(CString strPath)
{
    CComPtr<IShellWindows> pShellWindows;

    CoInitialize(NULL);

    if(SUCCEEDED(pShellWindows.CoCreateInstance(CLSID_ShellWindows)))
    {
        IDispatch* pFolder=NULL;
        VARIANT variant;
        V_VT(&variant) = VT_I4;

        for(V_I4(&variant) = 0; pShellWindows->Item(variant, &pFolder) == S_OK; V_I4(&variant)++)
        {
            CComPtr<IWebBrowserApp> pWebBrowserApp;
            if(SUCCEEDED(pFolder->QueryInterface(IID_PPV_ARGS(&pWebBrowserApp))))
            {
                BSTR LocationURL = NULL;
                pWebBrowserApp->get_LocationURL(&LocationURL);

                if(LocationURL != NULL && strPath.CompareNoCase(LocationURL) == 0)
                {
                    CComPtr<IServiceProvider> pServiceProvider;
                    if(SUCCEEDED(pWebBrowserApp->QueryInterface(IID_PPV_ARGS(&pServiceProvider))))
                    {
                        CComPtr<IShellBrowser> pShellBrowser;
                        if(SUCCEEDED(pServiceProvider->QueryInterface(IID_PPV_ARGS(&pShellBrowser))))
                        {
                            IShellView* pShellView;
                            if(SUCCEEDED(pShellBrowser->QueryActiveShellView(&pShellView)))
                            {
                                pShellView->Refresh();
                                pShellView->Release();
                            }
                        }
                    }
                }

                SysFreeString(LocationURL);
            }
            pFolder->Release();
            pFolder = NULL;
        }
    }

    CoUninitialize();
}

I've noticed that when my program does this refresh regularly it slowly grows in size and UMDH has shown me that I appear to be leaking pFolder and pShellWindow instances every time this runs. I can't work out why on earth this happens since as far as I can tell these are released properly. Can anyone see what I'm missing?


Solution

  • You release pShellWindows after CoUninitialize, which is incorrect.

    The rest of interfaces seem to be released fine. Note that you could improve cleanless and readability greatly by using CComQIPtr instead of QueryInterface, and not using raw pointers at all (BSTR, IFoo*) and replace them with smart auto-releasing wrappers.

    pFolder might be leaking too, if Item call is successful but returns code other than S_OK. Again, use of CComPtr<IFolder> instead of IFolder* would immediately resolve this problem without even drawing any attention to it.