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