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