ole32: Add some more tests for failure cases of Co* functions and make builtin ole32...
[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
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "shlguid.h"
29
30 #include "wine/test.h"
31
32 /* functions that are not present on all versions of Windows */
33 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
34
35 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08lx\n", hr)
36
37 static const CLSID CLSID_non_existent =   { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
38 static const CLSID CLSID_CDeviceMoniker = { 0x4315d437, 0x5b8c, 0x11d0, { 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 } };
39 static const WCHAR devicedotone[] = {'d','e','v','i','c','e','.','1',0};
40 static const WCHAR wszNonExistant[] = {'N','o','n','E','x','i','s','t','a','n','t',0};
41 static const WCHAR wszCLSID_CDeviceMoniker[] =
42 {
43     '{',
44     '4','3','1','5','d','4','3','7','-',
45     '5','b','8','c','-',
46     '1','1','d','0','-',
47     'b','d','3','b','-',
48     '0','0','a','0','c','9','1','1','c','e','8','6',
49     '}',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
60
61 static void test_ProgIDFromCLSID(void)
62 {
63     LPWSTR progid;
64     HRESULT hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, &progid);
65     ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08lx\n", hr);
66     if (hr == S_OK)
67     {
68         ok(!lstrcmpiW(progid, devicedotone), "Didn't get expected prog ID\n");
69         CoTaskMemFree(progid);
70     }
71
72     progid = (LPWSTR)0xdeadbeef;
73     hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
74     ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08lx\n", hr);
75     ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
76
77     hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, NULL);
78     ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08lx\n", hr);
79 }
80
81 static void test_CLSIDFromProgID(void)
82 {
83     CLSID clsid;
84     HRESULT hr = CLSIDFromProgID(devicedotone, &clsid);
85     ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08lx\n", hr);
86     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
87
88     hr = CLSIDFromString((LPOLESTR)devicedotone, &clsid);
89     ok_ole_success(hr, "CLSIDFromString");
90     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
91
92     /* test some failure cases */
93
94     hr = CLSIDFromProgID(wszNonExistant, NULL);
95     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
96
97     hr = CLSIDFromProgID(NULL, &clsid);
98     ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
99
100     memset(&clsid, 0xcc, sizeof(clsid));
101     hr = CLSIDFromProgID(wszNonExistant, &clsid);
102     ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on non-existant ProgID should have returned CO_E_CLASSSTRING instead of 0x%08lx\n", hr);
103     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
104 }
105
106 static void test_CLSIDFromString(void)
107 {
108     CLSID clsid;
109     HRESULT hr = CLSIDFromString((LPOLESTR)wszCLSID_CDeviceMoniker, &clsid);
110     ok_ole_success(hr, "CLSIDFromString");
111     ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n");
112
113     hr = CLSIDFromString(NULL, &clsid);
114     ok_ole_success(hr, "CLSIDFromString");
115     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
116 }
117
118 static void test_CoCreateInstance(void)
119 {
120     REFCLSID rclsid = &CLSID_MyComputer;
121     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
122     HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
123     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08lx\n", hr);
124     ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
125
126     OleInitialize(NULL);
127     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
128     ok_ole_success(hr, "CoCreateInstance");
129     IUnknown_Release(pUnk);
130     OleUninitialize();
131
132     hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
133     ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08lx\n", hr);
134 }
135
136 static void test_CoGetClassObject(void)
137 {
138     IUnknown *pUnk = (IUnknown *)0xdeadbeef;
139     HRESULT hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
140     ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08lx\n", hr);
141     ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
142
143     hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
144     ok(hr == E_INVALIDARG, "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
145 }
146
147 static ATOM register_dummy_class(void)
148 {
149     WNDCLASS wc =
150     {
151         0,
152         DefWindowProc,
153         0,
154         0,
155         GetModuleHandle(NULL),
156         NULL,
157         LoadCursor(NULL, IDC_ARROW),
158         (HBRUSH)(COLOR_BTNFACE+1),
159         NULL,
160         TEXT("WineOleTestClass"),
161     };
162     
163     return RegisterClass(&wc);
164 }
165
166 static void test_ole_menu(void)
167 {
168         HWND hwndFrame;
169         HRESULT hr;
170
171         hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
172         hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
173         todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
174
175         DestroyWindow(hwndFrame);
176 }
177
178
179 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
180 {
181     if (ppvObj == NULL) return E_POINTER;
182
183     if (IsEqualGUID(riid, &IID_IUnknown) ||
184         IsEqualGUID(riid, &IID_IClassFactory))
185     {
186         *ppvObj = (LPVOID)iface;
187         IMessageFilter_AddRef(iface);
188         return S_OK;
189     }
190
191     return E_NOINTERFACE;
192 }
193
194 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
195 {
196     return 2; /* non-heap object */
197 }
198
199 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
200 {
201     return 1; /* non-heap object */
202 }
203
204 static DWORD WINAPI MessageFilter_HandleInComingCall(
205   IMessageFilter *iface,
206   DWORD dwCallType,
207   HTASK threadIDCaller,
208   DWORD dwTickCount,
209   LPINTERFACEINFO lpInterfaceInfo)
210 {
211     trace("HandleInComingCall\n");
212     return SERVERCALL_ISHANDLED;
213 }
214
215 static DWORD WINAPI MessageFilter_RetryRejectedCall(
216   IMessageFilter *iface,
217   HTASK threadIDCallee,
218   DWORD dwTickCount,
219   DWORD dwRejectType)
220 {
221     trace("RetryRejectedCall\n");
222     return 0;
223 }
224
225 static DWORD WINAPI MessageFilter_MessagePending(
226   IMessageFilter *iface,
227   HTASK threadIDCallee,
228   DWORD dwTickCount,
229   DWORD dwPendingType)
230 {
231     trace("MessagePending\n");
232     return PENDINGMSG_WAITNOPROCESS;
233 }
234
235 static const IMessageFilterVtbl MessageFilter_Vtbl =
236 {
237     MessageFilter_QueryInterface,
238     MessageFilter_AddRef,
239     MessageFilter_Release,
240     MessageFilter_HandleInComingCall,
241     MessageFilter_RetryRejectedCall,
242     MessageFilter_MessagePending
243 };
244
245 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
246
247 static void test_CoRegisterMessageFilter(void)
248 {
249     HRESULT hr;
250     IMessageFilter *prev_filter;
251
252 #if 0 /* crashes without an apartment! */
253     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
254 #endif
255
256     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
257     prev_filter = (IMessageFilter *)0xdeadbeef;
258     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
259     ok(hr == CO_E_NOT_SUPPORTED,
260         "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08lx\n",
261         hr);
262     ok(prev_filter == (IMessageFilter *)0xdeadbeef,
263         "prev_filter should have been set to %p\n", prev_filter);
264     CoUninitialize();
265
266     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
267
268     hr = CoRegisterMessageFilter(NULL, NULL);
269     ok_ole_success(hr, "CoRegisterMessageFilter");
270
271     prev_filter = (IMessageFilter *)0xdeadbeef;
272     hr = CoRegisterMessageFilter(NULL, &prev_filter);
273     ok_ole_success(hr, "CoRegisterMessageFilter");
274     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
275
276     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
277     ok_ole_success(hr, "CoRegisterMessageFilter");
278     ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
279
280     hr = CoRegisterMessageFilter(NULL, NULL);
281     ok_ole_success(hr, "CoRegisterMessageFilter");
282
283     CoUninitialize();
284 }
285
286 static HRESULT WINAPI Test_IUnknown_QueryInterface(
287     LPUNKNOWN iface,
288     REFIID riid,
289     LPVOID *ppvObj)
290 {
291     if (ppvObj == NULL) return E_POINTER;
292
293     if (IsEqualIID(riid, &IID_IUnknown) ||
294         IsEqualIID(riid, &IID_IWineTest))
295     {
296         *ppvObj = (LPVOID)iface;
297         IUnknown_AddRef(iface);
298         return S_OK;
299     }
300
301     *ppvObj = NULL;
302     return E_NOINTERFACE;
303 }
304
305 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
306 {
307     return 2; /* non-heap-based object */
308 }
309
310 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
311 {
312     return 1; /* non-heap-based object */
313 }
314
315 static const IUnknownVtbl TestUnknown_Vtbl =
316 {
317     Test_IUnknown_QueryInterface,
318     Test_IUnknown_AddRef,
319     Test_IUnknown_Release,
320 };
321
322 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
323
324 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
325     IPSFactoryBuffer * This,
326     /* [in] */ REFIID riid,
327     /* [iid_is][out] */ void **ppvObject)
328 {
329     if (IsEqualIID(riid, &IID_IUnknown) ||
330         IsEqualIID(riid, &IID_IPSFactoryBuffer))
331     {
332         *ppvObject = This;
333         IPSFactoryBuffer_AddRef(This);
334         return S_OK;
335     }
336     return E_NOINTERFACE;
337 }
338         
339 static ULONG WINAPI PSFactoryBuffer_AddRef(
340     IPSFactoryBuffer * This)
341 {
342     return 2;
343 }
344
345 static ULONG WINAPI PSFactoryBuffer_Release(
346     IPSFactoryBuffer * This)
347 {
348     return 1;
349 }
350
351 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
352     IPSFactoryBuffer * This,
353     /* [in] */ IUnknown *pUnkOuter,
354     /* [in] */ REFIID riid,
355     /* [out] */ IRpcProxyBuffer **ppProxy,
356     /* [out] */ void **ppv)
357 {
358     return E_NOTIMPL;
359 }
360         
361 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
362     IPSFactoryBuffer * This,
363     /* [in] */ REFIID riid,
364     /* [unique][in] */ IUnknown *pUnkServer,
365     /* [out] */ IRpcStubBuffer **ppStub)
366 {
367     return E_NOTIMPL;
368 }
369
370 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
371 {
372     PSFactoryBuffer_QueryInterface,
373     PSFactoryBuffer_AddRef,
374     PSFactoryBuffer_Release,
375     PSFactoryBuffer_CreateProxy,
376     PSFactoryBuffer_CreateStub
377 };
378
379 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
380
381 static const CLSID CLSID_WineTestPSFactoryBuffer =
382 {
383     0x52011640,
384     0x8164,
385     0x4fd0,
386     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
387 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
388
389 static void test_CoRegisterPSClsid(void)
390 {
391     HRESULT hr;
392     DWORD dwRegistrationKey;
393     IStream *stream;
394     CLSID clsid;
395
396     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
397     ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returened CO_E_NOTINITIALIZED instead of 0x%08lx\n", hr);
398
399     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
400
401     hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
402         CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
403     ok_ole_success(hr, "CoRegisterClassObject");
404
405     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
406     ok_ole_success(hr, "CoRegisterPSClsid");
407
408     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
409     ok_ole_success(hr, "CreateStreamOnHGlobal");
410
411     hr = CoMarshalInterface(stream, &IID_IWineTest, (IUnknown *)&Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
412     ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08lx\n", hr);
413     IStream_Release(stream);
414
415     hr = CoRevokeClassObject(dwRegistrationKey);
416     ok_ole_success(hr, "CoRevokeClassObject");
417
418     CoUninitialize();
419
420     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
421
422     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
423     ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08lx\n", hr);
424
425     CoUninitialize();
426 }
427
428 static void test_CoGetPSClsid(void)
429 {
430     HRESULT hr;
431     CLSID clsid;
432
433     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
434     ok(hr == CO_E_NOTINITIALIZED,
435        "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08lx\n",
436        hr);
437
438     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
439
440     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
441     ok_ole_success(hr, "CoGetPSClsid");
442
443     hr = CoGetPSClsid(&IID_IWineTest, &clsid);
444     ok(hr == REGDB_E_IIDNOTREG,
445        "CoGetPSClsid for random IID returned 0x%08lx instead of REGDB_E_IIDNOTREG\n",
446        hr);
447
448     hr = CoGetPSClsid(&IID_IClassFactory, NULL);
449     ok(hr == E_INVALIDARG,
450        "CoGetPSClsid for null clsid returned 0x%08lx instead of E_INVALIDARG\n",
451        hr);
452
453     CoUninitialize();
454 }
455
456
457 START_TEST(compobj)
458 {
459     HMODULE hOle32 = GetModuleHandle("ole32");
460     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
461     {
462         trace("You need DCOM95 installed to run this test\n");
463         return;
464     }
465
466     test_ProgIDFromCLSID();
467     test_CLSIDFromProgID();
468     test_CLSIDFromString();
469     test_CoCreateInstance();
470     test_ole_menu();
471     test_CoGetClassObject();
472     test_CoRegisterMessageFilter();
473     test_CoRegisterPSClsid();
474     test_CoGetPSClsid();
475 }