user32/tests: Fix some window test failures on various Windows platforms.
[wine] / dlls / hlink / tests / hlink.c
1 /*
2  * Implementation of hyperlinking (hlink.dll)
3  *
4  * Copyright 2006 Mike McCormack
5  * Copyright 2007-2008 Jacek Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23
24 #include <stdio.h>
25
26 #include <initguid.h>
27 #include <hlink.h>
28 #include <hlguids.h>
29
30 #include "wine/test.h"
31
32 #define DEFINE_EXPECT(func) \
33     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
34
35 #define SET_EXPECT(func) \
36     expect_ ## func = TRUE
37
38 #define CHECK_EXPECT2(func) \
39     do { \
40         ok(expect_ ##func, "unexpected call " #func "\n"); \
41         called_ ## func = TRUE; \
42     }while(0)
43
44 #define CHECK_EXPECT(func) \
45     do { \
46         CHECK_EXPECT2(func); \
47         expect_ ## func = FALSE; \
48     }while(0)
49
50 #define CHECK_CALLED(func) \
51     do { \
52         ok(called_ ## func, "expected " #func "\n"); \
53         expect_ ## func = called_ ## func = FALSE; \
54     }while(0)
55
56 DEFINE_EXPECT(IsSystemMoniker);
57 DEFINE_EXPECT(BindToStorage);
58 DEFINE_EXPECT(GetDisplayName);
59
60 static const char *debugstr_w(LPCWSTR str)
61 {
62     static char buf[1024];
63     if(!str)
64         return "(null)";
65     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
66     return buf;
67 }
68
69 static const char *debugstr_guid(REFIID riid)
70 {
71     static char buf[50];
72
73     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
74             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
75             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
76             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
77
78     return buf;
79 }
80
81 static void test_HlinkIsShortcut(void)
82 {
83     int i;
84     HRESULT hres;
85
86     static const WCHAR file0[] = {'f','i','l','e',0};
87     static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
88     static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
89     static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
90     static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
91     static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
92     static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
93     static const WCHAR file7[] = {'.','u','r','l',0};
94
95     static struct {
96         LPCWSTR file;
97         HRESULT hres;
98     } shortcut_test[] = {
99         {file0, S_FALSE},
100         {file1, S_OK},
101         {file2, S_FALSE},
102         {file3, S_OK},
103         {file4, S_FALSE},
104         {file5, S_OK},
105         {file6, S_FALSE},
106         {file7, S_OK},
107         {NULL,  E_INVALIDARG}
108     };
109
110     for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
111         hres = HlinkIsShortcut(shortcut_test[i].file);
112         ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
113            i, hres, shortcut_test[i].hres);
114     }
115 }
116
117 static void test_reference(void)
118 {
119     HRESULT r;
120     IHlink *lnk = NULL;
121     IMoniker *mk = NULL;
122     const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
123     const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
124     LPWSTR str = NULL;
125
126     r = HlinkCreateFromString(url, NULL, NULL, NULL,
127                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
128     ok(r == S_OK, "failed to create link\n");
129     if (FAILED(r))
130         return;
131
132     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
133     ok(r == S_OK, "failed\n");
134
135     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
136     ok(r == S_OK, "failed\n");
137     ok(mk != NULL, "no moniker\n");
138     ok(str == NULL, "string should be null\n");
139
140     r = IMoniker_Release(mk);
141     ok( r == 1, "moniker refcount wrong\n");
142
143     r = IHlink_GetStringReference(lnk, -1, &str, NULL);
144     ok(r == S_OK, "failed\n");
145     CoTaskMemFree(str);
146
147     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
148     ok(r == S_OK, "failed\n");
149     todo_wine {
150     ok(!lstrcmpW(str, url2), "url wrong\n");
151     }
152     CoTaskMemFree(str);
153
154     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
155     ok(r == S_OK, "failed\n");
156
157     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
158     ok(r == S_OK, "failed\n");
159     ok(str == NULL, "string should be null\n");
160
161     /* Unimplented functions checks */
162     r = IHlink_GetAdditionalParams(lnk, NULL);
163     ok(r == E_NOTIMPL, "failed\n");
164
165     r = IHlink_SetAdditionalParams(lnk, NULL);
166     ok(r == E_NOTIMPL, "failed\n");
167
168     IHlink_Release(lnk);
169 }
170
171 /* url only */
172 static const unsigned char expected_hlink_data[] =
173 {
174     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
175     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
176     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
177     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
178     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
179     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
180     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
181     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
182     0x00,0x00,
183 };
184
185 /* url only (IE7) */
186 static const unsigned char expected_hlink_data_ie7[] =
187 {
188     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
189     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
190     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
191     0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
192     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
193     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
194     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
195     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
196     0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d,
197     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
198     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
199     0x00,0x00,
200 };
201
202 /* url + friendly name */
203 static const unsigned char expected_hlink_data2[] =
204 {
205     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
206     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
207     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
208     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
209     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
210     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
211     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
212     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
213     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
214     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
215     0x67,0x00,0x2f,0x00,0x00,0x00,
216 };
217
218 /* url + friendly name (IE7) */
219 static const unsigned char expected_hlink_data2_ie7[] =
220 {
221     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
222     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
223     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
224     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
225     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
226     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
227     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
228     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
229     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
230     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
231     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
232     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
233     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
234     0x00,0x00,0xa5,0xab,0x00,0x00,
235 };
236
237 /* url + friendly name + location */
238 static const unsigned char expected_hlink_data3[] =
239 {
240     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
241     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
242     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
243     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
244     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
245     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
246     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
247     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
248     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
249     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
250     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
251     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
252     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
253 };
254
255 /* url + friendly name + location (IE7) */
256 static const unsigned char expected_hlink_data3_ie7[] =
257 {
258     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
259     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
260     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
261     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
262     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
263     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
264     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
265     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
266     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
267     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
268     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
269     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
270     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
271     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
272     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
273     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
274 };
275
276 /* relative url */
277 static const unsigned char expected_hlink_data4[] =
278 {
279     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
280     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
281     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
282     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
283     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
284     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
285     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
286     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
287     0x00,0x00,0x00,0x00,0x00,
288 };
289
290 /* url + target frame name */
291 static const unsigned char expected_hlink_data5[] =
292 {
293     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
294     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
295     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
296     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
297     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
298     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
299     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
300     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
301     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
302     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
303     0x2f,0x00,0x00,0x00,
304 };
305
306 /* url + target frame name (IE7) */
307 static const unsigned char expected_hlink_data5_ie7[] =
308 {
309     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
310     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
311     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
312     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
313     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
314     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
315     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
316     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
317     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
318     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
319     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
320     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
321     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
322     0xa5,0xab,0x00,0x00,
323 };
324
325 /* filename */
326 static const unsigned char expected_hlink_data6[] =
327 {
328      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
329      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
330      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
331      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
332      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
333      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
334      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
335      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
336      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
337      0x5c,0x00,
338 };
339
340 static void test_persist_save_data(const char *testname, IHlink *lnk,
341                                    const unsigned char *expected_data,
342                                    unsigned int expected_data_size,
343                                    const unsigned char *expected_data_alt,
344                                    unsigned int expected_data_alt_size)
345 {
346     HRESULT hr;
347     IStream *stream;
348     IPersistStream *ps;
349     HGLOBAL hglobal;
350     DWORD data_size;
351     const unsigned char *data;
352     DWORD i;
353     BOOL same;
354     unsigned int expected_data_win9x_size = 0;
355
356     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
357     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
358
359     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
360     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
361
362     hr = IPersistStream_Save(ps, stream, TRUE);
363     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
364
365     hr = GetHGlobalFromStream(stream, &hglobal);
366     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
367
368     data_size = GlobalSize(hglobal);
369
370     data = GlobalLock(hglobal);
371
372     if (expected_data_size % 4)
373         expected_data_win9x_size =  4 * ((expected_data_size / 4) + 1);
374
375     /* first check we have the right amount of data */
376     ok((data_size == expected_data_size) ||
377        (data_size == expected_data_alt_size) ||
378        broken(data_size == expected_data_win9x_size), /* Win9x and WinMe */
379        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
380        testname, expected_data_size, expected_data_alt_size, data_size);
381
382     same = TRUE;
383     /* then do a byte-by-byte comparison */
384     for (i = 0; i < min(data_size, expected_data_size); i++)
385     {
386         if ((expected_data[i] != data[i]) &&
387             (((expected_data != expected_hlink_data2) &&
388               (expected_data != expected_hlink_data3)) ||
389              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
390         {
391             same = FALSE;
392             break;
393         }
394     }
395
396     if (!same && (expected_data_alt != expected_data))
397     {
398         /* then try the alternate data */
399         same = TRUE;
400         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
401         {
402             if ((expected_data_alt[i] != data[i]) &&
403                 (((expected_data_alt != expected_hlink_data2) &&
404                   (expected_data_alt != expected_hlink_data3)) ||
405                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
406             {
407                 same = FALSE;
408                 break;
409             }
410         }
411     }
412
413     ok(same, "%s: Saved data differs\n", testname);
414     if (!same)
415     {
416         for (i = 0; i < data_size; i++)
417         {
418             if (i % 8 == 0) printf("    ");
419             printf("0x%02x,", data[i]);
420             if (i % 8 == 7) printf("\n");
421         }
422         printf("\n");
423     }
424
425     GlobalUnlock(hglobal);
426
427     IStream_Release(stream);
428     IPersistStream_Release(ps);
429 }
430
431 static void test_persist(void)
432 {
433     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
434     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
435     static const WCHAR filename[] = { 'c',':','\\',0 };
436     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
437     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
438     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
439     HRESULT hr;
440     IHlink *lnk;
441
442     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
443                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
444     ok(hr == S_OK, "IHlinkCreateFromString failed with error 0x%08x\n", hr);
445     if (!lnk) {
446         skip("Can't create lnk, skipping test_persist.  Was wineprefixcreate run properly?\n");
447         return;
448     }
449     test_persist_save_data("url only", lnk,
450         expected_hlink_data, sizeof(expected_hlink_data),
451         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
452     IHlink_Release(lnk);
453
454     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
455                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
456     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
457     test_persist_save_data("url + friendly name", lnk,
458         expected_hlink_data2, sizeof(expected_hlink_data2),
459         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
460     IHlink_Release(lnk);
461
462     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
463                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
464     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
465     test_persist_save_data("url + friendly_name + location", lnk,
466         expected_hlink_data3, sizeof(expected_hlink_data3),
467         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
468     IHlink_Release(lnk);
469
470     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
471                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
472     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
473     test_persist_save_data("relative url", lnk,
474         expected_hlink_data4, sizeof(expected_hlink_data4),
475         expected_hlink_data4, sizeof(expected_hlink_data4));
476     IHlink_Release(lnk);
477
478     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
479                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
480     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
481     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
482     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
483     test_persist_save_data("url + target frame name", lnk,
484         expected_hlink_data5, sizeof(expected_hlink_data5),
485         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
486     IHlink_Release(lnk);
487
488     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
489                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
490     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
491     test_persist_save_data("filename", lnk,
492         expected_hlink_data6, sizeof(expected_hlink_data6),
493         expected_hlink_data6, sizeof(expected_hlink_data6));
494     IHlink_Release(lnk);
495 }
496
497 static void test_special_reference(void)
498 {
499     LPWSTR ref;
500     HRESULT hres;
501
502     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
503     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
504     ok(ref != NULL, "ref == NULL\n");
505     CoTaskMemFree(ref);
506
507     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
508     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
509     ok(ref != NULL, "ref == NULL\n");
510     CoTaskMemFree(ref);
511
512     ref = (void*)0xdeadbeef;
513     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
514     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
515     ok(ref == NULL, "ref=%p\n", ref);
516
517     ref = (void*)0xdeadbeef;
518     hres = HlinkGetSpecialReference(4, &ref);
519     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
520     ok(ref == NULL, "ref=%p\n", ref);
521 }
522
523 static void test_HlinkCreateExtensionServices(void)
524 {
525     IAuthenticate *authenticate;
526     IHttpNegotiate *http_negotiate;
527     LPWSTR password, username, headers;
528     HWND hwnd;
529     HRESULT hres;
530
531     static const WCHAR usernameW[] = {'u','s','e','r',0};
532     static const WCHAR passwordW[] = {'p','a','s','s',0};
533     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
534     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
535
536     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
537                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
538     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
539     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
540
541     password = username = (void*)0xdeadbeef;
542     hwnd = (void*)0xdeadbeef;
543     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
544     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
545     ok(!hwnd, "hwnd != NULL\n");
546     ok(!username, "username != NULL\n");
547     ok(!password, "password != NULL\n");
548
549     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
550     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
551
552     headers = (void*)0xdeadbeef;
553     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
554                                                0, &headers);
555     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
556     ok(headers == NULL, "headers != NULL\n");
557
558     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
559                                                0, NULL);
560     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
561
562     headers = (void*)0xdeadbeef;
563     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
564     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
565     ok(headers == NULL, "headers != NULL\n");
566
567     IHttpNegotiate_Release(http_negotiate);
568     IAuthenticate_Release(authenticate);
569
570
571     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
572                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
573     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
574     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
575
576     password = username = NULL;
577     hwnd = NULL;
578     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
579     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
580     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
581     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
582     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
583     CoTaskMemFree(username);
584     CoTaskMemFree(password);
585
586     password = username = (void*)0xdeadbeef;
587     hwnd = (void*)0xdeadbeef;
588     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
589     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
590     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
591     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
592
593     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
594     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
595
596     headers = (void*)0xdeadbeef;
597     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
598                                                0, &headers);
599     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
600     ok(!lstrcmpW(headers, headersexW), "unexpected headers \"%s\"\n", debugstr_w(headers));
601     CoTaskMemFree(headers);
602
603     headers = (void*)0xdeadbeef;
604     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
605     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
606     ok(headers == NULL, "unexpected headers \"%s\"\n", debugstr_w(headers));
607
608     IHttpNegotiate_Release(http_negotiate);
609     IAuthenticate_Release(authenticate);
610 }
611
612 static void test_HlinkParseDisplayName(void)
613 {
614     IMoniker *mon = NULL;
615     LPWSTR name;
616     DWORD issys;
617     ULONG eaten = 0;
618     IBindCtx *bctx;
619     HRESULT hres;
620
621     static const WCHAR winehq_urlW[] =
622             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
623              '/','s','i','t','e','/','a','b','o','u','t',0};
624     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
625     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
626             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
627             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
628
629     CreateBindCtx(0, &bctx);
630
631     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
632     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
633     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
634     ok(mon != NULL, "mon == NULL\n");
635
636     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
637     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
638     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", debugstr_w(name));
639     CoTaskMemFree(name);
640
641     hres = IMoniker_IsSystemMoniker(mon, &issys);
642     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
643     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
644
645     IMoniker_Release(mon);
646
647     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
648     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
649     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
650     ok(mon != NULL, "mon == NULL\n");
651
652     hres = IMoniker_IsSystemMoniker(mon, &issys);
653     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
654     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
655
656     IMoniker_Release(mon);
657
658     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
659      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
660     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
661     ok(mon != NULL, "mon == NULL\n");
662
663     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
664     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
665     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", debugstr_w(name));
666     CoTaskMemFree(name);
667
668     hres = IMoniker_IsSystemMoniker(mon, &issys);
669     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
670     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
671
672     IBindCtx_Release(bctx);
673 }
674
675 static IBindCtx *_bctx;
676
677 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
678 {
679     ok(0, "unexpected call\n");
680     return E_NOINTERFACE;
681 }
682
683 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
684 {
685     return 2;
686 }
687
688 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
689 {
690     return 1;
691 }
692
693 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
694         REFGUID guidService, REFIID riid, void **ppv)
695 {
696     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
697     return E_NOINTERFACE;
698 }
699
700 static IServiceProviderVtbl ServiceProviderVtbl = {
701     ServiceProvider_QueryInterface,
702     ServiceProvider_AddRef,
703     ServiceProvider_Release,
704     ServiceProvider_QueryService
705 };
706
707 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
708
709 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
710 {
711     *ppv = NULL;
712
713     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
714         *ppv = &ServiceProvider;
715         return S_OK;
716     }
717
718     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
719     return E_NOINTERFACE;
720 }
721
722 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
723 {
724     return 2;
725 }
726
727 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
728 {
729     return 1;
730 }
731
732 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
733         IBinding *pib)
734 {
735     ok(0, "unexpected call\n");
736     return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
740 {
741     ok(0, "unexpected call\n");
742     return E_NOTIMPL;
743 }
744
745 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
746 {
747     ok(0, "unexpected call\n");
748     return E_NOTIMPL;
749 }
750
751 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
752         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
753 {
754     ok(0, "unexpected call\n");
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
759 {
760     ok(0, "unexpected call\n");
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
765 {
766     ok(0, "unexpected call\n");
767     return E_NOTIMPL;
768 }
769
770 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
771         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
772 {
773     ok(0, "unexpected call\n");
774     return E_NOTIMPL;
775 }
776
777 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
778 {
779     ok(0, "unexpected call\n");
780     return E_NOTIMPL;
781 }
782
783 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
784     BindStatusCallback_QueryInterface,
785     BindStatusCallback_AddRef,
786     BindStatusCallback_Release,
787     BindStatusCallback_OnStartBinding,
788     BindStatusCallback_GetPriority,
789     BindStatusCallback_OnLowResource,
790     BindStatusCallback_OnProgress,
791     BindStatusCallback_OnStopBinding,
792     BindStatusCallback_GetBindInfo,
793     BindStatusCallback_OnDataAvailable,
794     BindStatusCallback_OnObjectAvailable
795 };
796
797 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
798
799 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
800 {
801     *ppv = NULL;
802
803     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
804     return E_NOINTERFACE;
805 }
806
807 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
808 {
809     return 2;
810 }
811
812 static ULONG WINAPI Moniker_Release(IMoniker *iface)
813 {
814     return 1;
815 }
816
817 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
818 {
819     ok(0, "unexpected call\n");
820     return E_NOTIMPL;
821 }
822
823 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
824 {
825     ok(0, "unexpected call\n");
826     return E_NOTIMPL;
827 }
828
829 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
830 {
831     ok(0, "unexpected call\n");
832     return E_NOTIMPL;
833 }
834
835 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
836 {
837     ok(0, "unexpected call\n");
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
842 {
843     ok(0, "unexpected call\n");
844     return E_NOTIMPL;
845 }
846
847 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
848         REFIID riidResult, void **ppvResult)
849 {
850     ok(0, "unexpected call\n");
851     return E_NOTIMPL;
852 }
853
854 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
855         REFIID riid, void **ppv)
856 {
857     IUnknown *unk;
858     HRESULT hres;
859
860     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
861
862     CHECK_EXPECT(BindToStorage);
863
864     ok(pbc == _bctx, "pbc != _bctx\n");
865     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
866     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
867     ok(ppv != NULL, "ppv == NULL\n");
868     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
869
870     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
871     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
872     ok(unk != NULL, "unk == NULL\n");
873
874     IUnknown_Release(unk);
875
876     return S_OK;
877 }
878
879 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
880         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
881 {
882     ok(0, "unexpected call\n");
883     return E_NOTIMPL;
884 }
885
886 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
887         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
888 {
889     ok(0, "unexpected call\n");
890     return E_NOTIMPL;
891 }
892
893 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
894 {
895     ok(0, "unexpected call\n");
896     return E_NOTIMPL;
897 }
898
899 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
900 {
901     ok(0, "unexpected call\n");
902     return E_NOTIMPL;
903 }
904
905 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
906 {
907     ok(0, "unexpected call\n");
908     return E_NOTIMPL;
909 }
910
911 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
912         IMoniker *pmkNewlyRunning)
913 {
914     ok(0, "unexpected call\n");
915     return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
919         IMoniker *pmkToLeft, FILETIME *pFileTime)
920 {
921     ok(0, "unexpected call\n");
922     return E_NOTIMPL;
923 }
924
925 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
926 {
927     ok(0, "unexpected call\n");
928     return E_NOTIMPL;
929 }
930
931 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
932         IMoniker **ppmkPrefix)
933 {
934     ok(0, "unexpected call\n");
935     return E_NOTIMPL;
936 }
937
938 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
939         IMoniker **pmkRelPath)
940 {
941     ok(0, "unexpected call\n");
942     return E_NOTIMPL;
943 }
944
945 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
946         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
947 {
948     static const WCHAR winehq_urlW[] =
949             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
950              '/','s','i','t','e','/','a','b','o','u','t',0};
951
952     CHECK_EXPECT(GetDisplayName);
953
954     ok(pbc != NULL, "pbc == NULL\n");
955     ok(pbc != _bctx, "pbc == _bctx\n");
956     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
957
958     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
959     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
960     return S_OK;
961 }
962
963 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
964         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
965 {
966     ok(0, "unexpected call\n");
967     return E_NOTIMPL;
968 }
969
970 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
971 {
972     CHECK_EXPECT2(IsSystemMoniker);
973
974     *pdwMksys = MKSYS_URLMONIKER;
975     return S_OK;
976 }
977
978 static IMonikerVtbl MonikerVtbl = {
979     Moniker_QueryInterface,
980     Moniker_AddRef,
981     Moniker_Release,
982     Moniker_GetClassID,
983     Moniker_IsDirty,
984     Moniker_Load,
985     Moniker_Save,
986     Moniker_GetSizeMax,
987     Moniker_BindToObject,
988     Moniker_BindToStorage,
989     Moniker_Reduce,
990     Moniker_ComposeWith,
991     Moniker_Enum,
992     Moniker_IsEqual,
993     Moniker_Hash,
994     Moniker_IsRunning,
995     Moniker_GetTimeOfLastChange,
996     Moniker_Inverse,
997     Moniker_CommonPrefixWith,
998     Moniker_RelativePathTo,
999     Moniker_GetDisplayName,
1000     Moniker_ParseDisplayName,
1001     Moniker_IsSystemMoniker
1002 };
1003
1004 static IMoniker Moniker = { &MonikerVtbl };
1005
1006 static void test_HlinkResolveMonikerForData(void)
1007 {
1008     IBindCtx *bctx;
1009     HRESULT hres;
1010
1011     CreateBindCtx(0, &bctx);
1012     _bctx = bctx;
1013
1014     SET_EXPECT(IsSystemMoniker);
1015     SET_EXPECT(GetDisplayName);
1016     SET_EXPECT(BindToStorage);
1017
1018     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1019     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1020
1021     CHECK_CALLED(IsSystemMoniker);
1022     CHECK_CALLED(GetDisplayName);
1023     CHECK_CALLED(BindToStorage);
1024
1025     IBindCtx_Release(bctx);
1026 }
1027
1028 START_TEST(hlink)
1029 {
1030     CoInitialize(NULL);
1031
1032     test_HlinkIsShortcut();
1033     test_reference();
1034     test_persist();
1035     test_special_reference();
1036     test_HlinkCreateExtensionServices();
1037     test_HlinkParseDisplayName();
1038     test_HlinkResolveMonikerForData();
1039
1040     CoUninitialize();
1041 }