1 /* 2 * Copyright 2008 Damjan Jovanovic 3 * 4 * ShellLink's barely documented cousin that handles URLs. 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 /* 22 * TODO: 23 * Implement the IShellLinkA/W interfaces 24 * Handle the SetURL flags 25 * Implement any other interfaces? Does any software actually use them? 26 * 27 * The installer for the Zuma Deluxe Popcap game is good for testing. 28 */ 29 30 #include "ieframe.h" 31 32 typedef struct 33 { 34 IUniformResourceLocatorA IUniformResourceLocatorA_iface; 35 IUniformResourceLocatorW IUniformResourceLocatorW_iface; 36 IPersistFile IPersistFile_iface; 37 IPropertySetStorage IPropertySetStorage_iface; 38 39 LONG refCount; 40 41 IPropertySetStorage *property_set_storage; 42 WCHAR *url; 43 BOOLEAN isDirty; 44 LPOLESTR currentFile; 45 } InternetShortcut; 46 47 /* utility functions */ 48 49 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface) 50 { 51 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorA_iface); 52 } 53 54 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface) 55 { 56 return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorW_iface); 57 } 58 59 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface) 60 { 61 return CONTAINING_RECORD(iface, InternetShortcut, IPersistFile_iface); 62 } 63 64 static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface) 65 { 66 return CONTAINING_RECORD(iface, InternetShortcut, IPropertySetStorage_iface); 67 } 68 69 static BOOL run_winemenubuilder( const WCHAR *args ) 70 { 71 static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0}; 72 LONG len; 73 LPWSTR buffer; 74 STARTUPINFOW si; 75 PROCESS_INFORMATION pi; 76 BOOL ret; 77 WCHAR app[MAX_PATH]; 78 void *redir; 79 80 GetSystemDirectoryW( app, MAX_PATH - sizeof(menubuilder)/sizeof(WCHAR) ); 81 strcatW( app, menubuilder ); 82 83 len = (strlenW( app ) + strlenW( args ) + 1) * sizeof(WCHAR); 84 buffer = heap_alloc( len ); 85 if( !buffer ) 86 return FALSE; 87 88 strcpyW( buffer, app ); 89 strcatW( buffer, args ); 90 91 TRACE("starting %s\n",debugstr_w(buffer)); 92 93 memset(&si, 0, sizeof(si)); 94 si.cb = sizeof(si); 95 96 Wow64DisableWow64FsRedirection( &redir ); 97 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ); 98 Wow64RevertWow64FsRedirection( redir ); 99 100 heap_free( buffer ); 101 102 if (ret) 103 { 104 CloseHandle( pi.hProcess ); 105 CloseHandle( pi.hThread ); 106 } 107 108 return ret; 109 } 110 111 static BOOL StartLinkProcessor( LPCOLESTR szLink ) 112 { 113 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 }; 114 LONG len; 115 LPWSTR buffer; 116 BOOL ret; 117 118 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR); 119 buffer = heap_alloc( len ); 120 if( !buffer ) 121 return FALSE; 122 123 sprintfW( buffer, szFormat, szLink ); 124 ret = run_winemenubuilder( buffer ); 125 heap_free( buffer ); 126 return ret; 127 } 128 129 /* interface functions */ 130 131 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject) 132 { 133 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject); 134 *ppvObject = NULL; 135 if (IsEqualGUID(&IID_IUnknown, riid)) 136 *ppvObject = &This->IUniformResourceLocatorA_iface; 137 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid)) 138 *ppvObject = &This->IUniformResourceLocatorA_iface; 139 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid)) 140 *ppvObject = &This->IUniformResourceLocatorW_iface; 141 else if (IsEqualGUID(&IID_IPersistFile, riid)) 142 *ppvObject = &This->IPersistFile_iface; 143 else if (IsEqualGUID(&IID_IPropertySetStorage, riid)) 144 *ppvObject = &This->IPropertySetStorage_iface; 145 else if (IsEqualGUID(&IID_IShellLinkA, riid)) 146 { 147 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n"); 148 return E_NOINTERFACE; 149 } 150 else if (IsEqualGUID(&IID_IShellLinkW, riid)) 151 { 152 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n"); 153 return E_NOINTERFACE; 154 } 155 else 156 { 157 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid)); 158 return E_NOINTERFACE; 159 } 160 IUnknown_AddRef((IUnknown*)*ppvObject); 161 return S_OK; 162 } 163 164 static ULONG Unknown_AddRef(InternetShortcut *This) 165 { 166 TRACE("(%p)\n", This); 167 return InterlockedIncrement(&This->refCount); 168 } 169 170 static ULONG Unknown_Release(InternetShortcut *This) 171 { 172 ULONG count; 173 TRACE("(%p)\n", This); 174 count = InterlockedDecrement(&This->refCount); 175 if (count == 0) 176 { 177 CoTaskMemFree(This->url); 178 CoTaskMemFree(This->currentFile); 179 IPropertySetStorage_Release(This->property_set_storage); 180 heap_free(This); 181 unlock_module(); 182 } 183 return count; 184 } 185 186 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject) 187 { 188 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 189 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject); 190 return Unknown_QueryInterface(This, riid, ppvObject); 191 } 192 193 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url) 194 { 195 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 196 TRACE("(%p)\n", url); 197 return Unknown_AddRef(This); 198 } 199 200 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url) 201 { 202 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 203 TRACE("(%p)\n", url); 204 return Unknown_Release(This); 205 } 206 207 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags) 208 { 209 WCHAR *newURL = NULL; 210 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 211 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags); 212 if (dwInFlags != 0) 213 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags); 214 if (pcszURL != NULL) 215 { 216 newURL = co_strdupW(pcszURL); 217 if (newURL == NULL) 218 return E_OUTOFMEMORY; 219 } 220 CoTaskMemFree(This->url); 221 This->url = newURL; 222 This->isDirty = TRUE; 223 return S_OK; 224 } 225 226 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL) 227 { 228 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 229 230 TRACE("(%p, %p)\n", url, ppszURL); 231 232 if (!This->url) { 233 *ppszURL = NULL; 234 return S_FALSE; 235 } 236 237 *ppszURL = co_strdupW(This->url); 238 if (!*ppszURL) 239 return E_OUTOFMEMORY; 240 241 return S_OK; 242 } 243 244 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo) 245 { 246 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url); 247 WCHAR app[64]; 248 HKEY hkey; 249 static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0}; 250 SHELLEXECUTEINFOW sei; 251 DWORD res, type; 252 HRESULT hres; 253 254 TRACE("%p %p\n", This, pCommandInfo ); 255 256 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW)) 257 return E_INVALIDARG; 258 259 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB) 260 { 261 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo); 262 return E_NOTIMPL; 263 } 264 265 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0); 266 if(FAILED(hres)) 267 return E_FAIL; 268 269 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey); 270 if(res != ERROR_SUCCESS) 271 return E_FAIL; 272 273 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL); 274 RegCloseKey(hkey); 275 if(res != ERROR_SUCCESS || type != REG_SZ) 276 return E_FAIL; 277 278 memset(&sei, 0, sizeof(sei)); 279 sei.cbSize = sizeof(sei); 280 sei.lpFile = This->url; 281 sei.nShow = SW_SHOW; 282 283 if( ShellExecuteExW(&sei) ) 284 return S_OK; 285 else 286 return E_FAIL; 287 } 288 289 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject) 290 { 291 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 292 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject); 293 return Unknown_QueryInterface(This, riid, ppvObject); 294 } 295 296 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url) 297 { 298 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 299 TRACE("(%p)\n", url); 300 return Unknown_AddRef(This); 301 } 302 303 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url) 304 { 305 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 306 TRACE("(%p)\n", url); 307 return Unknown_Release(This); 308 } 309 310 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags) 311 { 312 WCHAR *newURL = NULL; 313 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 314 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags); 315 if (dwInFlags != 0) 316 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags); 317 if (pcszURL != NULL) 318 { 319 newURL = co_strdupAtoW(pcszURL); 320 if (newURL == NULL) 321 return E_OUTOFMEMORY; 322 } 323 CoTaskMemFree(This->url); 324 This->url = newURL; 325 This->isDirty = TRUE; 326 return S_OK; 327 } 328 329 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL) 330 { 331 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 332 333 TRACE("(%p, %p)\n", url, ppszURL); 334 335 if (!This->url) { 336 *ppszURL = NULL; 337 return S_FALSE; 338 339 } 340 341 *ppszURL = co_strdupWtoA(This->url); 342 if (!*ppszURL) 343 return E_OUTOFMEMORY; 344 345 return S_OK; 346 } 347 348 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo) 349 { 350 URLINVOKECOMMANDINFOW wideCommandInfo; 351 int len; 352 WCHAR *wideVerb; 353 HRESULT res; 354 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url); 355 356 wideCommandInfo.dwcbSize = sizeof wideCommandInfo; 357 wideCommandInfo.dwFlags = pCommandInfo->dwFlags; 358 wideCommandInfo.hwndParent = pCommandInfo->hwndParent; 359 360 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0); 361 wideVerb = heap_alloc(len * sizeof(WCHAR)); 362 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len); 363 364 wideCommandInfo.pcszVerb = wideVerb; 365 366 res = UniformResourceLocatorW_InvokeCommand(&This->IUniformResourceLocatorW_iface, &wideCommandInfo); 367 heap_free(wideVerb); 368 369 return res; 370 } 371 372 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject) 373 { 374 InternetShortcut *This = impl_from_IPersistFile(pFile); 375 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject); 376 return Unknown_QueryInterface(This, riid, ppvObject); 377 } 378 379 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile) 380 { 381 InternetShortcut *This = impl_from_IPersistFile(pFile); 382 TRACE("(%p)\n", pFile); 383 return Unknown_AddRef(This); 384 } 385 386 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile) 387 { 388 InternetShortcut *This = impl_from_IPersistFile(pFile); 389 TRACE("(%p)\n", pFile); 390 return Unknown_Release(This); 391 } 392 393 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID) 394 { 395 TRACE("(%p, %p)\n", pFile, pClassID); 396 *pClassID = CLSID_InternetShortcut; 397 return S_OK; 398 } 399 400 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile) 401 { 402 InternetShortcut *This = impl_from_IPersistFile(pFile); 403 TRACE("(%p)\n", pFile); 404 return This->isDirty ? S_OK : S_FALSE; 405 } 406 407 /* Returns allocated profile string and a standard return code. */ 408 static HRESULT get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName, 409 LPCWSTR lpFileName, WCHAR **rString ) 410 { 411 DWORD r = 0; 412 DWORD len = 128; 413 WCHAR *buffer; 414 415 *rString = NULL; 416 buffer = CoTaskMemAlloc(len * sizeof(*buffer)); 417 if (!buffer) 418 return E_OUTOFMEMORY; 419 420 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName); 421 while (r == len-1) 422 { 423 WCHAR *realloc_buf; 424 425 len *= 2; 426 realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer)); 427 if (realloc_buf == NULL) 428 { 429 CoTaskMemFree(buffer); 430 return E_OUTOFMEMORY; 431 } 432 buffer = realloc_buf; 433 434 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName); 435 } 436 437 *rString = buffer; 438 return r ? S_OK : E_FAIL; 439 } 440 441 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode) 442 { 443 InternetShortcut *This = impl_from_IPersistFile(pFile); 444 static WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0}; 445 static WCHAR str_URL[] = {'U','R','L',0}; 446 static WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0}; 447 static WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0}; 448 WCHAR *filename = NULL; 449 WCHAR *url; 450 HRESULT hr; 451 IPropertyStorage *pPropStg; 452 WCHAR *iconfile; 453 WCHAR *iconindexstring; 454 455 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode); 456 457 if (dwMode != 0) 458 FIXME("ignoring unimplemented mode 0x%x\n", dwMode); 459 460 filename = co_strdupW(pszFileName); 461 if (!filename) 462 return E_OUTOFMEMORY; 463 464 if (FAILED(hr = get_profile_string(str_header, str_URL, pszFileName, &url))) 465 { 466 CoTaskMemFree(filename); 467 return hr; 468 } 469 470 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, 471 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropStg); 472 if (FAILED(hr)) 473 { 474 CoTaskMemFree(filename); 475 CoTaskMemFree(url); 476 return hr; 477 } 478 479 CoTaskMemFree(This->currentFile); 480 This->currentFile = filename; 481 CoTaskMemFree(This->url); 482 This->url = url; 483 This->isDirty = FALSE; 484 485 /* Now we're going to read in the iconfile and iconindex. 486 If we don't find them, that's not a failure case -- it's possible 487 that they just aren't in there. */ 488 489 if (get_profile_string(str_header, str_iconfile, pszFileName, &iconfile) == S_OK) 490 { 491 PROPSPEC ps; 492 PROPVARIANT pv; 493 ps.ulKind = PRSPEC_PROPID; 494 ps.u.propid = PID_IS_ICONFILE; 495 pv.vt = VT_LPWSTR; 496 pv.u.pwszVal = iconfile; 497 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0); 498 if (FAILED(hr)) 499 TRACE("Failed to store the iconfile to our property storage. hr = 0x%x\n", hr); 500 } 501 CoTaskMemFree(iconfile); 502 503 if (get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring) == S_OK) 504 { 505 int iconindex; 506 PROPSPEC ps; 507 PROPVARIANT pv; 508 iconindex = strtolW(iconindexstring, NULL, 10); 509 ps.ulKind = PRSPEC_PROPID; 510 ps.u.propid = PID_IS_ICONINDEX; 511 pv.vt = VT_I4; 512 pv.u.iVal = iconindex; 513 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0); 514 if (FAILED(hr)) 515 TRACE("Failed to store the iconindex to our property storage. hr = 0x%x\n", hr); 516 } 517 CoTaskMemFree(iconindexstring); 518 519 IPropertyStorage_Release(pPropStg); 520 return hr; 521 } 522 523 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember) 524 { 525 HRESULT hr = S_OK; 526 INT len; 527 CHAR *url; 528 InternetShortcut *This = impl_from_IPersistFile(pFile); 529 530 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember); 531 532 if (pszFileName != NULL && fRemember) 533 { 534 LPOLESTR oldFile = This->currentFile; 535 This->currentFile = co_strdupW(pszFileName); 536 if (This->currentFile == NULL) 537 { 538 This->currentFile = oldFile; 539 return E_OUTOFMEMORY; 540 } 541 CoTaskMemFree(oldFile); 542 } 543 if (This->url == NULL) 544 return E_FAIL; 545 546 /* Windows seems to always write: 547 * ASCII "[InternetShortcut]" headers 548 * ASCII names in "name=value" pairs 549 * An ASCII (probably UTF8?) value in "URL=..." 550 */ 551 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0); 552 url = heap_alloc(len); 553 if (url != NULL) 554 { 555 HANDLE file; 556 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0); 557 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 558 if (file != INVALID_HANDLE_VALUE) 559 { 560 DWORD bytesWritten; 561 char *iconfile; 562 char str_header[] = "[InternetShortcut]"; 563 char str_URL[] = "URL="; 564 char str_ICONFILE[] = "ICONFILE="; 565 char str_eol[] = "\r\n"; 566 IPropertyStorage *pPropStgRead; 567 PROPSPEC ps[2]; 568 PROPVARIANT pvread[2]; 569 ps[0].ulKind = PRSPEC_PROPID; 570 ps[0].u.propid = PID_IS_ICONFILE; 571 ps[1].ulKind = PRSPEC_PROPID; 572 ps[1].u.propid = PID_IS_ICONINDEX; 573 574 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL); 575 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL); 576 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL); 577 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL); 578 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL); 579 580 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead); 581 if (SUCCEEDED(hr)) 582 { 583 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread); 584 if (hr == S_FALSE) 585 { 586 /* None of the properties are present, that's ok */ 587 hr = S_OK; 588 IPropertyStorage_Release(pPropStgRead); 589 } 590 else if (SUCCEEDED(hr)) 591 { 592 char indexString[50]; 593 len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, NULL, 0, 0, 0); 594 iconfile = heap_alloc(len); 595 if (iconfile != NULL) 596 { 597 WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, iconfile, len, 0, 0); 598 WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL); 599 WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL); 600 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL); 601 } 602 603 sprintf(indexString, "ICONINDEX=%d", pvread[1].u.iVal); 604 WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL); 605 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL); 606 607 IPropertyStorage_Release(pPropStgRead); 608 PropVariantClear(&pvread[0]); 609 PropVariantClear(&pvread[1]); 610 } 611 else 612 { 613 TRACE("Unable to read properties.\n"); 614 } 615 } 616 else 617 { 618 TRACE("Unable to get the IPropertyStorage.\n"); 619 } 620 621 CloseHandle(file); 622 if (pszFileName == NULL || fRemember) 623 This->isDirty = FALSE; 624 StartLinkProcessor(pszFileName); 625 } 626 else 627 hr = E_FAIL; 628 heap_free(url); 629 } 630 else 631 hr = E_OUTOFMEMORY; 632 633 return hr; 634 } 635 636 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName) 637 { 638 FIXME("(%p, %p): stub\n", pFile, pszFileName); 639 return E_NOTIMPL; 640 } 641 642 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName) 643 { 644 HRESULT hr = S_OK; 645 InternetShortcut *This = impl_from_IPersistFile(pFile); 646 TRACE("(%p, %p)\n", pFile, ppszFileName); 647 if (This->currentFile == NULL) 648 *ppszFileName = NULL; 649 else 650 { 651 *ppszFileName = co_strdupW(This->currentFile); 652 if (*ppszFileName == NULL) 653 hr = E_OUTOFMEMORY; 654 } 655 return hr; 656 } 657 658 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject) 659 { 660 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 661 TRACE("(%p)\n", iface); 662 return Unknown_QueryInterface(This, riid, ppvObject); 663 } 664 665 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface) 666 { 667 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 668 TRACE("(%p)\n", iface); 669 return Unknown_AddRef(This); 670 } 671 672 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface) 673 { 674 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 675 TRACE("(%p)\n", iface); 676 return Unknown_Release(This); 677 } 678 679 static HRESULT WINAPI PropertySetStorage_Create( 680 IPropertySetStorage* iface, 681 REFFMTID rfmtid, 682 const CLSID *pclsid, 683 DWORD grfFlags, 684 DWORD grfMode, 685 IPropertyStorage **ppprstg) 686 { 687 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 688 TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg); 689 690 return IPropertySetStorage_Create(This->property_set_storage, 691 rfmtid, 692 pclsid, 693 grfFlags, 694 grfMode, 695 ppprstg); 696 } 697 698 static HRESULT WINAPI PropertySetStorage_Open( 699 IPropertySetStorage* iface, 700 REFFMTID rfmtid, 701 DWORD grfMode, 702 IPropertyStorage **ppprstg) 703 { 704 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 705 TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg); 706 707 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */ 708 return IPropertySetStorage_Open(This->property_set_storage, 709 rfmtid, 710 grfMode|STGM_SHARE_EXCLUSIVE, 711 ppprstg); 712 } 713 714 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid) 715 { 716 InternetShortcut *This = impl_from_IPropertySetStorage(iface); 717 TRACE("(%s)\n", debugstr_guid(rfmtid)); 718 719 720 return IPropertySetStorage_Delete(This->property_set_storage, 721 rfmtid); 722 } 723 724 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum) 725 { 726 FIXME("(%p): stub\n", ppenum); 727 return E_NOTIMPL; 728 } 729 730 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = { 731 UniformResourceLocatorW_QueryInterface, 732 UniformResourceLocatorW_AddRef, 733 UniformResourceLocatorW_Release, 734 UniformResourceLocatorW_SetUrl, 735 UniformResourceLocatorW_GetUrl, 736 UniformResourceLocatorW_InvokeCommand 737 }; 738 739 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = { 740 UniformResourceLocatorA_QueryInterface, 741 UniformResourceLocatorA_AddRef, 742 UniformResourceLocatorA_Release, 743 UniformResourceLocatorA_SetUrl, 744 UniformResourceLocatorA_GetUrl, 745 UniformResourceLocatorA_InvokeCommand 746 }; 747 748 static const IPersistFileVtbl persistFileVtbl = { 749 PersistFile_QueryInterface, 750 PersistFile_AddRef, 751 PersistFile_Release, 752 PersistFile_GetClassID, 753 PersistFile_IsDirty, 754 PersistFile_Load, 755 PersistFile_Save, 756 PersistFile_SaveCompleted, 757 PersistFile_GetCurFile 758 }; 759 760 static const IPropertySetStorageVtbl propertySetStorageVtbl = { 761 PropertySetStorage_QueryInterface, 762 PropertySetStorage_AddRef, 763 PropertySetStorage_Release, 764 PropertySetStorage_Create, 765 PropertySetStorage_Open, 766 PropertySetStorage_Delete, 767 PropertySetStorage_Enum 768 }; 769 770 static InternetShortcut *create_shortcut(void) 771 { 772 InternetShortcut *newshortcut; 773 774 newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut)); 775 if (newshortcut) 776 { 777 HRESULT hr; 778 IPropertyStorage *dummy; 779 780 newshortcut->IUniformResourceLocatorA_iface.lpVtbl = &uniformResourceLocatorAVtbl; 781 newshortcut->IUniformResourceLocatorW_iface.lpVtbl = &uniformResourceLocatorWVtbl; 782 newshortcut->IPersistFile_iface.lpVtbl = &persistFileVtbl; 783 newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl; 784 newshortcut->refCount = 1; 785 hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 786 STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage); 787 if (FAILED(hr)) 788 { 789 TRACE("Failed to create the storage object needed for the shortcut.\n"); 790 heap_free(newshortcut); 791 return NULL; 792 } 793 794 hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy); 795 if (FAILED(hr)) 796 { 797 TRACE("Failed to create the property object needed for the shortcut.\n"); 798 IPropertySetStorage_Release(newshortcut->property_set_storage); 799 heap_free(newshortcut); 800 return NULL; 801 } 802 IPropertyStorage_Release(dummy); 803 } 804 805 return newshortcut; 806 } 807 808 HRESULT WINAPI InternetShortcut_Create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 809 { 810 InternetShortcut *This; 811 HRESULT hres; 812 813 TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), ppv); 814 815 *ppv = NULL; 816 817 if(outer) 818 return CLASS_E_NOAGGREGATION; 819 820 This = create_shortcut(); 821 if(!This) 822 return E_OUTOFMEMORY; 823 824 hres = Unknown_QueryInterface(This, riid, ppv); 825 Unknown_Release(This); 826 return hres; 827 } 828 829 830 /********************************************************************** 831 * OpenURL (ieframe.@) 832 */ 833 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd) 834 { 835 InternetShortcut *shortcut; 836 WCHAR* urlfilepath = NULL; 837 int len; 838 839 shortcut = create_shortcut(); 840 841 if(!shortcut) 842 return; 843 844 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0); 845 urlfilepath = heap_alloc(len * sizeof(WCHAR)); 846 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len); 847 848 if(SUCCEEDED(IPersistFile_Load(&shortcut->IPersistFile_iface, urlfilepath, 0))) { 849 URLINVOKECOMMANDINFOW ici; 850 851 memset( &ici, 0, sizeof ici ); 852 ici.dwcbSize = sizeof ici; 853 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB; 854 ici.hwndParent = hWnd; 855 856 if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->IUniformResourceLocatorW_iface, (PURLINVOKECOMMANDINFOW) &ici))) 857 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl)); 858 } 859 860 heap_free(urlfilepath); 861 Unknown_Release(shortcut); 862 } 863