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