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