include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / ieframe / intshcut.c
blobb992305a7246fe212396843d8a70abdf610e3be2
1 /*
2 * Copyright 2008 Damjan Jovanovic
4 * ShellLink's barely documented cousin that handles URLs.
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.
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.
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
22 * TODO:
23 * Implement the IShellLinkA/W interfaces
24 * Handle the SetURL flags
25 * Implement any other interfaces? Does any software actually use them?
27 * The installer for the Zuma Deluxe Popcap game is good for testing.
30 #include <stdio.h>
32 #include "ieframe.h"
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"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(ieframe);
46 typedef struct
48 IUniformResourceLocatorA IUniformResourceLocatorA_iface;
49 IUniformResourceLocatorW IUniformResourceLocatorW_iface;
50 IPersistFile IPersistFile_iface;
51 IPropertySetStorage IPropertySetStorage_iface;
53 LONG refCount;
55 IPropertySetStorage *property_set_storage;
56 WCHAR *url;
57 BOOLEAN isDirty;
58 LPOLESTR currentFile;
59 } InternetShortcut;
61 /* utility functions */
63 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
65 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorA_iface);
68 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
70 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorW_iface);
73 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
75 return CONTAINING_RECORD(iface, InternetShortcut, IPersistFile_iface);
78 static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface)
80 return CONTAINING_RECORD(iface, InternetShortcut, IPropertySetStorage_iface);
83 static BOOL run_winemenubuilder( const WCHAR *args )
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;
94 GetSystemDirectoryW( app, MAX_PATH - ARRAY_SIZE( menubuilder ));
95 lstrcatW( app, menubuilder );
97 len = (lstrlenW( app ) + lstrlenW( args ) + 1) * sizeof(WCHAR);
98 buffer = malloc( len );
99 if( !buffer )
100 return FALSE;
102 lstrcpyW( buffer, app );
103 lstrcatW( buffer, args );
105 TRACE("starting %s\n",debugstr_w(buffer));
107 memset(&si, 0, sizeof(si));
108 si.cb = sizeof(si);
110 Wow64DisableWow64FsRedirection( &redir );
111 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi );
112 Wow64RevertWow64FsRedirection( redir );
114 free( buffer );
116 if (ret)
118 CloseHandle( pi.hProcess );
119 CloseHandle( pi.hThread );
122 return ret;
125 static BOOL StartLinkProcessor( LPCOLESTR szLink )
127 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
128 LONG len;
129 LPWSTR buffer;
130 BOOL ret;
132 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
133 buffer = malloc( len );
134 if( !buffer )
135 return FALSE;
137 swprintf( buffer, len / sizeof(WCHAR), szFormat, szLink );
138 ret = run_winemenubuilder( buffer );
139 free( buffer );
140 return ret;
143 /* interface functions */
145 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
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))
161 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
162 return E_NOINTERFACE;
164 else if (IsEqualGUID(&IID_IShellLinkW, riid))
166 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
167 return E_NOINTERFACE;
169 else
171 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
172 return E_NOINTERFACE;
174 IUnknown_AddRef((IUnknown*)*ppvObject);
175 return S_OK;
178 static ULONG Unknown_AddRef(InternetShortcut *This)
180 TRACE("(%p)\n", This);
181 return InterlockedIncrement(&This->refCount);
184 static ULONG Unknown_Release(InternetShortcut *This)
186 ULONG count;
187 TRACE("(%p)\n", This);
188 count = InterlockedDecrement(&This->refCount);
189 if (count == 0)
191 CoTaskMemFree(This->url);
192 CoTaskMemFree(This->currentFile);
193 IPropertySetStorage_Release(This->property_set_storage);
194 free(This);
195 unlock_module();
197 return count;
200 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
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);
207 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
209 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
210 TRACE("(%p)\n", url);
211 return Unknown_AddRef(This);
214 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
216 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
217 TRACE("(%p)\n", url);
218 return Unknown_Release(This);
221 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
223 WCHAR *newURL = NULL;
224 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
225 TRACE("(%p, %s, 0x%lx)\n", url, debugstr_w(pcszURL), dwInFlags);
226 if (dwInFlags != 0)
227 FIXME("ignoring unsupported flags 0x%lx\n", dwInFlags);
228 if (pcszURL != NULL)
230 newURL = co_strdupW(pcszURL);
231 if (newURL == NULL)
232 return E_OUTOFMEMORY;
234 CoTaskMemFree(This->url);
235 This->url = newURL;
236 This->isDirty = TRUE;
237 return S_OK;
240 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
242 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
244 TRACE("(%p, %p)\n", url, ppszURL);
246 if (!This->url) {
247 *ppszURL = NULL;
248 return S_FALSE;
251 *ppszURL = co_strdupW(This->url);
252 if (!*ppszURL)
253 return E_OUTOFMEMORY;
255 return S_OK;
258 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
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;
268 TRACE("%p %p\n", This, pCommandInfo );
270 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
271 return E_INVALIDARG;
273 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
275 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
276 return E_NOTIMPL;
279 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, ARRAY_SIZE(app), NULL, 0);
280 if(FAILED(hres))
281 return E_FAIL;
283 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
284 if(res != ERROR_SUCCESS)
285 return E_FAIL;
287 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
288 RegCloseKey(hkey);
289 if(res != ERROR_SUCCESS || type != REG_SZ)
290 return E_FAIL;
292 memset(&sei, 0, sizeof(sei));
293 sei.cbSize = sizeof(sei);
294 sei.lpFile = This->url;
295 sei.nShow = SW_SHOW;
297 if( ShellExecuteExW(&sei) )
298 return S_OK;
299 else
300 return E_FAIL;
303 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
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);
310 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
312 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
313 TRACE("(%p)\n", url);
314 return Unknown_AddRef(This);
317 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
319 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
320 TRACE("(%p)\n", url);
321 return Unknown_Release(This);
324 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
326 WCHAR *newURL = NULL;
327 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
328 TRACE("(%p, %s, 0x%lx)\n", url, debugstr_a(pcszURL), dwInFlags);
329 if (dwInFlags != 0)
330 FIXME("ignoring unsupported flags 0x%lx\n", dwInFlags);
331 if (pcszURL != NULL)
333 newURL = co_strdupAtoW(pcszURL);
334 if (newURL == NULL)
335 return E_OUTOFMEMORY;
337 CoTaskMemFree(This->url);
338 This->url = newURL;
339 This->isDirty = TRUE;
340 return S_OK;
343 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
345 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
347 TRACE("(%p, %p)\n", url, ppszURL);
349 if (!This->url) {
350 *ppszURL = NULL;
351 return S_FALSE;
355 *ppszURL = co_strdupWtoA(This->url);
356 if (!*ppszURL)
357 return E_OUTOFMEMORY;
359 return S_OK;
362 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
364 URLINVOKECOMMANDINFOW wideCommandInfo;
365 int len;
366 WCHAR *wideVerb;
367 HRESULT res;
368 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
370 wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
371 wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
372 wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
374 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
375 wideVerb = malloc(len * sizeof(WCHAR));
376 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
378 wideCommandInfo.pcszVerb = wideVerb;
380 res = UniformResourceLocatorW_InvokeCommand(&This->IUniformResourceLocatorW_iface, &wideCommandInfo);
381 free(wideVerb);
383 return res;
386 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
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);
393 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
395 InternetShortcut *This = impl_from_IPersistFile(pFile);
396 TRACE("(%p)\n", pFile);
397 return Unknown_AddRef(This);
400 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
402 InternetShortcut *This = impl_from_IPersistFile(pFile);
403 TRACE("(%p)\n", pFile);
404 return Unknown_Release(This);
407 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
409 TRACE("(%p, %p)\n", pFile, pClassID);
410 *pClassID = CLSID_InternetShortcut;
411 return S_OK;
414 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
416 InternetShortcut *This = impl_from_IPersistFile(pFile);
417 TRACE("(%p)\n", pFile);
418 return This->isDirty ? S_OK : S_FALSE;
421 /* Returns allocated profile string and a standard return code. */
422 static HRESULT get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName,
423 LPCWSTR lpFileName, WCHAR **rString )
425 DWORD r = 0;
426 DWORD len = 128;
427 WCHAR *buffer;
429 *rString = NULL;
430 buffer = CoTaskMemAlloc(len * sizeof(*buffer));
431 if (!buffer)
432 return E_OUTOFMEMORY;
434 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
435 while (r == len-1)
437 WCHAR *realloc_buf;
439 len *= 2;
440 realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer));
441 if (realloc_buf == NULL)
443 CoTaskMemFree(buffer);
444 return E_OUTOFMEMORY;
446 buffer = realloc_buf;
448 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
451 *rString = buffer;
452 return r ? S_OK : E_FAIL;
455 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
457 static const WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
458 static const WCHAR str_URL[] = {'U','R','L',0};
459 static const WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0};
460 static const WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0};
461 InternetShortcut *This = impl_from_IPersistFile(pFile);
462 WCHAR *filename = NULL;
463 WCHAR *url;
464 HRESULT hr;
465 IPropertyStorage *pPropStg;
466 WCHAR *iconfile;
467 WCHAR *iconindexstring;
469 TRACE("(%p, %s, 0x%lx)\n", pFile, debugstr_w(pszFileName), dwMode);
471 if (dwMode != 0)
472 FIXME("ignoring unimplemented mode 0x%lx\n", dwMode);
474 filename = co_strdupW(pszFileName);
475 if (!filename)
476 return E_OUTOFMEMORY;
478 if (FAILED(hr = get_profile_string(str_header, str_URL, pszFileName, &url)))
480 CoTaskMemFree(filename);
481 return hr;
484 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut,
485 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropStg);
486 if (FAILED(hr))
488 CoTaskMemFree(filename);
489 CoTaskMemFree(url);
490 return hr;
493 CoTaskMemFree(This->currentFile);
494 This->currentFile = filename;
495 CoTaskMemFree(This->url);
496 This->url = url;
497 This->isDirty = FALSE;
499 /* Now we're going to read in the iconfile and iconindex.
500 If we don't find them, that's not a failure case -- it's possible
501 that they just aren't in there. */
503 if (get_profile_string(str_header, str_iconfile, pszFileName, &iconfile) == S_OK)
505 PROPSPEC ps;
506 PROPVARIANT pv;
507 ps.ulKind = PRSPEC_PROPID;
508 ps.propid = PID_IS_ICONFILE;
509 pv.vt = VT_LPWSTR;
510 pv.pwszVal = iconfile;
511 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
512 if (FAILED(hr))
513 TRACE("Failed to store the iconfile to our property storage. hr = 0x%lx\n", hr);
515 CoTaskMemFree(iconfile);
517 if (get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring) == S_OK)
519 int iconindex;
520 PROPSPEC ps;
521 PROPVARIANT pv;
522 iconindex = wcstol(iconindexstring, NULL, 10);
523 ps.ulKind = PRSPEC_PROPID;
524 ps.propid = PID_IS_ICONINDEX;
525 pv.vt = VT_I4;
526 pv.iVal = iconindex;
527 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
528 if (FAILED(hr))
529 TRACE("Failed to store the iconindex to our property storage. hr = 0x%lx\n", hr);
531 CoTaskMemFree(iconindexstring);
533 IPropertyStorage_Release(pPropStg);
534 return hr;
537 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
539 HRESULT hr = S_OK;
540 INT len;
541 CHAR *url;
542 InternetShortcut *This = impl_from_IPersistFile(pFile);
544 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
546 if (pszFileName != NULL && fRemember)
548 LPOLESTR oldFile = This->currentFile;
549 This->currentFile = co_strdupW(pszFileName);
550 if (This->currentFile == NULL)
552 This->currentFile = oldFile;
553 return E_OUTOFMEMORY;
555 CoTaskMemFree(oldFile);
557 if (This->url == NULL)
558 return E_FAIL;
560 /* Windows seems to always write:
561 * ASCII "[InternetShortcut]" headers
562 * ASCII names in "name=value" pairs
563 * An ASCII (probably UTF8?) value in "URL=..."
565 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
566 url = malloc(len);
567 if (url != NULL)
569 HANDLE file;
570 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
571 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
572 if (file != INVALID_HANDLE_VALUE)
574 static const char str_header[] = "[InternetShortcut]";
575 static const char str_URL[] = "URL=";
576 static const char str_ICONFILE[] = "ICONFILE=";
577 static const char str_eol[] = "\r\n";
578 DWORD bytesWritten;
579 char *iconfile;
580 IPropertyStorage *pPropStgRead;
581 PROPSPEC ps[2];
582 PROPVARIANT pvread[2];
583 ps[0].ulKind = PRSPEC_PROPID;
584 ps[0].propid = PID_IS_ICONFILE;
585 ps[1].ulKind = PRSPEC_PROPID;
586 ps[1].propid = PID_IS_ICONINDEX;
588 WriteFile(file, str_header, ARRAY_SIZE(str_header) - 1, &bytesWritten, NULL);
589 WriteFile(file, str_eol, ARRAY_SIZE(str_eol) - 1, &bytesWritten, NULL);
590 WriteFile(file, str_URL, ARRAY_SIZE(str_URL) - 1, &bytesWritten, NULL);
591 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
592 WriteFile(file, str_eol, ARRAY_SIZE(str_eol) - 1, &bytesWritten, NULL);
594 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead);
595 if (SUCCEEDED(hr))
597 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
598 if (hr == S_FALSE)
600 /* None of the properties are present, that's ok */
601 hr = S_OK;
602 IPropertyStorage_Release(pPropStgRead);
604 else if (SUCCEEDED(hr))
606 char indexString[50];
607 len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].pwszVal, -1, NULL, 0, 0, 0);
608 iconfile = malloc(len);
609 if (iconfile != NULL)
611 WideCharToMultiByte(CP_UTF8, 0, pvread[0].pwszVal, -1, iconfile, len, 0, 0);
612 WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL);
613 WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL);
614 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
615 free(iconfile);
618 sprintf(indexString, "ICONINDEX=%d", pvread[1].iVal);
619 WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL);
620 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
622 IPropertyStorage_Release(pPropStgRead);
623 PropVariantClear(&pvread[0]);
624 PropVariantClear(&pvread[1]);
626 else
628 TRACE("Unable to read properties.\n");
631 else
633 TRACE("Unable to get the IPropertyStorage.\n");
636 CloseHandle(file);
637 if (pszFileName == NULL || fRemember)
638 This->isDirty = FALSE;
639 StartLinkProcessor(pszFileName);
641 else
642 hr = E_FAIL;
643 free(url);
645 else
646 hr = E_OUTOFMEMORY;
648 return hr;
651 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
653 FIXME("(%p, %p): stub\n", pFile, pszFileName);
654 return E_NOTIMPL;
657 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
659 HRESULT hr = S_OK;
660 InternetShortcut *This = impl_from_IPersistFile(pFile);
661 TRACE("(%p, %p)\n", pFile, ppszFileName);
662 if (This->currentFile == NULL)
663 *ppszFileName = NULL;
664 else
666 *ppszFileName = co_strdupW(This->currentFile);
667 if (*ppszFileName == NULL)
668 hr = E_OUTOFMEMORY;
670 return hr;
673 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject)
675 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
676 TRACE("(%p)\n", iface);
677 return Unknown_QueryInterface(This, riid, ppvObject);
680 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface)
682 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
683 TRACE("(%p)\n", iface);
684 return Unknown_AddRef(This);
687 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface)
689 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
690 TRACE("(%p)\n", iface);
691 return Unknown_Release(This);
694 static HRESULT WINAPI PropertySetStorage_Create(
695 IPropertySetStorage* iface,
696 REFFMTID rfmtid,
697 const CLSID *pclsid,
698 DWORD grfFlags,
699 DWORD grfMode,
700 IPropertyStorage **ppprstg)
702 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
703 TRACE("(%s, %p, 0x%lx, 0x%lx, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg);
705 return IPropertySetStorage_Create(This->property_set_storage,
706 rfmtid,
707 pclsid,
708 grfFlags,
709 grfMode,
710 ppprstg);
713 static HRESULT WINAPI PropertySetStorage_Open(
714 IPropertySetStorage* iface,
715 REFFMTID rfmtid,
716 DWORD grfMode,
717 IPropertyStorage **ppprstg)
719 const DWORD STGM_ACCESS_MASK = 0x0000000f;
720 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
721 TRACE("(%s, 0x%lx, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg);
723 /* ole32 doesn't like STGM_WRITE */
724 if ((grfMode & STGM_ACCESS_MASK) == STGM_WRITE)
725 grfMode = (grfMode & ~STGM_ACCESS_MASK) | STGM_READWRITE;
727 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */
728 return IPropertySetStorage_Open(This->property_set_storage,
729 rfmtid,
730 grfMode|STGM_SHARE_EXCLUSIVE,
731 ppprstg);
734 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid)
736 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
737 TRACE("(%s)\n", debugstr_guid(rfmtid));
740 return IPropertySetStorage_Delete(This->property_set_storage,
741 rfmtid);
744 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum)
746 FIXME("(%p): stub\n", ppenum);
747 return E_NOTIMPL;
750 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
751 UniformResourceLocatorW_QueryInterface,
752 UniformResourceLocatorW_AddRef,
753 UniformResourceLocatorW_Release,
754 UniformResourceLocatorW_SetUrl,
755 UniformResourceLocatorW_GetUrl,
756 UniformResourceLocatorW_InvokeCommand
759 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
760 UniformResourceLocatorA_QueryInterface,
761 UniformResourceLocatorA_AddRef,
762 UniformResourceLocatorA_Release,
763 UniformResourceLocatorA_SetUrl,
764 UniformResourceLocatorA_GetUrl,
765 UniformResourceLocatorA_InvokeCommand
768 static const IPersistFileVtbl persistFileVtbl = {
769 PersistFile_QueryInterface,
770 PersistFile_AddRef,
771 PersistFile_Release,
772 PersistFile_GetClassID,
773 PersistFile_IsDirty,
774 PersistFile_Load,
775 PersistFile_Save,
776 PersistFile_SaveCompleted,
777 PersistFile_GetCurFile
780 static const IPropertySetStorageVtbl propertySetStorageVtbl = {
781 PropertySetStorage_QueryInterface,
782 PropertySetStorage_AddRef,
783 PropertySetStorage_Release,
784 PropertySetStorage_Create,
785 PropertySetStorage_Open,
786 PropertySetStorage_Delete,
787 PropertySetStorage_Enum
790 static InternetShortcut *create_shortcut(void)
792 InternetShortcut *newshortcut;
794 newshortcut = calloc(1, sizeof(InternetShortcut));
795 if (newshortcut)
797 HRESULT hr;
798 IPropertyStorage *dummy;
800 newshortcut->IUniformResourceLocatorA_iface.lpVtbl = &uniformResourceLocatorAVtbl;
801 newshortcut->IUniformResourceLocatorW_iface.lpVtbl = &uniformResourceLocatorWVtbl;
802 newshortcut->IPersistFile_iface.lpVtbl = &persistFileVtbl;
803 newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl;
804 newshortcut->refCount = 1;
805 hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE,
806 STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage);
807 if (FAILED(hr))
809 TRACE("Failed to create the storage object needed for the shortcut.\n");
810 free(newshortcut);
811 return NULL;
814 hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy);
815 if (FAILED(hr))
817 TRACE("Failed to create the property object needed for the shortcut.\n");
818 IPropertySetStorage_Release(newshortcut->property_set_storage);
819 free(newshortcut);
820 return NULL;
822 IPropertyStorage_Release(dummy);
825 return newshortcut;
828 HRESULT WINAPI InternetShortcut_Create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
830 InternetShortcut *This;
831 HRESULT hres;
833 TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), ppv);
835 *ppv = NULL;
837 if(outer)
838 return CLASS_E_NOAGGREGATION;
840 This = create_shortcut();
841 if(!This)
842 return E_OUTOFMEMORY;
844 hres = Unknown_QueryInterface(This, riid, ppv);
845 Unknown_Release(This);
846 return hres;
850 /**********************************************************************
851 * OpenURL (ieframe.@)
853 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
855 InternetShortcut *shortcut;
856 WCHAR* urlfilepath = NULL;
857 int len;
859 shortcut = create_shortcut();
861 if(!shortcut)
862 return;
864 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
865 urlfilepath = malloc(len * sizeof(WCHAR));
866 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
868 if(SUCCEEDED(IPersistFile_Load(&shortcut->IPersistFile_iface, urlfilepath, 0))) {
869 URLINVOKECOMMANDINFOW ici;
871 memset( &ici, 0, sizeof ici );
872 ici.dwcbSize = sizeof ici;
873 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
874 ici.hwndParent = hWnd;
876 if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->IUniformResourceLocatorW_iface, (PURLINVOKECOMMANDINFOW) &ici)))
877 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl));
880 free(urlfilepath);
881 Unknown_Release(shortcut);