Release 1.5.29.
[wine] / dlls / ole32 / tests / defaulthandler.c
1 /*
2  * Default Handler Tests
3  *
4  * Copyright 2008 Huw Davies
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 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
30
31 #include "wine/test.h"
32
33 #define DEFINE_EXPECT(func) \
34     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
35
36 #define SET_EXPECT(func) \
37     expect_ ## func = TRUE
38
39 #define CHECK_EXPECT2(func) \
40     do { \
41         ok(expect_ ##func, "unexpected call " #func "\n"); \
42         called_ ## func = TRUE; \
43     }while(0)
44
45 #define CHECK_EXPECT(func) \
46     do { \
47         CHECK_EXPECT2(func); \
48         expect_ ## func = FALSE; \
49     }while(0)
50
51 #define CHECK_CALLED(func) \
52     do { \
53         ok(called_ ## func, "expected " #func "\n"); \
54         expect_ ## func = called_ ## func = FALSE; \
55     }while(0)
56
57 DEFINE_EXPECT(CF_QueryInterface_ClassFactory);
58 DEFINE_EXPECT(CF_CreateInstance);
59
60 static const char *debugstr_guid(REFIID riid)
61 {
62     static char buf[50];
63
64     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
65             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
66             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
67             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
68
69     return buf;
70 }
71
72 static HRESULT create_storage(IStorage **stg)
73 {
74     HRESULT hr;
75     ILockBytes *lock_bytes;
76
77     hr = CreateILockBytesOnHGlobal(NULL, TRUE, &lock_bytes);
78     if(SUCCEEDED(hr))
79     {
80         hr = StgCreateDocfileOnILockBytes(lock_bytes,
81                   STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, stg);
82         ILockBytes_Release(lock_bytes);
83     }
84     return hr;
85 }
86
87 typedef struct
88 {
89     DWORD version;
90     DWORD flags;
91     DWORD link_update_opt;
92     DWORD res;
93     DWORD moniker_size;
94 } ole_stream_header_t;
95
96 static void test_olestream(void)
97 {
98     HRESULT hr;
99     const CLSID non_existent_class = {0xa5f1772f, 0x3772, 0x490f, {0x9e, 0xc6, 0x77, 0x13, 0xe8, 0xb3, 0x4b, 0x5d}};
100     IOleObject *ole_obj;
101     IPersistStorage *persist;
102     IStorage *stg;
103     IStream *stm;
104     static const WCHAR olestream[] = {1,'O','l','e',0};
105     ULONG read;
106     ole_stream_header_t header;
107
108     hr = create_storage(&stg);
109     ok(hr == S_OK, "got %08x\n", hr);
110
111     hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm);
112     ok(hr == STG_E_FILENOTFOUND, "got %08x\n", hr);
113
114     hr = OleCreateDefaultHandler(&non_existent_class, 0, &IID_IOleObject, (void**)&ole_obj);
115     ok(hr == S_OK, "got %08x\n", hr);
116
117     hr = IOleObject_QueryInterface(ole_obj, &IID_IPersistStorage, (void**)&persist);
118     ok(hr == S_OK, "got %08x\n", hr);
119
120     hr = IPersistStorage_InitNew(persist, stg);
121     ok(hr == S_OK, "got %08x\n", hr);
122
123     hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm);
124     ok(hr == S_OK, "got %08x\n", hr);
125     hr = IStream_Read(stm, &header, sizeof(header), &read);
126     ok(hr == S_OK, "got %08x\n", hr);
127     ok(read == sizeof(header), "read %d\n", read);
128     ok(header.version == 0x02000001, "got version %08x\n", header.version);
129     ok(header.flags == 0x0, "got flags %08x\n", header.flags);
130     ok(header.link_update_opt == 0x0, "got link update option %08x\n", header.link_update_opt);
131     ok(header.res == 0x0, "got reserved %08x\n", header.res);
132     ok(header.moniker_size == 0x0, "got moniker size %08x\n", header.moniker_size);
133
134     IStream_Release(stm);
135
136     IPersistStorage_Release(persist);
137     IOleObject_Release(ole_obj);
138
139     IStorage_Release(stg);
140 }
141
142 static HRESULT WINAPI test_class_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
143 {
144     if(IsEqualGUID(riid, &IID_IUnknown)) {
145         *ppv = iface;
146         return S_OK;
147     }else if(IsEqualGUID(riid, &IID_IOleObject)) {
148         ok(0, "unexpected query for IOleObject interface\n");
149         *ppv = NULL;
150         return E_NOINTERFACE;
151     }
152
153     *ppv = NULL;
154     return E_NOINTERFACE;
155 }
156
157 static ULONG WINAPI test_class_AddRef(IUnknown *iface)
158 {
159     return 2;
160 }
161
162 static ULONG WINAPI test_class_Release(IUnknown *iface)
163 {
164     return 1;
165 }
166
167 static IUnknownVtbl test_class_vtbl = {
168     test_class_QueryInterface,
169     test_class_AddRef,
170     test_class_Release,
171 };
172
173 static IUnknown test_class = { &test_class_vtbl };
174
175 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
176 {
177     if(IsEqualGUID(riid, &IID_IUnknown)) {
178         *ppv = iface;
179         return S_OK;
180     }else if(IsEqualGUID(riid, &IID_IMarshal)) {
181         *ppv = NULL;
182         return E_NOINTERFACE;
183     }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
184         CHECK_EXPECT(CF_QueryInterface_ClassFactory);
185         *ppv = iface;
186         return S_OK;
187     }
188
189     ok(0, "unexpected interface: %s\n", debugstr_guid(riid));
190     *ppv = NULL;
191     return E_NOINTERFACE;
192 }
193
194 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
195 {
196     return 2;
197 }
198
199 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
200 {
201     return 1;
202 }
203
204 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
205         IUnknown *pUnkOuter, REFIID riid, void **ppv)
206 {
207     CHECK_EXPECT(CF_CreateInstance);
208
209     ok(pUnkOuter == NULL, "pUnkOuter != NULL\n");
210     todo_wine ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", debugstr_guid(riid));
211     if(IsEqualGUID(riid, &IID_IOleObject)) {
212         *ppv = NULL;
213         return E_NOINTERFACE;
214     }
215
216     *ppv = &test_class;
217     return S_OK;
218 }
219
220 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
221 {
222     ok(0, "unexpected call\n");
223     return E_NOTIMPL;
224 }
225
226 static IClassFactoryVtbl ClassFactoryVtbl = {
227     ClassFactory_QueryInterface,
228     ClassFactory_AddRef,
229     ClassFactory_Release,
230     ClassFactory_CreateInstance,
231     ClassFactory_LockServer
232 };
233
234 static IClassFactory ClassFactory = { &ClassFactoryVtbl };
235
236 static void test_default_handler_run(void)
237 {
238     const CLSID test_server_clsid = {0x0f77e570,0x80c3,0x11e2,{0x9e,0x96,0x08,0x00,0x20,0x0c,0x9a,0x66}};
239
240     IUnknown *unk;
241     IRunnableObject *ro;
242     DWORD class_reg;
243     HRESULT hres;
244
245     if(!GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx")) {
246         win_skip("skipping OleCreateDefaultHandler tests\n");
247         return;
248     }
249
250     hres = CoRegisterClassObject(&test_server_clsid, (IUnknown*)&ClassFactory,
251             CLSCTX_INPROC_SERVER, 0, &class_reg);
252     ok(hres == S_OK, "CoRegisterClassObject failed: %x\n", hres);
253
254     hres = OleCreateDefaultHandler(&test_server_clsid, NULL, &IID_IUnknown, (void**)&unk);
255     ok(hres == S_OK, "OleCreateDefaultHandler failed: %x\n", hres);
256
257     hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&ro);
258     ok(hres == S_OK, "QueryInterface(IRunnableObject) failed: %x\n", hres);
259     IUnknown_Release(unk);
260
261     hres = IRunnableObject_Run(ro, NULL);
262     ok(hres == REGDB_E_CLASSNOTREG, "Run returned: %x, expected REGDB_E_CLASSNOTREG\n", hres);
263     IRunnableObject_Release(ro);
264
265     CoRevokeClassObject(class_reg);
266
267     hres = CoRegisterClassObject(&test_server_clsid, (IUnknown*)&ClassFactory,
268             CLSCTX_LOCAL_SERVER, 0, &class_reg);
269     ok(hres == S_OK, "CoRegisterClassObject failed: %x\n", hres);
270
271     hres = OleCreateDefaultHandler(&test_server_clsid, NULL, &IID_IUnknown, (void**)&unk);
272     ok(hres == S_OK, "OleCreateDefaultHandler failed: %x\n", hres);
273
274     hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&ro);
275     ok(hres == S_OK, "QueryInterface(IRunnableObject) failed: %x\n", hres);
276     IUnknown_Release(unk);
277
278     SET_EXPECT(CF_QueryInterface_ClassFactory);
279     SET_EXPECT(CF_CreateInstance);
280     hres = IRunnableObject_Run(ro, NULL);
281     todo_wine ok(hres == S_OK, "Run failed: %x\n", hres);
282     CHECK_CALLED(CF_QueryInterface_ClassFactory);
283     CHECK_CALLED(CF_CreateInstance);
284     IRunnableObject_Release(ro);
285
286     CoRevokeClassObject(class_reg);
287 }
288
289 START_TEST(defaulthandler)
290 {
291     OleInitialize(NULL);
292
293     test_olestream();
294     test_default_handler_run();
295
296     OleUninitialize();
297 }