ole32: Add a test that shows CoFreeUnusedLibraries only frees unused libraries from...
[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 "wine/test.h"
33
34 /* functions that are not present on all versions of Windows */
35 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
36
37 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
38 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
39 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
40
41 static const CLSID CLSID_non_existent =   { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
42 static const CLSID CLSID_CDeviceMoniker = { 0x4315d437, 0x5b8c, 0x11d0, { 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 } };
43 static WCHAR devicedotone[] = {'d','e','v','i','c','e','.','1',0};
44 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
45 static WCHAR wszCLSID_CDeviceMoniker[] =
46 {
47     '{',
48     '4','3','1','5','d','4','3','7','-',
49     '5','b','8','c','-',
50     '1','1','d','0','-',
51     'b','d','3','b','-',
52     '0','0','a','0','c','9','1','1','c','e','8','6',
53     '}',0
54 };
55
56 static const IID IID_IWineTest =
57 {
58     0x5201163f,
59     0x8164,
60     0x4fd0,
61     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
62 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
63
64 static LONG cLocks;
65
66 static void LockModule(void)
67 {
68     InterlockedIncrement(&cLocks);
69 }
70
71 static void UnlockModule(void)
72 {
73     InterlockedDecrement(&cLocks);
74 }
75
76 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
77     LPCLASSFACTORY iface,
78     REFIID riid,
79     LPVOID *ppvObj)
80 {
81     if (ppvObj == NULL) return E_POINTER;
82
83     if (IsEqualGUID(riid, &IID_IUnknown) ||
84         IsEqualGUID(riid, &IID_IClassFactory))
85     {
86         *ppvObj = (LPVOID)iface;
87         IClassFactory_AddRef(iface);
88         return S_OK;
89     }
90
91     *ppvObj = NULL;
92     return E_NOINTERFACE;
93 }
94
95 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
96 {
97     LockModule();
98     return 2; /* non-heap-based object */
99 }
100
101 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
102 {
103     UnlockModule();
104     return 1; /* non-heap-based object */
105 }
106
107 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
108     LPCLASSFACTORY iface,
109     LPUNKNOWN pUnkOuter,
110     REFIID riid,
111     LPVOID *ppvObj)
112 {
113     *ppvObj = NULL;
114     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
115     return E_NOINTERFACE;
116 }
117
118 static HRESULT WINAPI Test_IClassFactory_LockServer(
119     LPCLASSFACTORY iface,
120     BOOL fLock)
121 {
122     return S_OK;
123 }
124
125 static const IClassFactoryVtbl TestClassFactory_Vtbl =
126 {
127     Test_IClassFactory_QueryInterface,
128     Test_IClassFactory_AddRef,
129     Test_IClassFactory_Release,
130     Test_IClassFactory_CreateInstance,
131     Test_IClassFactory_LockServer
132 };
133
134 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
135
136 static void test_ProgIDFromCLSID(void)
137 {
138     LPWSTR progid;
139     HRESULT hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, &progid);
140     ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
141     if (hr == S_OK)
142     {
143         ok(!lstrcmpiW(progid, devicedotone), "Didn't get expected prog ID\n");
144         CoTaskMemFree(progid);
145     }
146
147     progid = (LPWSTR)0xdeadbeef;
148     hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
149     ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
150     ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
151
152     hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, NULL);
153     ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
154 }
155
156 static void test_CLSIDFromProgID(void)
157 {
158     CLSID clsid;
159     HRESULT hr = CLSIDFromProgID(devicedotone, &clsid);
160     ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
161     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
162
163     hr = CLSIDFromString(devicedotone, &clsid);
164     ok_ole_success(hr, "CLSIDFromString");
165     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
166
167     /* test some failure cases */
168
169     hr = CLSIDFromProgID(wszNonExistent, NULL);
170     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
171
172     hr = CLSIDFromProgID(NULL, &clsid);
173     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
174
175     memset(&clsid, 0xcc, sizeof(clsid));
176     hr = CLSIDFromProgID(wszNonExistent, &clsid);
177     ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
178     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
179 }
180
181 static void test_CLSIDFromString(void)
182 {
183     CLSID clsid;
184     HRESULT hr = CLSIDFromString(wszCLSID_CDeviceMoniker, &clsid);
185     ok_ole_success(hr, "CLSIDFromString");
186     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
187
188     hr = CLSIDFromString(NULL, &clsid);
189     ok_ole_success(hr, "CLSIDFromString");
190     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
191 }
192
193 static void test_CoCreateInstance(void)
194 {
195     REFCLSID rclsid = &CLSID_MyComputer;
196     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
197     HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
198     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
199     ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
200
201     OleInitialize(NULL);
202     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
203     ok_ole_success(hr, "CoCreateInstance");
204     IUnknown_Release(pUnk);
205     OleUninitialize();
206
207     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
208     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
209 }
210
211 static void test_CoGetClassObject(void)
212 {
213     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
214     HRESULT hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
215     ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
216     ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
217
218     hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
219     ok(hr == E_INVALIDARG, "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
220 }
221
222 static ATOM register_dummy_class(void)
223 {
224     WNDCLASS wc =
225     {
226         0,
227         DefWindowProc,
228         0,
229         0,
230         GetModuleHandle(NULL),
231         NULL,
232         LoadCursor(NULL, IDC_ARROW),
233         (HBRUSH)(COLOR_BTNFACE+1),
234         NULL,
235         TEXT("WineOleTestClass"),
236     };
237
238     return RegisterClass(&wc);
239 }
240
241 static void test_ole_menu(void)
242 {
243         HWND hwndFrame;
244         HRESULT hr;
245
246         hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
247         hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
248         todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
249
250         DestroyWindow(hwndFrame);
251 }
252
253
254 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
255 {
256     if (ppvObj == NULL) return E_POINTER;
257
258     if (IsEqualGUID(riid, &IID_IUnknown) ||
259         IsEqualGUID(riid, &IID_IClassFactory))
260     {
261         *ppvObj = (LPVOID)iface;
262         IMessageFilter_AddRef(iface);
263         return S_OK;
264     }
265
266     return E_NOINTERFACE;
267 }
268
269 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
270 {
271     return 2; /* non-heap object */
272 }
273
274 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
275 {
276     return 1; /* non-heap object */
277 }
278
279 static DWORD WINAPI MessageFilter_HandleInComingCall(
280   IMessageFilter *iface,
281   DWORD dwCallType,
282   HTASK threadIDCaller,
283   DWORD dwTickCount,
284   LPINTERFACEINFO lpInterfaceInfo)
285 {
286     trace("HandleInComingCall\n");
287     return SERVERCALL_ISHANDLED;
288 }
289
290 static DWORD WINAPI MessageFilter_RetryRejectedCall(
291   IMessageFilter *iface,
292   HTASK threadIDCallee,
293   DWORD dwTickCount,
294   DWORD dwRejectType)
295 {
296     trace("RetryRejectedCall\n");
297     return 0;
298 }
299
300 static DWORD WINAPI MessageFilter_MessagePending(
301   IMessageFilter *iface,
302   HTASK threadIDCallee,
303   DWORD dwTickCount,
304   DWORD dwPendingType)
305 {
306     trace("MessagePending\n");
307     return PENDINGMSG_WAITNOPROCESS;
308 }
309
310 static const IMessageFilterVtbl MessageFilter_Vtbl =
311 {
312     MessageFilter_QueryInterface,
313     MessageFilter_AddRef,
314     MessageFilter_Release,
315     MessageFilter_HandleInComingCall,
316     MessageFilter_RetryRejectedCall,
317     MessageFilter_MessagePending
318 };
319
320 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
321
322 static void test_CoRegisterMessageFilter(void)
323 {
324     HRESULT hr;
325     IMessageFilter *prev_filter;
326
327     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
328     ok(hr == CO_E_NOT_SUPPORTED,
329         "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
330         hr);
331
332     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
333     prev_filter = (IMessageFilter *)0xdeadbeef;
334     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
335     ok(hr == CO_E_NOT_SUPPORTED,
336         "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
337         hr);
338     ok(prev_filter == (IMessageFilter *)0xdeadbeef,
339         "prev_filter should have been set to %p\n", prev_filter);
340     CoUninitialize();
341
342     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
343
344     hr = CoRegisterMessageFilter(NULL, NULL);
345     ok_ole_success(hr, "CoRegisterMessageFilter");
346
347     prev_filter = (IMessageFilter *)0xdeadbeef;
348     hr = CoRegisterMessageFilter(NULL, &prev_filter);
349     ok_ole_success(hr, "CoRegisterMessageFilter");
350     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
351
352     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
353     ok_ole_success(hr, "CoRegisterMessageFilter");
354     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
355
356     hr = CoRegisterMessageFilter(NULL, NULL);
357     ok_ole_success(hr, "CoRegisterMessageFilter");
358
359     CoUninitialize();
360 }
361
362 static HRESULT WINAPI Test_IUnknown_QueryInterface(
363     LPUNKNOWN iface,
364     REFIID riid,
365     LPVOID *ppvObj)
366 {
367     if (ppvObj == NULL) return E_POINTER;
368
369     if (IsEqualIID(riid, &IID_IUnknown) ||
370         IsEqualIID(riid, &IID_IWineTest))
371     {
372         *ppvObj = (LPVOID)iface;
373         IUnknown_AddRef(iface);
374         return S_OK;
375     }
376
377     *ppvObj = NULL;
378     return E_NOINTERFACE;
379 }
380
381 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
382 {
383     return 2; /* non-heap-based object */
384 }
385
386 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
387 {
388     return 1; /* non-heap-based object */
389 }
390
391 static const IUnknownVtbl TestUnknown_Vtbl =
392 {
393     Test_IUnknown_QueryInterface,
394     Test_IUnknown_AddRef,
395     Test_IUnknown_Release,
396 };
397
398 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
399
400 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
401     IPSFactoryBuffer * This,
402     /* [in] */ REFIID riid,
403     /* [iid_is][out] */ void **ppvObject)
404 {
405     if (IsEqualIID(riid, &IID_IUnknown) ||
406         IsEqualIID(riid, &IID_IPSFactoryBuffer))
407     {
408         *ppvObject = This;
409         IPSFactoryBuffer_AddRef(This);
410         return S_OK;
411     }
412     return E_NOINTERFACE;
413 }
414
415 static ULONG WINAPI PSFactoryBuffer_AddRef(
416     IPSFactoryBuffer * This)
417 {
418     return 2;
419 }
420
421 static ULONG WINAPI PSFactoryBuffer_Release(
422     IPSFactoryBuffer * This)
423 {
424     return 1;
425 }
426
427 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
428     IPSFactoryBuffer * This,
429     /* [in] */ IUnknown *pUnkOuter,
430     /* [in] */ REFIID riid,
431     /* [out] */ IRpcProxyBuffer **ppProxy,
432     /* [out] */ void **ppv)
433 {
434     return E_NOTIMPL;
435 }
436
437 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
438     IPSFactoryBuffer * This,
439     /* [in] */ REFIID riid,
440     /* [unique][in] */ IUnknown *pUnkServer,
441     /* [out] */ IRpcStubBuffer **ppStub)
442 {
443     return E_NOTIMPL;
444 }
445
446 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
447 {
448     PSFactoryBuffer_QueryInterface,
449     PSFactoryBuffer_AddRef,
450     PSFactoryBuffer_Release,
451     PSFactoryBuffer_CreateProxy,
452     PSFactoryBuffer_CreateStub
453 };
454
455 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
456
457 static const CLSID CLSID_WineTestPSFactoryBuffer =
458 {
459     0x52011640,
460     0x8164,
461     0x4fd0,
462     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
463 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
464
465 static void test_CoRegisterPSClsid(void)
466 {
467     HRESULT hr;
468     DWORD dwRegistrationKey;
469     IStream *stream;
470     CLSID clsid;
471
472     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
473     ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returened CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
474
475     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
476
477     hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
478         CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
479     ok_ole_success(hr, "CoRegisterClassObject");
480
481     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
482     ok_ole_success(hr, "CoRegisterPSClsid");
483
484     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
485     ok_ole_success(hr, "CreateStreamOnHGlobal");
486
487     hr = CoMarshalInterface(stream, &IID_IWineTest, (IUnknown *)&Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
488     ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
489     IStream_Release(stream);
490
491     hr = CoRevokeClassObject(dwRegistrationKey);
492     ok_ole_success(hr, "CoRevokeClassObject");
493
494     CoUninitialize();
495
496     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
497
498     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
499     ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
500
501     CoUninitialize();
502 }
503
504 static void test_CoGetPSClsid(void)
505 {
506     HRESULT hr;
507     CLSID clsid;
508
509     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
510     ok(hr == CO_E_NOTINITIALIZED,
511        "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
512        hr);
513
514     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
515
516     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
517     ok_ole_success(hr, "CoGetPSClsid");
518
519     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
520     ok(hr == REGDB_E_IIDNOTREG,
521        "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
522        hr);
523
524     hr = CoGetPSClsid(&IID_IClassFactory, NULL);
525     ok(hr == E_INVALIDARG,
526        "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
527        hr);
528
529     CoUninitialize();
530 }
531
532 /* basic test, mainly for invalid arguments. see marshal.c for more */
533 static void test_CoUnmarshalInterface(void)
534 {
535     IUnknown *pProxy;
536     IStream *pStream;
537     HRESULT hr;
538
539     hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
540     ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
541
542     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
543     ok_ole_success(hr, "CreateStreamOnHGlobal");
544
545     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
546     todo_wine
547     ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
548
549     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
550
551     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
552     ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
553
554     CoUninitialize();
555
556     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
557     ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
558
559     IStream_Release(pStream);
560 }
561
562 static void test_CoGetInterfaceAndReleaseStream(void)
563 {
564     HRESULT hr;
565     IUnknown *pUnk;
566
567     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
568
569     hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
570     ok(hr == E_INVALIDARG, "hr %08x\n", hr);
571
572     CoUninitialize();
573 }
574
575 /* basic test, mainly for invalid arguments. see marshal.c for more */
576 static void test_CoMarshalInterface(void)
577 {
578     IStream *pStream;
579     HRESULT hr;
580     static const LARGE_INTEGER llZero;
581
582     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
583
584     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
585     ok_ole_success(hr, "CreateStreamOnHGlobal");
586
587     hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
588     ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
589
590     hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
591     ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
592
593     hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
594     ok_ole_success(hr, "CoMarshalInterface");
595
596     /* stream not rewound */
597     hr = CoReleaseMarshalData(pStream);
598     ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
599
600     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
601     ok_ole_success(hr, "IStream_Seek");
602
603     hr = CoReleaseMarshalData(pStream);
604     ok_ole_success(hr, "CoReleaseMarshalData");
605
606     IStream_Release(pStream);
607
608     CoUninitialize();
609 }
610
611 static void test_CoMarshalInterThreadInterfaceInStream(void)
612 {
613     IStream *pStream;
614     HRESULT hr;
615     IClassFactory *pProxy;
616
617     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
618
619     cLocks = 0;
620
621     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
622     ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
623
624     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
625     ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
626
627     ok_no_locks();
628
629     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
630     ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
631
632     ok_more_than_one_lock();
633
634     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
635     ok_ole_success(hr, "CoUnmarshalInterface");
636
637     IClassFactory_Release(pProxy);
638
639     ok_no_locks();
640
641     CoUninitialize();
642 }
643
644 static void test_CoRegisterClassObject(void)
645 {
646     static const CLSID CLSID_WineOOPTest = {
647         0x5201163f,
648         0x8164,
649         0x4fd0,
650         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
651     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
652     DWORD cookie;
653     HRESULT hr;
654
655     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
656
657     /* CLSCTX_INPROC_SERVER */
658     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
659                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
660     ok_ole_success(hr, "CoRegisterClassObject");
661     hr = CoRevokeClassObject(cookie);
662     ok_ole_success(hr, "CoRevokeClassObject");
663
664     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
665                                CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
666     ok_ole_success(hr, "CoRegisterClassObject");
667     hr = CoRevokeClassObject(cookie);
668     ok_ole_success(hr, "CoRevokeClassObject");
669
670     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
671                                CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
672     ok_ole_success(hr, "CoRegisterClassObject");
673     hr = CoRevokeClassObject(cookie);
674     ok_ole_success(hr, "CoRevokeClassObject");
675
676     /* CLSCTX_LOCAL_SERVER */
677     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
678                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
679     ok_ole_success(hr, "CoRegisterClassObject");
680     hr = CoRevokeClassObject(cookie);
681     ok_ole_success(hr, "CoRevokeClassObject");
682
683     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
684                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
685     ok_ole_success(hr, "CoRegisterClassObject");
686     hr = CoRevokeClassObject(cookie);
687     ok_ole_success(hr, "CoRevokeClassObject");
688
689     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
690                                CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
691     ok_ole_success(hr, "CoRegisterClassObject");
692     hr = CoRevokeClassObject(cookie);
693     ok_ole_success(hr, "CoRevokeClassObject");
694
695     /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
696     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
697                                CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
698     ok_ole_success(hr, "CoRegisterClassObject");
699     hr = CoRevokeClassObject(cookie);
700     ok_ole_success(hr, "CoRevokeClassObject");
701
702     CoUninitialize();
703 }
704
705 static DWORD CALLBACK free_libraries_thread(LPVOID p)
706 {
707     CoFreeUnusedLibraries();
708     return 0;
709 }
710
711 static inline BOOL is_module_loaded(const char *module)
712 {
713     return GetModuleHandle(module) ? TRUE : FALSE;
714 }
715
716 static void test_CoFreeUnusedLibraries(void)
717 {
718     HRESULT hr;
719     IUnknown *pUnk;
720     DWORD tid;
721     HANDLE thread;
722
723     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
724
725     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
726
727     hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
728     if (hr == REGDB_E_CLASSNOTREG)
729     {
730         trace("IE not installed so can't run CoFreeUnusedLibraries test\n");
731         return;
732     }
733     ok_ole_success(hr, "CoCreateInstance");
734
735     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
736
737     IUnknown_Release(pUnk);
738
739     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
740
741     thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
742     WaitForSingleObject(thread, INFINITE);
743     CloseHandle(thread);
744
745     todo_wine
746     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
747
748     CoFreeUnusedLibraries();
749
750     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
751
752     CoUninitialize();
753 }
754
755
756 START_TEST(compobj)
757 {
758     HMODULE hOle32 = GetModuleHandle("ole32");
759     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
760     {
761         trace("You need DCOM95 installed to run this test\n");
762         return;
763     }
764
765     test_ProgIDFromCLSID();
766     test_CLSIDFromProgID();
767     test_CLSIDFromString();
768     test_CoCreateInstance();
769     test_ole_menu();
770     test_CoGetClassObject();
771     test_CoRegisterMessageFilter();
772     test_CoRegisterPSClsid();
773     test_CoGetPSClsid();
774     test_CoUnmarshalInterface();
775     test_CoGetInterfaceAndReleaseStream();
776     test_CoMarshalInterface();
777     test_CoMarshalInterThreadInterfaceInStream();
778     test_CoRegisterClassObject();
779     test_CoFreeUnusedLibraries();
780 }