31b35167e3dcc6482cf9c25e94ff00b898b274e7
[reactos.git] / reactos / dll / win32 / ieframe / intshcut.c
1 /*
2 * Copyright 2008 Damjan Jovanovic
3 *
4 * ShellLink's barely documented cousin that handles URLs.
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 /*
22 * TODO:
23 * Implement the IShellLinkA/W interfaces
24 * Handle the SetURL flags
25 * Implement any other interfaces? Does any software actually use them?
26 *
27 * The installer for the Zuma Deluxe Popcap game is good for testing.
28 */
29
30 #include <stdio.h>
31
32 #include "ieframe.h"
33
34 //#include "shlobj.h"
35 //#include "shobjidl.h"
36 #include <intshcut.h>
37 #include <shellapi.h>
38 #include <winreg.h>
39 //#include "shlwapi.h"
40 //#include "shlguid.h"
41
42 #include <wine/debug.h>
43
44 WINE_DEFAULT_DEBUG_CHANNEL(ieframe);
45
46 typedef struct
47 {
48 IUniformResourceLocatorA IUniformResourceLocatorA_iface;
49 IUniformResourceLocatorW IUniformResourceLocatorW_iface;
50 IPersistFile IPersistFile_iface;
51 IPropertySetStorage IPropertySetStorage_iface;
52
53 LONG refCount;
54
55 IPropertySetStorage *property_set_storage;
56 WCHAR *url;
57 BOOLEAN isDirty;
58 LPOLESTR currentFile;
59 } InternetShortcut;
60
61 /* utility functions */
62
63 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
64 {
65 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorA_iface);
66 }
67
68 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
69 {
70 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorW_iface);
71 }
72
73 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
74 {
75 return CONTAINING_RECORD(iface, InternetShortcut, IPersistFile_iface);
76 }
77
78 static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface)
79 {
80 return CONTAINING_RECORD(iface, InternetShortcut, IPropertySetStorage_iface);
81 }
82
83 static BOOL run_winemenubuilder( const WCHAR *args )
84 {
85 static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
86 LONG len;
87 LPWSTR buffer;
88 STARTUPINFOW si;
89 PROCESS_INFORMATION pi;
90 BOOL ret;
91 WCHAR app[MAX_PATH];
92 void *redir;
93
94 GetSystemDirectoryW( app, MAX_PATH - sizeof(menubuilder)/sizeof(WCHAR) );
95 strcatW( app, menubuilder );
96
97 len = (strlenW( app ) + strlenW( args ) + 1) * sizeof(WCHAR);
98 buffer = heap_alloc( len );
99 if( !buffer )
100 return FALSE;
101
102 strcpyW( buffer, app );
103 strcatW( buffer, args );
104
105 TRACE("starting %s\n",debugstr_w(buffer));
106
107 memset(&si, 0, sizeof(si));
108 si.cb = sizeof(si);
109
110 Wow64DisableWow64FsRedirection( &redir );
111 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi );
112 Wow64RevertWow64FsRedirection( redir );
113
114 heap_free( buffer );
115
116 if (ret)
117 {
118 CloseHandle( pi.hProcess );
119 CloseHandle( pi.hThread );
120 }
121
122 return ret;
123 }
124
125 static BOOL StartLinkProcessor( LPCOLESTR szLink )
126 {
127 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
128 LONG len;
129 LPWSTR buffer;
130 BOOL ret;
131
132 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
133 buffer = heap_alloc( len );
134 if( !buffer )
135 return FALSE;
136
137 sprintfW( buffer, szFormat, szLink );
138 ret = run_winemenubuilder( buffer );
139 heap_free( buffer );
140 return ret;
141 }
142
143 /* interface functions */
144
145 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
146 {
147 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
148 *ppvObject = NULL;
149 if (IsEqualGUID(&IID_IUnknown, riid))
150 *ppvObject = &This->IUniformResourceLocatorA_iface;
151 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
152 *ppvObject = &This->IUniformResourceLocatorA_iface;
153 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
154 *ppvObject = &This->IUniformResourceLocatorW_iface;
155 else if (IsEqualGUID(&IID_IPersistFile, riid))
156 *ppvObject = &This->IPersistFile_iface;
157 else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
158 *ppvObject = &This->IPropertySetStorage_iface;
159 else if (IsEqualGUID(&IID_IShellLinkA, riid))
160 {
161 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
162 return E_NOINTERFACE;
163 }
164 else if (IsEqualGUID(&IID_IShellLinkW, riid))
165 {
166 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
167 return E_NOINTERFACE;
168 }
169 else
170 {
171 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
172 return E_NOINTERFACE;
173 }
174 IUnknown_AddRef((IUnknown*)*ppvObject);
175 return S_OK;
176 }
177
178 static ULONG Unknown_AddRef(InternetShortcut *This)
179 {
180 TRACE("(%p)\n", This);
181 return InterlockedIncrement(&This->refCount);
182 }
183
184 static ULONG Unknown_Release(InternetShortcut *This)
185 {
186 ULONG count;
187 TRACE("(%p)\n", This);
188 count = InterlockedDecrement(&This->refCount);
189 if (count == 0)
190 {
191 CoTaskMemFree(This->url);
192 CoTaskMemFree(This->currentFile);
193 IPropertySetStorage_Release(This->property_set_storage);
194 heap_free(This);
195 unlock_module();
196 }
197 return count;
198 }
199
200 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
201 {
202 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
203 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
204 return Unknown_QueryInterface(This, riid, ppvObject);
205 }
206
207 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
208 {
209 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
210 TRACE("(%p)\n", url);
211 return Unknown_AddRef(This);
212 }
213
214 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
215 {
216 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
217 TRACE("(%p)\n", url);
218 return Unknown_Release(This);
219 }
220
221 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
222 {
223 WCHAR *newURL = NULL;
224 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
225 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
226 if (dwInFlags != 0)
227 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
228 if (pcszURL != NULL)
229 {
230 newURL = co_strdupW(pcszURL);
231 if (newURL == NULL)
232 return E_OUTOFMEMORY;
233 }
234 CoTaskMemFree(This->url);
235 This->url = newURL;
236 This->isDirty = TRUE;
237 return S_OK;
238 }
239
240 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
241 {
242 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
243
244 TRACE("(%p, %p)\n", url, ppszURL);
245
246 if (!This->url) {
247 *ppszURL = NULL;
248 return S_FALSE;
249 }
250
251 *ppszURL = co_strdupW(This->url);
252 if (!*ppszURL)
253 return E_OUTOFMEMORY;
254
255 return S_OK;
256 }
257
258 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
259 {
260 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
261 WCHAR app[64];
262 HKEY hkey;
263 static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
264 SHELLEXECUTEINFOW sei;
265 DWORD res, type;
266 HRESULT hres;
267
268 TRACE("%p %p\n", This, pCommandInfo );
269
270 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
271 return E_INVALIDARG;
272
273 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
274 {
275 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
276 return E_NOTIMPL;
277 }
278
279 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0);
280 if(FAILED(hres))
281 return E_FAIL;
282
283 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
284 if(res != ERROR_SUCCESS)
285 return E_FAIL;
286
287 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
288 RegCloseKey(hkey);
289 if(res != ERROR_SUCCESS || type != REG_SZ)
290 return E_FAIL;
291
292 memset(&sei, 0, sizeof(sei));
293 sei.cbSize = sizeof(sei);
294 sei.lpFile = This->url;
295 sei.nShow = SW_SHOW;
296
297 if( ShellExecuteExW(&sei) )
298 return S_OK;
299 else
300 return E_FAIL;
301 }
302
303 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
304 {
305 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
306 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
307 return Unknown_QueryInterface(This, riid, ppvObject);
308 }
309
310 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
311 {
312 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
313 TRACE("(%p)\n", url);
314 return Unknown_AddRef(This);
315 }
316
317 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
318 {
319 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
320 TRACE("(%p)\n", url);
321 return Unknown_Release(This);
322 }
323
324 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
325 {
326 WCHAR *newURL = NULL;
327 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
328 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
329 if (dwInFlags != 0)
330 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
331 if (pcszURL != NULL)
332 {
333 newURL = co_strdupAtoW(pcszURL);
334 if (newURL == NULL)
335 return E_OUTOFMEMORY;
336 }
337 CoTaskMemFree(This->url);
338 This->url = newURL;
339 This->isDirty = TRUE;
340 return S_OK;
341 }
342
343 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
344 {
345 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
346
347 TRACE("(%p, %p)\n", url, ppszURL);
348
349 if (!This->url) {
350 *ppszURL = NULL;
351 return S_FALSE;
352
353 }
354
355 *ppszURL = co_strdupWtoA(This->url);
356 if (!*ppszURL)
357 return E_OUTOFMEMORY;
358
359 return S_OK;
360 }
361
362 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
363 {
364 URLINVOKECOMMANDINFOW wideCommandInfo;
365 int len;
366 WCHAR *wideVerb;
367 HRESULT res;
368 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
369
370 wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
371 wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
372 wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
373
374 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
375 wideVerb = heap_alloc(len * sizeof(WCHAR));
376 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
377
378 wideCommandInfo.pcszVerb = wideVerb;
379
380 res = UniformResourceLocatorW_InvokeCommand(&This->IUniformResourceLocatorW_iface, &wideCommandInfo);
381 heap_free(wideVerb);
382
383 return res;
384 }
385
386 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
387 {
388 InternetShortcut *This = impl_from_IPersistFile(pFile);
389 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
390 return Unknown_QueryInterface(This, riid, ppvObject);
391 }
392
393 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
394 {
395 InternetShortcut *This = impl_from_IPersistFile(pFile);
396 TRACE("(%p)\n", pFile);
397 return Unknown_AddRef(This);
398 }
399
400 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
401 {
402 InternetShortcut *This = impl_from_IPersistFile(pFile);
403 TRACE("(%p)\n", pFile);
404 return Unknown_Release(This);
405 }
406
407 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
408 {
409 TRACE("(%p, %p)\n", pFile, pClassID);
410 *pClassID = CLSID_InternetShortcut;
411 return S_OK;
412 }
413
414 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
415 {
416 InternetShortcut *This = impl_from_IPersistFile(pFile);
417 TRACE("(%p)\n", pFile);
418 return This->isDirty ? S_OK : S_FALSE;
419 }
420
421 /* A helper function: Allocate and fill rString. Return number of bytes read. */
422 static DWORD get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName,
423 LPCWSTR lpFileName, WCHAR **rString )
424 {
425 DWORD r = 0;
426 DWORD len = 128;
427 WCHAR *buffer;
428
429 buffer = CoTaskMemAlloc(len * sizeof(*buffer));
430 if (buffer != NULL)
431 {
432 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
433 while (r == len-1)
434 {
435 WCHAR *realloc_buf;
436
437 len *= 2;
438 realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer));
439 if (realloc_buf == NULL)
440 {
441 CoTaskMemFree(buffer);
442 *rString = NULL;
443 return 0;
444 }
445 buffer = realloc_buf;
446
447 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
448 }
449 }
450
451 *rString = buffer;
452 return r;
453 }
454
455 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
456 {
457 WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
458 WCHAR str_URL[] = {'U','R','L',0};
459 WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0};
460 WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0};
461 WCHAR *filename = NULL;
462 HRESULT hr;
463 InternetShortcut *This = impl_from_IPersistFile(pFile);
464 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
465 if (dwMode != 0)
466 FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
467 filename = co_strdupW(pszFileName);
468 if (filename != NULL)
469 {
470 DWORD r;
471 WCHAR *url;
472
473 r = get_profile_string(str_header, str_URL, pszFileName, &url);
474
475 if (url == NULL)
476 {
477 hr = E_OUTOFMEMORY;
478 CoTaskMemFree(filename);
479 }
480 else if (r == 0)
481 {
482 hr = E_FAIL;
483 CoTaskMemFree(filename);
484 }
485 else
486 {
487 hr = S_OK;
488 CoTaskMemFree(This->currentFile);
489 This->currentFile = filename;
490 CoTaskMemFree(This->url);
491 This->url = url;
492 This->isDirty = FALSE;
493 }
494
495 /* Now we're going to read in the iconfile and iconindex.
496 If we don't find them, that's not a failure case -- it's possible
497 that they just aren't in there. */
498 if (SUCCEEDED(hr))
499 {
500 IPropertyStorage *pPropStg;
501 WCHAR *iconfile;
502 WCHAR *iconindexstring;
503 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut,
504 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
505 &pPropStg);
506
507 r = get_profile_string(str_header, str_iconfile, pszFileName, &iconfile);
508 if (iconfile != NULL)
509 {
510 PROPSPEC ps;
511 PROPVARIANT pv;
512 ps.ulKind = PRSPEC_PROPID;
513 ps.u.propid = PID_IS_ICONFILE;
514 pv.vt = VT_LPWSTR;
515 pv.u.pwszVal = iconfile;
516 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
517 if (FAILED(hr))
518 {
519 TRACE("Failed to store the iconfile to our property storage. hr = 0x%x\n", hr);
520 }
521
522 CoTaskMemFree(iconfile);
523 }
524
525 r = get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring);
526
527 if (iconindexstring != NULL)
528 {
529 int iconindex;
530 PROPSPEC ps;
531 PROPVARIANT pv;
532 char *iconindexastring = co_strdupWtoA(iconindexstring);
533 sscanf(iconindexastring, "%d", &iconindex);
534 CoTaskMemFree(iconindexastring);
535 ps.ulKind = PRSPEC_PROPID;
536 ps.u.propid = PID_IS_ICONINDEX;
537 pv.vt = VT_I4;
538 pv.u.iVal = iconindex;
539 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
540 if (FAILED(hr))
541 {
542 TRACE("Failed to store the iconindex to our property storage. hr = 0x%x\n", hr);
543 }
544
545 CoTaskMemFree(iconindexstring);
546 }
547
548 IPropertyStorage_Release(pPropStg);
549 }
550 else
551 hr = E_OUTOFMEMORY;
552 }
553 else
554 hr = E_OUTOFMEMORY;
555 return hr;
556 }
557
558 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
559 {
560 HRESULT hr = S_OK;
561 INT len;
562 CHAR *url;
563 InternetShortcut *This = impl_from_IPersistFile(pFile);
564
565 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
566
567 if (pszFileName != NULL && fRemember)
568 {
569 LPOLESTR oldFile = This->currentFile;
570 This->currentFile = co_strdupW(pszFileName);
571 if (This->currentFile == NULL)
572 {
573 This->currentFile = oldFile;
574 return E_OUTOFMEMORY;
575 }
576 CoTaskMemFree(oldFile);
577 }
578 if (This->url == NULL)
579 return E_FAIL;
580
581 /* Windows seems to always write:
582 * ASCII "[InternetShortcut]" headers
583 * ASCII names in "name=value" pairs
584 * An ASCII (probably UTF8?) value in "URL=..."
585 */
586 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
587 url = heap_alloc(len);
588 if (url != NULL)
589 {
590 HANDLE file;
591 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
592 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
593 if (file != INVALID_HANDLE_VALUE)
594 {
595 DWORD bytesWritten;
596 char *iconfile;
597 char str_header[] = "[InternetShortcut]";
598 char str_URL[] = "URL=";
599 char str_ICONFILE[] = "ICONFILE=";
600 char str_eol[] = "\r\n";
601 IPropertyStorage *pPropStgRead;
602 PROPSPEC ps[2];
603 PROPVARIANT pvread[2];
604 ps[0].ulKind = PRSPEC_PROPID;
605 ps[0].u.propid = PID_IS_ICONFILE;
606 ps[1].ulKind = PRSPEC_PROPID;
607 ps[1].u.propid = PID_IS_ICONINDEX;
608
609 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
610 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
611 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
612 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
613 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
614
615 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead);
616 if (SUCCEEDED(hr))
617 {
618 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
619 if (hr == S_FALSE)
620 {
621 /* None of the properties are present, that's ok */
622 hr = S_OK;
623 IPropertyStorage_Release(pPropStgRead);
624 }
625 else if (SUCCEEDED(hr))
626 {
627 char indexString[50];
628 len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, NULL, 0, 0, 0);
629 iconfile = heap_alloc(len);
630 if (iconfile != NULL)
631 {
632 WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, iconfile, len, 0, 0);
633 WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL);
634 WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL);
635 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
636 }
637
638 sprintf(indexString, "ICONINDEX=%d", pvread[1].u.iVal);
639 WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL);
640 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
641
642 IPropertyStorage_Release(pPropStgRead);
643 PropVariantClear(&pvread[0]);
644 PropVariantClear(&pvread[1]);
645 }
646 else
647 {
648 TRACE("Unable to read properties.\n");
649 }
650 }
651 else
652 {
653 TRACE("Unable to get the IPropertyStorage.\n");
654 }
655
656 CloseHandle(file);
657 if (pszFileName == NULL || fRemember)
658 This->isDirty = FALSE;
659 StartLinkProcessor(pszFileName);
660 }
661 else
662 hr = E_FAIL;
663 heap_free(url);
664 }
665 else
666 hr = E_OUTOFMEMORY;
667
668 return hr;
669 }
670
671 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
672 {
673 FIXME("(%p, %p): stub\n", pFile, pszFileName);
674 return E_NOTIMPL;
675 }
676
677 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
678 {
679 HRESULT hr = S_OK;
680 InternetShortcut *This = impl_from_IPersistFile(pFile);
681 TRACE("(%p, %p)\n", pFile, ppszFileName);
682 if (This->currentFile == NULL)
683 *ppszFileName = NULL;
684 else
685 {
686 *ppszFileName = co_strdupW(This->currentFile);
687 if (*ppszFileName == NULL)
688 hr = E_OUTOFMEMORY;
689 }
690 return hr;
691 }
692
693 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject)
694 {
695 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
696 TRACE("(%p)\n", iface);
697 return Unknown_QueryInterface(This, riid, ppvObject);
698 }
699
700 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface)
701 {
702 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
703 TRACE("(%p)\n", iface);
704 return Unknown_AddRef(This);
705 }
706
707 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface)
708 {
709 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
710 TRACE("(%p)\n", iface);
711 return Unknown_Release(This);
712 }
713
714 static HRESULT WINAPI PropertySetStorage_Create(
715 IPropertySetStorage* iface,
716 REFFMTID rfmtid,
717 const CLSID *pclsid,
718 DWORD grfFlags,
719 DWORD grfMode,
720 IPropertyStorage **ppprstg)
721 {
722 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
723 TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg);
724
725 return IPropertySetStorage_Create(This->property_set_storage,
726 rfmtid,
727 pclsid,
728 grfFlags,
729 grfMode,
730 ppprstg);
731 }
732
733 static HRESULT WINAPI PropertySetStorage_Open(
734 IPropertySetStorage* iface,
735 REFFMTID rfmtid,
736 DWORD grfMode,
737 IPropertyStorage **ppprstg)
738 {
739 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
740 TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg);
741
742 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */
743 return IPropertySetStorage_Open(This->property_set_storage,
744 rfmtid,
745 grfMode|STGM_SHARE_EXCLUSIVE,
746 ppprstg);
747 }
748
749 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid)
750 {
751 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
752 TRACE("(%s)\n", debugstr_guid(rfmtid));
753
754
755 return IPropertySetStorage_Delete(This->property_set_storage,
756 rfmtid);
757 }
758
759 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum)
760 {
761 FIXME("(%p): stub\n", ppenum);
762 return E_NOTIMPL;
763 }
764
765 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
766 UniformResourceLocatorW_QueryInterface,
767 UniformResourceLocatorW_AddRef,
768 UniformResourceLocatorW_Release,
769 UniformResourceLocatorW_SetUrl,
770 UniformResourceLocatorW_GetUrl,
771 UniformResourceLocatorW_InvokeCommand
772 };
773
774 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
775 UniformResourceLocatorA_QueryInterface,
776 UniformResourceLocatorA_AddRef,
777 UniformResourceLocatorA_Release,
778 UniformResourceLocatorA_SetUrl,
779 UniformResourceLocatorA_GetUrl,
780 UniformResourceLocatorA_InvokeCommand
781 };
782
783 static const IPersistFileVtbl persistFileVtbl = {
784 PersistFile_QueryInterface,
785 PersistFile_AddRef,
786 PersistFile_Release,
787 PersistFile_GetClassID,
788 PersistFile_IsDirty,
789 PersistFile_Load,
790 PersistFile_Save,
791 PersistFile_SaveCompleted,
792 PersistFile_GetCurFile
793 };
794
795 static const IPropertySetStorageVtbl propertySetStorageVtbl = {
796 PropertySetStorage_QueryInterface,
797 PropertySetStorage_AddRef,
798 PropertySetStorage_Release,
799 PropertySetStorage_Create,
800 PropertySetStorage_Open,
801 PropertySetStorage_Delete,
802 PropertySetStorage_Enum
803 };
804
805 static InternetShortcut *create_shortcut(void)
806 {
807 InternetShortcut *newshortcut;
808
809 newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
810 if (newshortcut)
811 {
812 HRESULT hr;
813 IPropertyStorage *dummy;
814
815 newshortcut->IUniformResourceLocatorA_iface.lpVtbl = &uniformResourceLocatorAVtbl;
816 newshortcut->IUniformResourceLocatorW_iface.lpVtbl = &uniformResourceLocatorWVtbl;
817 newshortcut->IPersistFile_iface.lpVtbl = &persistFileVtbl;
818 newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl;
819 newshortcut->refCount = 1;
820 hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE,
821 STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage);
822 if (FAILED(hr))
823 {
824 TRACE("Failed to create the storage object needed for the shortcut.\n");
825 heap_free(newshortcut);
826 return NULL;
827 }
828
829 hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy);
830 if (FAILED(hr))
831 {
832 TRACE("Failed to create the property object needed for the shortcut.\n");
833 IPropertySetStorage_Release(newshortcut->property_set_storage);
834 heap_free(newshortcut);
835 return NULL;
836 }
837 IPropertyStorage_Release(dummy);
838 }
839
840 return newshortcut;
841 }
842
843 HRESULT WINAPI InternetShortcut_Create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
844 {
845 InternetShortcut *This;
846 HRESULT hres;
847
848 TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), ppv);
849
850 *ppv = NULL;
851
852 if(outer)
853 return CLASS_E_NOAGGREGATION;
854
855 This = create_shortcut();
856 if(!This)
857 return E_OUTOFMEMORY;
858
859 hres = Unknown_QueryInterface(This, riid, ppv);
860 Unknown_Release(This);
861 return hres;
862 }
863
864
865 /**********************************************************************
866 * OpenURL (ieframe.@)
867 */
868 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
869 {
870 InternetShortcut *shortcut;
871 WCHAR* urlfilepath = NULL;
872 int len;
873
874 shortcut = create_shortcut();
875
876 if(!shortcut)
877 return;
878
879 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
880 urlfilepath = heap_alloc(len * sizeof(WCHAR));
881 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
882
883 if(SUCCEEDED(IPersistFile_Load(&shortcut->IPersistFile_iface, urlfilepath, 0))) {
884 URLINVOKECOMMANDINFOW ici;
885
886 memset( &ici, 0, sizeof ici );
887 ici.dwcbSize = sizeof ici;
888 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
889 ici.hwndParent = hWnd;
890
891 if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->IUniformResourceLocatorW_iface, (PURLINVOKECOMMANDINFOW) &ici)))
892 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl));
893 }
894
895 heap_free(urlfilepath);
896 Unknown_Release(shortcut);
897 }