#include <atlbase.h>
#include <atlcom.h>

#include "hnxGC.h"

struct __declspec(uuid("2ECBF8CD-E787-43c0-BC72-5547B5EB11D1")) 
INode : public IUnknown {
    virtual void SetLink(IUnknown * pNext) = 0;
};

class CFoo : public INode {
public:
    HNXGC_ENABLE(CFoo)
    HNXGC_IMPLEMENT_IUNKNOWN

    ~CFoo() {
        printf("COM object [%p] destroyed\n", this);
    }
    void * _hnxgcGetCompleteObject() {
        return this;
    }

    void * _hnxgcQueryInterface(const IID & iid) {
        if (iid == __uuidof(IUnknown)) {
            return static_cast<IUnknown*>(this);
        } else if (iid == __uuidof(INode)) {
            return static_cast<INode*>(this);
        }
        return NULL;
    }

    gcptr<IUnknown>			m_pNext;		
    
    void SetLink(IUnknown *pNext) {
        pNext->AddRef();
        m_pNext.Attach(pNext);
    }
public:
    static INode* CreateInstance();
};

INode * CFoo::CreateInstance()
{
    gcptr<CFoo> pObj = gcnew CFoo;
    INode * pRet = pObj;
    pRet->AddRef();
    return pRet;
}

int main(int argc, char* argv[])
{
    CoInitialize(NULL);

    CComPtr<INode> pFirst;
    CComPtr<INode> pLast;
    
    // create a single-linked list of nodes
    for (int i = 0; i < 5; i++) {
        CComPtr<INode> pCurr;
    
        pCurr.Attach(CFoo::CreateInstance());

        if (!pFirst) {
            pFirst = pCurr;
        }

        if (pLast) {
            pLast->SetLink(pCurr);
        }

        pLast = pCurr;
    }

    // form a circular-referenced relation
    pLast->SetLink(pFirst);	

    hnxgc.Collect();	// <-- this will not collect live objects

    // after use, make objects unreachable
    printf("=== After Use ===\n");
    pFirst = pLast = NULL;

    // implicit garbage collection before CoUnitialize()
    hnxgc.Collect();

    printf("=== End of Program ===\n");
    CoUninitialize();

    return 0;
}

