如何判断我是否泄漏了IMalloc内存?

时间:2009-11-05 19:38:55

标签: windows visual-c++ com

我想知道是否有一种完善的标准方法来确保一个人的进程不会泄漏基于COM的资源(例如IMalloc'd对象)?

以下面的代码为例:

HRESULT STDMETHODCALLTYPE CShellBrowserDialog::OnStateChange(__RPC__in_opt IShellView *ppshv, ULONG uChange)
{
    TRACE("ICommDlgBrowser::OnStateChange\n");

    if (uChange == CDBOSC_SELCHANGE)
    {
        CComPtr<IDataObject> data;

        if (ppshv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (void**)&data) == S_OK )
        {
            UINT cfFormat = RegisterClipboardFormat(CFSTR_SHELLIDLIST);

            FORMATETC fmtetc = { cfFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
            STGMEDIUM stgmed;

            if (data->GetData(&fmtetc, &stgmed) == S_OK)
            {
                TCHAR path[MAX_PATH];

                // check if this single selection (or multiple)
                CIDA * cida = (CIDA*)stgmed.hGlobal;
                if (cida->cidl == 1)
                {
                    const ITEMIDLIST * pidlDirectory = (const ITEMIDLIST *)(((LPBYTE)cida) + cida->aoffset[0]);
                    const ITEMIDLIST * pidlFile = (const ITEMIDLIST *)(((LPBYTE)cida) + cida->aoffset[1]);
                    ITEMIDLIST * pidl = Pidl_Concatenate(pidlDirectory, pidlFile);

                    // we now have the absolute pidl of the currently selected filesystem object
                    if (!SHGetPathFromIDList(pidl, path))
                        strcpy_s(path, _T("<this object has no path>"));

                    // free our absolute pidl
                    Pidl_Free(pidl);
                }
                else if (cida->cidl > 1)
                    strcpy_s(path, _T("{multiple selection}"));
                else
                    strcpy_s(path, _T("-"));

                // trace the current selection
                TRACE(_T("  Current Selection = %s\n"), path);

                // release the data
                ReleaseStgMedium(&stgmed);
            }
        }
    }

    return E_NOTIMPL;
}

因此,在上面的代码中,我至少有三个分配发生在我调用的代码中,其中只有一个分配被自动正确清理。第一个是获取IDataObject指针,该指针递增该对象的引用计数。但是CComPtr&LT;&GT;为我处理这个问题。

但是有IDataObject :: GetData,它为我分配一个HGLOBAL。还有一个实用函数Pidl_Concatenate,它为我创建了一个PIDL(代码遗漏了,但你可以想象它通过IMalloc :: Alloc()完成了显而易见的事情)。我有另一个实用程序Pidl_Free为我释放内存,但必须手动调用[这使得代码充满异常安全问题(它完全不安全,因为它目前写的 - 我讨厌MS的编码机制 - 只是问无法正确释放内存]。

我将增强这段代码,使其具有某种类型的PIDL类,并且可能也是一个CIDA类,以确保即使在异常情况下它们也能正确释放。但我仍然想知道在C ++中编写COM应用程序是否有一个很好的实用程序或习惯用法可以确保为该应用程序的生命周期调用所有IMallocs和AddRef / Dispose!

2 个答案:

答案 0 :(得分:2)

实现IMallocSpy界面(请参阅CoRegisterMallocSpy功能)可以帮助您解决问题。
请注意,这仅用于调试,请注意。网上有警示tales ......

答案 1 :(得分:0)

您无法释放IDataObject :: GetData返回的全局句柄,否则在清理数据后其他程序无法从剪贴板粘贴。 你从shell获得的任何pidl需要使用IMalloc :: Free或ILFree释放(一旦OLE32.DLL加载到进程中,效果相同)。例外是指向项目列表中间的指针,不能单独释放。如果您担心异常,请使用try / catch / finally保护您的代码,并将免费代码放在finally块中。