kernel32/tests: Add a few more tests, fix some failures on Windows.
[wine/wine64.git] / dlls / shdocvw / intshcut.c
blobe24d56dc9ab47fd4d9179c6fe543b8bd4160b0aa
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 * fd.o desktop and menu integration
24 * Implement the IShellLinkA/W interfaces
25 * Handle the SetURL flags
26 * Loading .url files
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"
33 #include "shdocvw.h"
34 #include "objidl.h"
35 #include "shobjidl.h"
36 #include "intshcut.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
40 typedef struct
42 IUniformResourceLocatorA uniformResourceLocatorA;
43 IUniformResourceLocatorW uniformResourceLocatorW;
44 IPersistFile persistFile;
46 LONG refCount;
48 WCHAR *url;
49 BOOLEAN isDirty;
50 LPOLESTR currentFile;
51 } InternetShortcut;
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);
75 *ppvObject = NULL;
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");
87 return E_NOINTERFACE;
89 else if (IsEqualGUID(&IID_IShellLinkW, riid))
91 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
92 return E_NOINTERFACE;
94 else
96 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
97 return E_NOINTERFACE;
99 IUnknown_AddRef((IUnknown*)*ppvObject);
100 return S_OK;
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)
111 ULONG count;
112 TRACE("(%p)\n", This);
113 count = InterlockedDecrement(&This->refCount);
114 if (count == 0)
116 CoTaskMemFree(This->url);
117 CoTaskMemFree(This->currentFile);
118 heap_free(This);
119 SHDOCVW_UnlockModule();
121 return count;
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);
150 if (dwInFlags != 0)
151 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
152 if (pcszURL != NULL)
154 newURL = co_strdupW(pcszURL);
155 if (newURL == NULL)
156 return E_OUTOFMEMORY;
158 CoTaskMemFree(This->url);
159 This->url = newURL;
160 This->isDirty = TRUE;
161 return S_OK;
164 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
166 HRESULT hr = S_OK;
167 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
168 TRACE("(%p, %p)\n", url, ppszURL);
169 if (This->url == NULL)
170 *ppszURL = NULL;
171 else
173 *ppszURL = co_strdupW(This->url);
174 if (*ppszURL == NULL)
175 hr = E_OUTOFMEMORY;
177 return hr;
180 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
182 FIXME("(%p, %p): stub\n", url, pCommandInfo);
183 return E_NOTIMPL;
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);
212 if (dwInFlags != 0)
213 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
214 if (pcszURL != NULL)
216 newURL = co_strdupAtoW(pcszURL);
217 if (newURL == NULL)
218 return E_OUTOFMEMORY;
220 CoTaskMemFree(This->url);
221 This->url = newURL;
222 This->isDirty = TRUE;
223 return S_OK;
226 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
228 HRESULT hr = S_OK;
229 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
230 TRACE("(%p, %p)\n", url, ppszURL);
231 if (This->url == NULL)
232 *ppszURL = NULL;
233 else
235 *ppszURL = co_strdupWtoA(This->url);
236 if (*ppszURL == NULL)
237 hr = E_OUTOFMEMORY;
239 return hr;
242 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
244 FIXME("(%p, %p): stub\n", url, pCommandInfo);
245 return E_NOTIMPL;
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;
273 return S_OK;
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);
286 return E_NOTIMPL;
289 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
291 HRESULT hr = S_OK;
292 INT len;
293 CHAR *url;
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)
310 return E_FAIL;
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);
319 if (url != NULL)
321 HANDLE file;
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)
326 DWORD bytesWritten;
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);
336 CloseHandle(file);
337 if (pszFileName == NULL || fRemember)
338 This->isDirty = FALSE;
340 else
341 hr = E_FAIL;
342 heap_free(url);
344 else
345 hr = E_OUTOFMEMORY;
347 return hr;
350 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
352 FIXME("(%p, %p): stub\n", pFile, pszFileName);
353 return E_NOTIMPL;
356 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
358 HRESULT hr = S_OK;
359 InternetShortcut *This = impl_from_IPersistFile(pFile);
360 TRACE("(%p, %p)\n", pFile, ppszFileName);
361 if (This->currentFile == NULL)
362 *ppszFileName = NULL;
363 else
365 *ppszFileName = co_strdupW(This->currentFile);
366 if (*ppszFileName == NULL)
367 hr = E_OUTOFMEMORY;
369 return hr;
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,
394 PersistFile_AddRef,
395 PersistFile_Release,
396 PersistFile_GetClassID,
397 PersistFile_IsDirty,
398 PersistFile_Load,
399 PersistFile_Save,
400 PersistFile_SaveCompleted,
401 PersistFile_GetCurFile
404 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
406 InternetShortcut *This;
407 HRESULT hr;
409 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
411 *ppv = NULL;
413 if(pOuter)
414 return CLASS_E_NOAGGREGATION;
416 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
417 if (This)
419 This->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
420 This->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
421 This->persistFile.lpVtbl = &persistFileVtbl;
422 This->refCount = 0;
423 hr = Unknown_QueryInterface(This, riid, ppv);
424 if (SUCCEEDED(hr))
425 SHDOCVW_LockModule();
426 else
427 heap_free(This);
428 return hr;
430 else
431 return E_OUTOFMEMORY;