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