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.
30 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw
);
40 IUniformResourceLocatorA uniformResourceLocatorA
;
41 IUniformResourceLocatorW uniformResourceLocatorW
;
42 IPersistFile persistFile
;
51 /* utility functions */
53 static inline InternetShortcut
* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA
*iface
)
55 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, uniformResourceLocatorA
));
58 static inline InternetShortcut
* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW
*iface
)
60 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, uniformResourceLocatorW
));
63 static inline InternetShortcut
* impl_from_IPersistFile(IPersistFile
*iface
)
65 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, persistFile
));
68 static BOOL
run_winemenubuilder( const WCHAR
*args
)
70 static const WCHAR menubuilder
[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
74 PROCESS_INFORMATION pi
;
79 GetSystemDirectoryW( app
, MAX_PATH
- sizeof(menubuilder
)/sizeof(WCHAR
) );
80 strcatW( app
, menubuilder
);
82 len
= (strlenW( app
) + strlenW( args
) + 1) * sizeof(WCHAR
);
83 buffer
= heap_alloc( len
);
87 strcpyW( buffer
, app
);
88 strcatW( buffer
, args
);
90 TRACE("starting %s\n",debugstr_w(buffer
));
92 memset(&si
, 0, sizeof(si
));
95 Wow64DisableWow64FsRedirection( &redir
);
96 ret
= CreateProcessW( app
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
97 Wow64RevertWow64FsRedirection( redir
);
103 CloseHandle( pi
.hProcess
);
104 CloseHandle( pi
.hThread
);
110 static BOOL
StartLinkProcessor( LPCOLESTR szLink
)
112 static const WCHAR szFormat
[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
117 len
= sizeof(szFormat
) + lstrlenW( szLink
) * sizeof(WCHAR
);
118 buffer
= heap_alloc( len
);
122 wsprintfW( buffer
, szFormat
, szLink
);
123 ret
= run_winemenubuilder( buffer
);
128 /* interface functions */
130 static HRESULT
Unknown_QueryInterface(InternetShortcut
*This
, REFIID riid
, PVOID
*ppvObject
)
132 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
134 if (IsEqualGUID(&IID_IUnknown
, riid
))
135 *ppvObject
= &This
->uniformResourceLocatorA
;
136 else if (IsEqualGUID(&IID_IUniformResourceLocatorA
, riid
))
137 *ppvObject
= &This
->uniformResourceLocatorA
;
138 else if (IsEqualGUID(&IID_IUniformResourceLocatorW
, riid
))
139 *ppvObject
= &This
->uniformResourceLocatorW
;
140 else if (IsEqualGUID(&IID_IPersistFile
, riid
))
141 *ppvObject
= &This
->persistFile
;
142 else if (IsEqualGUID(&IID_IShellLinkA
, riid
))
144 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
145 return E_NOINTERFACE
;
147 else if (IsEqualGUID(&IID_IShellLinkW
, riid
))
149 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
150 return E_NOINTERFACE
;
154 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid
));
155 return E_NOINTERFACE
;
157 IUnknown_AddRef((IUnknown
*)*ppvObject
);
161 static ULONG
Unknown_AddRef(InternetShortcut
*This
)
163 TRACE("(%p)\n", This
);
164 return InterlockedIncrement(&This
->refCount
);
167 static ULONG
Unknown_Release(InternetShortcut
*This
)
170 TRACE("(%p)\n", This
);
171 count
= InterlockedDecrement(&This
->refCount
);
174 CoTaskMemFree(This
->url
);
175 CoTaskMemFree(This
->currentFile
);
177 SHDOCVW_UnlockModule();
182 static HRESULT WINAPI
UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW
*url
, REFIID riid
, PVOID
*ppvObject
)
184 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
185 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
186 return Unknown_QueryInterface(This
, riid
, ppvObject
);
189 static ULONG WINAPI
UniformResourceLocatorW_AddRef(IUniformResourceLocatorW
*url
)
191 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
192 TRACE("(%p)\n", url
);
193 return Unknown_AddRef(This
);
196 static ULONG WINAPI
UniformResourceLocatorW_Release(IUniformResourceLocatorW
*url
)
198 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
199 TRACE("(%p)\n", url
);
200 return Unknown_Release(This
);
203 static HRESULT WINAPI
UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW
*url
, LPCWSTR pcszURL
, DWORD dwInFlags
)
205 WCHAR
*newURL
= NULL
;
206 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
207 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_w(pcszURL
), dwInFlags
);
209 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
212 newURL
= co_strdupW(pcszURL
);
214 return E_OUTOFMEMORY
;
216 CoTaskMemFree(This
->url
);
218 This
->isDirty
= TRUE
;
222 static HRESULT WINAPI
UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW
*url
, LPWSTR
*ppszURL
)
225 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
226 TRACE("(%p, %p)\n", url
, ppszURL
);
227 if (This
->url
== NULL
)
231 *ppszURL
= co_strdupW(This
->url
);
232 if (*ppszURL
== NULL
)
238 static HRESULT WINAPI
UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW
*url
, PURLINVOKECOMMANDINFOW pCommandInfo
)
240 FIXME("(%p, %p): stub\n", url
, pCommandInfo
);
244 static HRESULT WINAPI
UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA
*url
, REFIID riid
, PVOID
*ppvObject
)
246 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
247 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
248 return Unknown_QueryInterface(This
, riid
, ppvObject
);
251 static ULONG WINAPI
UniformResourceLocatorA_AddRef(IUniformResourceLocatorA
*url
)
253 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
254 TRACE("(%p)\n", url
);
255 return Unknown_AddRef(This
);
258 static ULONG WINAPI
UniformResourceLocatorA_Release(IUniformResourceLocatorA
*url
)
260 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
261 TRACE("(%p)\n", url
);
262 return Unknown_Release(This
);
265 static HRESULT WINAPI
UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA
*url
, LPCSTR pcszURL
, DWORD dwInFlags
)
267 WCHAR
*newURL
= NULL
;
268 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
269 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_a(pcszURL
), dwInFlags
);
271 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
274 newURL
= co_strdupAtoW(pcszURL
);
276 return E_OUTOFMEMORY
;
278 CoTaskMemFree(This
->url
);
280 This
->isDirty
= TRUE
;
284 static HRESULT WINAPI
UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA
*url
, LPSTR
*ppszURL
)
287 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
288 TRACE("(%p, %p)\n", url
, ppszURL
);
289 if (This
->url
== NULL
)
293 *ppszURL
= co_strdupWtoA(This
->url
);
294 if (*ppszURL
== NULL
)
300 static HRESULT WINAPI
UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA
*url
, PURLINVOKECOMMANDINFOA pCommandInfo
)
302 FIXME("(%p, %p): stub\n", url
, pCommandInfo
);
306 static HRESULT WINAPI
PersistFile_QueryInterface(IPersistFile
*pFile
, REFIID riid
, PVOID
*ppvObject
)
308 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
309 TRACE("(%p, %s, %p)\n", pFile
, debugstr_guid(riid
), ppvObject
);
310 return Unknown_QueryInterface(This
, riid
, ppvObject
);
313 static ULONG WINAPI
PersistFile_AddRef(IPersistFile
*pFile
)
315 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
316 TRACE("(%p)\n", pFile
);
317 return Unknown_AddRef(This
);
320 static ULONG WINAPI
PersistFile_Release(IPersistFile
*pFile
)
322 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
323 TRACE("(%p)\n", pFile
);
324 return Unknown_Release(This
);
327 static HRESULT WINAPI
PersistFile_GetClassID(IPersistFile
*pFile
, CLSID
*pClassID
)
329 TRACE("(%p, %p)\n", pFile
, pClassID
);
330 *pClassID
= CLSID_InternetShortcut
;
334 static HRESULT WINAPI
PersistFile_IsDirty(IPersistFile
*pFile
)
336 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
337 TRACE("(%p)\n", pFile
);
338 return This
->isDirty
? S_OK
: S_FALSE
;
341 static HRESULT WINAPI
PersistFile_Load(IPersistFile
*pFile
, LPCOLESTR pszFileName
, DWORD dwMode
)
343 WCHAR str_header
[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
344 WCHAR str_URL
[] = {'U','R','L',0};
345 WCHAR
*filename
= NULL
;
347 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
348 TRACE("(%p, %s, 0x%x)\n", pFile
, debugstr_w(pszFileName
), dwMode
);
350 FIXME("ignoring unimplemented mode 0x%x\n", dwMode
);
351 filename
= co_strdupW(pszFileName
);
352 if (filename
!= NULL
)
356 WCHAR
*url
= CoTaskMemAlloc(len
*sizeof(WCHAR
));
359 r
= GetPrivateProfileStringW(str_header
, str_URL
, NULL
, url
, len
, pszFileName
);
364 url
= CoTaskMemAlloc(len
*sizeof(WCHAR
));
367 r
= GetPrivateProfileStringW(str_header
, str_URL
, NULL
, url
, len
, pszFileName
);
371 else if (url
!= NULL
)
373 CoTaskMemFree(This
->currentFile
);
374 This
->currentFile
= filename
;
375 CoTaskMemFree(This
->url
);
377 This
->isDirty
= FALSE
;
386 CoTaskMemFree(filename
);
393 static HRESULT WINAPI
PersistFile_Save(IPersistFile
*pFile
, LPCOLESTR pszFileName
, BOOL fRemember
)
398 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
400 TRACE("(%p, %s, %d)\n", pFile
, debugstr_w(pszFileName
), fRemember
);
402 if (pszFileName
!= NULL
&& fRemember
)
404 LPOLESTR oldFile
= This
->currentFile
;
405 This
->currentFile
= co_strdupW(pszFileName
);
406 if (This
->currentFile
== NULL
)
408 This
->currentFile
= oldFile
;
409 return E_OUTOFMEMORY
;
411 CoTaskMemFree(oldFile
);
413 if (This
->url
== NULL
)
416 /* Windows seems to always write:
417 * ASCII "[InternetShortcut]" headers
418 * ASCII names in "name=value" pairs
419 * An ASCII (probably UTF8?) value in "URL=..."
421 len
= WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, NULL
, 0, 0, 0);
422 url
= heap_alloc(len
);
426 WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, url
, len
, 0, 0);
427 file
= CreateFileW(pszFileName
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
428 if (file
!= INVALID_HANDLE_VALUE
)
431 char str_header
[] = "[InternetShortcut]";
432 char str_URL
[] = "URL=";
433 char str_eol
[] = "\r\n";
435 WriteFile(file
, str_header
, lstrlenA(str_header
), &bytesWritten
, NULL
);
436 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
437 WriteFile(file
, str_URL
, lstrlenA(str_URL
), &bytesWritten
, NULL
);
438 WriteFile(file
, url
, lstrlenA(url
), &bytesWritten
, NULL
);
439 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
441 if (pszFileName
== NULL
|| fRemember
)
442 This
->isDirty
= FALSE
;
443 StartLinkProcessor(pszFileName
);
455 static HRESULT WINAPI
PersistFile_SaveCompleted(IPersistFile
*pFile
, LPCOLESTR pszFileName
)
457 FIXME("(%p, %p): stub\n", pFile
, pszFileName
);
461 static HRESULT WINAPI
PersistFile_GetCurFile(IPersistFile
*pFile
, LPOLESTR
*ppszFileName
)
464 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
465 TRACE("(%p, %p)\n", pFile
, ppszFileName
);
466 if (This
->currentFile
== NULL
)
467 *ppszFileName
= NULL
;
470 *ppszFileName
= co_strdupW(This
->currentFile
);
471 if (*ppszFileName
== NULL
)
479 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl
= {
480 UniformResourceLocatorW_QueryInterface
,
481 UniformResourceLocatorW_AddRef
,
482 UniformResourceLocatorW_Release
,
483 UniformResourceLocatorW_SetUrl
,
484 UniformResourceLocatorW_GetUrl
,
485 UniformResourceLocatorW_InvokeCommand
488 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl
= {
489 UniformResourceLocatorA_QueryInterface
,
490 UniformResourceLocatorA_AddRef
,
491 UniformResourceLocatorA_Release
,
492 UniformResourceLocatorA_SetUrl
,
493 UniformResourceLocatorA_GetUrl
,
494 UniformResourceLocatorA_InvokeCommand
497 static const IPersistFileVtbl persistFileVtbl
= {
498 PersistFile_QueryInterface
,
501 PersistFile_GetClassID
,
505 PersistFile_SaveCompleted
,
506 PersistFile_GetCurFile
509 HRESULT
InternetShortcut_Create(IUnknown
*pOuter
, REFIID riid
, void **ppv
)
511 InternetShortcut
*This
;
514 TRACE("(%p, %s, %p)\n", pOuter
, debugstr_guid(riid
), ppv
);
519 return CLASS_E_NOAGGREGATION
;
521 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(InternetShortcut
));
524 This
->uniformResourceLocatorA
.lpVtbl
= &uniformResourceLocatorAVtbl
;
525 This
->uniformResourceLocatorW
.lpVtbl
= &uniformResourceLocatorWVtbl
;
526 This
->persistFile
.lpVtbl
= &persistFileVtbl
;
528 hr
= Unknown_QueryInterface(This
, riid
, ppv
);
530 SHDOCVW_LockModule();
536 return E_OUTOFMEMORY
;