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