ole32: Fix reading from an HGLOBALStreamImpl with an invalid HGLOBAL.
[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 static const CLSID CLSID_WineOOPTest = {
64     0x5201163f,
65     0x8164,
66     0x4fd0,
67     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
68 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
69
70 static LONG cLocks;
71
72 static void LockModule(void)
73 {
74     InterlockedIncrement(&cLocks);
75 }
76
77 static void UnlockModule(void)
78 {
79     InterlockedDecrement(&cLocks);
80 }
81
82 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
83     LPCLASSFACTORY iface,
84     REFIID riid,
85     LPVOID *ppvObj)
86 {
87     if (ppvObj == NULL) return E_POINTER;
88
89     if (IsEqualGUID(riid, &IID_IUnknown) ||
90         IsEqualGUID(riid, &IID_IClassFactory))
91     {
92         *ppvObj = (LPVOID)iface;
93         IClassFactory_AddRef(iface);
94         return S_OK;
95     }
96
97     *ppvObj = NULL;
98     return E_NOINTERFACE;
99 }
100
101 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
102 {
103     LockModule();
104     return 2; /* non-heap-based object */
105 }
106
107 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
108 {
109     UnlockModule();
110     return 1; /* non-heap-based object */
111 }
112
113 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
114     LPCLASSFACTORY iface,
115     LPUNKNOWN pUnkOuter,
116     REFIID riid,
117     LPVOID *ppvObj)
118 {
119     *ppvObj = NULL;
120     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
121     return E_NOINTERFACE;
122 }
123
124 static HRESULT WINAPI Test_IClassFactory_LockServer(
125     LPCLASSFACTORY iface,
126     BOOL fLock)
127 {
128     return S_OK;
129 }
130
131 static const IClassFactoryVtbl TestClassFactory_Vtbl =
132 {
133     Test_IClassFactory_QueryInterface,
134     Test_IClassFactory_AddRef,
135     Test_IClassFactory_Release,
136     Test_IClassFactory_CreateInstance,
137     Test_IClassFactory_LockServer
138 };
139
140 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
141
142 static void test_ProgIDFromCLSID(void)
143 {
144     LPWSTR progid;
145     HRESULT hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, &progid);
146     ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
147     if (hr == S_OK)
148     {
149         ok(!lstrcmpiW(progid, devicedotone), "Didn't get expected prog ID\n");
150         CoTaskMemFree(progid);
151     }
152
153     progid = (LPWSTR)0xdeadbeef;
154     hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
155     ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
156     ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
157
158     hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, NULL);
159     ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
160 }
161
162 static void test_CLSIDFromProgID(void)
163 {
164     CLSID clsid;
165     HRESULT hr = CLSIDFromProgID(devicedotone, &clsid);
166     ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
167     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
168
169     hr = CLSIDFromString(devicedotone, &clsid);
170     ok_ole_success(hr, "CLSIDFromString");
171     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
172
173     /* test some failure cases */
174
175     hr = CLSIDFromProgID(wszNonExistent, NULL);
176     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
177
178     hr = CLSIDFromProgID(NULL, &clsid);
179     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
180
181     memset(&clsid, 0xcc, sizeof(clsid));
182     hr = CLSIDFromProgID(wszNonExistent, &clsid);
183     ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
184     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
185 }
186
187 static void test_CLSIDFromString(void)
188 {
189     CLSID clsid;
190     HRESULT hr = CLSIDFromString(wszCLSID_CDeviceMoniker, &clsid);
191     ok_ole_success(hr, "CLSIDFromString");
192     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
193
194     hr = CLSIDFromString(NULL, &clsid);
195     ok_ole_success(hr, "CLSIDFromString");
196     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
197 }
198
199 static void test_CoCreateInstance(void)
200 {
201     REFCLSID rclsid = &CLSID_MyComputer;
202     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
203     HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
204     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
205     ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
206
207     OleInitialize(NULL);
208     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
209     ok_ole_success(hr, "CoCreateInstance");
210     IUnknown_Release(pUnk);
211     OleUninitialize();
212
213     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
214     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
215 }
216
217 static void test_CoGetClassObject(void)
218 {
219     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
220     HRESULT hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
221     ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
222     ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
223
224     hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
225     ok(hr == E_INVALIDARG, "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
226 }
227
228 static ATOM register_dummy_class(void)
229 {
230     WNDCLASS wc =
231     {
232         0,
233         DefWindowProc,
234         0,
235         0,
236         GetModuleHandle(NULL),
237         NULL,
238         LoadCursor(NULL, IDC_ARROW),
239         (HBRUSH)(COLOR_BTNFACE+1),
240         NULL,
241         TEXT("WineOleTestClass"),
242     };
243
244     return RegisterClass(&wc);
245 }
246
247 static void test_ole_menu(void)
248 {
249         HWND hwndFrame;
250         HRESULT hr;
251
252         hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
253         hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
254         todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
255
256         DestroyWindow(hwndFrame);
257 }
258
259
260 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
261 {
262     if (ppvObj == NULL) return E_POINTER;
263
264     if (IsEqualGUID(riid, &IID_IUnknown) ||
265         IsEqualGUID(riid, &IID_IClassFactory))
266     {
267         *ppvObj = (LPVOID)iface;
268         IMessageFilter_AddRef(iface);
269         return S_OK;
270     }
271
272     return E_NOINTERFACE;
273 }
274
275 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
276 {
277     return 2; /* non-heap object */
278 }
279
280 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
281 {
282     return 1; /* non-heap object */
283 }
284
285 static DWORD WINAPI MessageFilter_HandleInComingCall(
286   IMessageFilter *iface,
287   DWORD dwCallType,
288   HTASK threadIDCaller,
289   DWORD dwTickCount,
290   LPINTERFACEINFO lpInterfaceInfo)
291 {
292     trace("HandleInComingCall\n");
293     return SERVERCALL_ISHANDLED;
294 }
295
296 static DWORD WINAPI MessageFilter_RetryRejectedCall(
297   IMessageFilter *iface,
298   HTASK threadIDCallee,
299   DWORD dwTickCount,
300   DWORD dwRejectType)
301 {
302     trace("RetryRejectedCall\n");
303     return 0;
304 }
305
306 static DWORD WINAPI MessageFilter_MessagePending(
307   IMessageFilter *iface,
308   HTASK threadIDCallee,
309   DWORD dwTickCount,
310   DWORD dwPendingType)
311 {
312     trace("MessagePending\n");
313     return PENDINGMSG_WAITNOPROCESS;
314 }
315
316 static const IMessageFilterVtbl MessageFilter_Vtbl =
317 {
318     MessageFilter_QueryInterface,
319     MessageFilter_AddRef,
320     MessageFilter_Release,
321     MessageFilter_HandleInComingCall,
322     MessageFilter_RetryRejectedCall,
323     MessageFilter_MessagePending
324 };
325
326 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
327
328 static void test_CoRegisterMessageFilter(void)
329 {
330     HRESULT hr;
331     IMessageFilter *prev_filter;
332
333     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
334     ok(hr == CO_E_NOT_SUPPORTED,
335         "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
336         hr);
337
338     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
339     prev_filter = (IMessageFilter *)0xdeadbeef;
340     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
341     ok(hr == CO_E_NOT_SUPPORTED,
342         "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
343         hr);
344     ok(prev_filter == (IMessageFilter *)0xdeadbeef,
345         "prev_filter should have been set to %p\n", prev_filter);
346     CoUninitialize();
347
348     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
349
350     hr = CoRegisterMessageFilter(NULL, NULL);
351     ok_ole_success(hr, "CoRegisterMessageFilter");
352
353     prev_filter = (IMessageFilter *)0xdeadbeef;
354     hr = CoRegisterMessageFilter(NULL, &prev_filter);
355     ok_ole_success(hr, "CoRegisterMessageFilter");
356     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
357
358     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
359     ok_ole_success(hr, "CoRegisterMessageFilter");
360     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
361
362     hr = CoRegisterMessageFilter(NULL, NULL);
363     ok_ole_success(hr, "CoRegisterMessageFilter");
364
365     CoUninitialize();
366 }
367
368 static HRESULT WINAPI Test_IUnknown_QueryInterface(
369     LPUNKNOWN iface,
370     REFIID riid,
371     LPVOID *ppvObj)
372 {
373     if (ppvObj == NULL) return E_POINTER;
374
375     if (IsEqualIID(riid, &IID_IUnknown) ||
376         IsEqualIID(riid, &IID_IWineTest))
377     {
378         *ppvObj = (LPVOID)iface;
379         IUnknown_AddRef(iface);
380         return S_OK;
381     }
382
383     *ppvObj = NULL;
384     return E_NOINTERFACE;
385 }
386
387 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
388 {
389     return 2; /* non-heap-based object */
390 }
391
392 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
393 {
394     return 1; /* non-heap-based object */
395 }
396
397 static const IUnknownVtbl TestUnknown_Vtbl =
398 {
399     Test_IUnknown_QueryInterface,
400     Test_IUnknown_AddRef,
401     Test_IUnknown_Release,
402 };
403
404 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
405
406 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
407     IPSFactoryBuffer * This,
408     /* [in] */ REFIID riid,
409     /* [iid_is][out] */ void **ppvObject)
410 {
411     if (IsEqualIID(riid, &IID_IUnknown) ||
412         IsEqualIID(riid, &IID_IPSFactoryBuffer))
413     {
414         *ppvObject = This;
415         IPSFactoryBuffer_AddRef(This);
416         return S_OK;
417     }
418     return E_NOINTERFACE;
419 }
420
421 static ULONG WINAPI PSFactoryBuffer_AddRef(
422     IPSFactoryBuffer * This)
423 {
424     return 2;
425 }
426
427 static ULONG WINAPI PSFactoryBuffer_Release(
428     IPSFactoryBuffer * This)
429 {
430     return 1;
431 }
432
433 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
434     IPSFactoryBuffer * This,
435     /* [in] */ IUnknown *pUnkOuter,
436     /* [in] */ REFIID riid,
437     /* [out] */ IRpcProxyBuffer **ppProxy,
438     /* [out] */ void **ppv)
439 {
440     return E_NOTIMPL;
441 }
442
443 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
444     IPSFactoryBuffer * This,
445     /* [in] */ REFIID riid,
446     /* [unique][in] */ IUnknown *pUnkServer,
447     /* [out] */ IRpcStubBuffer **ppStub)
448 {
449     return E_NOTIMPL;
450 }
451
452 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
453 {
454     PSFactoryBuffer_QueryInterface,
455     PSFactoryBuffer_AddRef,
456     PSFactoryBuffer_Release,
457     PSFactoryBuffer_CreateProxy,
458     PSFactoryBuffer_CreateStub
459 };
460
461 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
462
463 static const CLSID CLSID_WineTestPSFactoryBuffer =
464 {
465     0x52011640,
466     0x8164,
467     0x4fd0,
468     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
469 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
470
471 static void test_CoRegisterPSClsid(void)
472 {
473     HRESULT hr;
474     DWORD dwRegistrationKey;
475     IStream *stream;
476     CLSID clsid;
477
478     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
479     ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returened CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
480
481     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
482
483     hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
484         CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
485     ok_ole_success(hr, "CoRegisterClassObject");
486
487     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
488     ok_ole_success(hr, "CoRegisterPSClsid");
489
490     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
491     ok_ole_success(hr, "CreateStreamOnHGlobal");
492
493     hr = CoMarshalInterface(stream, &IID_IWineTest, (IUnknown *)&Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
494     ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
495     IStream_Release(stream);
496
497     hr = CoRevokeClassObject(dwRegistrationKey);
498     ok_ole_success(hr, "CoRevokeClassObject");
499
500     CoUninitialize();
501
502     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
503
504     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
505     ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
506
507     CoUninitialize();
508 }
509
510 static void test_CoGetPSClsid(void)
511 {
512     HRESULT hr;
513     CLSID clsid;
514
515     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
516     ok(hr == CO_E_NOTINITIALIZED,
517        "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
518        hr);
519
520     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
521
522     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
523     ok_ole_success(hr, "CoGetPSClsid");
524
525     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
526     ok(hr == REGDB_E_IIDNOTREG,
527        "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
528        hr);
529
530     hr = CoGetPSClsid(&IID_IClassFactory, NULL);
531     ok(hr == E_INVALIDARG,
532        "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
533        hr);
534
535     CoUninitialize();
536 }
537
538 /* basic test, mainly for invalid arguments. see marshal.c for more */
539 static void test_CoUnmarshalInterface(void)
540 {
541     IUnknown *pProxy;
542     IStream *pStream;
543     HRESULT hr;
544
545     hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
546     ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
547
548     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
549     ok_ole_success(hr, "CreateStreamOnHGlobal");
550
551     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
552     todo_wine
553     ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
554
555     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
556
557     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
558     ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
559
560     CoUninitialize();
561
562     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
563     ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
564
565     IStream_Release(pStream);
566 }
567
568 static void test_CoGetInterfaceAndReleaseStream(void)
569 {
570     HRESULT hr;
571     IUnknown *pUnk;
572
573     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
574
575     hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
576     ok(hr == E_INVALIDARG, "hr %08x\n", hr);
577
578     CoUninitialize();
579 }
580
581 /* basic test, mainly for invalid arguments. see marshal.c for more */
582 static void test_CoMarshalInterface(void)
583 {
584     IStream *pStream;
585     HRESULT hr;
586     static const LARGE_INTEGER llZero;
587
588     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
589
590     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
591     ok_ole_success(hr, "CreateStreamOnHGlobal");
592
593     hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
594     ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
595
596     hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
597     ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
598
599     hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
600     ok_ole_success(hr, "CoMarshalInterface");
601
602     /* stream not rewound */
603     hr = CoReleaseMarshalData(pStream);
604     ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
605
606     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
607     ok_ole_success(hr, "IStream_Seek");
608
609     hr = CoReleaseMarshalData(pStream);
610     ok_ole_success(hr, "CoReleaseMarshalData");
611
612     IStream_Release(pStream);
613
614     CoUninitialize();
615 }
616
617 static void test_CoMarshalInterThreadInterfaceInStream(void)
618 {
619     IStream *pStream;
620     HRESULT hr;
621     IClassFactory *pProxy;
622
623     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
624
625     cLocks = 0;
626
627     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
628     ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
629
630     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
631     ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
632
633     ok_no_locks();
634
635     hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
636     ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
637
638     ok_more_than_one_lock();
639
640     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
641     ok_ole_success(hr, "CoUnmarshalInterface");
642
643     IClassFactory_Release(pProxy);
644
645     ok_no_locks();
646
647     CoUninitialize();
648 }
649
650 static void test_CoRegisterClassObject(void)
651 {
652     DWORD cookie;
653     HRESULT hr;
654     IClassFactory *pcf;
655
656     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
657
658     /* CLSCTX_INPROC_SERVER */
659     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
660                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
661     ok_ole_success(hr, "CoRegisterClassObject");
662     hr = CoRevokeClassObject(cookie);
663     ok_ole_success(hr, "CoRevokeClassObject");
664
665     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
666                                CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
667     ok_ole_success(hr, "CoRegisterClassObject");
668     hr = CoRevokeClassObject(cookie);
669     ok_ole_success(hr, "CoRevokeClassObject");
670
671     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
672                                CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
673     ok_ole_success(hr, "CoRegisterClassObject");
674     hr = CoRevokeClassObject(cookie);
675     ok_ole_success(hr, "CoRevokeClassObject");
676
677     /* CLSCTX_LOCAL_SERVER */
678     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
679                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
680     ok_ole_success(hr, "CoRegisterClassObject");
681     hr = CoRevokeClassObject(cookie);
682     ok_ole_success(hr, "CoRevokeClassObject");
683
684     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
685                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
686     ok_ole_success(hr, "CoRegisterClassObject");
687     hr = CoRevokeClassObject(cookie);
688     ok_ole_success(hr, "CoRevokeClassObject");
689
690     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
691                                CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
692     ok_ole_success(hr, "CoRegisterClassObject");
693     hr = CoRevokeClassObject(cookie);
694     ok_ole_success(hr, "CoRevokeClassObject");
695
696     /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
697     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
698                                CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
699     ok_ole_success(hr, "CoRegisterClassObject");
700     hr = CoRevokeClassObject(cookie);
701     ok_ole_success(hr, "CoRevokeClassObject");
702
703     /* test whether registered class becomes invalid when apartment is destroyed */
704     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
705                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
706     ok_ole_success(hr, "CoRegisterClassObject");
707
708     CoUninitialize();
709     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
710
711     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
712                           &IID_IClassFactory, (void **)&pcf);
713     ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
714
715     /* crashes with at least win9x DCOM! */
716     if (0)
717         hr = CoRevokeClassObject(cookie);
718
719     CoUninitialize();
720 }
721
722 static HRESULT get_class_object(CLSCTX clsctx)
723 {
724     HRESULT hr;
725     IClassFactory *pcf;
726
727     hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
728                           (void **)&pcf);
729
730     if (SUCCEEDED(hr))
731         IClassFactory_Release(pcf);
732
733     return hr;
734 }
735
736 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
737 {
738     CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
739     HRESULT hr;
740
741     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
742
743     hr = get_class_object(clsctx);
744
745     CoUninitialize();
746
747     return hr;
748 }
749
750 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
751 {
752     CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
753     HRESULT hr;
754     IClassFactory *pcf;
755     IMultiQI *pMQI;
756
757     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
758
759     hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
760                           (void **)&pcf);
761
762     if (SUCCEEDED(hr))
763     {
764         hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
765         if (SUCCEEDED(hr))
766             IMultiQI_Release(pMQI);
767         IClassFactory_Release(pcf);
768     }
769
770     CoUninitialize();
771
772     return hr;
773 }
774
775 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
776 {
777     HRESULT hr;
778     DWORD cookie;
779
780     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
781
782     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
783                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
784
785     CoUninitialize();
786
787     return hr;
788 }
789
790 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
791 {
792     DWORD cookie = (DWORD_PTR)pv;
793     HRESULT hr;
794
795     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
796
797     hr = CoRevokeClassObject(cookie);
798
799     CoUninitialize();
800
801     return hr;
802 }
803
804 static void test_registered_object_thread_affinity(void)
805 {
806     HRESULT hr;
807     DWORD cookie;
808     HANDLE thread;
809     DWORD tid;
810     DWORD exitcode;
811
812     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
813
814     /* CLSCTX_INPROC_SERVER */
815
816     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
817                                CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
818     ok_ole_success(hr, "CoRegisterClassObject");
819
820     thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
821     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
822     WaitForSingleObject(thread, INFINITE);
823     GetExitCodeThread(thread, &exitcode);
824     hr = exitcode;
825     ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
826        "registered in different thread should return REGDB_E_CLASSNOTREG "
827        "instead of 0x%08x\n", hr);
828
829     hr = get_class_object(CLSCTX_INPROC_SERVER);
830     ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
831        "thread should return S_OK instead of 0x%08x\n", hr);
832
833     thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
834     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
835     WaitForSingleObject(thread, INFINITE);
836     GetExitCodeThread(thread, &exitcode);
837     hr = exitcode;
838     ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
839
840     hr = CoRevokeClassObject(cookie);
841     ok_ole_success(hr, "CoRevokeClassObject");
842
843     /* CLSCTX_LOCAL_SERVER */
844
845     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
846                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
847     ok_ole_success(hr, "CoRegisterClassObject");
848
849     thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
850     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
851     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
852     {
853         MSG msg;
854         while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
855         {
856             TranslateMessage(&msg);
857             DispatchMessageA(&msg);
858         }
859     }
860     GetExitCodeThread(thread, &exitcode);
861     hr = exitcode;
862     ok(hr == S_OK, "CoGetClassObject on local server object "
863        "registered in different thread should return S_OK "
864        "instead of 0x%08x\n", hr);
865
866     hr = get_class_object(CLSCTX_LOCAL_SERVER);
867     ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
868        "thread should return S_OK instead of 0x%08x\n", hr);
869
870     thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)cookie, 0, &tid);
871     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
872     WaitForSingleObject(thread, INFINITE);
873     GetExitCodeThread(thread, &exitcode);
874     hr = exitcode;
875     ok(hr == RPC_E_WRONG_THREAD, "CoRevokeClassObject called from different "
876        "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
877
878     thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
879     ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
880     WaitForSingleObject(thread, INFINITE);
881     GetExitCodeThread(thread, &exitcode);
882     hr = exitcode;
883     ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
884         "thread should return S_OK instead of 0x%08x\n", hr);
885
886     hr = CoRevokeClassObject(cookie);
887     ok_ole_success(hr, "CoRevokeClassObject");
888
889     CoUninitialize();
890 }
891
892 static DWORD CALLBACK free_libraries_thread(LPVOID p)
893 {
894     CoFreeUnusedLibraries();
895     return 0;
896 }
897
898 static inline BOOL is_module_loaded(const char *module)
899 {
900     return GetModuleHandle(module) ? TRUE : FALSE;
901 }
902
903 static void test_CoFreeUnusedLibraries(void)
904 {
905     HRESULT hr;
906     IUnknown *pUnk;
907     DWORD tid;
908     HANDLE thread;
909
910     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
911
912     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
913
914     hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
915     if (hr == REGDB_E_CLASSNOTREG)
916     {
917         trace("IE not installed so can't run CoFreeUnusedLibraries test\n");
918         return;
919     }
920     ok_ole_success(hr, "CoCreateInstance");
921
922     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
923
924     IUnknown_Release(pUnk);
925
926     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
927
928     thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
929     WaitForSingleObject(thread, INFINITE);
930     CloseHandle(thread);
931
932     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
933
934     CoFreeUnusedLibraries();
935
936     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
937
938     CoUninitialize();
939 }
940
941
942 START_TEST(compobj)
943 {
944     HMODULE hOle32 = GetModuleHandle("ole32");
945     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
946     {
947         trace("You need DCOM95 installed to run this test\n");
948         return;
949     }
950
951     test_ProgIDFromCLSID();
952     test_CLSIDFromProgID();
953     test_CLSIDFromString();
954     test_CoCreateInstance();
955     test_ole_menu();
956     test_CoGetClassObject();
957     test_CoRegisterMessageFilter();
958     test_CoRegisterPSClsid();
959     test_CoGetPSClsid();
960     test_CoUnmarshalInterface();
961     test_CoGetInterfaceAndReleaseStream();
962     test_CoMarshalInterface();
963     test_CoMarshalInterThreadInterfaceInStream();
964     test_CoRegisterClassObject();
965     test_registered_object_thread_affinity();
966     test_CoFreeUnusedLibraries();
967 }