comctl32/listview: Free ID array when removing all items.
[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 registered class becomes invalid when apartment is destroyed */
841     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
842                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
843     ok_ole_success(hr, "CoRegisterClassObject");
844
845     CoUninitialize();
846     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
847
848     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
849                           &IID_IClassFactory, (void **)&pcf);
850     ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
851
852     /* crashes with at least win9x DCOM! */
853     if (0)
854         hr = CoRevokeClassObject(cookie);
855
856     CoUninitialize();
857 }
858
859 static HRESULT get_class_object(CLSCTX clsctx)
860 {
861     HRESULT hr;
862     IClassFactory *pcf;
863
864     hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
865                           (void **)&pcf);
866
867     if (SUCCEEDED(hr))
868         IClassFactory_Release(pcf);
869
870     return hr;
871 }
872
873 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
874 {
875     CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
876     HRESULT hr;
877
878     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
879
880     hr = get_class_object(clsctx);
881
882     CoUninitialize();
883
884     return hr;
885 }
886
887 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
888 {
889     CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
890     HRESULT hr;
891     IClassFactory *pcf;
892     IMultiQI *pMQI;
893
894     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
895
896     hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
897                           (void **)&pcf);
898
899     if (SUCCEEDED(hr))
900     {
901         hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
902         if (SUCCEEDED(hr))
903             IMultiQI_Release(pMQI);
904         IClassFactory_Release(pcf);
905     }
906
907     CoUninitialize();
908
909     return hr;
910 }
911
912 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
913 {
914     HRESULT hr;
915     DWORD cookie;
916
917     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
918
919     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
920                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
921
922     CoUninitialize();
923
924     return hr;
925 }
926
927 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
928 {
929     DWORD cookie = (DWORD_PTR)pv;
930     HRESULT hr;
931
932     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
933
934     hr = CoRevokeClassObject(cookie);
935
936     CoUninitialize();
937
938     return hr;
939 }
940
941 static void test_registered_object_thread_affinity(void)
942 {
943     HRESULT hr;
944     DWORD cookie;
945     HANDLE thread;
946     DWORD tid;
947     DWORD exitcode;
948
949     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
950
951     /* CLSCTX_INPROC_SERVER */
952
953     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
954                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
955     ok_ole_success(hr, "CoRegisterClassObject");
956
957     thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
958     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
959     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
960     GetExitCodeThread(thread, &exitcode);
961     hr = exitcode;
962     ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
963        "registered in different thread should return REGDB_E_CLASSNOTREG "
964        "instead of 0x%08x\n", hr);
965
966     hr = get_class_object(CLSCTX_INPROC_SERVER);
967     ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
968        "thread should return S_OK instead of 0x%08x\n", hr);
969
970     thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
971     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
972     ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
973     GetExitCodeThread(thread, &exitcode);
974     hr = exitcode;
975     ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
976
977     hr = CoRevokeClassObject(cookie);
978     ok_ole_success(hr, "CoRevokeClassObject");
979
980     /* CLSCTX_LOCAL_SERVER */
981
982     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
983                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
984     ok_ole_success(hr, "CoRegisterClassObject");
985
986     thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
987     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
988     while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
989     {
990         MSG msg;
991         while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
992         {
993             TranslateMessage(&msg);
994             DispatchMessageA(&msg);
995         }
996     }
997     GetExitCodeThread(thread, &exitcode);
998     hr = exitcode;
999     ok(hr == S_OK, "CoGetClassObject on local server object "
1000        "registered in different thread should return S_OK "
1001        "instead of 0x%08x\n", hr);
1002
1003     hr = get_class_object(CLSCTX_LOCAL_SERVER);
1004     ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1005        "thread should return S_OK instead of 0x%08x\n", hr);
1006
1007     thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1008     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1009     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1010     GetExitCodeThread(thread, &exitcode);
1011     hr = exitcode;
1012     ok(hr == RPC_E_WRONG_THREAD, "CoRevokeClassObject called from different "
1013        "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1014
1015     thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 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 == S_OK, "CoRegisterClassObject with same CLSID but in different "
1021         "thread should return S_OK instead of 0x%08x\n", hr);
1022
1023     hr = CoRevokeClassObject(cookie);
1024     ok_ole_success(hr, "CoRevokeClassObject");
1025
1026     CoUninitialize();
1027 }
1028
1029 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1030 {
1031     CoFreeUnusedLibraries();
1032     return 0;
1033 }
1034
1035 static inline BOOL is_module_loaded(const char *module)
1036 {
1037     return GetModuleHandle(module) ? TRUE : FALSE;
1038 }
1039
1040 static void test_CoFreeUnusedLibraries(void)
1041 {
1042     HRESULT hr;
1043     IUnknown *pUnk;
1044     DWORD tid;
1045     HANDLE thread;
1046
1047     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1048
1049     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1050
1051     hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1052     if (hr == REGDB_E_CLASSNOTREG)
1053     {
1054         skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1055         CoUninitialize();
1056         return;
1057     }
1058     ok_ole_success(hr, "CoCreateInstance");
1059
1060     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1061
1062     ok(pUnk != NULL ||
1063        broken(pUnk == NULL), /* win9x */
1064        "Expected a valid pointer\n");
1065     if (pUnk)
1066         IUnknown_Release(pUnk);
1067
1068     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1069
1070     thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1071     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1072     CloseHandle(thread);
1073
1074     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1075
1076     CoFreeUnusedLibraries();
1077
1078     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1079
1080     CoUninitialize();
1081 }
1082
1083 static void test_CoGetObjectContext(void)
1084 {
1085     HRESULT hr;
1086     ULONG refs;
1087     IComThreadingInfo *pComThreadingInfo;
1088     IContextCallback *pContextCallback;
1089     IObjContext *pObjContext;
1090     APTTYPE apttype;
1091     THDTYPE thdtype;
1092     struct info info;
1093     HANDLE thread;
1094     DWORD tid, exitcode;
1095
1096     if (!pCoGetObjectContext)
1097     {
1098         skip("CoGetObjectContext not present\n");
1099         return;
1100     }
1101
1102     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1103     ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1104     ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1105
1106     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1107        thread has already done so */
1108
1109     info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1110     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1111
1112     info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1113     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1114
1115     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1116     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1117
1118     ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1119
1120     pComThreadingInfo = NULL;
1121     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1122     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1123     IComThreadingInfo_Release(pComThreadingInfo);
1124
1125     SetEvent(info.stop);
1126     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1127
1128     GetExitCodeThread(thread, &exitcode);
1129     hr = exitcode;
1130     ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1131
1132     CloseHandle(thread);
1133     CloseHandle(info.wait);
1134     CloseHandle(info.stop);
1135
1136     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1137
1138     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1139     ok_ole_success(hr, "CoGetObjectContext");
1140
1141     hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1142     ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1143     ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1144
1145     hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1146     ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1147     ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1148
1149     refs = IComThreadingInfo_Release(pComThreadingInfo);
1150     ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1151
1152     hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1153     ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1154
1155     if (hr == S_OK)
1156     {
1157         refs = IContextCallback_Release(pContextCallback);
1158         ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1159     }
1160
1161     CoUninitialize();
1162
1163     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1164
1165     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1166     ok_ole_success(hr, "CoGetObjectContext");
1167
1168     hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1169     ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1170     ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1171
1172     hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1173     ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1174     ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1175
1176     refs = IComThreadingInfo_Release(pComThreadingInfo);
1177     ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1178
1179     hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1180     ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1181
1182     if (hr == S_OK)
1183     {
1184         refs = IContextCallback_Release(pContextCallback);
1185         ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1186     }
1187
1188     hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1189     ok_ole_success(hr, "CoGetObjectContext");
1190
1191     refs = IObjContext_Release(pObjContext);
1192     ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1193
1194     CoUninitialize();
1195 }
1196
1197 typedef struct {
1198     const IUnknownVtbl *lpVtbl;
1199     LONG refs;
1200 } Test_CallContext;
1201
1202 static HRESULT WINAPI Test_CallContext_QueryInterface(
1203     IUnknown *iface,
1204     REFIID riid,
1205     LPVOID *ppvObj)
1206 {
1207     if (ppvObj == NULL) return E_POINTER;
1208
1209     if (IsEqualGUID(riid, &IID_IUnknown))
1210     {
1211         *ppvObj = iface;
1212         IUnknown_AddRef(iface);
1213         return S_OK;
1214     }
1215
1216     *ppvObj = NULL;
1217     return E_NOINTERFACE;
1218 }
1219
1220 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
1221 {
1222     Test_CallContext *This = (Test_CallContext*)iface;
1223     return InterlockedIncrement(&This->refs);
1224 }
1225
1226 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
1227 {
1228     Test_CallContext *This = (Test_CallContext*)iface;
1229     ULONG refs = InterlockedDecrement(&This->refs);
1230     if (!refs)
1231         HeapFree(GetProcessHeap(), 0, This);
1232     return refs;
1233 }
1234
1235 static const IUnknownVtbl TestCallContext_Vtbl =
1236 {
1237     Test_CallContext_QueryInterface,
1238     Test_CallContext_AddRef,
1239     Test_CallContext_Release
1240 };
1241
1242 static void test_CoGetCallContext(void)
1243 {
1244     HRESULT hr;
1245     ULONG refs;
1246     IUnknown *pUnk;
1247     IUnknown *test_object;
1248
1249     if (!pCoSwitchCallContext)
1250     {
1251         skip("CoSwitchCallContext not present\n");
1252         return;
1253     }
1254
1255     CoInitialize(NULL);
1256
1257     test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
1258     ((Test_CallContext*)test_object)->lpVtbl = &TestCallContext_Vtbl;
1259     ((Test_CallContext*)test_object)->refs = 1;
1260
1261     hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1262     ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1263
1264     pUnk = (IUnknown*)0xdeadbeef;
1265     hr = pCoSwitchCallContext(test_object, &pUnk);
1266     ok_ole_success(hr, "CoSwitchCallContext");
1267     ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
1268     refs = IUnknown_AddRef(test_object);
1269     ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1270     IUnknown_Release(test_object);
1271
1272     pUnk = (IUnknown*)0xdeadbeef;
1273     hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1274     ok_ole_success(hr, "CoGetCallContext");
1275     ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk);
1276     refs = IUnknown_AddRef(test_object);
1277     ok(refs == 3, "Expected refcount 3, got %d\n", refs);
1278     IUnknown_Release(test_object);
1279     IUnknown_Release(pUnk);
1280
1281     pUnk = (IUnknown*)0xdeadbeef;
1282     hr = pCoSwitchCallContext(NULL, &pUnk);
1283     ok_ole_success(hr, "CoSwitchCallContext");
1284     ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk);
1285     refs = IUnknown_AddRef(test_object);
1286     ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1287     IUnknown_Release(test_object);
1288
1289     hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1290     ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1291
1292     IUnknown_Release(test_object);
1293
1294     CoUninitialize();
1295 }
1296
1297 static void test_CoGetContextToken(void)
1298 {
1299     HRESULT hr;
1300     ULONG refs;
1301     ULONG_PTR token;
1302     IObjContext *ctx;
1303     struct info info;
1304     HANDLE thread;
1305     DWORD tid, exitcode;
1306
1307     if (!pCoGetContextToken)
1308     {
1309         win_skip("CoGetContextToken not present\n");
1310         return;
1311     }
1312
1313     token = 0xdeadbeef;
1314     hr = pCoGetContextToken(&token);
1315     ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
1316     ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
1317
1318     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1319        thread has already done so */
1320
1321     info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1322     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1323
1324     info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1325     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1326
1327     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1328     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1329
1330     ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1331
1332     token = 0;
1333     hr = pCoGetContextToken(&token);
1334     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1335
1336     SetEvent(info.stop);
1337     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1338
1339     GetExitCodeThread(thread, &exitcode);
1340     hr = exitcode;
1341     ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1342
1343     CloseHandle(thread);
1344     CloseHandle(info.wait);
1345     CloseHandle(info.stop);
1346
1347     CoInitialize(NULL);
1348
1349     hr = pCoGetContextToken(NULL);
1350     ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
1351
1352     token = 0;
1353     hr = pCoGetContextToken(&token);
1354     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1355     ok(token, "Expected token != 0\n");
1356
1357     refs = IUnknown_AddRef((IUnknown *)token);
1358     todo_wine ok(refs == 1, "Expected 1, got %u\n", refs);
1359
1360     hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
1361     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1362     todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1363
1364     refs = IUnknown_AddRef((IUnknown *)ctx);
1365     todo_wine ok(refs == 3, "Expected 3, got %u\n", refs);
1366
1367     refs = IUnknown_Release((IUnknown *)ctx);
1368     todo_wine ok(refs == 2, "Expected 2, got %u\n", refs);
1369
1370     refs = IUnknown_Release((IUnknown *)token);
1371     ok(refs == 1, "Expected 1, got %u\n", refs);
1372
1373     /* CoGetContextToken does not add a reference */
1374     token = 0;
1375     hr = pCoGetContextToken(&token);
1376     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1377     ok(token, "Expected token != 0\n");
1378     todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1379
1380     refs = IUnknown_AddRef((IUnknown *)ctx);
1381     ok(refs == 2, "Expected 1, got %u\n", refs);
1382
1383     refs = IUnknown_Release((IUnknown *)ctx);
1384     ok(refs == 1, "Expected 0, got %u\n", refs);
1385
1386     refs = IUnknown_Release((IUnknown *)ctx);
1387     ok(refs == 0, "Expected 0, got %u\n", refs);
1388
1389     CoUninitialize();
1390 }
1391
1392 static void test_CoGetTreatAsClass(void)
1393 {
1394     HRESULT hr;
1395     CLSID out;
1396     static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1397
1398     if (!pCoGetTreatAsClass)
1399     {
1400         win_skip("CoGetTreatAsClass not present\n");
1401         return;
1402     }
1403     hr = pCoGetTreatAsClass(&deadbeef,&out);
1404     ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
1405     ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
1406 }
1407
1408 static void test_CoInitializeEx(void)
1409 {
1410     HRESULT hr;
1411
1412     hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1413     ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
1414
1415     /* Calling OleInitialize for the first time should yield S_OK even with
1416      * apartment already initialized by previous CoInitialize(Ex) calls. */
1417     hr = OleInitialize(NULL);
1418     todo_wine ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
1419
1420     /* Subsequent calls to OleInitialize should return S_FALSE */
1421     hr = OleInitialize(NULL);
1422     ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
1423
1424     /* Cleanup */
1425     CoUninitialize();
1426     OleUninitialize();
1427 }
1428
1429 START_TEST(compobj)
1430 {
1431     HMODULE hOle32 = GetModuleHandle("ole32");
1432     pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
1433     pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext");
1434     pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
1435     pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
1436     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
1437     {
1438         trace("You need DCOM95 installed to run this test\n");
1439         return;
1440     }
1441
1442     test_ProgIDFromCLSID();
1443     test_CLSIDFromProgID();
1444     test_CLSIDFromString();
1445     test_StringFromGUID2();
1446     test_CoCreateInstance();
1447     test_ole_menu();
1448     test_CoGetClassObject();
1449     test_CoRegisterMessageFilter();
1450     test_CoRegisterPSClsid();
1451     test_CoGetPSClsid();
1452     test_CoUnmarshalInterface();
1453     test_CoGetInterfaceAndReleaseStream();
1454     test_CoMarshalInterface();
1455     test_CoMarshalInterThreadInterfaceInStream();
1456     test_CoRegisterClassObject();
1457     test_registered_object_thread_affinity();
1458     test_CoFreeUnusedLibraries();
1459     test_CoGetObjectContext();
1460     test_CoGetCallContext();
1461     test_CoGetContextToken();
1462     test_CoGetTreatAsClass();
1463     test_CoInitializeEx();
1464 }