755d15a9f66adfa572b7ab0ac3e557f565663663
[reactos.git] / rostests / winetests / ole32 / compobj.c
1 /*
2 * Component Object Tests
3 *
4 * Copyright 2005 Robert Shearman
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define COBJMACROS
22 #define CONST_VTABLE
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #define USE_COM_CONTEXT_DEF
29 #include "initguid.h"
30 #include "objbase.h"
31 #include "shlguid.h"
32 #include "urlmon.h" /* for CLSID_FileProtocol */
33
34 #include "ctxtcall.h"
35
36 #include "wine/test.h"
37
38 extern const IID GUID_NULL;
39
40 /* functions that are not present on all versions of Windows */
41 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
42 HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
43 HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
44 HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
45 HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
46
47 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
48 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
49 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
50
51 static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
52 static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } };
53 static WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
54 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
55 static WCHAR wszCLSID_StdFont[] =
56 {
57 '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
58 '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
59 };
60
61 static const IID IID_IWineTest =
62 {
63 0x5201163f,
64 0x8164,
65 0x4fd0,
66 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
67 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
68 static const CLSID CLSID_WineOOPTest = {
69 0x5201163f,
70 0x8164,
71 0x4fd0,
72 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
73 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
74
75 static LONG cLocks;
76
77 static void LockModule(void)
78 {
79 InterlockedIncrement(&cLocks);
80 }
81
82 static void UnlockModule(void)
83 {
84 InterlockedDecrement(&cLocks);
85 }
86
87 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
88 LPCLASSFACTORY iface,
89 REFIID riid,
90 LPVOID *ppvObj)
91 {
92 if (ppvObj == NULL) return E_POINTER;
93
94 if (IsEqualGUID(riid, &IID_IUnknown) ||
95 IsEqualGUID(riid, &IID_IClassFactory))
96 {
97 *ppvObj = iface;
98 IClassFactory_AddRef(iface);
99 return S_OK;
100 }
101
102 *ppvObj = NULL;
103 return E_NOINTERFACE;
104 }
105
106 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
107 {
108 LockModule();
109 return 2; /* non-heap-based object */
110 }
111
112 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
113 {
114 UnlockModule();
115 return 1; /* non-heap-based object */
116 }
117
118 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
119 LPCLASSFACTORY iface,
120 LPUNKNOWN pUnkOuter,
121 REFIID riid,
122 LPVOID *ppvObj)
123 {
124 *ppvObj = NULL;
125 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
126 return E_NOINTERFACE;
127 }
128
129 static HRESULT WINAPI Test_IClassFactory_LockServer(
130 LPCLASSFACTORY iface,
131 BOOL fLock)
132 {
133 return S_OK;
134 }
135
136 static const IClassFactoryVtbl TestClassFactory_Vtbl =
137 {
138 Test_IClassFactory_QueryInterface,
139 Test_IClassFactory_AddRef,
140 Test_IClassFactory_Release,
141 Test_IClassFactory_CreateInstance,
142 Test_IClassFactory_LockServer
143 };
144
145 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
146
147 static void test_ProgIDFromCLSID(void)
148 {
149 LPWSTR progid;
150 HRESULT hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
151 ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
152 if (hr == S_OK)
153 {
154 ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n");
155 CoTaskMemFree(progid);
156 }
157
158 progid = (LPWSTR)0xdeadbeef;
159 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
160 ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
161 ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
162
163 hr = ProgIDFromCLSID(&CLSID_StdFont, NULL);
164 ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
165 }
166
167 static void test_CLSIDFromProgID(void)
168 {
169 CLSID clsid;
170 HRESULT hr = CLSIDFromProgID(stdfont, &clsid);
171 ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
172 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
173
174 hr = CLSIDFromString(stdfont, &clsid);
175 ok_ole_success(hr, "CLSIDFromString");
176 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
177
178 /* test some failure cases */
179
180 hr = CLSIDFromProgID(wszNonExistent, NULL);
181 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
182
183 hr = CLSIDFromProgID(NULL, &clsid);
184 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
185
186 memset(&clsid, 0xcc, sizeof(clsid));
187 hr = CLSIDFromProgID(wszNonExistent, &clsid);
188 ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
189 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
190 }
191
192 static void test_CLSIDFromString(void)
193 {
194 CLSID clsid;
195 HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid);
196 ok_ole_success(hr, "CLSIDFromString");
197 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
198
199 hr = CLSIDFromString(NULL, &clsid);
200 ok_ole_success(hr, "CLSIDFromString");
201 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
202 }
203
204 static void test_StringFromGUID2(void)
205 {
206 WCHAR str[50];
207 int len;
208
209 /* invalid pointer */
210 SetLastError(0xdeadbeef);
211 len = StringFromGUID2(NULL,str,50);
212 ok(len == 0, "len: %d (expected 0)\n", len);
213 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %x\n", GetLastError());
214
215 /* Test corner cases for buffer size */
216 len = StringFromGUID2(&CLSID_StdFont,str,50);
217 ok(len == 39, "len: %d (expected 39)\n", len);
218 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
219
220 memset(str,0,sizeof str);
221 len = StringFromGUID2(&CLSID_StdFont,str,39);
222 ok(len == 39, "len: %d (expected 39)\n", len);
223 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
224
225 len = StringFromGUID2(&CLSID_StdFont,str,38);
226 ok(len == 0, "len: %d (expected 0)\n", len);
227
228 len = StringFromGUID2(&CLSID_StdFont,str,30);
229 ok(len == 0, "len: %d (expected 0)\n", len);
230 }
231
232 struct info
233 {
234 HANDLE wait, stop;
235 };
236
237 static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
238 {
239 HRESULT hr;
240 struct info *info = pv;
241
242 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
243
244 SetEvent(info->wait);
245 WaitForSingleObject(info->stop, 10000);
246
247 CoUninitialize();
248 return hr;
249 }
250
251 static void test_CoCreateInstance(void)
252 {
253 HRESULT hr;
254 HANDLE thread;
255 DWORD tid, exitcode;
256 IUnknown *pUnk;
257 struct info info;
258 REFCLSID rclsid = &CLSID_InternetZoneManager;
259
260 pUnk = (IUnknown *)0xdeadbeef;
261 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
262 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
263 ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
264
265 OleInitialize(NULL);
266
267 /* test errors returned for non-registered clsids */
268 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
269 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
270 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk);
271 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
272 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk);
273 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
274 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk);
275 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
276
277 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
278 if(hr == REGDB_E_CLASSNOTREG)
279 {
280 skip("IE not installed so can't test CoCreateInstance\n");
281 OleUninitialize();
282 return;
283 }
284
285 ok_ole_success(hr, "CoCreateInstance");
286 if(pUnk) IUnknown_Release(pUnk);
287 OleUninitialize();
288
289 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
290 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
291
292 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
293 thread has already done so */
294
295 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
296 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
297
298 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
299 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
300
301 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
302 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
303
304 ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
305
306 pUnk = (IUnknown *)0xdeadbeef;
307 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
308 ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr);
309 if (pUnk) IUnknown_Release(pUnk);
310
311 SetEvent(info.stop);
312 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
313
314 GetExitCodeThread(thread, &exitcode);
315 hr = exitcode;
316 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
317
318 CloseHandle(thread);
319 CloseHandle(info.wait);
320 CloseHandle(info.stop);
321 }
322
323 static void test_CoGetClassObject(void)
324 {
325 HRESULT hr;
326 HANDLE thread;
327 DWORD tid, exitcode;
328 IUnknown *pUnk;
329 struct info info;
330 REFCLSID rclsid = &CLSID_InternetZoneManager;
331
332 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
333 ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
334 ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
335
336 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
337 ok(hr == E_INVALIDARG ||
338 broken(hr == CO_E_NOTINITIALIZED), /* win9x */
339 "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
340
341 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
342 thread has already done so */
343
344 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
345 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
346
347 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
348 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
349
350 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
351 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
352
353 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
354
355 pUnk = (IUnknown *)0xdeadbeef;
356 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
357 if(hr == REGDB_E_CLASSNOTREG)
358 skip("IE not installed so can't test CoGetClassObject\n");
359 else
360 {
361 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
362 if (pUnk) IUnknown_Release(pUnk);
363 }
364
365 SetEvent(info.stop);
366 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
367
368 GetExitCodeThread(thread, &exitcode);
369 hr = exitcode;
370 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
371
372 CloseHandle(thread);
373 CloseHandle(info.wait);
374 CloseHandle(info.stop);
375 }
376
377 static ATOM register_dummy_class(void)
378 {
379 WNDCLASS wc =
380 {
381 0,
382 DefWindowProc,
383 0,
384 0,
385 GetModuleHandle(NULL),
386 NULL,
387 LoadCursor(NULL, IDC_ARROW),
388 (HBRUSH)(COLOR_BTNFACE+1),
389 NULL,
390 TEXT("WineOleTestClass"),
391 };
392
393 return RegisterClass(&wc);
394 }
395
396 static void test_ole_menu(void)
397 {
398 HWND hwndFrame;
399 HRESULT hr;
400
401 hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
402 hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
403 todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
404
405 DestroyWindow(hwndFrame);
406 }
407
408
409 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
410 {
411 if (ppvObj == NULL) return E_POINTER;
412
413 if (IsEqualGUID(riid, &IID_IUnknown) ||
414 IsEqualGUID(riid, &IID_IClassFactory))
415 {
416 *ppvObj = iface;
417 IMessageFilter_AddRef(iface);
418 return S_OK;
419 }
420
421 return E_NOINTERFACE;
422 }
423
424 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
425 {
426 return 2; /* non-heap object */
427 }
428
429 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
430 {
431 return 1; /* non-heap object */
432 }
433
434 static DWORD WINAPI MessageFilter_HandleInComingCall(
435 IMessageFilter *iface,
436 DWORD dwCallType,
437 HTASK threadIDCaller,
438 DWORD dwTickCount,
439 LPINTERFACEINFO lpInterfaceInfo)
440 {
441 trace("HandleInComingCall\n");
442 return SERVERCALL_ISHANDLED;
443 }
444
445 static DWORD WINAPI MessageFilter_RetryRejectedCall(
446 IMessageFilter *iface,
447 HTASK threadIDCallee,
448 DWORD dwTickCount,
449 DWORD dwRejectType)
450 {
451 trace("RetryRejectedCall\n");
452 return 0;
453 }
454
455 static DWORD WINAPI MessageFilter_MessagePending(
456 IMessageFilter *iface,
457 HTASK threadIDCallee,
458 DWORD dwTickCount,
459 DWORD dwPendingType)
460 {
461 trace("MessagePending\n");
462 return PENDINGMSG_WAITNOPROCESS;
463 }
464
465 static const IMessageFilterVtbl MessageFilter_Vtbl =
466 {
467 MessageFilter_QueryInterface,
468 MessageFilter_AddRef,
469 MessageFilter_Release,
470 MessageFilter_HandleInComingCall,
471 MessageFilter_RetryRejectedCall,
472 MessageFilter_MessagePending
473 };
474
475 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
476
477 static void test_CoRegisterMessageFilter(void)
478 {
479 HRESULT hr;
480 IMessageFilter *prev_filter;
481
482 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
483 ok(hr == CO_E_NOT_SUPPORTED,
484 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
485 hr);
486
487 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
488 prev_filter = (IMessageFilter *)0xdeadbeef;
489 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
490 ok(hr == CO_E_NOT_SUPPORTED,
491 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
492 hr);
493 ok(prev_filter == (IMessageFilter *)0xdeadbeef,
494 "prev_filter should have been set to %p\n", prev_filter);
495 CoUninitialize();
496
497 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
498
499 hr = CoRegisterMessageFilter(NULL, NULL);
500 ok_ole_success(hr, "CoRegisterMessageFilter");
501
502 prev_filter = (IMessageFilter *)0xdeadbeef;
503 hr = CoRegisterMessageFilter(NULL, &prev_filter);
504 ok_ole_success(hr, "CoRegisterMessageFilter");
505 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
506
507 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
508 ok_ole_success(hr, "CoRegisterMessageFilter");
509 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
510
511 hr = CoRegisterMessageFilter(NULL, NULL);
512 ok_ole_success(hr, "CoRegisterMessageFilter");
513
514 CoUninitialize();
515 }
516
517 static HRESULT WINAPI Test_IUnknown_QueryInterface(
518 LPUNKNOWN iface,
519 REFIID riid,
520 LPVOID *ppvObj)
521 {
522 if (ppvObj == NULL) return E_POINTER;
523
524 if (IsEqualIID(riid, &IID_IUnknown) ||
525 IsEqualIID(riid, &IID_IWineTest))
526 {
527 *ppvObj = iface;
528 IUnknown_AddRef(iface);
529 return S_OK;
530 }
531
532 *ppvObj = NULL;
533 return E_NOINTERFACE;
534 }
535
536 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
537 {
538 return 2; /* non-heap-based object */
539 }
540
541 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
542 {
543 return 1; /* non-heap-based object */
544 }
545
546 static const IUnknownVtbl TestUnknown_Vtbl =
547 {
548 Test_IUnknown_QueryInterface,
549 Test_IUnknown_AddRef,
550 Test_IUnknown_Release,
551 };
552
553 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
554
555 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
556 IPSFactoryBuffer * This,
557 /* [in] */ REFIID riid,
558 /* [iid_is][out] */ void **ppvObject)
559 {
560 if (IsEqualIID(riid, &IID_IUnknown) ||
561 IsEqualIID(riid, &IID_IPSFactoryBuffer))
562 {
563 *ppvObject = This;
564 IPSFactoryBuffer_AddRef(This);
565 return S_OK;
566 }
567 return E_NOINTERFACE;
568 }
569
570 static ULONG WINAPI PSFactoryBuffer_AddRef(
571 IPSFactoryBuffer * This)
572 {
573 return 2;
574 }
575
576 static ULONG WINAPI PSFactoryBuffer_Release(
577 IPSFactoryBuffer * This)
578 {
579 return 1;
580 }
581
582 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
583 IPSFactoryBuffer * This,
584 /* [in] */ IUnknown *pUnkOuter,
585 /* [in] */ REFIID riid,
586 /* [out] */ IRpcProxyBuffer **ppProxy,
587 /* [out] */ void **ppv)
588 {
589 return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
593 IPSFactoryBuffer * This,
594 /* [in] */ REFIID riid,
595 /* [unique][in] */ IUnknown *pUnkServer,
596 /* [out] */ IRpcStubBuffer **ppStub)
597 {
598 return E_NOTIMPL;
599 }
600
601 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
602 {
603 PSFactoryBuffer_QueryInterface,
604 PSFactoryBuffer_AddRef,
605 PSFactoryBuffer_Release,
606 PSFactoryBuffer_CreateProxy,
607 PSFactoryBuffer_CreateStub
608 };
609
610 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
611
612 static const CLSID CLSID_WineTestPSFactoryBuffer =
613 {
614 0x52011640,
615 0x8164,
616 0x4fd0,
617 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
618 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
619
620 static void test_CoRegisterPSClsid(void)
621 {
622 HRESULT hr;
623 DWORD dwRegistrationKey;
624 IStream *stream;
625 CLSID clsid;
626
627 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
628 ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returened CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
629
630 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
631
632 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
633 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
634 ok_ole_success(hr, "CoRegisterClassObject");
635
636 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
637 ok_ole_success(hr, "CoRegisterPSClsid");
638
639 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
640 ok_ole_success(hr, "CreateStreamOnHGlobal");
641
642 hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
643 ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
644 IStream_Release(stream);
645
646 hr = CoRevokeClassObject(dwRegistrationKey);
647 ok_ole_success(hr, "CoRevokeClassObject");
648
649 CoUninitialize();
650
651 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
652
653 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
654 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
655
656 CoUninitialize();
657 }
658
659 static void test_CoGetPSClsid(void)
660 {
661 HRESULT hr;
662 CLSID clsid;
663
664 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
665 ok(hr == CO_E_NOTINITIALIZED,
666 "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
667 hr);
668
669 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
670
671 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
672 ok_ole_success(hr, "CoGetPSClsid");
673
674 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
675 ok(hr == REGDB_E_IIDNOTREG,
676 "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
677 hr);
678
679 hr = CoGetPSClsid(&IID_IClassFactory, NULL);
680 ok(hr == E_INVALIDARG,
681 "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
682 hr);
683
684 CoUninitialize();
685 }
686
687 /* basic test, mainly for invalid arguments. see marshal.c for more */
688 static void test_CoUnmarshalInterface(void)
689 {
690 IUnknown *pProxy;
691 IStream *pStream;
692 HRESULT hr;
693
694 hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
695 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
696
697 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
698 ok_ole_success(hr, "CreateStreamOnHGlobal");
699
700 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
701 todo_wine
702 ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
703
704 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
705
706 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
707 ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
708
709 CoUninitialize();
710
711 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
712 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
713
714 IStream_Release(pStream);
715 }
716
717 static void test_CoGetInterfaceAndReleaseStream(void)
718 {
719 HRESULT hr;
720 IUnknown *pUnk;
721
722 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
723
724 hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
725 ok(hr == E_INVALIDARG, "hr %08x\n", hr);
726
727 CoUninitialize();
728 }
729
730 /* basic test, mainly for invalid arguments. see marshal.c for more */
731 static void test_CoMarshalInterface(void)
732 {
733 IStream *pStream;
734 HRESULT hr;
735 static const LARGE_INTEGER llZero;
736
737 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
738
739 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
740 ok_ole_success(hr, "CreateStreamOnHGlobal");
741
742 hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
743 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
744
745 hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
746 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
747
748 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
749 ok_ole_success(hr, "CoMarshalInterface");
750
751 /* stream not rewound */
752 hr = CoReleaseMarshalData(pStream);
753 ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
754
755 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
756 ok_ole_success(hr, "IStream_Seek");
757
758 hr = CoReleaseMarshalData(pStream);
759 ok_ole_success(hr, "CoReleaseMarshalData");
760
761 IStream_Release(pStream);
762
763 CoUninitialize();
764 }
765
766 static void test_CoMarshalInterThreadInterfaceInStream(void)
767 {
768 IStream *pStream;
769 HRESULT hr;
770 IClassFactory *pProxy;
771
772 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
773
774 cLocks = 0;
775
776 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
777 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
778
779 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
780 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
781
782 ok_no_locks();
783
784 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
785 ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
786
787 ok_more_than_one_lock();
788
789 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
790 ok_ole_success(hr, "CoUnmarshalInterface");
791
792 IClassFactory_Release(pProxy);
793 IStream_Release(pStream);
794
795 ok_no_locks();
796
797 CoUninitialize();
798 }
799
800 static void test_CoRegisterClassObject(void)
801 {
802 DWORD cookie;
803 HRESULT hr;
804 IClassFactory *pcf;
805
806 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
807
808 /* CLSCTX_INPROC_SERVER */
809 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
810 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
811 ok_ole_success(hr, "CoRegisterClassObject");
812 hr = CoRevokeClassObject(cookie);
813 ok_ole_success(hr, "CoRevokeClassObject");
814
815 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
816 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
817 ok_ole_success(hr, "CoRegisterClassObject");
818 hr = CoRevokeClassObject(cookie);
819 ok_ole_success(hr, "CoRevokeClassObject");
820
821 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
822 CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
823 ok_ole_success(hr, "CoRegisterClassObject");
824 hr = CoRevokeClassObject(cookie);
825 ok_ole_success(hr, "CoRevokeClassObject");
826
827 /* CLSCTX_LOCAL_SERVER */
828 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
829 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
830 ok_ole_success(hr, "CoRegisterClassObject");
831 hr = CoRevokeClassObject(cookie);
832 ok_ole_success(hr, "CoRevokeClassObject");
833
834 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
835 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
836 ok_ole_success(hr, "CoRegisterClassObject");
837 hr = CoRevokeClassObject(cookie);
838 ok_ole_success(hr, "CoRevokeClassObject");
839
840 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
841 CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
842 ok_ole_success(hr, "CoRegisterClassObject");
843 hr = CoRevokeClassObject(cookie);
844 ok_ole_success(hr, "CoRevokeClassObject");
845
846 /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
847 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
848 CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
849 ok_ole_success(hr, "CoRegisterClassObject");
850 hr = CoRevokeClassObject(cookie);
851 ok_ole_success(hr, "CoRevokeClassObject");
852
853 /* test whether an object that doesn't support IClassFactory can be
854 * registered for CLSCTX_LOCAL_SERVER */
855 hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown,
856 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
857 ok_ole_success(hr, "CoRegisterClassObject");
858 hr = CoRevokeClassObject(cookie);
859 ok_ole_success(hr, "CoRevokeClassObject");
860
861 /* test whether registered class becomes invalid when apartment is destroyed */
862 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
863 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
864 ok_ole_success(hr, "CoRegisterClassObject");
865
866 CoUninitialize();
867 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
868
869 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
870 &IID_IClassFactory, (void **)&pcf);
871 ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
872
873 /* crashes with at least win9x DCOM! */
874 if (0)
875 hr = CoRevokeClassObject(cookie);
876
877 CoUninitialize();
878 }
879
880 static HRESULT get_class_object(CLSCTX clsctx)
881 {
882 HRESULT hr;
883 IClassFactory *pcf;
884
885 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
886 (void **)&pcf);
887
888 if (SUCCEEDED(hr))
889 IClassFactory_Release(pcf);
890
891 return hr;
892 }
893
894 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
895 {
896 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
897 HRESULT hr;
898
899 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
900
901 hr = get_class_object(clsctx);
902
903 CoUninitialize();
904
905 return hr;
906 }
907
908 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
909 {
910 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
911 HRESULT hr;
912 IClassFactory *pcf;
913 IMultiQI *pMQI;
914
915 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
916
917 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
918 (void **)&pcf);
919
920 if (SUCCEEDED(hr))
921 {
922 hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
923 if (SUCCEEDED(hr))
924 IMultiQI_Release(pMQI);
925 IClassFactory_Release(pcf);
926 }
927
928 CoUninitialize();
929
930 return hr;
931 }
932
933 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
934 {
935 HRESULT hr;
936 DWORD cookie;
937
938 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
939
940 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
941 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
942
943 CoUninitialize();
944
945 return hr;
946 }
947
948 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
949 {
950 DWORD cookie = (DWORD_PTR)pv;
951 HRESULT hr;
952
953 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
954
955 hr = CoRevokeClassObject(cookie);
956
957 CoUninitialize();
958
959 return hr;
960 }
961
962 static void test_registered_object_thread_affinity(void)
963 {
964 HRESULT hr;
965 DWORD cookie;
966 HANDLE thread;
967 DWORD tid;
968 DWORD exitcode;
969
970 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
971
972 /* CLSCTX_INPROC_SERVER */
973
974 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
975 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
976 ok_ole_success(hr, "CoRegisterClassObject");
977
978 thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
979 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
980 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
981 GetExitCodeThread(thread, &exitcode);
982 hr = exitcode;
983 ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
984 "registered in different thread should return REGDB_E_CLASSNOTREG "
985 "instead of 0x%08x\n", hr);
986
987 hr = get_class_object(CLSCTX_INPROC_SERVER);
988 ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
989 "thread should return S_OK instead of 0x%08x\n", hr);
990
991 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
992 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
993 ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
994 GetExitCodeThread(thread, &exitcode);
995 hr = exitcode;
996 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
997
998 hr = CoRevokeClassObject(cookie);
999 ok_ole_success(hr, "CoRevokeClassObject");
1000
1001 /* CLSCTX_LOCAL_SERVER */
1002
1003 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1004 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1005 ok_ole_success(hr, "CoRegisterClassObject");
1006
1007 thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
1008 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1009 while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1010 {
1011 MSG msg;
1012 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1013 {
1014 TranslateMessage(&msg);
1015 DispatchMessageA(&msg);
1016 }
1017 }
1018 GetExitCodeThread(thread, &exitcode);
1019 hr = exitcode;
1020 ok(hr == S_OK, "CoGetClassObject on local server object "
1021 "registered in different thread should return S_OK "
1022 "instead of 0x%08x\n", hr);
1023
1024 hr = get_class_object(CLSCTX_LOCAL_SERVER);
1025 ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1026 "thread should return S_OK instead of 0x%08x\n", hr);
1027
1028 thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1029 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1030 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1031 GetExitCodeThread(thread, &exitcode);
1032 hr = exitcode;
1033 ok(hr == RPC_E_WRONG_THREAD, "CoRevokeClassObject called from different "
1034 "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1035
1036 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1037 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1038 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1039 GetExitCodeThread(thread, &exitcode);
1040 hr = exitcode;
1041 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
1042 "thread should return S_OK instead of 0x%08x\n", hr);
1043
1044 hr = CoRevokeClassObject(cookie);
1045 ok_ole_success(hr, "CoRevokeClassObject");
1046
1047 CoUninitialize();
1048 }
1049
1050 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1051 {
1052 CoFreeUnusedLibraries();
1053 return 0;
1054 }
1055
1056 static inline BOOL is_module_loaded(const char *module)
1057 {
1058 return GetModuleHandle(module) ? TRUE : FALSE;
1059 }
1060
1061 static void test_CoFreeUnusedLibraries(void)
1062 {
1063 HRESULT hr;
1064 IUnknown *pUnk;
1065 DWORD tid;
1066 HANDLE thread;
1067
1068 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1069
1070 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1071
1072 hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1073 if (hr == REGDB_E_CLASSNOTREG)
1074 {
1075 skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1076 CoUninitialize();
1077 return;
1078 }
1079 ok_ole_success(hr, "CoCreateInstance");
1080
1081 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1082
1083 ok(pUnk != NULL ||
1084 broken(pUnk == NULL), /* win9x */
1085 "Expected a valid pointer\n");
1086 if (pUnk)
1087 IUnknown_Release(pUnk);
1088
1089 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1090
1091 thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1092 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1093 CloseHandle(thread);
1094
1095 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1096
1097 CoFreeUnusedLibraries();
1098
1099 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1100
1101 CoUninitialize();
1102 }
1103
1104 static void test_CoGetObjectContext(void)
1105 {
1106 HRESULT hr;
1107 ULONG refs;
1108 IComThreadingInfo *pComThreadingInfo;
1109 IContextCallback *pContextCallback;
1110 IObjContext *pObjContext;
1111 APTTYPE apttype;
1112 THDTYPE thdtype;
1113 struct info info;
1114 HANDLE thread;
1115 DWORD tid, exitcode;
1116
1117 if (!pCoGetObjectContext)
1118 {
1119 skip("CoGetObjectContext not present\n");
1120 return;
1121 }
1122
1123 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1124 ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1125 ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1126
1127 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1128 thread has already done so */
1129
1130 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1131 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1132
1133 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1134 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1135
1136 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1137 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1138
1139 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1140
1141 pComThreadingInfo = NULL;
1142 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1143 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1144 IComThreadingInfo_Release(pComThreadingInfo);
1145
1146 SetEvent(info.stop);
1147 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1148
1149 GetExitCodeThread(thread, &exitcode);
1150 hr = exitcode;
1151 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1152
1153 CloseHandle(thread);
1154 CloseHandle(info.wait);
1155 CloseHandle(info.stop);
1156
1157 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1158
1159 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1160 ok_ole_success(hr, "CoGetObjectContext");
1161
1162 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1163 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1164 ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1165
1166 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1167 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1168 ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1169
1170 refs = IComThreadingInfo_Release(pComThreadingInfo);
1171 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1172
1173 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1174 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1175
1176 if (hr == S_OK)
1177 {
1178 refs = IContextCallback_Release(pContextCallback);
1179 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1180 }
1181
1182 CoUninitialize();
1183
1184 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1185
1186 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1187 ok_ole_success(hr, "CoGetObjectContext");
1188
1189 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1190 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1191 ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1192
1193 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1194 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1195 ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1196
1197 refs = IComThreadingInfo_Release(pComThreadingInfo);
1198 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1199
1200 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1201 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1202
1203 if (hr == S_OK)
1204 {
1205 refs = IContextCallback_Release(pContextCallback);
1206 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1207 }
1208
1209 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1210 ok_ole_success(hr, "CoGetObjectContext");
1211
1212 refs = IObjContext_Release(pObjContext);
1213 ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1214
1215 CoUninitialize();
1216 }
1217
1218 typedef struct {
1219 const IUnknownVtbl *lpVtbl;
1220 LONG refs;
1221 } Test_CallContext;
1222
1223 static HRESULT WINAPI Test_CallContext_QueryInterface(
1224 IUnknown *iface,
1225 REFIID riid,
1226 LPVOID *ppvObj)
1227 {
1228 if (ppvObj == NULL) return E_POINTER;
1229
1230 if (IsEqualGUID(riid, &IID_IUnknown))
1231 {
1232 *ppvObj = iface;
1233 IUnknown_AddRef(iface);
1234 return S_OK;
1235 }
1236
1237 *ppvObj = NULL;
1238 return E_NOINTERFACE;
1239 }
1240
1241 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
1242 {
1243 Test_CallContext *This = (Test_CallContext*)iface;
1244 return InterlockedIncrement(&This->refs);
1245 }
1246
1247 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
1248 {
1249 Test_CallContext *This = (Test_CallContext*)iface;
1250 ULONG refs = InterlockedDecrement(&This->refs);
1251 if (!refs)
1252 HeapFree(GetProcessHeap(), 0, This);
1253 return refs;
1254 }
1255
1256 static const IUnknownVtbl TestCallContext_Vtbl =
1257 {
1258 Test_CallContext_QueryInterface,
1259 Test_CallContext_AddRef,
1260 Test_CallContext_Release
1261 };
1262
1263 static void test_CoGetCallContext(void)
1264 {
1265 HRESULT hr;
1266 ULONG refs;
1267 IUnknown *pUnk;
1268 IUnknown *test_object;
1269
1270 if (!pCoSwitchCallContext)
1271 {
1272 skip("CoSwitchCallContext not present\n");
1273 return;
1274 }
1275
1276 CoInitialize(NULL);
1277
1278 test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
1279 ((Test_CallContext*)test_object)->lpVtbl = &TestCallContext_Vtbl;
1280 ((Test_CallContext*)test_object)->refs = 1;
1281
1282 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1283 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1284
1285 pUnk = (IUnknown*)0xdeadbeef;
1286 hr = pCoSwitchCallContext(test_object, &pUnk);
1287 ok_ole_success(hr, "CoSwitchCallContext");
1288 ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
1289 refs = IUnknown_AddRef(test_object);
1290 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1291 IUnknown_Release(test_object);
1292
1293 pUnk = (IUnknown*)0xdeadbeef;
1294 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1295 ok_ole_success(hr, "CoGetCallContext");
1296 ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk);
1297 refs = IUnknown_AddRef(test_object);
1298 ok(refs == 3, "Expected refcount 3, got %d\n", refs);
1299 IUnknown_Release(test_object);
1300 IUnknown_Release(pUnk);
1301
1302 pUnk = (IUnknown*)0xdeadbeef;
1303 hr = pCoSwitchCallContext(NULL, &pUnk);
1304 ok_ole_success(hr, "CoSwitchCallContext");
1305 ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk);
1306 refs = IUnknown_AddRef(test_object);
1307 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1308 IUnknown_Release(test_object);
1309
1310 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1311 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1312
1313 IUnknown_Release(test_object);
1314
1315 CoUninitialize();
1316 }
1317
1318 static void test_CoGetContextToken(void)
1319 {
1320 HRESULT hr;
1321 ULONG refs;
1322 ULONG_PTR token;
1323 IObjContext *ctx;
1324 struct info info;
1325 HANDLE thread;
1326 DWORD tid, exitcode;
1327
1328 if (!pCoGetContextToken)
1329 {
1330 win_skip("CoGetContextToken not present\n");
1331 return;
1332 }
1333
1334 token = 0xdeadbeef;
1335 hr = pCoGetContextToken(&token);
1336 ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
1337 ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
1338
1339 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1340 thread has already done so */
1341
1342 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1343 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1344
1345 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1346 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1347
1348 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1349 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1350
1351 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1352
1353 token = 0;
1354 hr = pCoGetContextToken(&token);
1355 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1356
1357 SetEvent(info.stop);
1358 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1359
1360 GetExitCodeThread(thread, &exitcode);
1361 hr = exitcode;
1362 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1363
1364 CloseHandle(thread);
1365 CloseHandle(info.wait);
1366 CloseHandle(info.stop);
1367
1368 CoInitialize(NULL);
1369
1370 hr = pCoGetContextToken(NULL);
1371 ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
1372
1373 token = 0;
1374 hr = pCoGetContextToken(&token);
1375 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1376 ok(token, "Expected token != 0\n");
1377
1378 refs = IUnknown_AddRef((IUnknown *)token);
1379 todo_wine ok(refs == 1, "Expected 1, got %u\n", refs);
1380
1381 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
1382 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1383 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1384
1385 refs = IUnknown_AddRef((IUnknown *)ctx);
1386 todo_wine ok(refs == 3, "Expected 3, got %u\n", refs);
1387
1388 refs = IUnknown_Release((IUnknown *)ctx);
1389 todo_wine ok(refs == 2, "Expected 2, got %u\n", refs);
1390
1391 refs = IUnknown_Release((IUnknown *)token);
1392 ok(refs == 1, "Expected 1, got %u\n", refs);
1393
1394 /* CoGetContextToken does not add a reference */
1395 token = 0;
1396 hr = pCoGetContextToken(&token);
1397 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1398 ok(token, "Expected token != 0\n");
1399 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1400
1401 refs = IUnknown_AddRef((IUnknown *)ctx);
1402 ok(refs == 2, "Expected 1, got %u\n", refs);
1403
1404 refs = IUnknown_Release((IUnknown *)ctx);
1405 ok(refs == 1, "Expected 0, got %u\n", refs);
1406
1407 refs = IUnknown_Release((IUnknown *)ctx);
1408 ok(refs == 0, "Expected 0, got %u\n", refs);
1409
1410 CoUninitialize();
1411 }
1412
1413 static void test_CoGetTreatAsClass(void)
1414 {
1415 HRESULT hr;
1416 CLSID out;
1417 static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1418
1419 if (!pCoGetTreatAsClass)
1420 {
1421 win_skip("CoGetTreatAsClass not present\n");
1422 return;
1423 }
1424 hr = pCoGetTreatAsClass(&deadbeef,&out);
1425 ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
1426 ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
1427 }
1428
1429 static void test_CoInitializeEx(void)
1430 {
1431 HRESULT hr;
1432
1433 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1434 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
1435
1436 /* Calling OleInitialize for the first time should yield S_OK even with
1437 * apartment already initialized by previous CoInitialize(Ex) calls. */
1438 hr = OleInitialize(NULL);
1439 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
1440
1441 /* Subsequent calls to OleInitialize should return S_FALSE */
1442 hr = OleInitialize(NULL);
1443 ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
1444
1445 /* Cleanup */
1446 CoUninitialize();
1447 OleUninitialize();
1448 }
1449
1450 START_TEST(compobj)
1451 {
1452 HMODULE hOle32 = GetModuleHandle("ole32");
1453 pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
1454 pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext");
1455 pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
1456 pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
1457 if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
1458 {
1459 trace("You need DCOM95 installed to run this test\n");
1460 return;
1461 }
1462
1463 test_ProgIDFromCLSID();
1464 test_CLSIDFromProgID();
1465 test_CLSIDFromString();
1466 test_StringFromGUID2();
1467 test_CoCreateInstance();
1468 test_ole_menu();
1469 test_CoGetClassObject();
1470 test_CoRegisterMessageFilter();
1471 test_CoRegisterPSClsid();
1472 test_CoGetPSClsid();
1473 test_CoUnmarshalInterface();
1474 test_CoGetInterfaceAndReleaseStream();
1475 test_CoMarshalInterface();
1476 test_CoMarshalInterThreadInterfaceInStream();
1477 test_CoRegisterClassObject();
1478 test_registered_object_thread_affinity();
1479 test_CoFreeUnusedLibraries();
1480 test_CoGetObjectContext();
1481 test_CoGetCallContext();
1482 test_CoGetContextToken();
1483 test_CoGetTreatAsClass();
1484 test_CoInitializeEx();
1485 }