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