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
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.
32 #define NONAMELESSUNION
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ieframe
);
50 IUniformResourceLocatorA IUniformResourceLocatorA_iface
;
51 IUniformResourceLocatorW IUniformResourceLocatorW_iface
;
52 IPersistFile IPersistFile_iface
;
53 IPropertySetStorage IPropertySetStorage_iface
;
57 IPropertySetStorage
*property_set_storage
;
63 /* utility functions */
65 static inline InternetShortcut
* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA
*iface
)
67 return CONTAINING_RECORD(iface
, InternetShortcut
, IUniformResourceLocatorA_iface
);
70 static inline InternetShortcut
* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW
*iface
)
72 return CONTAINING_RECORD(iface
, InternetShortcut
, IUniformResourceLocatorW_iface
);
75 static inline InternetShortcut
* impl_from_IPersistFile(IPersistFile
*iface
)
77 return CONTAINING_RECORD(iface
, InternetShortcut
, IPersistFile_iface
);
80 static inline InternetShortcut
* impl_from_IPropertySetStorage(IPropertySetStorage
*iface
)
82 return CONTAINING_RECORD(iface
, InternetShortcut
, IPropertySetStorage_iface
);
85 static BOOL
run_winemenubuilder( const WCHAR
*args
)
87 static const WCHAR menubuilder
[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
91 PROCESS_INFORMATION pi
;
96 GetSystemDirectoryW( app
, MAX_PATH
- ARRAY_SIZE( menubuilder
));
97 lstrcatW( app
, menubuilder
);
99 len
= (lstrlenW( app
) + lstrlenW( args
) + 1) * sizeof(WCHAR
);
100 buffer
= heap_alloc( len
);
104 lstrcpyW( buffer
, app
);
105 lstrcatW( buffer
, args
);
107 TRACE("starting %s\n",debugstr_w(buffer
));
109 memset(&si
, 0, sizeof(si
));
112 Wow64DisableWow64FsRedirection( &redir
);
113 ret
= CreateProcessW( app
, buffer
, NULL
, NULL
, FALSE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
);
114 Wow64RevertWow64FsRedirection( redir
);
120 CloseHandle( pi
.hProcess
);
121 CloseHandle( pi
.hThread
);
127 static BOOL
StartLinkProcessor( LPCOLESTR szLink
)
129 static const WCHAR szFormat
[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
134 len
= sizeof(szFormat
) + lstrlenW( szLink
) * sizeof(WCHAR
);
135 buffer
= heap_alloc( len
);
139 swprintf( buffer
, len
/ sizeof(WCHAR
), szFormat
, szLink
);
140 ret
= run_winemenubuilder( buffer
);
145 /* interface functions */
147 static HRESULT
Unknown_QueryInterface(InternetShortcut
*This
, REFIID riid
, PVOID
*ppvObject
)
149 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
151 if (IsEqualGUID(&IID_IUnknown
, riid
))
152 *ppvObject
= &This
->IUniformResourceLocatorA_iface
;
153 else if (IsEqualGUID(&IID_IUniformResourceLocatorA
, riid
))
154 *ppvObject
= &This
->IUniformResourceLocatorA_iface
;
155 else if (IsEqualGUID(&IID_IUniformResourceLocatorW
, riid
))
156 *ppvObject
= &This
->IUniformResourceLocatorW_iface
;
157 else if (IsEqualGUID(&IID_IPersistFile
, riid
))
158 *ppvObject
= &This
->IPersistFile_iface
;
159 else if (IsEqualGUID(&IID_IPropertySetStorage
, riid
))
160 *ppvObject
= &This
->IPropertySetStorage_iface
;
161 else if (IsEqualGUID(&IID_IShellLinkA
, riid
))
163 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
164 return E_NOINTERFACE
;
166 else if (IsEqualGUID(&IID_IShellLinkW
, riid
))
168 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
169 return E_NOINTERFACE
;
173 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid
));
174 return E_NOINTERFACE
;
176 IUnknown_AddRef((IUnknown
*)*ppvObject
);
180 static ULONG
Unknown_AddRef(InternetShortcut
*This
)
182 TRACE("(%p)\n", This
);
183 return InterlockedIncrement(&This
->refCount
);
186 static ULONG
Unknown_Release(InternetShortcut
*This
)
189 TRACE("(%p)\n", This
);
190 count
= InterlockedDecrement(&This
->refCount
);
193 CoTaskMemFree(This
->url
);
194 CoTaskMemFree(This
->currentFile
);
195 IPropertySetStorage_Release(This
->property_set_storage
);
202 static HRESULT WINAPI
UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW
*url
, REFIID riid
, PVOID
*ppvObject
)
204 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
205 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
206 return Unknown_QueryInterface(This
, riid
, ppvObject
);
209 static ULONG WINAPI
UniformResourceLocatorW_AddRef(IUniformResourceLocatorW
*url
)
211 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
212 TRACE("(%p)\n", url
);
213 return Unknown_AddRef(This
);
216 static ULONG WINAPI
UniformResourceLocatorW_Release(IUniformResourceLocatorW
*url
)
218 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
219 TRACE("(%p)\n", url
);
220 return Unknown_Release(This
);
223 static HRESULT WINAPI
UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW
*url
, LPCWSTR pcszURL
, DWORD dwInFlags
)
225 WCHAR
*newURL
= NULL
;
226 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
227 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_w(pcszURL
), dwInFlags
);
229 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
232 newURL
= co_strdupW(pcszURL
);
234 return E_OUTOFMEMORY
;
236 CoTaskMemFree(This
->url
);
238 This
->isDirty
= TRUE
;
242 static HRESULT WINAPI
UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW
*url
, LPWSTR
*ppszURL
)
244 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
246 TRACE("(%p, %p)\n", url
, ppszURL
);
253 *ppszURL
= co_strdupW(This
->url
);
255 return E_OUTOFMEMORY
;
260 static HRESULT WINAPI
UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW
*url
, PURLINVOKECOMMANDINFOW pCommandInfo
)
262 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
265 static const WCHAR wszURLProtocol
[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
266 SHELLEXECUTEINFOW sei
;
270 TRACE("%p %p\n", This
, pCommandInfo
);
272 if (pCommandInfo
->dwcbSize
< sizeof (URLINVOKECOMMANDINFOW
))
275 if (pCommandInfo
->dwFlags
!= IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB
)
277 FIXME("(%p, %p): non-default verbs not implemented\n", url
, pCommandInfo
);
281 hres
= CoInternetParseUrl(This
->url
, PARSE_SCHEMA
, 0, app
, ARRAY_SIZE(app
), NULL
, 0);
285 res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, app
, &hkey
);
286 if(res
!= ERROR_SUCCESS
)
289 res
= RegQueryValueExW(hkey
, wszURLProtocol
, NULL
, &type
, NULL
, NULL
);
291 if(res
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
294 memset(&sei
, 0, sizeof(sei
));
295 sei
.cbSize
= sizeof(sei
);
296 sei
.lpFile
= This
->url
;
299 if( ShellExecuteExW(&sei
) )
305 static HRESULT WINAPI
UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA
*url
, REFIID riid
, PVOID
*ppvObject
)
307 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
308 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
309 return Unknown_QueryInterface(This
, riid
, ppvObject
);
312 static ULONG WINAPI
UniformResourceLocatorA_AddRef(IUniformResourceLocatorA
*url
)
314 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
315 TRACE("(%p)\n", url
);
316 return Unknown_AddRef(This
);
319 static ULONG WINAPI
UniformResourceLocatorA_Release(IUniformResourceLocatorA
*url
)
321 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
322 TRACE("(%p)\n", url
);
323 return Unknown_Release(This
);
326 static HRESULT WINAPI
UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA
*url
, LPCSTR pcszURL
, DWORD dwInFlags
)
328 WCHAR
*newURL
= NULL
;
329 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
330 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_a(pcszURL
), dwInFlags
);
332 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
335 newURL
= co_strdupAtoW(pcszURL
);
337 return E_OUTOFMEMORY
;
339 CoTaskMemFree(This
->url
);
341 This
->isDirty
= TRUE
;
345 static HRESULT WINAPI
UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA
*url
, LPSTR
*ppszURL
)
347 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
349 TRACE("(%p, %p)\n", url
, ppszURL
);
357 *ppszURL
= co_strdupWtoA(This
->url
);
359 return E_OUTOFMEMORY
;
364 static HRESULT WINAPI
UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA
*url
, PURLINVOKECOMMANDINFOA pCommandInfo
)
366 URLINVOKECOMMANDINFOW wideCommandInfo
;
370 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
372 wideCommandInfo
.dwcbSize
= sizeof wideCommandInfo
;
373 wideCommandInfo
.dwFlags
= pCommandInfo
->dwFlags
;
374 wideCommandInfo
.hwndParent
= pCommandInfo
->hwndParent
;
376 len
= MultiByteToWideChar(CP_ACP
, 0, pCommandInfo
->pcszVerb
, -1, NULL
, 0);
377 wideVerb
= heap_alloc(len
* sizeof(WCHAR
));
378 MultiByteToWideChar(CP_ACP
, 0, pCommandInfo
->pcszVerb
, -1, wideVerb
, len
);
380 wideCommandInfo
.pcszVerb
= wideVerb
;
382 res
= UniformResourceLocatorW_InvokeCommand(&This
->IUniformResourceLocatorW_iface
, &wideCommandInfo
);
388 static HRESULT WINAPI
PersistFile_QueryInterface(IPersistFile
*pFile
, REFIID riid
, PVOID
*ppvObject
)
390 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
391 TRACE("(%p, %s, %p)\n", pFile
, debugstr_guid(riid
), ppvObject
);
392 return Unknown_QueryInterface(This
, riid
, ppvObject
);
395 static ULONG WINAPI
PersistFile_AddRef(IPersistFile
*pFile
)
397 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
398 TRACE("(%p)\n", pFile
);
399 return Unknown_AddRef(This
);
402 static ULONG WINAPI
PersistFile_Release(IPersistFile
*pFile
)
404 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
405 TRACE("(%p)\n", pFile
);
406 return Unknown_Release(This
);
409 static HRESULT WINAPI
PersistFile_GetClassID(IPersistFile
*pFile
, CLSID
*pClassID
)
411 TRACE("(%p, %p)\n", pFile
, pClassID
);
412 *pClassID
= CLSID_InternetShortcut
;
416 static HRESULT WINAPI
PersistFile_IsDirty(IPersistFile
*pFile
)
418 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
419 TRACE("(%p)\n", pFile
);
420 return This
->isDirty
? S_OK
: S_FALSE
;
423 /* Returns allocated profile string and a standard return code. */
424 static HRESULT
get_profile_string(LPCWSTR lpAppName
, LPCWSTR lpKeyName
,
425 LPCWSTR lpFileName
, WCHAR
**rString
)
432 buffer
= CoTaskMemAlloc(len
* sizeof(*buffer
));
434 return E_OUTOFMEMORY
;
436 r
= GetPrivateProfileStringW(lpAppName
, lpKeyName
, NULL
, buffer
, len
, lpFileName
);
442 realloc_buf
= CoTaskMemRealloc(buffer
, len
* sizeof(*buffer
));
443 if (realloc_buf
== NULL
)
445 CoTaskMemFree(buffer
);
446 return E_OUTOFMEMORY
;
448 buffer
= realloc_buf
;
450 r
= GetPrivateProfileStringW(lpAppName
, lpKeyName
, NULL
, buffer
, len
, lpFileName
);
454 return r
? S_OK
: E_FAIL
;
457 static HRESULT WINAPI
PersistFile_Load(IPersistFile
*pFile
, LPCOLESTR pszFileName
, DWORD dwMode
)
459 static const WCHAR str_header
[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
460 static const WCHAR str_URL
[] = {'U','R','L',0};
461 static const WCHAR str_iconfile
[] = {'i','c','o','n','f','i','l','e',0};
462 static const WCHAR str_iconindex
[] = {'i','c','o','n','i','n','d','e','x',0};
463 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
464 WCHAR
*filename
= NULL
;
467 IPropertyStorage
*pPropStg
;
469 WCHAR
*iconindexstring
;
471 TRACE("(%p, %s, 0x%x)\n", pFile
, debugstr_w(pszFileName
), dwMode
);
474 FIXME("ignoring unimplemented mode 0x%x\n", dwMode
);
476 filename
= co_strdupW(pszFileName
);
478 return E_OUTOFMEMORY
;
480 if (FAILED(hr
= get_profile_string(str_header
, str_URL
, pszFileName
, &url
)))
482 CoTaskMemFree(filename
);
486 hr
= IPropertySetStorage_Open(This
->property_set_storage
, &FMTID_Intshcut
,
487 STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
, &pPropStg
);
490 CoTaskMemFree(filename
);
495 CoTaskMemFree(This
->currentFile
);
496 This
->currentFile
= filename
;
497 CoTaskMemFree(This
->url
);
499 This
->isDirty
= FALSE
;
501 /* Now we're going to read in the iconfile and iconindex.
502 If we don't find them, that's not a failure case -- it's possible
503 that they just aren't in there. */
505 if (get_profile_string(str_header
, str_iconfile
, pszFileName
, &iconfile
) == S_OK
)
509 ps
.ulKind
= PRSPEC_PROPID
;
510 ps
.u
.propid
= PID_IS_ICONFILE
;
512 pv
.u
.pwszVal
= iconfile
;
513 hr
= IPropertyStorage_WriteMultiple(pPropStg
, 1, &ps
, &pv
, 0);
515 TRACE("Failed to store the iconfile to our property storage. hr = 0x%x\n", hr
);
517 CoTaskMemFree(iconfile
);
519 if (get_profile_string(str_header
, str_iconindex
, pszFileName
, &iconindexstring
) == S_OK
)
524 iconindex
= wcstol(iconindexstring
, NULL
, 10);
525 ps
.ulKind
= PRSPEC_PROPID
;
526 ps
.u
.propid
= PID_IS_ICONINDEX
;
528 pv
.u
.iVal
= iconindex
;
529 hr
= IPropertyStorage_WriteMultiple(pPropStg
, 1, &ps
, &pv
, 0);
531 TRACE("Failed to store the iconindex to our property storage. hr = 0x%x\n", hr
);
533 CoTaskMemFree(iconindexstring
);
535 IPropertyStorage_Release(pPropStg
);
539 static HRESULT WINAPI
PersistFile_Save(IPersistFile
*pFile
, LPCOLESTR pszFileName
, BOOL fRemember
)
544 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
546 TRACE("(%p, %s, %d)\n", pFile
, debugstr_w(pszFileName
), fRemember
);
548 if (pszFileName
!= NULL
&& fRemember
)
550 LPOLESTR oldFile
= This
->currentFile
;
551 This
->currentFile
= co_strdupW(pszFileName
);
552 if (This
->currentFile
== NULL
)
554 This
->currentFile
= oldFile
;
555 return E_OUTOFMEMORY
;
557 CoTaskMemFree(oldFile
);
559 if (This
->url
== NULL
)
562 /* Windows seems to always write:
563 * ASCII "[InternetShortcut]" headers
564 * ASCII names in "name=value" pairs
565 * An ASCII (probably UTF8?) value in "URL=..."
567 len
= WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, NULL
, 0, 0, 0);
568 url
= heap_alloc(len
);
572 WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, url
, len
, 0, 0);
573 file
= CreateFileW(pszFileName
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
574 if (file
!= INVALID_HANDLE_VALUE
)
576 static const char str_header
[] = "[InternetShortcut]";
577 static const char str_URL
[] = "URL=";
578 static const char str_ICONFILE
[] = "ICONFILE=";
579 static const char str_eol
[] = "\r\n";
582 IPropertyStorage
*pPropStgRead
;
584 PROPVARIANT pvread
[2];
585 ps
[0].ulKind
= PRSPEC_PROPID
;
586 ps
[0].u
.propid
= PID_IS_ICONFILE
;
587 ps
[1].ulKind
= PRSPEC_PROPID
;
588 ps
[1].u
.propid
= PID_IS_ICONINDEX
;
590 WriteFile(file
, str_header
, ARRAY_SIZE(str_header
) - 1, &bytesWritten
, NULL
);
591 WriteFile(file
, str_eol
, ARRAY_SIZE(str_eol
) - 1, &bytesWritten
, NULL
);
592 WriteFile(file
, str_URL
, ARRAY_SIZE(str_URL
) - 1, &bytesWritten
, NULL
);
593 WriteFile(file
, url
, lstrlenA(url
), &bytesWritten
, NULL
);
594 WriteFile(file
, str_eol
, ARRAY_SIZE(str_eol
) - 1, &bytesWritten
, NULL
);
596 hr
= IPropertySetStorage_Open(This
->property_set_storage
, &FMTID_Intshcut
, STGM_READ
|STGM_SHARE_EXCLUSIVE
, &pPropStgRead
);
599 hr
= IPropertyStorage_ReadMultiple(pPropStgRead
, 2, ps
, pvread
);
602 /* None of the properties are present, that's ok */
604 IPropertyStorage_Release(pPropStgRead
);
606 else if (SUCCEEDED(hr
))
608 char indexString
[50];
609 len
= WideCharToMultiByte(CP_UTF8
, 0, pvread
[0].u
.pwszVal
, -1, NULL
, 0, 0, 0);
610 iconfile
= heap_alloc(len
);
611 if (iconfile
!= NULL
)
613 WideCharToMultiByte(CP_UTF8
, 0, pvread
[0].u
.pwszVal
, -1, iconfile
, len
, 0, 0);
614 WriteFile(file
, str_ICONFILE
, lstrlenA(str_ICONFILE
), &bytesWritten
, NULL
);
615 WriteFile(file
, iconfile
, lstrlenA(iconfile
), &bytesWritten
, NULL
);
616 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
619 sprintf(indexString
, "ICONINDEX=%d", pvread
[1].u
.iVal
);
620 WriteFile(file
, indexString
, lstrlenA(indexString
), &bytesWritten
, NULL
);
621 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
623 IPropertyStorage_Release(pPropStgRead
);
624 PropVariantClear(&pvread
[0]);
625 PropVariantClear(&pvread
[1]);
629 TRACE("Unable to read properties.\n");
634 TRACE("Unable to get the IPropertyStorage.\n");
638 if (pszFileName
== NULL
|| fRemember
)
639 This
->isDirty
= FALSE
;
640 StartLinkProcessor(pszFileName
);
652 static HRESULT WINAPI
PersistFile_SaveCompleted(IPersistFile
*pFile
, LPCOLESTR pszFileName
)
654 FIXME("(%p, %p): stub\n", pFile
, pszFileName
);
658 static HRESULT WINAPI
PersistFile_GetCurFile(IPersistFile
*pFile
, LPOLESTR
*ppszFileName
)
661 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
662 TRACE("(%p, %p)\n", pFile
, ppszFileName
);
663 if (This
->currentFile
== NULL
)
664 *ppszFileName
= NULL
;
667 *ppszFileName
= co_strdupW(This
->currentFile
);
668 if (*ppszFileName
== NULL
)
674 static HRESULT WINAPI
PropertySetStorage_QueryInterface(IPropertySetStorage
*iface
, REFIID riid
, PVOID
*ppvObject
)
676 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
677 TRACE("(%p)\n", iface
);
678 return Unknown_QueryInterface(This
, riid
, ppvObject
);
681 static ULONG WINAPI
PropertySetStorage_AddRef(IPropertySetStorage
*iface
)
683 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
684 TRACE("(%p)\n", iface
);
685 return Unknown_AddRef(This
);
688 static ULONG WINAPI
PropertySetStorage_Release(IPropertySetStorage
*iface
)
690 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
691 TRACE("(%p)\n", iface
);
692 return Unknown_Release(This
);
695 static HRESULT WINAPI
PropertySetStorage_Create(
696 IPropertySetStorage
* iface
,
701 IPropertyStorage
**ppprstg
)
703 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
704 TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid
), pclsid
, grfFlags
, grfMode
, ppprstg
);
706 return IPropertySetStorage_Create(This
->property_set_storage
,
714 static HRESULT WINAPI
PropertySetStorage_Open(
715 IPropertySetStorage
* iface
,
718 IPropertyStorage
**ppprstg
)
720 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
721 TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid
), grfMode
, ppprstg
);
723 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */
724 return IPropertySetStorage_Open(This
->property_set_storage
,
726 grfMode
|STGM_SHARE_EXCLUSIVE
,
730 static HRESULT WINAPI
PropertySetStorage_Delete(IPropertySetStorage
*iface
, REFFMTID rfmtid
)
732 InternetShortcut
*This
= impl_from_IPropertySetStorage(iface
);
733 TRACE("(%s)\n", debugstr_guid(rfmtid
));
736 return IPropertySetStorage_Delete(This
->property_set_storage
,
740 static HRESULT WINAPI
PropertySetStorage_Enum(IPropertySetStorage
*iface
, IEnumSTATPROPSETSTG
**ppenum
)
742 FIXME("(%p): stub\n", ppenum
);
746 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl
= {
747 UniformResourceLocatorW_QueryInterface
,
748 UniformResourceLocatorW_AddRef
,
749 UniformResourceLocatorW_Release
,
750 UniformResourceLocatorW_SetUrl
,
751 UniformResourceLocatorW_GetUrl
,
752 UniformResourceLocatorW_InvokeCommand
755 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl
= {
756 UniformResourceLocatorA_QueryInterface
,
757 UniformResourceLocatorA_AddRef
,
758 UniformResourceLocatorA_Release
,
759 UniformResourceLocatorA_SetUrl
,
760 UniformResourceLocatorA_GetUrl
,
761 UniformResourceLocatorA_InvokeCommand
764 static const IPersistFileVtbl persistFileVtbl
= {
765 PersistFile_QueryInterface
,
768 PersistFile_GetClassID
,
772 PersistFile_SaveCompleted
,
773 PersistFile_GetCurFile
776 static const IPropertySetStorageVtbl propertySetStorageVtbl
= {
777 PropertySetStorage_QueryInterface
,
778 PropertySetStorage_AddRef
,
779 PropertySetStorage_Release
,
780 PropertySetStorage_Create
,
781 PropertySetStorage_Open
,
782 PropertySetStorage_Delete
,
783 PropertySetStorage_Enum
786 static InternetShortcut
*create_shortcut(void)
788 InternetShortcut
*newshortcut
;
790 newshortcut
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(InternetShortcut
));
794 IPropertyStorage
*dummy
;
796 newshortcut
->IUniformResourceLocatorA_iface
.lpVtbl
= &uniformResourceLocatorAVtbl
;
797 newshortcut
->IUniformResourceLocatorW_iface
.lpVtbl
= &uniformResourceLocatorWVtbl
;
798 newshortcut
->IPersistFile_iface
.lpVtbl
= &persistFileVtbl
;
799 newshortcut
->IPropertySetStorage_iface
.lpVtbl
= &propertySetStorageVtbl
;
800 newshortcut
->refCount
= 1;
801 hr
= StgCreateStorageEx(NULL
, STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
,
802 STGFMT_STORAGE
, 0, NULL
, NULL
, &IID_IPropertySetStorage
, (void **) &newshortcut
->property_set_storage
);
805 TRACE("Failed to create the storage object needed for the shortcut.\n");
806 heap_free(newshortcut
);
810 hr
= IPropertySetStorage_Create(newshortcut
->property_set_storage
, &FMTID_Intshcut
, NULL
, PROPSETFLAG_DEFAULT
, STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
, &dummy
);
813 TRACE("Failed to create the property object needed for the shortcut.\n");
814 IPropertySetStorage_Release(newshortcut
->property_set_storage
);
815 heap_free(newshortcut
);
818 IPropertyStorage_Release(dummy
);
824 HRESULT WINAPI
InternetShortcut_Create(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
826 InternetShortcut
*This
;
829 TRACE("(%p, %s, %p)\n", outer
, debugstr_guid(riid
), ppv
);
834 return CLASS_E_NOAGGREGATION
;
836 This
= create_shortcut();
838 return E_OUTOFMEMORY
;
840 hres
= Unknown_QueryInterface(This
, riid
, ppv
);
841 Unknown_Release(This
);
846 /**********************************************************************
847 * OpenURL (ieframe.@)
849 void WINAPI
OpenURL(HWND hWnd
, HINSTANCE hInst
, LPCSTR lpcstrUrl
, int nShowCmd
)
851 InternetShortcut
*shortcut
;
852 WCHAR
* urlfilepath
= NULL
;
855 shortcut
= create_shortcut();
860 len
= MultiByteToWideChar(CP_ACP
, 0, lpcstrUrl
, -1, NULL
, 0);
861 urlfilepath
= heap_alloc(len
* sizeof(WCHAR
));
862 MultiByteToWideChar(CP_ACP
, 0, lpcstrUrl
, -1, urlfilepath
, len
);
864 if(SUCCEEDED(IPersistFile_Load(&shortcut
->IPersistFile_iface
, urlfilepath
, 0))) {
865 URLINVOKECOMMANDINFOW ici
;
867 memset( &ici
, 0, sizeof ici
);
868 ici
.dwcbSize
= sizeof ici
;
869 ici
.dwFlags
= IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB
;
870 ici
.hwndParent
= hWnd
;
872 if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut
->IUniformResourceLocatorW_iface
, (PURLINVOKECOMMANDINFOW
) &ici
)))
873 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl
));
876 heap_free(urlfilepath
);
877 Unknown_Release(shortcut
);