Search code examples
c++pointersdomcommfc

Retrieving address/pointer (IXMLDOMNode*) from struct stored in LPARAM of CTreeCtrl - not working


In a custom CTreeCtrl class, I add as LPARAM a pointer to a custom struct->containing the address to a IXMLDOMNode*.

Later on, I want to fetch the pointer from the LPARAM and cast the address in it back to a IXMLDOMNode*.

This works fine, as long as I use it in the same scope/function (tested in function only). When I use it in a other function/class to retrieve the pointer and cast the contained address to IXMLDOMNode* it is the correct - given - address. The problem is, that when I try to use a function of it (e.g. get_nodeName(BSTR *name)) it throws an unhandled exception.

Unhandled exception at 0x6522b1b8 in Program.exe: 0xC0000005: Access violation reading location 0x00000000.

Insert:

HTREEITEM InsertIntoTree(CustomTreeCtrl &xCtrl, const HTREEITEM hCurrent, CComPtr<IXMLDOMNode> &cpCurrent)
{
    TVINSERTSTRUCT tvItem = {0};
    //[...]
    //tvItem.item.mask has TVIF_PARAM && other flags set...

    tvItem.item.lParam = TreeItemData(cpCurrent, 0).Alloc()->Address();
    //[...]
}

Get (testing location in CustomTreeCtrl):

else
{
    TreeItemData *tiData = TreeItemData::GetPointer(GetItemData(m_hActiveItem)); //Fine
    CComPtr<IXMLDOMNode> F = tiData->GetCComPtr(); //Fine
    BSTR Name = nullptr;
    F->get_nodeName(&Name); //Unhandled Exception
}

Structure:

struct TreeItemData
{
    //[...]
    TreeItemData(CComPtr<IXMLDOMNode> &pNode, DWORD dwFlags)
    {
        m_dwCComPtrAddress  =   reinterpret_cast<DWORD>(&*pNode);
        m_dwFlags           =   dwFlags;
    }

    CComPtr<IXMLDOMNode> GetCComPtr(void)
    {
        return CComPtr<IXMLDOMNode>(reinterpret_cast<IXMLDOMNode*>(m_dwCComPtrAddress));
    }

    TreeItemData *Alloc(void)
    {
        return new TreeItemData(*this);
    }

    LPARAM Address(void)
    {
        return reinterpret_cast<LPARAM>(&*this);
    }

    static TreeItemData *GetPointer(DWORD Address)
    {
        return reinterpret_cast<TreeItemData*>(Address);
    }

    //[...]

    DWORD m_dwCComPtrAddress;
    DWORD m_dwFlags;
};

Q: What could possibly be wrong ? How can I get my - working - pointer to IXMLDOMNode back ?


Solution

    1. Always use DWORD_PTR if you have pointer. Just for 64bit compatibility.
    2. COM Pointer use reference counting. CComPtr care about this ref counting. You pass a CComPtr to your struct. You get the objects pointer out of the CComPtr without increasing the ref count. So you object may already be destroyed when you try to use it, because the CComPtr is already destroyed.

    Use also a smart pointer inside your TreeItemData structure. This also makes sure that your objects are released when your tree item structure is freeded.

    Warning: You know that you have to free all this strcutures, when you delete a tree item from the CTreeCtrl.