1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Test for CComQIPtr
5  * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include <atlbase.h>
9 #include <atlcom.h>
10 
11 #ifdef HAVE_APITEST
12     #include <apitest.h>
13 #else
14     #include <stdlib.h>
15     #include <stdio.h>
16     #include <stdarg.h>
17     int g_tests_executed = 0;
18     int g_tests_failed = 0;
19     void ok_func(const char *file, int line, BOOL value, const char *fmt, ...)
20     {
21         va_list va;
22         va_start(va, fmt);
23         if (!value)
24         {
25             printf("%s (%d): ", file, line);
26             vprintf(fmt, va);
27             g_tests_failed++;
28         }
29         g_tests_executed++;
30         va_end(va);
31     }
32     #undef ok
33     #define ok(value, ...)  ok_func(__FILE__, __LINE__, value, __VA_ARGS__)
34     #define START_TEST(x)   int main(void)
35 #endif
36 
37 
38 static LONG g_QI = 0;
39 
40 class CQITestObject :
41     public IPersist,
42     public IStdMarshalInfo
43 {
44 public:
45     LONG m_dwRef;
46 
47     CQITestObject()
48         :m_dwRef(1)
49     {
50     }
51     ~CQITestObject()
52     {
53     }
54 
55     STDMETHOD_(ULONG, AddRef)()
56     {
57         InterlockedIncrement(&m_dwRef);
58         return 2;
59     }
60 
61     STDMETHOD_(ULONG, Release)()
62     {
63         InterlockedDecrement(&m_dwRef);
64         return 1;
65     }
66 
67     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
68     {
69         InterlockedIncrement(&g_QI);
70         if (iid == IID_IUnknown || iid == IID_IPersist)
71         {
72             AddRef();
73             *ppvObject = static_cast<IPersist*>(this);
74             return S_OK;
75         }
76         else if (iid == IID_IStdMarshalInfo)
77         {
78             AddRef();
79             *ppvObject = static_cast<IStdMarshalInfo*>(this);
80             return S_OK;
81         }
82         return E_NOINTERFACE;
83     }
84 
85     // *** IPersist methods ***
86     STDMETHOD(GetClassID)(CLSID *pClassID)
87     {
88         return E_NOTIMPL;
89     }
90 
91     // *** IStdMarshalInfo methods ***
92     STDMETHOD(GetClassForHandler)(DWORD dwDestContext, void *pvDestContext, CLSID *pClsid)
93     {
94         return E_NOTIMPL;
95     }
96 };
97 
98 // Yes this sucks, but we have to support GCC. (CORE-12710)
99 #ifdef __REACTOS__
100 #define DECLARE_QIPTR(type)     CComQIIDPtr<I_ID(type)>
101 #elif defined(__GNUC__)
102 #define DECLARE_QIPTR(type)     CComQIIDPtr<I_ID(type)>
103 #else
104 #define DECLARE_QIPTR(type)     CComQIPtr<type>
105 #endif
106 
107 START_TEST(CComQIPtr)
108 {
109     CQITestObject testObject;
110     IUnknown* unk = static_cast<IPersist*>(&testObject);
111     ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
112     ok(g_QI == 0, "Expected g_QI 0, got %lu\n", g_QI);
113 
114     {
115         DECLARE_QIPTR(IPersist) ppPersist(unk);
116         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
117         ok(g_QI == 1, "Expected g_QI 1, got %lu\n", g_QI);
118 
119         DECLARE_QIPTR(IStdMarshalInfo) ppMarshal(ppPersist);
120         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
121         ok(g_QI == 2, "Expected g_QI 2, got %lu\n", g_QI);
122     }
123     ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
124     {
125         DECLARE_QIPTR(IStdMarshalInfo) ppMarshal;
126         ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
127         ok(g_QI == 2, "Expected g_QI 2, got %lu\n", g_QI);
128 
129         ppMarshal = unk;
130         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
131         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
132 
133         ppMarshal = static_cast<IUnknown*>(NULL);
134         ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
135         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
136 
137         CComPtr<IUnknown> spUnk(unk);
138         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
139         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
140 
141         ppMarshal = spUnk;
142         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
143         ok(g_QI == 4, "Expected g_QI 4, got %lu\n", g_QI);
144 
145         spUnk.Release();
146         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
147         ok(g_QI == 4, "Expected g_QI 4, got %lu\n", g_QI);
148 
149         spUnk = ppMarshal;
150         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
151 #ifdef __REACTOS__
152         // CORE-12710
153         todo_if(1)
154 #endif
155         ok(g_QI == 5, "Expected g_QI 5, got %lu\n", g_QI);
156     }
157 
158 #ifndef HAVE_APITEST
159     printf("CComQIPtr: %i tests executed (0 marked as todo, %i failures), 0 skipped.\n", g_tests_executed, g_tests_failed);
160     return g_tests_failed;
161 #endif
162 }
163