1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * PROJECT:     ReactOS api tests
 * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
 * PURPOSE:     Test for CComQIPtr
 * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
 */

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

#ifdef HAVE_APITEST
    #include <apitest.h>
#else
    #include "atltest.h"
#endif


static LONG g_QI = 0;

class CQITestObject :
    public IPersist,
    public IStdMarshalInfo
{
public:
    LONG m_dwRef;

    CQITestObject()
        :m_dwRef(1)
    {
    }
    ~CQITestObject()
    {
    }

    STDMETHOD_(ULONG, AddRef)()
    {
        InterlockedIncrement(&m_dwRef);
        return 2;
    }

    STDMETHOD_(ULONG, Release)()
    {
        InterlockedDecrement(&m_dwRef);
        return 1;
    }

    STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
    {
        InterlockedIncrement(&g_QI);
        if (iid == IID_IUnknown || iid == IID_IPersist)
        {
            AddRef();
            *ppvObject = static_cast<IPersist*>(this);
            return S_OK;
        }
        else if (iid == IID_IStdMarshalInfo)
        {
            AddRef();
            *ppvObject = static_cast<IStdMarshalInfo*>(this);
            return S_OK;
        }
        return E_NOINTERFACE;
    }

    // *** IPersist methods ***
    STDMETHOD(GetClassID)(CLSID *pClassID)
    {
        return E_NOTIMPL;
    }

    // *** IStdMarshalInfo methods ***
    STDMETHOD(GetClassForHandler)(DWORD dwDestContext, void *pvDestContext, CLSID *pClsid)
    {
        return E_NOTIMPL;
    }
};

// Yes this sucks, but we have to support GCC. (CORE-12710)
#ifdef __REACTOS__
#define DECLARE_QIPTR(type)     CComQIIDPtr<I_ID(type)>
#elif defined(__GNUC__)
#define DECLARE_QIPTR(type)     CComQIIDPtr<I_ID(type)>
#else
#define DECLARE_QIPTR(type)     CComQIPtr<type>
#endif

START_TEST(CComQIPtr)
{
    CQITestObject testObject;
    IUnknown* unk = static_cast<IPersist*>(&testObject);
    ok_long(testObject.m_dwRef, 1);
    ok_long(g_QI, 0);

    {
        DECLARE_QIPTR(IPersist) ppPersist(unk);
        ok_long(testObject.m_dwRef, 2);
        ok_long(g_QI, 1);

        DECLARE_QIPTR(IStdMarshalInfo) ppMarshal(ppPersist);
        ok_long(testObject.m_dwRef, 3);
        ok_long(g_QI, 2);
    }
    ok_long(testObject.m_dwRef, 1);
    {
        DECLARE_QIPTR(IStdMarshalInfo) ppMarshal;
        ok_long(testObject.m_dwRef, 1);
        ok_long(g_QI, 2);

        ppMarshal = unk;<--- ppMarshal is assigned
        ok_long(testObject.m_dwRef, 2);
        ok_long(g_QI, 3);

        ppMarshal = static_cast<IUnknown*>(NULL);<--- ppMarshal is overwritten<--- ppMarshal is assigned
        ok_long(testObject.m_dwRef, 1);
        ok_long(g_QI, 3);

        CComPtr<IUnknown> spUnk(unk);
        ok_long(testObject.m_dwRef, 2);
        ok_long(g_QI, 3);

        ppMarshal = spUnk;<--- ppMarshal is overwritten
        ok_long(testObject.m_dwRef, 3);
        ok_long(g_QI, 4);

        spUnk.Release();
        ok_long(testObject.m_dwRef, 2);
        ok_long(g_QI, 4);

        spUnk = ppMarshal;
        ok_long(testObject.m_dwRef, 3);
#ifdef __REACTOS__
        // CORE-12710
        todo_if(1)
#endif
        ok_long(g_QI, 5);
    }
}