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 __REACTOS__
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 #else
102 #define DECLARE_QIPTR(type)     CComQIPtr<type>
103 #endif
104 
105 START_TEST(CComQIPtr)
106 {
107     CQITestObject testObject;
108     IUnknown* unk = static_cast<IPersist*>(&testObject);
109     ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
110     ok(g_QI == 0, "Expected g_QI 0, got %lu\n", g_QI);
111 
112     {
113         DECLARE_QIPTR(IPersist) ppPersist(unk);
114         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
115         ok(g_QI == 1, "Expected g_QI 1, got %lu\n", g_QI);
116 
117         DECLARE_QIPTR(IStdMarshalInfo) ppMarshal(ppPersist);
118         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
119         ok(g_QI == 2, "Expected g_QI 2, got %lu\n", g_QI);
120     }
121     ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
122     {
123         DECLARE_QIPTR(IStdMarshalInfo) ppMarshal;
124         ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
125         ok(g_QI == 2, "Expected g_QI 2, got %lu\n", g_QI);
126 
127         ppMarshal = unk;
128         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
129         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
130 
131         ppMarshal = static_cast<IUnknown*>(NULL);
132         ok(testObject.m_dwRef == 1, "Expected m_dwRef 1, got %lu\n", testObject.m_dwRef);
133         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
134 
135         CComPtr<IUnknown> spUnk(unk);
136         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
137         ok(g_QI == 3, "Expected g_QI 3, got %lu\n", g_QI);
138 
139         ppMarshal = spUnk;
140         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
141         ok(g_QI == 4, "Expected g_QI 4, got %lu\n", g_QI);
142 
143         spUnk.Release();
144         ok(testObject.m_dwRef == 2, "Expected m_dwRef 2, got %lu\n", testObject.m_dwRef);
145         ok(g_QI == 4, "Expected g_QI 4, got %lu\n", g_QI);
146 
147         spUnk = ppMarshal;
148         ok(testObject.m_dwRef == 3, "Expected m_dwRef 3, got %lu\n", testObject.m_dwRef);
149 #ifdef __REACTOS__
150         // CORE-12710
151         todo_if(1)
152 #endif
153         ok(g_QI == 5, "Expected g_QI 5, got %lu\n", g_QI);
154     }
155 
156 #ifndef __REACTOS__
157     printf("CComQIPtr: %i tests executed (0 marked as todo, %i failures), 0 skipped.\n", g_tests_executed, g_tests_failed);
158     return g_tests_failed;
159 #endif
160 }
161