5e07359fdf54206f2cc0ee34c713717eaff24b9d
[reactos.git] / rostests / winetests / hlink / 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 }