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 * fd.o desktop and menu integration
24 * Implement the IShellLinkA/W interfaces
25 * Handle the SetURL flags
27 * Implement any other interfaces? Does any software actually use them?
29 * The installer for the Zuma Deluxe Popcap game is good for testing.
32 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw
);
42 IUniformResourceLocatorA uniformResourceLocatorA
;
43 IUniformResourceLocatorW uniformResourceLocatorW
;
44 IPersistFile persistFile
;
53 /* utility functions */
55 static inline InternetShortcut
* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA
*iface
)
57 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, uniformResourceLocatorA
));
60 static inline InternetShortcut
* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW
*iface
)
62 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, uniformResourceLocatorW
));
65 static inline InternetShortcut
* impl_from_IPersistFile(IPersistFile
*iface
)
67 return (InternetShortcut
*)((char*)iface
- FIELD_OFFSET(InternetShortcut
, persistFile
));
70 /* interface functions */
72 static HRESULT WINAPI
Unknown_QueryInterface(InternetShortcut
*This
, REFIID riid
, PVOID
*ppvObject
)
74 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
76 if (IsEqualGUID(&IID_IUnknown
, riid
))
77 *ppvObject
= &This
->uniformResourceLocatorA
;
78 else if (IsEqualGUID(&IID_IUniformResourceLocatorA
, riid
))
79 *ppvObject
= &This
->uniformResourceLocatorA
;
80 else if (IsEqualGUID(&IID_IUniformResourceLocatorW
, riid
))
81 *ppvObject
= &This
->uniformResourceLocatorW
;
82 else if (IsEqualGUID(&IID_IPersistFile
, riid
))
83 *ppvObject
= &This
->persistFile
;
84 else if (IsEqualGUID(&IID_IShellLinkA
, riid
))
86 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
89 else if (IsEqualGUID(&IID_IShellLinkW
, riid
))
91 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
96 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid
));
99 IUnknown_AddRef((IUnknown
*)*ppvObject
);
103 static ULONG WINAPI
Unknown_AddRef(InternetShortcut
*This
)
105 TRACE("(%p)\n", This
);
106 return InterlockedIncrement(&This
->refCount
);
109 static ULONG WINAPI
Unknown_Release(InternetShortcut
*This
)
112 TRACE("(%p)\n", This
);
113 count
= InterlockedDecrement(&This
->refCount
);
116 CoTaskMemFree(This
->url
);
117 CoTaskMemFree(This
->currentFile
);
119 SHDOCVW_UnlockModule();
124 static HRESULT WINAPI
UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW
*url
, REFIID riid
, PVOID
*ppvObject
)
126 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
127 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
128 return Unknown_QueryInterface(This
, riid
, ppvObject
);
131 static ULONG WINAPI
UniformResourceLocatorW_AddRef(IUniformResourceLocatorW
*url
)
133 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
134 TRACE("(%p)\n", url
);
135 return Unknown_AddRef(This
);
138 static ULONG WINAPI
UniformResourceLocatorW_Release(IUniformResourceLocatorW
*url
)
140 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
141 TRACE("(%p)\n", url
);
142 return Unknown_Release(This
);
145 static HRESULT WINAPI
UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW
*url
, LPCWSTR pcszURL
, DWORD dwInFlags
)
147 WCHAR
*newURL
= NULL
;
148 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
149 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_w(pcszURL
), dwInFlags
);
151 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
154 newURL
= co_strdupW(pcszURL
);
156 return E_OUTOFMEMORY
;
158 CoTaskMemFree(This
->url
);
160 This
->isDirty
= TRUE
;
164 static HRESULT WINAPI
UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW
*url
, LPWSTR
*ppszURL
)
167 InternetShortcut
*This
= impl_from_IUniformResourceLocatorW(url
);
168 TRACE("(%p, %p)\n", url
, ppszURL
);
169 if (This
->url
== NULL
)
173 *ppszURL
= co_strdupW(This
->url
);
174 if (*ppszURL
== NULL
)
180 static HRESULT WINAPI
UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW
*url
, PURLINVOKECOMMANDINFOW pCommandInfo
)
182 FIXME("(%p, %p): stub\n", url
, pCommandInfo
);
186 static HRESULT WINAPI
UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA
*url
, REFIID riid
, PVOID
*ppvObject
)
188 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
189 TRACE("(%p, %s, %p)\n", url
, debugstr_guid(riid
), ppvObject
);
190 return Unknown_QueryInterface(This
, riid
, ppvObject
);
193 static ULONG WINAPI
UniformResourceLocatorA_AddRef(IUniformResourceLocatorA
*url
)
195 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
196 TRACE("(%p)\n", url
);
197 return Unknown_AddRef(This
);
200 static ULONG WINAPI
UniformResourceLocatorA_Release(IUniformResourceLocatorA
*url
)
202 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
203 TRACE("(%p)\n", url
);
204 return Unknown_Release(This
);
207 static HRESULT WINAPI
UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA
*url
, LPCSTR pcszURL
, DWORD dwInFlags
)
209 WCHAR
*newURL
= NULL
;
210 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
211 TRACE("(%p, %s, 0x%x)\n", url
, debugstr_a(pcszURL
), dwInFlags
);
213 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags
);
216 newURL
= co_strdupAtoW(pcszURL
);
218 return E_OUTOFMEMORY
;
220 CoTaskMemFree(This
->url
);
222 This
->isDirty
= TRUE
;
226 static HRESULT WINAPI
UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA
*url
, LPSTR
*ppszURL
)
229 InternetShortcut
*This
= impl_from_IUniformResourceLocatorA(url
);
230 TRACE("(%p, %p)\n", url
, ppszURL
);
231 if (This
->url
== NULL
)
235 *ppszURL
= co_strdupWtoA(This
->url
);
236 if (*ppszURL
== NULL
)
242 static HRESULT WINAPI
UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA
*url
, PURLINVOKECOMMANDINFOA pCommandInfo
)
244 FIXME("(%p, %p): stub\n", url
, pCommandInfo
);
248 static HRESULT WINAPI
PersistFile_QueryInterface(IPersistFile
*pFile
, REFIID riid
, PVOID
*ppvObject
)
250 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
251 TRACE("(%p, %s, %p)\n", pFile
, debugstr_guid(riid
), ppvObject
);
252 return Unknown_QueryInterface(This
, riid
, ppvObject
);
255 static ULONG WINAPI
PersistFile_AddRef(IPersistFile
*pFile
)
257 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
258 TRACE("(%p)\n", pFile
);
259 return Unknown_AddRef(This
);
262 static ULONG WINAPI
PersistFile_Release(IPersistFile
*pFile
)
264 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
265 TRACE("(%p)\n", pFile
);
266 return Unknown_Release(This
);
269 static HRESULT WINAPI
PersistFile_GetClassID(IPersistFile
*pFile
, CLSID
*pClassID
)
271 TRACE("(%p, %p)\n", pFile
, pClassID
);
272 *pClassID
= CLSID_InternetShortcut
;
276 static HRESULT WINAPI
PersistFile_IsDirty(IPersistFile
*pFile
)
278 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
279 TRACE("(%p)\n", pFile
);
280 return This
->isDirty
? S_OK
: S_FALSE
;
283 static HRESULT WINAPI
PersistFile_Load(IPersistFile
*pFile
, LPCOLESTR pszFileName
, DWORD dwMode
)
285 FIXME("(%p, %p, 0x%x): stub\n", pFile
, pszFileName
, dwMode
);
289 static HRESULT WINAPI
PersistFile_Save(IPersistFile
*pFile
, LPCOLESTR pszFileName
, BOOL fRemember
)
294 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
296 TRACE("(%p, %s, %d)\n", pFile
, debugstr_w(pszFileName
), fRemember
);
298 if (pszFileName
!= NULL
&& fRemember
)
300 LPOLESTR oldFile
= This
->currentFile
;
301 This
->currentFile
= co_strdupW(pszFileName
);
302 if (This
->currentFile
== NULL
)
304 This
->currentFile
= oldFile
;
305 return E_OUTOFMEMORY
;
307 CoTaskMemFree(oldFile
);
309 if (This
->url
== NULL
)
312 /* Windows seems to always write:
313 * ASCII "[InternetShortcut]" headers
314 * ASCII names in "name=value" pairs
315 * An ASCII (probably UTF8?) value in "URL=..."
317 len
= WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, NULL
, 0, 0, 0);
318 url
= heap_alloc(len
);
322 WideCharToMultiByte(CP_UTF8
, 0, This
->url
, -1, url
, len
, 0, 0);
323 file
= CreateFileW(pszFileName
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
324 if (file
!= INVALID_HANDLE_VALUE
)
327 char str_header
[] = "[InternetShortcut]";
328 char str_URL
[] = "URL=";
329 char str_eol
[] = "\r\n";
331 WriteFile(file
, str_header
, lstrlenA(str_header
), &bytesWritten
, NULL
);
332 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
333 WriteFile(file
, str_URL
, lstrlenA(str_URL
), &bytesWritten
, NULL
);
334 WriteFile(file
, url
, lstrlenA(url
), &bytesWritten
, NULL
);
335 WriteFile(file
, str_eol
, lstrlenA(str_eol
), &bytesWritten
, NULL
);
337 if (pszFileName
== NULL
|| fRemember
)
338 This
->isDirty
= FALSE
;
350 static HRESULT WINAPI
PersistFile_SaveCompleted(IPersistFile
*pFile
, LPCOLESTR pszFileName
)
352 FIXME("(%p, %p): stub\n", pFile
, pszFileName
);
356 static HRESULT WINAPI
PersistFile_GetCurFile(IPersistFile
*pFile
, LPOLESTR
*ppszFileName
)
359 InternetShortcut
*This
= impl_from_IPersistFile(pFile
);
360 TRACE("(%p, %p)\n", pFile
, ppszFileName
);
361 if (This
->currentFile
== NULL
)
362 *ppszFileName
= NULL
;
365 *ppszFileName
= co_strdupW(This
->currentFile
);
366 if (*ppszFileName
== NULL
)
374 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl
= {
375 UniformResourceLocatorW_QueryInterface
,
376 UniformResourceLocatorW_AddRef
,
377 UniformResourceLocatorW_Release
,
378 UniformResourceLocatorW_SetUrl
,
379 UniformResourceLocatorW_GetUrl
,
380 UniformResourceLocatorW_InvokeCommand
383 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl
= {
384 UniformResourceLocatorA_QueryInterface
,
385 UniformResourceLocatorA_AddRef
,
386 UniformResourceLocatorA_Release
,
387 UniformResourceLocatorA_SetUrl
,
388 UniformResourceLocatorA_GetUrl
,
389 UniformResourceLocatorA_InvokeCommand
392 static const IPersistFileVtbl persistFileVtbl
= {
393 PersistFile_QueryInterface
,
396 PersistFile_GetClassID
,
400 PersistFile_SaveCompleted
,
401 PersistFile_GetCurFile
404 HRESULT
InternetShortcut_Create(IUnknown
*pOuter
, REFIID riid
, void **ppv
)
406 InternetShortcut
*This
;
409 TRACE("(%p, %s, %p)\n", pOuter
, debugstr_guid(riid
), ppv
);
414 return CLASS_E_NOAGGREGATION
;
416 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(InternetShortcut
));
419 This
->uniformResourceLocatorA
.lpVtbl
= &uniformResourceLocatorAVtbl
;
420 This
->uniformResourceLocatorW
.lpVtbl
= &uniformResourceLocatorWVtbl
;
421 This
->persistFile
.lpVtbl
= &persistFileVtbl
;
423 hr
= Unknown_QueryInterface(This
, riid
, ppv
);
425 SHDOCVW_LockModule();
431 return E_OUTOFMEMORY
;