d3d9: Use D3DQUERYTYPE instead of HRESULT in IDirect3DQuery9Impl_GetType().
[wine] / dlls / shdocvw / 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(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 BOOL check_ie(void)
183 {
184     IHTMLDocument5 *doc;
185     HRESULT hres;
186
187     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
188                             &IID_IHTMLDocument5, (void**)&doc);
189     if(FAILED(hres))
190         return FALSE;
191
192     IHTMLDocument5_Release(doc);
193     return TRUE;
194 }
195
196 static void test_ReadAndWriteProperties(void)
197 {
198     int iconIndex = 7;
199     PROPSPEC ps[2];
200     HRESULT hr;
201     IUniformResourceLocatorA *urlA;
202     IUniformResourceLocatorA *urlAFromFile;
203     WCHAR fileNameW[MAX_PATH];
204
205     static const WCHAR shortcutW[] = {'t','e','s','t','s','h','o','r','t','c','u','t','.','u','r','l',0};
206     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};
207     char testurl[] = "http://some/bogus/url.html";
208
209     ps[0].ulKind = PRSPEC_PROPID;
210     U(ps[0]).propid = PID_IS_ICONFILE;
211     ps[1].ulKind = PRSPEC_PROPID;
212     U(ps[1]).propid = PID_IS_ICONINDEX;
213
214     /* Make sure we have a valid temporary directory */
215     GetTempPathW(MAX_PATH, fileNameW);
216     lstrcatW(fileNameW, shortcutW);
217
218     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
219     if (hr == S_OK)
220     {
221         IPersistFile *pf;
222         IPropertyStorage *pPropStgWrite;
223         IPropertySetStorage *pPropSetStg;
224         PROPVARIANT pv[2];
225
226         /* We need to set a URL -- IPersistFile refuses to save without one. */
227         hr = urlA->lpVtbl->SetURL(urlA, testurl, 0);
228         ok(hr == S_OK, "Failed to set a URL.  hr=0x%x\n", hr);
229
230         /* Write this shortcut out to a file so that we can test reading it in again. */
231         hr = urlA->lpVtbl->QueryInterface(urlA, &IID_IPersistFile, (void **) &pf);
232         ok(hr == S_OK, "Failed to get the IPersistFile for writing.  hr=0x%x\n", hr);
233
234         hr = IPersistFile_Save(pf, fileNameW, TRUE);
235         ok(hr == S_OK, "Failed to save via IPersistFile. hr=0x%x\n", hr);
236
237         IPersistFile_Release(pf);
238
239         pv[0].vt = VT_LPWSTR;
240         U(pv[0]).pwszVal = (void *) iconPath;
241         pv[1].vt = VT_I4;
242         U(pv[1]).iVal = iconIndex;
243         hr = urlA->lpVtbl->QueryInterface(urlA, &IID_IPropertySetStorage, (void **) &pPropSetStg);
244         ok(hr == S_OK, "Unable to get an IPropertySetStorage, hr=0x%x\n", hr);
245
246         hr = IPropertySetStorage_Open(pPropSetStg, &FMTID_Intshcut, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropStgWrite);
247         ok(hr == S_OK, "Unable to get an IPropertyStorage for writing, hr=0x%x\n", hr);
248
249         hr = IPropertyStorage_WriteMultiple(pPropStgWrite, 2, ps, pv, 0);
250         ok(hr == S_OK, "Unable to set properties, hr=0x%x\n", hr);
251
252         hr = IPropertyStorage_Commit(pPropStgWrite, STGC_DEFAULT);
253         ok(hr == S_OK, "Failed to commit properties, hr=0x%x\n", hr);
254
255         pPropStgWrite->lpVtbl->Release(pPropStgWrite);
256         urlA->lpVtbl->Release(urlA);
257         IPropertySetStorage_Release(pPropSetStg);
258     }
259     else
260         skip("could not create a CLSID_InternetShortcut for property tests, hr=0x%x\n", hr);
261
262     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlAFromFile);
263     if (hr == S_OK)
264     {
265         IPropertySetStorage *pPropSetStg;
266         IPropertyStorage *pPropStgRead;
267         PROPVARIANT pvread[2];
268         IPersistFile *pf;
269         LPSTR url = NULL;
270
271         /* Now read that .url file back in. */
272         hr = urlAFromFile->lpVtbl->QueryInterface(urlAFromFile, &IID_IPersistFile, (void **) &pf);
273         ok(hr == S_OK, "Failed to get the IPersistFile for reading.  hr=0x%x\n", hr);
274
275         hr = IPersistFile_Load(pf, fileNameW, 0);
276         ok(hr == S_OK, "Failed to load via IPersistFile. hr=0x%x\n", hr);
277         IPersistFile_Release(pf);
278
279
280         hr = urlAFromFile->lpVtbl->GetURL(urlAFromFile, &url);
281         ok(hr == S_OK, "Unable to get url from file, hr=0x%x\n", hr);
282         ok(lstrcmp(url, testurl) == 0, "Wrong url read from file: %s\n",url);
283
284
285         hr = urlAFromFile->lpVtbl->QueryInterface(urlAFromFile, &IID_IPropertySetStorage, (void **) &pPropSetStg);
286         ok(hr == S_OK, "Unable to get an IPropertySetStorage, hr=0x%x\n", hr);
287
288         hr = IPropertySetStorage_Open(pPropSetStg, &FMTID_Intshcut, STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropStgRead);
289         ok(hr == S_OK, "Unable to get an IPropertyStorage for reading, hr=0x%x\n", hr);
290
291         hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
292         ok(hr == S_OK, "Unable to read properties, hr=0x%x\n", hr);
293
294         todo_wine /* Wine doesn't yet support setting properties after save */
295         {
296             ok(U(pvread[1]).iVal == iconIndex, "Read wrong icon index: %d\n", U(pvread[1]).iVal);
297
298             ok(lstrcmpW(U(pvread[0]).pwszVal, iconPath) == 0, "Wrong icon path read: %s\n", wine_dbgstr_w(U(pvread[0]).pwszVal));
299         }
300
301         PropVariantClear(&pvread[0]);
302         PropVariantClear(&pvread[1]);
303         IPropertyStorage_Release(pPropStgRead);
304         IPropertySetStorage_Release(pPropSetStg);
305         urlAFromFile->lpVtbl->Release(urlAFromFile);
306         DeleteFileW(fileNameW);
307     }
308     else
309         skip("could not create a CLSID_InternetShortcut for property tests, hr=0x%x\n", hr);
310 }
311
312 static void test_NullURLs(void)
313 {
314     LPSTR url = NULL;
315     HRESULT hr;
316     IUniformResourceLocatorA *urlA;
317
318     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
319     ok(hr == S_OK, "Could not create InternetShortcut object: %08x\n", hr);
320
321     hr = urlA->lpVtbl->GetURL(urlA, &url);
322     ok(hr == S_FALSE, "getting uninitialized URL unexpectedly failed, hr=0x%x\n", hr);
323     ok(url == NULL, "uninitialized URL is not NULL but %s\n", url);
324
325     hr = urlA->lpVtbl->SetURL(urlA, NULL, 0);
326     ok(hr == S_OK, "setting NULL URL unexpectedly failed, hr=0x%x\n", hr);
327
328     hr = urlA->lpVtbl->GetURL(urlA, &url);
329     ok(hr == S_FALSE, "getting NULL URL unexpectedly failed, hr=0x%x\n", hr);
330     ok(url == NULL, "URL unexpectedly not NULL but %s\n", url);
331
332     urlA->lpVtbl->Release(urlA);
333 }
334
335 typedef struct {
336     const char *data;
337     const char *url;
338 } load_test_t;
339
340 static const load_test_t load_tests[] = {
341     {"[InternetShortcut]\n"
342      "URL=http://www.winehq.org/\n"
343      "HotKey=0\n"
344      "IDList=\n"
345      "[{000214A0-0000-0000-C000-000000000046}]\n"
346      "Prop0=1,2\n",
347
348      "http://www.winehq.org/"
349     }
350 };
351
352 static void test_Load(void)
353 {
354     IPersistFile *persist_file;
355     const load_test_t *test;
356     WCHAR file_path[MAX_PATH];
357     DWORD size;
358     HANDLE file;
359     HRESULT hres;
360
361     static const WCHAR test_urlW[] = {'t','e','s','t','.','u','r','l',0};
362
363     GetTempPathW(MAX_PATH, file_path);
364     lstrcatW(file_path, test_urlW);
365
366     for(test = load_tests; test < load_tests + sizeof(load_tests)/sizeof(*load_tests); test++) {
367         file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
368         ok(file != INVALID_HANDLE_VALUE, "could not create test file\n");
369         if(file == INVALID_HANDLE_VALUE)
370             continue;
371
372         WriteFile(file, test->data, strlen(test->data), &size, NULL);
373         CloseHandle(file);
374
375         hres = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IPersistFile, (void**)&persist_file);
376         ok(hres == S_OK, "Could not create InternetShortcut instance: %08x\n", hres);
377
378         hres = IPersistFile_Load(persist_file, file_path, 0);
379         ok(hres == S_OK, "Load failed: %08x\n", hres);
380
381         test_shortcut_url((IUnknown*)persist_file, test->url);
382
383         IPersistFile_Release(persist_file);
384         DeleteFileW(file_path);
385     }
386 }
387
388 static void test_SetURLFlags(void)
389 {
390     HRESULT hr;
391     IUniformResourceLocatorA *urlA;
392
393     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA);
394     ok(hr == S_OK, "Could not create InternetShortcut object: %08x\n", hr);
395
396     check_string_transform(urlA, "somerandomstring", 0, NULL, TRUE);
397     check_string_transform(urlA, "www.winehq.org", 0, NULL, TRUE);
398
399     check_string_transform(urlA, "www.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "http://www.winehq.org/", FALSE);
400     check_string_transform(urlA, "ftp.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "ftp://ftp.winehq.org/", FALSE);
401
402     urlA->lpVtbl->Release(urlA);
403 }
404
405 static void test_InternetShortcut(void)
406 {
407     IUniformResourceLocatorA *url;
408     HRESULT hres;
409
410     hres = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&url);
411     if(FAILED(hres)) {
412         win_skip("Could not create CLSID_InternetShortcut instance: %08x\n", hres);
413         return;
414     }
415
416     test_Aggregability();
417     test_QueryInterface();
418     test_NullURLs();
419     test_SetURLFlags();
420     test_ReadAndWriteProperties();
421     test_Load();
422 }
423
424 START_TEST(intshcut)
425 {
426     OleInitialize(NULL);
427
428     if(check_ie())
429         test_InternetShortcut();
430     else
431         win_skip("Too old IE\n");
432
433     OleUninitialize();
434 }