ole32/tests: Prevent a crash.
[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 HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
37
38 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
39 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
40 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
41
42 static const CLSID CLSID_non_existent =   { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
43 static const CLSID CLSID_CDeviceMoniker = { 0x4315d437, 0x5b8c, 0x11d0, { 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 } };
44 static WCHAR devicedotone[] = {'d','e','v','i','c','e','.','1',0};
45 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
46 static WCHAR wszCLSID_CDeviceMoniker[] =
47 {
48     '{',
49     '4','3','1','5','d','4','3','7','-',
50     '5','b','8','c','-',
51     '1','1','d','0','-',
52     'b','d','3','b','-',
53     '0','0','a','0','c','9','1','1','c','e','8','6',
54     '}',0
55 };
56
57 static const IID IID_IWineTest =
58 {
59     0x5201163f,
60     0x8164,
61     0x4fd0,
62     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
63 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
64 static const CLSID CLSID_WineOOPTest = {
65     0x5201163f,
66     0x8164,
67     0x4fd0,
68     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
69 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
70
71 static LONG cLocks;
72
73 static void LockModule(void)
74 {
75     InterlockedIncrement(&cLocks);
76 }
77
78 static void UnlockModule(void)
79 {
80     InterlockedDecrement(&cLocks);
81 }
82
83 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
84     LPCLASSFACTORY iface,
85     REFIID riid,
86     LPVOID *ppvObj)
87 {
88     if (ppvObj == NULL) return E_POINTER;
89
90     if (IsEqualGUID(riid, &IID_IUnknown) ||
91         IsEqualGUID(riid, &IID_IClassFactory))
92     {
93         *ppvObj = (LPVOID)iface;
94         IClassFactory_AddRef(iface);
95         return S_OK;
96     }
97
98     *ppvObj = NULL;
99     return E_NOINTERFACE;
100 }
101
102 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
103 {
104     LockModule();
105     return 2; /* non-heap-based object */
106 }
107
108 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
109 {
110     UnlockModule();
111     return 1; /* non-heap-based object */
112 }
113
114 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
115     LPCLASSFACTORY iface,
116     LPUNKNOWN pUnkOuter,
117     REFIID riid,
118     LPVOID *ppvObj)
119 {
120     *ppvObj = NULL;
121     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
122     return E_NOINTERFACE;
123 }
124
125 static HRESULT WINAPI Test_IClassFactory_LockServer(
126     LPCLASSFACTORY iface,
127     BOOL fLock)
128 {
129     return S_OK;
130 }
131
132 static const IClassFactoryVtbl TestClassFactory_Vtbl =
133 {
134     Test_IClassFactory_QueryInterface,
135     Test_IClassFactory_AddRef,
136     Test_IClassFactory_Release,
137     Test_IClassFactory_CreateInstance,
138     Test_IClassFactory_LockServer
139 };
140
141 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
142
143 static void test_ProgIDFromCLSID(void)
144 {
145     LPWSTR progid;
146     HRESULT hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, &progid);
147     ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
148     if (hr == S_OK)
149     {
150         ok(!lstrcmpiW(progid, devicedotone), "Didn't get expected prog ID\n");
151         CoTaskMemFree(progid);
152     }
153
154     progid = (LPWSTR)0xdeadbeef;
155     hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
156     ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
157     ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
158
159     hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, NULL);
160     ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
161 }
162
163 static void test_CLSIDFromProgID(void)
164 {
165     CLSID clsid;
166     HRESULT hr = CLSIDFromProgID(devicedotone, &clsid);
167     ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
168     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
169
170     hr = CLSIDFromString(devicedotone, &clsid);
171     ok_ole_success(hr, "CLSIDFromString");
172     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
173
174     /* test some failure cases */
175
176     hr = CLSIDFromProgID(wszNonExistent, NULL);
177     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
178
179     hr = CLSIDFromProgID(NULL, &clsid);
180     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
181
182     memset(&clsid, 0xcc, sizeof(clsid));
183     hr = CLSIDFromProgID(wszNonExistent, &clsid);
184     ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
185     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
186 }
187
188 static void test_CLSIDFromString(void)
189 {
190     CLSID clsid;
191     HRESULT hr = CLSIDFromString(wszCLSID_CDeviceMoniker, &clsid);
192     ok_ole_success(hr, "CLSIDFromString");
193     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
194
195     hr = CLSIDFromString(NULL, &clsid);
196     ok_ole_success(hr, "CLSIDFromString");
197     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
198 }
199
200 static void test_StringFromGUID2(void)
201 {
202   WCHAR str[50];
203   int len;
204   /* Test corner cases for buffer size */
205   len = StringFromGUID2(&CLSID_CDeviceMoniker,str,50);
206   ok(len == 39, "len: %d (expected 39)\n", len);
207   ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n");
208
209   memset(str,0,sizeof str);
210   len = StringFromGUID2(&CLSID_CDeviceMoniker,str,39);
211   ok(len == 39, "len: %d (expected 39)\n", len);
212   ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n");
213
214   len = StringFromGUID2(&CLSID_CDeviceMoniker,str,38);
215   ok(len == 0, "len: %d (expected 0)\n", len);
216
217   len = StringFromGUID2(&CLSID_CDeviceMoniker,str,30);
218   ok(len == 0, "len: %d (expected 0)\n", len);
219 }
220
221 static void test_CoCreateInstance(void)
222 {
223     REFCLSID rclsid = &CLSID_MyComputer;
224     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
225     HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
226     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
227     ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
228
229     OleInitialize(NULL);
230     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
231     ok_ole_success(hr, "CoCreateInstance");
232     if(pUnk) IUnknown_Release(pUnk);
233     OleUninitialize();
234
235     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
236     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
237 }
238
239 static void test_CoGetClassObject(void)
240 {
241     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
242     HRESULT hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
243     ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
244     ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
245
246     hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
247     ok(hr == E_INVALIDARG, "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)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_IUnknown, (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, "Expected a valid pointer\n");
948     if (pUnk)
949         IUnknown_Release(pUnk);
950
951     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
952
953     thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
954     WaitForSingleObject(thread, INFINITE);
955     CloseHandle(thread);
956
957     ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
958
959     CoFreeUnusedLibraries();
960
961     ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
962
963     CoUninitialize();
964 }
965
966 static void test_CoGetObjectContext(void)
967 {
968     HRESULT hr;
969     ULONG refs;
970     IComThreadingInfo *pComThreadingInfo;
971     APTTYPE apttype;
972     THDTYPE thdtype;
973
974     if (!pCoGetObjectContext)
975     {
976         skip("CoGetObjectContext not present\n");
977         return;
978     }
979
980     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
981     ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
982     ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
983
984     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
985
986     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
987     ok_ole_success(hr, "CoGetObjectContext");
988
989     hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
990     ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
991     ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
992
993     hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
994     ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
995     ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
996
997     refs = IComThreadingInfo_Release(pComThreadingInfo);
998     ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
999
1000     CoUninitialize();
1001
1002     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1003
1004     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1005     ok_ole_success(hr, "CoGetObjectContext");
1006
1007     hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1008     ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1009     ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1010
1011     hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1012     ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1013     ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1014
1015     refs = IComThreadingInfo_Release(pComThreadingInfo);
1016     ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1017
1018     CoUninitialize();
1019 }
1020
1021 START_TEST(compobj)
1022 {
1023     HMODULE hOle32 = GetModuleHandle("ole32");
1024     pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
1025     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
1026     {
1027         trace("You need DCOM95 installed to run this test\n");
1028         return;
1029     }
1030
1031     test_ProgIDFromCLSID();
1032     test_CLSIDFromProgID();
1033     test_CLSIDFromString();
1034     test_StringFromGUID2();
1035     test_CoCreateInstance();
1036     test_ole_menu();
1037     test_CoGetClassObject();
1038     test_CoRegisterMessageFilter();
1039     test_CoRegisterPSClsid();
1040     test_CoGetPSClsid();
1041     test_CoUnmarshalInterface();
1042     test_CoGetInterfaceAndReleaseStream();
1043     test_CoMarshalInterface();
1044     test_CoMarshalInterThreadInterfaceInStream();
1045     test_CoRegisterClassObject();
1046     test_registered_object_thread_affinity();
1047     test_CoFreeUnusedLibraries();
1048     test_CoGetObjectContext();
1049 }