2 * PROJECT: ReactOS api tests
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: Tests for IInitializeSpy
5 * PROGRAMMERS: Mark Jansen
8 #define WIN32_NO_STATUS
10 #define COM_NO_WINDOWS_H
13 #include <wine/test.h>
19 #include <unknownbase.h>
21 #define test_S_OK(hres, message) ok((hres) == S_OK, "%s (0x%lx instead of S_OK)\n", (message), (hres))
22 #define test_HRES(hres, hresExpected, message) ok((hres) == (hresExpected), "%s (0x%lx instead of 0x%lx)\n", (message), (hres), (hresExpected))
23 #define test_ref(spy, expectedRef) ok((spy)->GetRef() == (expectedRef), "unexpected refcount, %ld instead of %d\n", (spy)->GetRef(), (expectedRef))
26 typedef HRESULT (WINAPI
*pCoRegisterInitializeSpy_t
)(_In_ LPINITIALIZESPY pSpy
, _Out_ ULARGE_INTEGER
*puliCookie
);
27 typedef HRESULT (WINAPI
*pCoRevokeInitializeSpy_t
)(_In_ ULARGE_INTEGER uliCookie
);
28 pCoRegisterInitializeSpy_t pCoRegisterInitializeSpy
;
29 pCoRevokeInitializeSpy_t pCoRevokeInitializeSpy
;
32 const DWORD INVALID_VALUE
= 0xdeadbeef;
35 class CTestSpy
: public CUnknownBase
<IInitializeSpy
>
39 ULARGE_INTEGER Cookie
;
41 // expected values to check against
46 // keeping count of the times called
48 LONG m_PostInitCalled
;
49 LONG m_PreUninitCalled
;
50 LONG m_PostUninitCalled
;
53 bool m_FailQueryInterface
;
54 bool m_AlwaysReturnOK
;
57 : CUnknownBase( false, 0 ),
62 m_FailQueryInterface(false),
63 m_AlwaysReturnOK(false)
65 Cookie
.HighPart
= Cookie
.LowPart
= INVALID_VALUE
;
71 // always try to revoke if we succeeded to register.
74 hr
= pCoRevokeInitializeSpy(Cookie
);
75 test_S_OK(hr
, "CoRevokeInitializeSpy");
78 ok(GetRef() == 0, "Expected m_lRef to be 0, was: %ld\n", GetRef());
81 HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid
, void** ppv
)
83 if (m_FailQueryInterface
)
87 return CUnknownBase::QueryInterface(riid
, ppv
);
90 const QITAB
* GetQITab()
92 static const QITAB tab
[] = { { &IID_IInitializeSpy
, OFFSETOFCLASS(IInitializeSpy
, CTestSpy
) }, { 0 } };
97 HRESULT STDMETHODCALLTYPE
PreInitialize(DWORD dwCoInit
, DWORD dwCurThreadAptRefs
)
99 InterlockedIncrement(&m_PreInitCalled
);
100 ok(m_CoInit
== dwCoInit
, "Unexpected dwCoInit: got %lx, expected %lx\n", dwCoInit
, m_CoInit
);
101 DWORD expectApt
= m_hrCoInit
== RPC_E_CHANGED_MODE
? m_CurAptRefs
: m_CurAptRefs
-1;
102 ok(expectApt
== dwCurThreadAptRefs
, "Unexpected dwCurThreadAptRefs: got %lx, expected %lx\n", dwCurThreadAptRefs
, expectApt
);
106 HRESULT STDMETHODCALLTYPE
PostInitialize(HRESULT hrCoInit
, DWORD dwCoInit
, DWORD dwNewThreadAptRefs
)
108 InterlockedIncrement(&m_PostInitCalled
);
109 ok(m_PreInitCalled
== m_PostInitCalled
, "Expected balanced pre/post: %ld / %ld\n", m_PreInitCalled
, m_PostInitCalled
);
110 test_HRES(hrCoInit
, m_hrCoInit
, "Unexpected hrCoInit in PostInitialize");
111 ok(m_CoInit
== dwCoInit
, "Unexpected dwCoInit: got %lx, expected %lx\n", dwCoInit
, m_CoInit
);
112 ok(m_CurAptRefs
== dwNewThreadAptRefs
, "Unexpected dwNewThreadAptRefs: got %lx, expected %lx\n", dwNewThreadAptRefs
, m_CurAptRefs
);
113 if (m_AlwaysReturnOK
)
118 HRESULT STDMETHODCALLTYPE
PreUninitialize(DWORD dwCurThreadAptRefs
)
120 InterlockedIncrement(&m_PreUninitCalled
);
121 ok(m_CurAptRefs
== dwCurThreadAptRefs
, "Unexpected dwCurThreadAptRefs: got %lx, expected %lx\n", dwCurThreadAptRefs
, m_CurAptRefs
);
125 HRESULT STDMETHODCALLTYPE
PostUninitialize(DWORD dwNewThreadAptRefs
)
127 InterlockedIncrement(&m_PostUninitCalled
);
128 ok(m_PreUninitCalled
== m_PostUninitCalled
, "Expected balanced pre/post: %ld / %ld\n", m_PreUninitCalled
, m_PostUninitCalled
);
129 DWORD apt
= m_CurAptRefs
? (m_CurAptRefs
-1) : 0;
130 ok(apt
== dwNewThreadAptRefs
, "Unexpected dwNewThreadAptRefs: got %lx, expected %lx\n", dwNewThreadAptRefs
, apt
);
137 m_PostInitCalled
= 0;
138 m_PreUninitCalled
= 0;
139 m_PostUninitCalled
= 0;
142 void Expect(HRESULT hrCoInit
, DWORD CoInit
, DWORD CurAptRefs
)
144 m_hrCoInit
= hrCoInit
;
146 m_CurAptRefs
= CurAptRefs
;
149 void Check(LONG PreInit
, LONG PostInit
, LONG PreUninit
, LONG PostUninit
)
151 ok(m_PreInitCalled
== PreInit
, "Expected PreInit to be %ld, was: %ld\n", PreInit
, m_PreInitCalled
);
152 ok(m_PostInitCalled
== PostInit
, "Expected PostInit to be %ld, was: %ld\n", PostInit
, m_PostInitCalled
);
153 ok(m_PreUninitCalled
== PreUninit
, "Expected PreUninit to be %ld, was: %ld\n", PreUninit
, m_PreUninitCalled
);
154 ok(m_PostUninitCalled
== PostUninit
, "Expected PostUninit to be %ld, was: %ld\n", PostUninit
, m_PostUninitCalled
);
159 void test_IInitializeSpy_register2()
163 // first we register 2 spies
164 spy
.hr
= pCoRegisterInitializeSpy(&spy
, &spy
.Cookie
);
165 test_S_OK(spy
.hr
, "CoRegisterInitializeSpy");
168 spy2
.hr
= pCoRegisterInitializeSpy(&spy2
, &spy2
.Cookie
);
169 test_S_OK(spy2
.hr
, "CoRegisterInitializeSpy");
172 // tell them what we expect
173 spy
.Expect(S_OK
, COINIT_APARTMENTTHREADED
, 1);
174 spy2
.Expect(S_OK
, COINIT_APARTMENTTHREADED
, 1);
176 // Call CoInitializeEx and validate the results
177 HRESULT hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
178 test_S_OK(hr
, "CoInitializeEx");
179 spy
.Check(1, 1, 0, 0);
180 spy2
.Check(1, 1, 0, 0);
182 // Calling CoInit twice with the same apartment makes it return S_FALSE but still increment count
183 spy
.Expect(S_FALSE
, COINIT_APARTMENTTHREADED
, 2);
184 spy2
.Expect(S_FALSE
, COINIT_APARTMENTTHREADED
, 2);
186 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
187 test_HRES(hr
, S_FALSE
, "CoInitializeEx");
188 spy
.Check(2, 2, 0, 0);
189 spy2
.Check(2, 2, 0, 0);
191 /* the order we registered the spies in is important here.
192 we have the second one to forcibly return S_OK, which makes the first spy see
193 S_OK instead of S_FALSE.. */
194 spy
.Expect(S_OK
, COINIT_APARTMENTTHREADED
, 3);
195 spy2
.m_AlwaysReturnOK
= true;
196 spy2
.Expect(S_FALSE
, COINIT_APARTMENTTHREADED
, 3);
198 // and the S_OK also influences the returned value from CoInit.
199 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
200 test_S_OK(hr
, "CoInitializeEx");
201 spy
.Check(3, 3, 0, 0);
202 spy2
.Check(3, 3, 0, 0);
205 spy
.Check(3, 3, 1, 1);
206 spy2
.Check(3, 3, 1, 1);
208 spy
.m_CurAptRefs
= spy2
.m_CurAptRefs
= 2;
211 spy
.Check(3, 3, 2, 2);
212 spy2
.Check(3, 3, 2, 2);
214 spy
.m_CurAptRefs
= spy2
.m_CurAptRefs
= 1;
217 spy
.Check(3, 3, 3, 3);
218 spy2
.Check(3, 3, 3, 3);
220 spy
.m_CurAptRefs
= spy2
.m_CurAptRefs
= 0;
223 spy
.Check(3, 3, 4, 4);
224 spy2
.Check(3, 3, 4, 4);
227 void test_IInitializeSpy_switch_apt()
231 spy
.hr
= pCoRegisterInitializeSpy(&spy
, &spy
.Cookie
);
232 test_S_OK(spy
.hr
, "CoRegisterInitializeSpy");
235 spy
.Expect(S_OK
, COINIT_APARTMENTTHREADED
, 1);
237 HRESULT hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
238 test_S_OK(hr
, "CoInitializeEx");
239 spy
.Check(1, 1, 0, 0);
241 spy
.Expect(RPC_E_CHANGED_MODE
, COINIT_MULTITHREADED
, 1);
243 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
244 test_HRES(hr
, RPC_E_CHANGED_MODE
, "CoInitializeEx");
245 spy
.Check(2, 2, 0, 0);
249 spy
.Check(2, 2, 1, 1);
251 spy
.m_CurAptRefs
= 0;
254 spy
.Check(2, 2, 2, 2);
257 spy
.Check(2, 2, 3, 3);
260 void test_IInitializeSpy_fail()
264 spy
.m_FailQueryInterface
= true;
266 spy
.hr
= pCoRegisterInitializeSpy(&spy
, &spy
.Cookie
);
267 test_HRES(spy
.hr
, E_NOINTERFACE
, "Unexpected hr while registering invalid interface");
269 ok(spy
.Cookie
.HighPart
== 0xffffffff, "Unexpected Cookie.HighPart, expected 0xffffffff got: 0x%08lx\n", spy
.Cookie
.HighPart
);
270 ok(spy
.Cookie
.LowPart
== 0xffffffff, "Unexpected Cookie.HighPart, expected 0xffffffff got: 0x%08lx\n", spy
.Cookie
.LowPart
);
272 spy
.Cookie
.HighPart
= spy
.Cookie
.LowPart
= 0xffffffff;
273 HRESULT hr
= pCoRevokeInitializeSpy(spy
.Cookie
);
274 test_HRES(hr
, E_INVALIDARG
, "Unexpected hr while unregistering invalid interface");
277 spy
.Cookie
.HighPart
= spy
.Cookie
.LowPart
= 0;
278 hr
= pCoRevokeInitializeSpy(spy
.Cookie
);
279 test_HRES(hr
, E_INVALIDARG
, "Unexpected hr while unregistering invalid interface");
282 /* we should not crash here, just return E_NOINTERFACE
283 do note the Cookie is not even being touched at all, compared to calling this with an interface
284 that does not respond to IID_IInitializeSpy */
285 spy
.Cookie
.HighPart
= spy
.Cookie
.LowPart
= INVALID_VALUE
;
286 hr
= pCoRegisterInitializeSpy(NULL
, &spy
.Cookie
);
287 test_HRES(spy
.hr
, E_NOINTERFACE
, "Unexpected hr while registering NULL interface");
288 ok(spy
.Cookie
.HighPart
== INVALID_VALUE
, "Unexpected Cookie.HighPart, expected 0xdeadbeef got: %lx\n", spy
.Cookie
.HighPart
);
289 ok(spy
.Cookie
.LowPart
== INVALID_VALUE
, "Unexpected Cookie.HighPart, expected 0xdeadbeef got: %lx\n", spy
.Cookie
.LowPart
);
292 void test_IInitializeSpy_twice()
296 spy
.hr
= pCoRegisterInitializeSpy(&spy
, &spy
.Cookie
);
297 test_S_OK(spy
.hr
, "CoRegisterInitializeSpy");
300 ULARGE_INTEGER Cookie
= { { INVALID_VALUE
, INVALID_VALUE
} };
301 HRESULT hr
= pCoRegisterInitializeSpy(&spy
, &Cookie
);
302 test_S_OK(hr
, "CoRegisterInitializeSpy");
305 hr
= pCoRevokeInitializeSpy(Cookie
);
306 test_S_OK(hr
, "CoRevokeInitializeSpy");
311 START_TEST(initializespy
)
313 HMODULE ole32
= LoadLibraryA("ole32.dll");
314 pCoRegisterInitializeSpy
= (pCoRegisterInitializeSpy_t
)GetProcAddress(ole32
, "CoRegisterInitializeSpy");
315 pCoRevokeInitializeSpy
= (pCoRevokeInitializeSpy_t
)GetProcAddress(ole32
, "CoRevokeInitializeSpy");
317 test_IInitializeSpy_register2();
318 test_IInitializeSpy_switch_apt();
319 test_IInitializeSpy_fail();
320 test_IInitializeSpy_twice();