ieframe/tests: Use proper helpers for iface calls.
[wine] / dlls / ieframe / tests / intshcut.c
1 /*
2  * Unit tests to document InternetShortcut's behaviour
3  *
4  * Copyright 2008 Damjan Jovanovic
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 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "shlobj.h"
33 #include "shobjidl.h"
34 #include "shlguid.h"
35 #include "ole2.h"
36 #include "mshtml.h"
37 #include "initguid.h"
38 #include "isguids.h"
39 #include "intshcut.h"
40
41 #include "wine/test.h"
42
43 static HRESULT WINAPI Unknown_QueryInterface(IUnknown *pUnknown, REFIID riid, void **ppvObject)
44 {
45     if (IsEqualGUID(&IID_IUnknown, riid))
46     {
47         *ppvObject = pUnknown;
48         return S_OK;
49     }
50     return E_NOINTERFACE;
51 }
52
53 static ULONG WINAPI Unknown_AddRef(IUnknown *pUnknown)
54 {
55     return 2;
56 }
57
58 static ULONG WINAPI Unknown_Release(IUnknown *pUnknown)
59 {
60     return 1;
61 }
62
63 static IUnknownVtbl unknownVtbl = {
64     Unknown_QueryInterface,
65     Unknown_AddRef,
66     Unknown_Release
67 };
68
69 static IUnknown unknown = {
70     &unknownVtbl
71 };
72
73 static const char *printGUID(const GUID *guid)
74 {
75     static char guidSTR[39];
76
77     if (!guid) return NULL;
78
79     sprintf(guidSTR, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
80      guid->Data1, guid->Data2, guid->Data3,
81      guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
82      guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
83     return guidSTR;
84 }
85
86 static void test_Aggregability(void)
87 {
88     HRESULT hr;
89     IUnknown *pUnknown = NULL;
90
91     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown);
92     ok(hr == S_OK, "could not create instance of CLSID_InternetShortcut with IID_IUnknown, hr = 0x%x\n", hr);
93     if (pUnknown)
94         IUnknown_Release(pUnknown);
95
96     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&pUnknown);
97     ok(hr == S_OK, "could not create instance of CLSID_InternetShortcut with IID_IUniformResourceLocatorA, hr = 0x%x\n", hr);
98     if (pUnknown)
99         IUnknown_Release(pUnknown);
100
101     hr = CoCreateInstance(&CLSID_InternetShortcut, &unknown, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown);
102     ok(hr == CLASS_E_NOAGGREGATION, "aggregation didn't fail like it should, hr = 0x%x\n", hr);
103     if (pUnknown)
104         IUnknown_Release(pUnknown);
105 }
106
107 static void can_query_interface(IUnknown *pUnknown, REFIID riid)
108 {
109     HRESULT hr;
110     IUnknown *newInterface;
111     hr = IUnknown_QueryInterface(pUnknown, riid, (void**)&newInterface);
112     ok(hr == S_OK, "interface %s could not be queried\n", printGUID(riid));
113     if (SUCCEEDED(hr))
114         IUnknown_Release(newInterface);
115 }
116
117 static void test_QueryInterface(void)
118 {
119     HRESULT hr;
120     IUnknown *pUnknown;
121
122     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown);
123     ok(hr == S_OK, "Could not create InternetShortcut object: %08x\n", hr);
124
125     can_query_interface(pUnknown, &IID_IUniformResourceLocatorA);
126     can_query_interface(pUnknown, &IID_IUniformResourceLocatorW);
127     can_query_interface(pUnknown, &IID_IPersistFile);
128     IUnknown_Release(pUnknown);
129 }
130
131 #define test_shortcut_url(a,b) _test_shortcut_url(__LINE__,a,b)
132 static void _test_shortcut_url(unsigned line, IUnknown *unk, const char *exurl)
133 {
134     IUniformResourceLocatorA *locator_a;
135     char *url_a;
136     HRESULT hres;
137
138     hres = IUnknown_QueryInterface(unk, &IID_IUniformResourceLocatorA, (void**)&locator_a);
139     ok_(__FILE__,line)(hres == S_OK, "Could not get IUniformResourceLocatorA iface: %08x\n", hres);
140
141     hres = locator_a->lpVtbl->GetURL(locator_a, &url_a);
142     ok_(__FILE__,line)(hres == S_OK, "GetURL failed: %08x\n", hres);
143     ok_(__FILE__,line)(!strcmp(url_a, exurl), "unexpected URL, got %s, expected %s\n", url_a, exurl);
144     CoTaskMemFree(url_a);
145
146     IUnknown_Release((IUnknown*)locator_a);
147 }
148
149 #define check_string_transform(a,b,c,d,e) _check_string_transform(__LINE__,a,b,c,d,e)
150 static void _check_string_transform(unsigned line, IUniformResourceLocatorA *urlA, LPCSTR input, DWORD flags,
151         LPCSTR expectedOutput, BOOL is_todo)
152 {
153     CHAR *output;
154     HRESULT hr;
155
156     hr = urlA->lpVtbl->SetURL(urlA, input, flags);
157     ok_(__FILE__,line)(hr == S_OK, "SetUrl failed, hr=0x%x\n", hr);
158     if (FAILED(hr))
159         return;
160
161     output = (void*)0xdeadbeef;
162     hr = urlA->lpVtbl->GetURL(urlA, &output);
163     if(expectedOutput) {
164         if(is_todo) {
165             todo_wine
166             ok_(__FILE__,line)(hr == S_OK, "GetUrl failed, hr=0x%x\n", hr);
167         }else {
168             ok_(__FILE__,line)(hr == S_OK, "GetUrl failed, hr=0x%x\n", hr);
169         }
170         todo_wine
171         ok_(__FILE__,line)(!lstrcmpA(output, expectedOutput), "unexpected URL change %s -> %s (expected %s)\n",
172             input, output, expectedOutput);
173         CoTaskMemFree(output);
174     }else {
175         todo_wine
176         ok_(__FILE__,line)(hr == S_FALSE, "GetUrl failed, hr=0x%x\n", hr);
177         todo_wine
178         ok_(__FILE__,line)(!output, "GetUrl returned %s\n", output);
179     }
180 }
181
182 static void test_ReadAndWriteProperties(void)
183 {
184     int iconIndex = 7;
185     PROPSPEC ps[2];
186     HRESULT hr;
187     IUniformResourceLocatorA *urlA;
188     IUniformResourceLocatorA *urlAFromFile;
189     WCHAR fileNameW[MAX_PATH];
190
191     static const WCHAR shortcutW[] = {'t','e','s','t','s','h','o','r','t','c','u','t','.','u','r','l',0};
192     WCHAR iconPath[] = {'f','i','l','e',':','/','/','/','C',':','/','a','r','b','i','t','r','a','r','y','/','i','c','o','n','/','p','a','t','h',0};
193     char testurl[] = "http://some/bogus/url.html";
194
195     ps[0].ulKind = PRSPEC_PROPID;
196     U(ps[0]).propid = PID_IS_ICONFILE;
197     ps[1].ulKind = PRSPEC_PROPID;
198     U(ps[1]).propid = PID_IS_ICONINDEX;
199
200     /* Make sure we have a valid temporary directory */
201     GetTempPathW(MAX_PATH, fileNameW);
202     lstrcatW(fileNameW, shortcutW);
203
204     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
205     ok(hr == S_OK, "Could not create CLSID_InternetShortcut instance: %08x\n", hr);
206     if (hr == S_OK)
207     {
208         IPersistFile *pf;
209         IPropertyStorage *pPropStgWrite;
210         IPropertySetStorage *pPropSetStg;
211         PROPVARIANT pv[2];
212
213         /* We need to set a URL -- IPersistFile refuses to save without one. */
214         hr = urlA->lpVtbl->SetURL(urlA, testurl, 0);
215         ok(hr == S_OK, "Failed to set a URL.  hr=0x%x\n", hr);
216
217         /* Write this shortcut out to a file so that we can test reading it in again. */
218         hr = urlA->lpVtbl->QueryInterface(urlA, &IID_IPersistFile, (void **) &pf);
219         ok(hr == S_OK, "Failed to get the IPersistFile for writing.  hr=0x%x\n", hr);
220
221         hr = IPersistFile_Save(pf, fileNameW, TRUE);
222         ok(hr == S_OK, "Failed to save via IPersistFile. hr=0x%x\n", hr);
223
224         IPersistFile_Release(pf);
225
226         pv[0].vt = VT_LPWSTR;
227         U(pv[0]).pwszVal = (void *) iconPath;
228         pv[1].vt = VT_I4;
229         U(pv[1]).iVal = iconIndex;
230         hr = urlA->lpVtbl->QueryInterface(urlA, &IID_IPropertySetStorage, (void **) &pPropSetStg);
231         ok(hr == S_OK, "Unable to get an IPropertySetStorage, hr=0x%x\n", hr);
232
233         hr = IPropertySetStorage_Open(pPropSetStg, &FMTID_Intshcut, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropStgWrite);
234         ok(hr == S_OK, "Unable to get an IPropertyStorage for writing, hr=0x%x\n", hr);
235
236         hr = IPropertyStorage_WriteMultiple(pPropStgWrite, 2, ps, pv, 0);
237         ok(hr == S_OK, "Unable to set properties, hr=0x%x\n", hr);
238
239         hr = IPropertyStorage_Commit(pPropStgWrite, STGC_DEFAULT);
240         ok(hr == S_OK, "Failed to commit properties, hr=0x%x\n", hr);
241
242         pPropStgWrite->lpVtbl->Release(pPropStgWrite);
243         urlA->lpVtbl->Release(urlA);
244         IPropertySetStorage_Release(pPropSetStg);
245     }
246
247     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlAFromFile);
248     ok(hr == S_OK, "Could not create CLSID_InternetShortcut instance: %08x\n", hr);
249     if (hr == S_OK)
250     {
251         IPropertySetStorage *pPropSetStg;
252         IPropertyStorage *pPropStgRead;
253         PROPVARIANT pvread[2];
254         IPersistFile *pf;
255         LPSTR url = NULL;
256
257         /* Now read that .url file back in. */
258         hr = urlAFromFile->lpVtbl->QueryInterface(urlAFromFile, &IID_IPersistFile, (void **) &pf);
259         ok(hr == S_OK, "Failed to get the IPersistFile for reading.  hr=0x%x\n", hr);
260
261         hr = IPersistFile_Load(pf, fileNameW, 0);
262         ok(hr == S_OK, "Failed to load via IPersistFile. hr=0x%x\n", hr);
263         IPersistFile_Release(pf);
264
265
266         hr = urlAFromFile->lpVtbl->GetURL(urlAFromFile, &url);
267         ok(hr == S_OK, "Unable to get url from file, hr=0x%x\n", hr);
268         ok(lstrcmp(url, testurl) == 0, "Wrong url read from file: %s\n",url);
269
270
271         hr = urlAFromFile->lpVtbl->QueryInterface(urlAFromFile, &IID_IPropertySetStorage, (void **) &pPropSetStg);
272         ok(hr == S_OK, "Unable to get an IPropertySetStorage, hr=0x%x\n", hr);
273
274         hr = IPropertySetStorage_Open(pPropSetStg, &FMTID_Intshcut, STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropStgRead);
275         ok(hr == S_OK, "Unable to get an IPropertyStorage for reading, hr=0x%x\n", hr);
276
277         hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
278         ok(hr == S_OK, "Unable to read properties, hr=0x%x\n", hr);
279
280         todo_wine /* Wine doesn't yet support setting properties after save */
281         {
282             ok(U(pvread[1]).iVal == iconIndex, "Read wrong icon index: %d\n", U(pvread[1]).iVal);
283
284             ok(lstrcmpW(U(pvread[0]).pwszVal, iconPath) == 0, "Wrong icon path read: %s\n", wine_dbgstr_w(U(pvread[0]).pwszVal));
285         }
286
287         PropVariantClear(&pvread[0]);
288         PropVariantClear(&pvread[1]);
289         IPropertyStorage_Release(pPropStgRead);
290         IPropertySetStorage_Release(pPropSetStg);
291         urlAFromFile->lpVtbl->Release(urlAFromFile);
292         DeleteFileW(fileNameW);
293     }
294 }
295
296 static void test_NullURLs(void)
297 {
298     LPSTR url = NULL;
299     HRESULT hr;
300     IUniformResourceLocatorA *urlA;
301
302     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
303     ok(hr == S_OK, "Could not create InternetShortcut object: %08x\n", hr);
304
305     hr = urlA->lpVtbl->GetURL(urlA, &url);
306     ok(hr == S_FALSE, "getting uninitialized URL unexpectedly failed, hr=0x%x\n", hr);
307     ok(url == NULL, "uninitialized URL is not NULL but %s\n", url);
308
309     hr = urlA->lpVtbl->SetURL(urlA, NULL, 0);
310     ok(hr == S_OK, "setting NULL URL unexpectedly failed, hr=0x%x\n", hr);
311
312     hr = urlA->lpVtbl->GetURL(urlA, &url);
313     ok(hr == S_FALSE, "getting NULL URL unexpectedly failed, hr=0x%x\n", hr);
314     ok(url == NULL, "URL unexpectedly not NULL but %s\n", url);
315
316     urlA->lpVtbl->Release(urlA);
317 }
318
319 typedef struct {
320     const char *data;
321     const char *url;
322 } load_test_t;
323
324 static const load_test_t load_tests[] = {
325     {"[InternetShortcut]\n"
326      "URL=http://www.winehq.org/\n"
327      "HotKey=0\n"
328      "IDList=\n"
329      "[{000214A0-0000-0000-C000-000000000046}]\n"
330      "Prop0=1,2\n",
331
332      "http://www.winehq.org/"
333     }
334 };
335
336 static void test_Load(void)
337 {
338     IPersistFile *persist_file;
339     const load_test_t *test;
340     WCHAR file_path[MAX_PATH];
341     DWORD size;
342     HANDLE file;
343     HRESULT hres;
344
345     static const WCHAR test_urlW[] = {'t','e','s','t','.','u','r','l',0};
346
347     GetTempPathW(MAX_PATH, file_path);
348     lstrcatW(file_path, test_urlW);
349
350     for(test = load_tests; test < load_tests + sizeof(load_tests)/sizeof(*load_tests); test++) {
351         file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
352         ok(file != INVALID_HANDLE_VALUE, "could not create test file\n");
353         if(file == INVALID_HANDLE_VALUE)
354             continue;
355
356         WriteFile(file, test->data, strlen(test->data), &size, NULL);
357         CloseHandle(file);
358
359         hres = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IPersistFile, (void**)&persist_file);
360         ok(hres == S_OK, "Could not create InternetShortcut instance: %08x\n", hres);
361
362         hres = IPersistFile_Load(persist_file, file_path, 0);
363         ok(hres == S_OK, "Load failed: %08x\n", hres);
364
365         test_shortcut_url((IUnknown*)persist_file, test->url);
366
367         IPersistFile_Release(persist_file);
368         DeleteFileW(file_path);
369     }
370 }
371
372 static void test_SetURLFlags(void)
373 {
374     HRESULT hr;
375     IUniformResourceLocatorA *urlA;
376
377     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
378     ok(hr == S_OK, "Could not create InternetShortcut object: %08x\n", hr);
379
380     check_string_transform(urlA, "somerandomstring", 0, NULL, TRUE);
381     check_string_transform(urlA, "www.winehq.org", 0, NULL, TRUE);
382
383     check_string_transform(urlA, "www.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "http://www.winehq.org/", FALSE);
384     check_string_transform(urlA, "ftp.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "ftp://ftp.winehq.org/", FALSE);
385
386     urlA->lpVtbl->Release(urlA);
387 }
388
389 static void test_InternetShortcut(void)
390 {
391     IUniformResourceLocatorA *url;
392     HRESULT hres;
393
394     hres = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&url);
395     ok(hres == S_OK, "Could not create CLSID_InternetShortcut instance: %08x\n", hres);
396     if(FAILED(hres))
397         return;
398
399     test_Aggregability();
400     test_QueryInterface();
401     test_NullURLs();
402     test_SetURLFlags();
403     test_ReadAndWriteProperties();
404     test_Load();
405 }
406
407 START_TEST(intshcut)
408 {
409     OleInitialize(NULL);
410
411     test_InternetShortcut();
412
413     OleUninitialize();
414 }