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