usp10/test: Add Tibetan shaping test.
[wine.git] / dlls / shdocvw / intshcut.c
blob4a2dd6a790b3c6373f14bfc114c1c48b93f7e9cd
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 <stdarg.h>
31 #include <stdio.h>
33 #define NONAMELESSUNION
34 #include "wine/debug.h"
35 #include "shdocvw.h"
36 #include "objidl.h"
37 #include "shobjidl.h"
38 #include "intshcut.h"
39 #include "shellapi.h"
40 #include "winreg.h"
41 #include "shlwapi.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
45 typedef struct
47 IUniformResourceLocatorA IUniformResourceLocatorA_iface;
48 IUniformResourceLocatorW IUniformResourceLocatorW_iface;
49 IPersistFile IPersistFile_iface;
50 IPropertySetStorage IPropertySetStorage_iface;
52 LONG refCount;
54 IPropertySetStorage *property_set_storage;
55 WCHAR *url;
56 BOOLEAN isDirty;
57 LPOLESTR currentFile;
58 } InternetShortcut;
60 /* utility functions */
62 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
64 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorA_iface);
67 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
69 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorW_iface);
72 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
74 return CONTAINING_RECORD(iface, InternetShortcut, IPersistFile_iface);
77 static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface)
79 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, IPropertySetStorage_iface));
82 static BOOL run_winemenubuilder( const WCHAR *args )
84 static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
85 LONG len;
86 LPWSTR buffer;
87 STARTUPINFOW si;
88 PROCESS_INFORMATION pi;
89 BOOL ret;
90 WCHAR app[MAX_PATH];
91 void *redir;
93 GetSystemDirectoryW( app, MAX_PATH - sizeof(menubuilder)/sizeof(WCHAR) );
94 strcatW( app, menubuilder );
96 len = (strlenW( app ) + strlenW( args ) + 1) * sizeof(WCHAR);
97 buffer = heap_alloc( len );
98 if( !buffer )
99 return FALSE;
101 strcpyW( buffer, app );
102 strcatW( buffer, args );
104 TRACE("starting %s\n",debugstr_w(buffer));
106 memset(&si, 0, sizeof(si));
107 si.cb = sizeof(si);
109 Wow64DisableWow64FsRedirection( &redir );
110 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
111 Wow64RevertWow64FsRedirection( redir );
113 heap_free( buffer );
115 if (ret)
117 CloseHandle( pi.hProcess );
118 CloseHandle( pi.hThread );
121 return ret;
124 static BOOL StartLinkProcessor( LPCOLESTR szLink )
126 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
127 LONG len;
128 LPWSTR buffer;
129 BOOL ret;
131 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
132 buffer = heap_alloc( len );
133 if( !buffer )
134 return FALSE;
136 wsprintfW( buffer, szFormat, szLink );
137 ret = run_winemenubuilder( buffer );
138 heap_free( buffer );
139 return ret;
142 /* interface functions */
144 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
146 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
147 *ppvObject = NULL;
148 if (IsEqualGUID(&IID_IUnknown, riid))
149 *ppvObject = &This->IUniformResourceLocatorA_iface;
150 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
151 *ppvObject = &This->IUniformResourceLocatorA_iface;
152 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
153 *ppvObject = &This->IUniformResourceLocatorW_iface;
154 else if (IsEqualGUID(&IID_IPersistFile, riid))
155 *ppvObject = &This->IPersistFile_iface;
156 else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
157 *ppvObject = &This->IPropertySetStorage_iface;
158 else if (IsEqualGUID(&IID_IShellLinkA, riid))
160 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
161 return E_NOINTERFACE;
163 else if (IsEqualGUID(&IID_IShellLinkW, riid))
165 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
166 return E_NOINTERFACE;
168 else
170 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
171 return E_NOINTERFACE;
173 IUnknown_AddRef((IUnknown*)*ppvObject);
174 return S_OK;
177 static ULONG Unknown_AddRef(InternetShortcut *This)
179 TRACE("(%p)\n", This);
180 return InterlockedIncrement(&This->refCount);
183 static ULONG Unknown_Release(InternetShortcut *This)
185 ULONG count;
186 TRACE("(%p)\n", This);
187 count = InterlockedDecrement(&This->refCount);
188 if (count == 0)
190 CoTaskMemFree(This->url);
191 CoTaskMemFree(This->currentFile);
192 IPropertySetStorage_Release(This->property_set_storage);
193 heap_free(This);
194 SHDOCVW_UnlockModule();
196 return count;
199 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
201 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
202 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
203 return Unknown_QueryInterface(This, riid, ppvObject);
206 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
208 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
209 TRACE("(%p)\n", url);
210 return Unknown_AddRef(This);
213 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
215 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
216 TRACE("(%p)\n", url);
217 return Unknown_Release(This);
220 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
222 WCHAR *newURL = NULL;
223 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
224 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
225 if (dwInFlags != 0)
226 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
227 if (pcszURL != NULL)
229 newURL = co_strdupW(pcszURL);
230 if (newURL == NULL)
231 return E_OUTOFMEMORY;
233 CoTaskMemFree(This->url);
234 This->url = newURL;
235 This->isDirty = TRUE;
236 return S_OK;
239 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
241 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
243 TRACE("(%p, %p)\n", url, ppszURL);
245 if (!This->url) {
246 *ppszURL = NULL;
247 return S_FALSE;
250 *ppszURL = co_strdupW(This->url);
251 if (!*ppszURL)
252 return E_OUTOFMEMORY;
254 return S_OK;
257 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
259 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
260 WCHAR app[64];
261 HKEY hkey;
262 static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
263 SHELLEXECUTEINFOW sei;
264 DWORD res, type;
265 HRESULT hres;
267 TRACE("%p %p\n", This, pCommandInfo );
269 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
270 return E_INVALIDARG;
272 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
274 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
275 return E_NOTIMPL;
278 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0);
279 if(FAILED(hres))
280 return E_FAIL;
282 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
283 if(res != ERROR_SUCCESS)
284 return E_FAIL;
286 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
287 RegCloseKey(hkey);
288 if(res != ERROR_SUCCESS || type != REG_SZ)
289 return E_FAIL;
291 memset(&sei, 0, sizeof(sei));
292 sei.cbSize = sizeof(sei);
293 sei.lpFile = This->url;
294 sei.nShow = SW_SHOW;
296 if( ShellExecuteExW(&sei) )
297 return S_OK;
298 else
299 return E_FAIL;
302 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
304 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
305 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
306 return Unknown_QueryInterface(This, riid, ppvObject);
309 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
311 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
312 TRACE("(%p)\n", url);
313 return Unknown_AddRef(This);
316 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
318 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
319 TRACE("(%p)\n", url);
320 return Unknown_Release(This);
323 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
325 WCHAR *newURL = NULL;
326 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
327 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
328 if (dwInFlags != 0)
329 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
330 if (pcszURL != NULL)
332 newURL = co_strdupAtoW(pcszURL);
333 if (newURL == NULL)
334 return E_OUTOFMEMORY;
336 CoTaskMemFree(This->url);
337 This->url = newURL;
338 This->isDirty = TRUE;
339 return S_OK;
342 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
344 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
346 TRACE("(%p, %p)\n", url, ppszURL);
348 if (!This->url) {
349 *ppszURL = NULL;
350 return S_FALSE;
354 *ppszURL = co_strdupWtoA(This->url);
355 if (!*ppszURL)
356 return E_OUTOFMEMORY;
358 return S_OK;
361 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
363 URLINVOKECOMMANDINFOW wideCommandInfo;
364 int len;
365 WCHAR *wideVerb;
366 HRESULT res;
367 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
369 wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
370 wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
371 wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
373 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
374 wideVerb = heap_alloc(len * sizeof(WCHAR));
375 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
377 wideCommandInfo.pcszVerb = wideVerb;
379 res = UniformResourceLocatorW_InvokeCommand(&This->IUniformResourceLocatorW_iface, &wideCommandInfo);
380 heap_free(wideVerb);
382 return res;
385 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
387 InternetShortcut *This = impl_from_IPersistFile(pFile);
388 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
389 return Unknown_QueryInterface(This, riid, ppvObject);
392 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
394 InternetShortcut *This = impl_from_IPersistFile(pFile);
395 TRACE("(%p)\n", pFile);
396 return Unknown_AddRef(This);
399 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
401 InternetShortcut *This = impl_from_IPersistFile(pFile);
402 TRACE("(%p)\n", pFile);
403 return Unknown_Release(This);
406 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
408 TRACE("(%p, %p)\n", pFile, pClassID);
409 *pClassID = CLSID_InternetShortcut;
410 return S_OK;
413 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
415 InternetShortcut *This = impl_from_IPersistFile(pFile);
416 TRACE("(%p)\n", pFile);
417 return This->isDirty ? S_OK : S_FALSE;
420 /* A helper function: Allocate and fill rString. Return number of bytes read. */
421 static DWORD get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName,
422 LPCWSTR lpFileName, WCHAR **rString )
424 DWORD r = 0;
425 DWORD len = 128;
426 WCHAR *buffer;
428 buffer = CoTaskMemAlloc(len * sizeof(*buffer));
429 if (buffer != NULL)
431 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
432 while (r == len-1)
434 WCHAR *realloc_buf;
436 len *= 2;
437 realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer));
438 if (realloc_buf == NULL)
440 CoTaskMemFree(buffer);
441 *rString = NULL;
442 return 0;
444 buffer = realloc_buf;
446 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
450 *rString = buffer;
451 return r;
454 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
456 WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
457 WCHAR str_URL[] = {'U','R','L',0};
458 WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0};
459 WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0};
460 WCHAR *filename = NULL;
461 HRESULT hr;
462 InternetShortcut *This = impl_from_IPersistFile(pFile);
463 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
464 if (dwMode != 0)
465 FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
466 filename = co_strdupW(pszFileName);
467 if (filename != NULL)
469 DWORD r;
470 WCHAR *url;
472 r = get_profile_string(str_header, str_URL, pszFileName, &url);
474 if (url == NULL)
476 hr = E_OUTOFMEMORY;
477 CoTaskMemFree(filename);
479 else if (r == 0)
481 hr = E_FAIL;
482 CoTaskMemFree(filename);
484 else
486 hr = S_OK;
487 CoTaskMemFree(This->currentFile);
488 This->currentFile = filename;
489 CoTaskMemFree(This->url);
490 This->url = url;
491 This->isDirty = FALSE;
494 /* Now we're going to read in the iconfile and iconindex.
495 If we don't find them, that's not a failure case -- it's possible
496 that they just aren't in there. */
497 if (SUCCEEDED(hr))
499 IPropertyStorage *pPropStg;
500 WCHAR *iconfile;
501 WCHAR *iconindexstring;
502 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut,
503 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
504 &pPropStg);
506 r = get_profile_string(str_header, str_iconfile, pszFileName, &iconfile);
507 if (iconfile != NULL)
509 PROPSPEC ps;
510 PROPVARIANT pv;
511 ps.ulKind = PRSPEC_PROPID;
512 ps.u.propid = PID_IS_ICONFILE;
513 pv.vt = VT_LPWSTR;
514 pv.u.pwszVal = iconfile;
515 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
516 if (FAILED(hr))
518 TRACE("Failed to store the iconfile to our property storage. hr = 0x%x\n", hr);
521 CoTaskMemFree(iconfile);
524 r = get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring);
526 if (iconindexstring != NULL)
528 int iconindex;
529 PROPSPEC ps;
530 PROPVARIANT pv;
531 char *iconindexastring = co_strdupWtoA(iconindexstring);
532 sscanf(iconindexastring, "%d", &iconindex);
533 CoTaskMemFree(iconindexastring);
534 ps.ulKind = PRSPEC_PROPID;
535 ps.u.propid = PID_IS_ICONINDEX;
536 pv.vt = VT_I4;
537 pv.u.iVal = iconindex;
538 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
539 if (FAILED(hr))
541 TRACE("Failed to store the iconindex to our property storage. hr = 0x%x\n", hr);
544 CoTaskMemFree(iconindexstring);
547 IPropertyStorage_Release(pPropStg);
549 else
550 hr = E_OUTOFMEMORY;
552 else
553 hr = E_OUTOFMEMORY;
554 return hr;
557 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
559 HRESULT hr = S_OK;
560 INT len;
561 CHAR *url;
562 InternetShortcut *This = impl_from_IPersistFile(pFile);
564 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
566 if (pszFileName != NULL && fRemember)
568 LPOLESTR oldFile = This->currentFile;
569 This->currentFile = co_strdupW(pszFileName);
570 if (This->currentFile == NULL)
572 This->currentFile = oldFile;
573 return E_OUTOFMEMORY;
575 CoTaskMemFree(oldFile);
577 if (This->url == NULL)
578 return E_FAIL;
580 /* Windows seems to always write:
581 * ASCII "[InternetShortcut]" headers
582 * ASCII names in "name=value" pairs
583 * An ASCII (probably UTF8?) value in "URL=..."
585 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
586 url = heap_alloc(len);
587 if (url != NULL)
589 HANDLE file;
590 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
591 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
592 if (file != INVALID_HANDLE_VALUE)
594 DWORD bytesWritten;
595 char *iconfile;
596 char str_header[] = "[InternetShortcut]";
597 char str_URL[] = "URL=";
598 char str_ICONFILE[] = "ICONFILE=";
599 char str_eol[] = "\r\n";
600 IPropertyStorage *pPropStgRead;
601 PROPSPEC ps[2];
602 PROPVARIANT pvread[2];
603 ps[0].ulKind = PRSPEC_PROPID;
604 ps[0].u.propid = PID_IS_ICONFILE;
605 ps[1].ulKind = PRSPEC_PROPID;
606 ps[1].u.propid = PID_IS_ICONINDEX;
608 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
609 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
610 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
611 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
612 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
614 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead);
615 if SUCCEEDED(hr)
617 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
618 if (hr == S_FALSE)
620 /* None of the properties are present, that's ok */
621 hr = S_OK;
622 IPropertyStorage_Release(pPropStgRead);
624 else if SUCCEEDED(hr)
626 char indexString[50];
627 len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, NULL, 0, 0, 0);
628 iconfile = heap_alloc(len);
629 if (iconfile != NULL)
631 WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, iconfile, len, 0, 0);
632 WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL);
633 WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL);
634 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
637 sprintf(indexString, "ICONINDEX=%d", pvread[1].u.iVal);
638 WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL);
639 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
641 IPropertyStorage_Release(pPropStgRead);
642 PropVariantClear(&pvread[0]);
643 PropVariantClear(&pvread[1]);
645 else
647 TRACE("Unable to read properties.\n");
650 else
652 TRACE("Unable to get the IPropertyStorage.\n");
655 CloseHandle(file);
656 if (pszFileName == NULL || fRemember)
657 This->isDirty = FALSE;
658 StartLinkProcessor(pszFileName);
660 else
661 hr = E_FAIL;
662 heap_free(url);
664 else
665 hr = E_OUTOFMEMORY;
667 return hr;
670 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
672 FIXME("(%p, %p): stub\n", pFile, pszFileName);
673 return E_NOTIMPL;
676 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
678 HRESULT hr = S_OK;
679 InternetShortcut *This = impl_from_IPersistFile(pFile);
680 TRACE("(%p, %p)\n", pFile, ppszFileName);
681 if (This->currentFile == NULL)
682 *ppszFileName = NULL;
683 else
685 *ppszFileName = co_strdupW(This->currentFile);
686 if (*ppszFileName == NULL)
687 hr = E_OUTOFMEMORY;
689 return hr;
692 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject)
694 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
695 TRACE("(%p)\n", iface);
696 return Unknown_QueryInterface(This, riid, ppvObject);
699 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface)
701 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
702 TRACE("(%p)\n", iface);
703 return Unknown_AddRef(This);
706 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface)
708 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
709 TRACE("(%p)\n", iface);
710 return Unknown_Release(This);
713 static HRESULT WINAPI PropertySetStorage_Create(
714 IPropertySetStorage* iface,
715 REFFMTID rfmtid,
716 const CLSID *pclsid,
717 DWORD grfFlags,
718 DWORD grfMode,
719 IPropertyStorage **ppprstg)
721 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
722 TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg);
724 return IPropertySetStorage_Create(This->property_set_storage,
725 rfmtid,
726 pclsid,
727 grfFlags,
728 grfMode,
729 ppprstg);
732 static HRESULT WINAPI PropertySetStorage_Open(
733 IPropertySetStorage* iface,
734 REFFMTID rfmtid,
735 DWORD grfMode,
736 IPropertyStorage **ppprstg)
738 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
739 TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg);
741 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */
742 return IPropertySetStorage_Open(This->property_set_storage,
743 rfmtid,
744 grfMode|STGM_SHARE_EXCLUSIVE,
745 ppprstg);
748 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid)
750 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
751 TRACE("(%s)\n", debugstr_guid(rfmtid));
754 return IPropertySetStorage_Delete(This->property_set_storage,
755 rfmtid);
758 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum)
760 FIXME("(%p): stub\n", ppenum);
761 return E_NOTIMPL;
764 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
765 UniformResourceLocatorW_QueryInterface,
766 UniformResourceLocatorW_AddRef,
767 UniformResourceLocatorW_Release,
768 UniformResourceLocatorW_SetUrl,
769 UniformResourceLocatorW_GetUrl,
770 UniformResourceLocatorW_InvokeCommand
773 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
774 UniformResourceLocatorA_QueryInterface,
775 UniformResourceLocatorA_AddRef,
776 UniformResourceLocatorA_Release,
777 UniformResourceLocatorA_SetUrl,
778 UniformResourceLocatorA_GetUrl,
779 UniformResourceLocatorA_InvokeCommand
782 static const IPersistFileVtbl persistFileVtbl = {
783 PersistFile_QueryInterface,
784 PersistFile_AddRef,
785 PersistFile_Release,
786 PersistFile_GetClassID,
787 PersistFile_IsDirty,
788 PersistFile_Load,
789 PersistFile_Save,
790 PersistFile_SaveCompleted,
791 PersistFile_GetCurFile
794 static const IPropertySetStorageVtbl propertySetStorageVtbl = {
795 PropertySetStorage_QueryInterface,
796 PropertySetStorage_AddRef,
797 PropertySetStorage_Release,
798 PropertySetStorage_Create,
799 PropertySetStorage_Open,
800 PropertySetStorage_Delete,
801 PropertySetStorage_Enum
804 static InternetShortcut *create_shortcut(void)
806 InternetShortcut *newshortcut;
808 newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
809 if (newshortcut)
811 HRESULT hr;
812 IPropertyStorage *dummy;
814 newshortcut->IUniformResourceLocatorA_iface.lpVtbl = &uniformResourceLocatorAVtbl;
815 newshortcut->IUniformResourceLocatorW_iface.lpVtbl = &uniformResourceLocatorWVtbl;
816 newshortcut->IPersistFile_iface.lpVtbl = &persistFileVtbl;
817 newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl;
818 newshortcut->refCount = 0;
819 hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage);
820 if FAILED(hr)
822 TRACE("Failed to create the storage object needed for the shortcut.\n");
823 heap_free(newshortcut);
824 return NULL;
827 hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy);
828 if FAILED(hr)
830 TRACE("Failed to create the property object needed for the shortcut.\n");
831 IPropertySetStorage_Release(newshortcut->property_set_storage);
832 heap_free(newshortcut);
833 return NULL;
835 IPropertySetStorage_Release(dummy);
838 return newshortcut;
841 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
843 InternetShortcut *This;
844 HRESULT hr;
846 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
848 *ppv = NULL;
850 if(pOuter)
851 return CLASS_E_NOAGGREGATION;
853 This = create_shortcut();
854 if (This)
856 hr = Unknown_QueryInterface(This, riid, ppv);
857 if (SUCCEEDED(hr))
858 SHDOCVW_LockModule();
859 else
860 heap_free(This);
861 return hr;
863 else
864 return E_OUTOFMEMORY;
868 /**********************************************************************
869 * OpenURL (SHDOCVW.@)
871 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
873 InternetShortcut *shortcut;
874 WCHAR* urlfilepath = NULL;
875 shortcut = create_shortcut();
877 if (shortcut)
879 int len;
881 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
882 urlfilepath = heap_alloc(len * sizeof(WCHAR));
883 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
885 if(SUCCEEDED(IPersistFile_Load(&shortcut->IPersistFile_iface, urlfilepath, 0)))
887 URLINVOKECOMMANDINFOW ici;
889 memset( &ici, 0, sizeof ici );
890 ici.dwcbSize = sizeof ici;
891 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
892 ici.hwndParent = hWnd;
894 if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->IUniformResourceLocatorW_iface, (PURLINVOKECOMMANDINFOW) &ici)))
895 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl));
898 heap_free(shortcut);
899 heap_free(urlfilepath);