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