1 /* 2 * Implementation of hyperlinking (hlink.dll) 3 * 4 * Copyright 2005 Aric Stewart for CodeWeavers 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 #include "hlink_private.h" 22 23 #include "winreg.h" 24 #include "rpcproxy.h" 25 #include "hlguids.h" 26 27 #include "wine/debug.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(hlink); 30 31 static HINSTANCE instance; 32 33 typedef HRESULT (*LPFNCREATEINSTANCE)(IUnknown*, REFIID, LPVOID*); 34 35 typedef struct 36 { 37 IClassFactory IClassFactory_iface; 38 LPFNCREATEINSTANCE lpfnCI; 39 } CFImpl; 40 41 static inline CFImpl *impl_from_IClassFactory(IClassFactory *iface) 42 { 43 return CONTAINING_RECORD(iface, CFImpl, IClassFactory_iface); 44 } 45 46 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 47 { 48 TRACE("%p %d %p\n", hinstDLL, fdwReason, lpvReserved); 49 50 switch (fdwReason) 51 { 52 case DLL_PROCESS_ATTACH: 53 instance = hinstDLL; 54 DisableThreadLibraryCalls(hinstDLL); 55 break; 56 } 57 return TRUE; 58 } 59 60 /*********************************************************************** 61 * DllCanUnloadNow (HLINK.@) 62 */ 63 HRESULT WINAPI DllCanUnloadNow( void ) 64 { 65 return S_FALSE; 66 } 67 68 /*********************************************************************** 69 * HlinkCreateFromMoniker (HLINK.@) 70 */ 71 HRESULT WINAPI HlinkCreateFromMoniker( IMoniker *pimkTrgt, LPCWSTR pwzLocation, 72 LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, 73 IUnknown* piunkOuter, REFIID riid, void** ppvObj) 74 { 75 IHlink *hl = NULL; 76 HRESULT r; 77 78 TRACE("%p %s %s %p %i %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation), 79 debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter, 80 debugstr_guid(riid), ppvObj); 81 82 r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl); 83 if (FAILED(r)) 84 return r; 85 86 IHlink_SetMonikerReference(hl, HLINKSETF_LOCATION | HLINKSETF_TARGET, pimkTrgt, pwzLocation); 87 88 if (pwzFriendlyName) 89 IHlink_SetFriendlyName(hl, pwzFriendlyName); 90 if (pihlsite) 91 IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); 92 93 *ppvObj = hl; 94 95 TRACE("Returning %i\n",r); 96 97 return r; 98 } 99 100 /*********************************************************************** 101 * HlinkCreateFromString (HLINK.@) 102 */ 103 HRESULT WINAPI HlinkCreateFromString( LPCWSTR pwzTarget, LPCWSTR pwzLocation, 104 LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, 105 IUnknown* piunkOuter, REFIID riid, void** ppvObj) 106 { 107 IHlink *hl = NULL; 108 HRESULT r; 109 WCHAR *hash, *tgt; 110 const WCHAR *loc; 111 112 TRACE("%s %s %s %p %i %p %s %p\n", debugstr_w(pwzTarget), 113 debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite, 114 dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj); 115 116 r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl); 117 if (FAILED(r)) 118 return r; 119 120 if (pwzTarget) 121 { 122 hash = strchrW(pwzTarget, '#'); 123 if (hash) 124 { 125 if (hash == pwzTarget) 126 tgt = NULL; 127 else 128 { 129 int tgt_len = hash - pwzTarget; 130 tgt = heap_alloc((tgt_len + 1) * sizeof(WCHAR)); 131 if (!tgt) 132 return E_OUTOFMEMORY; 133 memcpy(tgt, pwzTarget, tgt_len * sizeof(WCHAR)); 134 tgt[tgt_len] = 0; 135 } 136 if (!pwzLocation) 137 loc = hash + 1; 138 else 139 loc = pwzLocation; 140 } 141 else 142 { 143 tgt = hlink_strdupW(pwzTarget); 144 if (!tgt) 145 return E_OUTOFMEMORY; 146 loc = pwzLocation; 147 } 148 } 149 else 150 { 151 tgt = NULL; 152 loc = pwzLocation; 153 } 154 155 IHlink_SetStringReference(hl, HLINKSETF_TARGET | HLINKSETF_LOCATION, tgt, loc); 156 157 heap_free(tgt); 158 159 if (pwzFriendlyName) 160 IHlink_SetFriendlyName(hl, pwzFriendlyName); 161 162 if (pihlsite) 163 IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); 164 165 TRACE("Returning %i\n",r); 166 *ppvObj = hl; 167 168 return r; 169 } 170 171 172 /*********************************************************************** 173 * HlinkCreateBrowseContext (HLINK.@) 174 */ 175 HRESULT WINAPI HlinkCreateBrowseContext( IUnknown* piunkOuter, REFIID riid, void** ppvObj) 176 { 177 TRACE("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj); 178 return CoCreateInstance(&CLSID_StdHlinkBrowseContext, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj); 179 } 180 181 /*********************************************************************** 182 * HlinkNavigate (HLINK.@) 183 */ 184 HRESULT WINAPI HlinkNavigate(IHlink *phl, IHlinkFrame *phlFrame, 185 DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pbsc, 186 IHlinkBrowseContext *phlbc) 187 { 188 HRESULT r = S_OK; 189 190 TRACE("%p %p %i %p %p %p\n", phl, phlFrame, grfHLNF, pbc, pbsc, phlbc); 191 192 if (phlFrame) 193 r = IHlinkFrame_Navigate(phlFrame, grfHLNF, pbc, pbsc, phl); 194 else if (phl) 195 r = IHlink_Navigate(phl, grfHLNF, pbc, pbsc, phlbc); 196 197 return r; 198 } 199 200 /*********************************************************************** 201 * HlinkOnNavigate (HLINK.@) 202 */ 203 HRESULT WINAPI HlinkOnNavigate( IHlinkFrame *phlFrame, 204 IHlinkBrowseContext* phlbc, DWORD grfHLNF, IMoniker *pmkTarget, 205 LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, ULONG* puHLID) 206 { 207 HRESULT r; 208 209 TRACE("%p %p %i %p %s %s %p\n",phlFrame, phlbc, grfHLNF, pmkTarget, 210 debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); 211 212 r = IHlinkBrowseContext_OnNavigateHlink(phlbc, grfHLNF, pmkTarget, 213 pwzLocation, pwzFriendlyName, puHLID); 214 215 if (phlFrame) 216 r = IHlinkFrame_OnNavigate(phlFrame,grfHLNF,pmkTarget, pwzLocation, 217 pwzFriendlyName, 0); 218 219 return r; 220 } 221 222 /*********************************************************************** 223 * HlinkCreateFromData (HLINK.@) 224 */ 225 HRESULT WINAPI HlinkCreateFromData(IDataObject *piDataObj, 226 IHlinkSite *pihlsite, DWORD dwSiteData, IUnknown *piunkOuter, 227 REFIID riid, void **ppvObj) 228 { 229 FIXME("%p, %p, %d, %p, %s, %p\n", piDataObj, pihlsite, dwSiteData, 230 piunkOuter, debugstr_guid(riid), ppvObj); 231 *ppvObj = NULL; 232 return E_NOTIMPL; 233 } 234 235 /*********************************************************************** 236 * HlinkQueryCreateFromData (HLINK.@) 237 */ 238 HRESULT WINAPI HlinkQueryCreateFromData(IDataObject* piDataObj) 239 { 240 FIXME("%p\n", piDataObj); 241 return E_NOTIMPL; 242 } 243 244 /*********************************************************************** 245 * HlinkNavigateToStringReference (HLINK.@) 246 */ 247 HRESULT WINAPI HlinkNavigateToStringReference( LPCWSTR pwzTarget, 248 LPCWSTR pwzLocation, IHlinkSite *pihlsite, DWORD dwSiteData, 249 IHlinkFrame *pihlframe, DWORD grfHLNF, LPBC pibc, 250 IBindStatusCallback *pibsc, IHlinkBrowseContext *pihlbc) 251 { 252 HRESULT r; 253 IHlink *hlink = NULL; 254 255 TRACE("%s %s %p %08x %p %08x %p %p %p\n", 256 debugstr_w(pwzTarget), debugstr_w(pwzLocation), pihlsite, 257 dwSiteData, pihlframe, grfHLNF, pibc, pibsc, pihlbc); 258 259 r = HlinkCreateFromString( pwzTarget, pwzLocation, NULL, pihlsite, 260 dwSiteData, NULL, &IID_IHlink, (LPVOID*) &hlink ); 261 if (SUCCEEDED(r)) { 262 r = HlinkNavigate(hlink, pihlframe, grfHLNF, pibc, pibsc, pihlbc); 263 IHlink_Release(hlink); 264 } 265 266 return r; 267 } 268 269 /*********************************************************************** 270 * HlinkIsShortcut (HLINK.@) 271 */ 272 HRESULT WINAPI HlinkIsShortcut(LPCWSTR pwzFileName) 273 { 274 int len; 275 276 static const WCHAR url_ext[] = {'.','u','r','l',0}; 277 278 TRACE("(%s)\n", debugstr_w(pwzFileName)); 279 280 if(!pwzFileName) 281 return E_INVALIDARG; 282 283 len = strlenW(pwzFileName)-4; 284 if(len < 0) 285 return S_FALSE; 286 287 return strcmpiW(pwzFileName+len, url_ext) ? S_FALSE : S_OK; 288 } 289 290 /*********************************************************************** 291 * HlinkGetSpecialReference (HLINK.@) 292 */ 293 HRESULT WINAPI HlinkGetSpecialReference(ULONG uReference, LPWSTR *ppwzReference) 294 { 295 DWORD res, type, size = 100; 296 LPCWSTR value_name; 297 WCHAR *buf; 298 HKEY hkey; 299 300 static const WCHAR start_pageW[] = {'S','t','a','r','t',' ','P','a','g','e',0}; 301 static const WCHAR search_pageW[] = {'S','e','a','r','c','h',' ','P','a','g','e',0}; 302 303 static const WCHAR ie_main_keyW[] = 304 {'S','o','f','t','w','a','r','e', 305 '\\','M','i','c','r','o','s','o','f','t','\\', 306 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r', 307 '\\','M','a','i','n',0}; 308 309 TRACE("(%u %p)\n", uReference, ppwzReference); 310 311 *ppwzReference = NULL; 312 313 switch(uReference) { 314 case HLSR_HOME: 315 value_name = start_pageW; 316 break; 317 case HLSR_SEARCHPAGE: 318 value_name = search_pageW; 319 break; 320 case HLSR_HISTORYFOLDER: 321 return E_NOTIMPL; 322 default: 323 return E_INVALIDARG; 324 } 325 326 res = RegOpenKeyW(HKEY_CURRENT_USER, ie_main_keyW, &hkey); 327 if(res != ERROR_SUCCESS) { 328 WARN("Could not open key: %u\n", res); 329 return HRESULT_FROM_WIN32(res); 330 } 331 332 buf = CoTaskMemAlloc(size); 333 res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size); 334 buf = CoTaskMemRealloc(buf, size); 335 if(res == ERROR_MORE_DATA) 336 res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size); 337 RegCloseKey(hkey); 338 if(res != ERROR_SUCCESS) { 339 WARN("Could not query value %s: %u\n", debugstr_w(value_name), res); 340 CoTaskMemFree(buf); 341 return HRESULT_FROM_WIN32(res); 342 } 343 344 *ppwzReference = buf; 345 return S_OK; 346 } 347 348 /*********************************************************************** 349 * HlinkTranslateURL (HLINK.@) 350 */ 351 HRESULT WINAPI HlinkTranslateURL(LPCWSTR pwzURL, DWORD grfFlags, LPWSTR *ppwzTranslatedURL) 352 { 353 FIXME("(%s %08x %p)\n", debugstr_w(pwzURL), grfFlags, ppwzTranslatedURL); 354 return E_NOTIMPL; 355 } 356 357 /*********************************************************************** 358 * HlinkUpdateStackItem (HLINK.@) 359 */ 360 HRESULT WINAPI HlinkUpdateStackItem(IHlinkFrame *frame, IHlinkBrowseContext *bc, 361 ULONG hlid, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name) 362 { 363 HRESULT hr; 364 365 TRACE("(%p %p 0x%x %p %s %s)\n", frame, bc, hlid, target, debugstr_w(location), debugstr_w(friendly_name)); 366 367 if (!frame && !bc) return E_INVALIDARG; 368 369 if (frame) 370 hr = IHlinkFrame_UpdateHlink(frame, hlid, target, location, friendly_name); 371 else 372 hr = IHlinkBrowseContext_UpdateHlink(bc, hlid, target, location, friendly_name); 373 374 return hr; 375 } 376 377 /*********************************************************************** 378 * HlinkParseDisplayName (HLINK.@) 379 */ 380 HRESULT WINAPI HlinkParseDisplayName(LPBC pibc, LPCWSTR pwzDisplayName, BOOL fNoForceAbs, 381 ULONG *pcchEaten, IMoniker **ppimk) 382 { 383 static const WCHAR file_colonW[] = {'f','i','l','e',':'}; 384 ULONG eaten = 0; 385 HRESULT hres; 386 387 TRACE("(%p %s %x %p %p)\n", pibc, debugstr_w(pwzDisplayName), fNoForceAbs, pcchEaten, ppimk); 388 389 if(fNoForceAbs) 390 FIXME("Unsupported fNoForceAbs\n"); 391 392 if(!strncmpiW(pwzDisplayName, file_colonW, ARRAY_SIZE(file_colonW))) { 393 pwzDisplayName += ARRAY_SIZE(file_colonW); 394 eaten += ARRAY_SIZE(file_colonW); 395 396 while(*pwzDisplayName == '/') { 397 pwzDisplayName++; 398 eaten++; 399 } 400 }else { 401 hres = MkParseDisplayNameEx(pibc, pwzDisplayName, pcchEaten, ppimk); 402 if(SUCCEEDED(hres)) 403 return hres; 404 405 hres = MkParseDisplayName(pibc, pwzDisplayName, pcchEaten, ppimk); 406 if(SUCCEEDED(hres)) 407 return hres; 408 } 409 410 hres = CreateFileMoniker(pwzDisplayName, ppimk); 411 if(SUCCEEDED(hres)) 412 *pcchEaten = eaten + strlenW(pwzDisplayName); 413 414 return hres; 415 } 416 417 /*********************************************************************** 418 * HlinkResolveMonikerForData (HLINK.@) 419 */ 420 HRESULT WINAPI HlinkResolveMonikerForData(LPMONIKER pimkReference, DWORD reserved, LPBC pibc, 421 ULONG cFmtetc, FORMATETC *rgFmtetc, IBindStatusCallback *pibsc, LPMONIKER pimkBase) 422 { 423 LPOLESTR name = NULL; 424 IBindCtx *bctx; 425 DWORD mksys = 0; 426 void *obj = NULL; 427 HRESULT hres; 428 429 TRACE("(%p %x %p %d %p %p %p)\n", pimkReference, reserved, pibc, cFmtetc, rgFmtetc, pibsc, pimkBase); 430 431 if(cFmtetc || rgFmtetc || pimkBase) 432 FIXME("Unsupported args\n"); 433 434 hres = RegisterBindStatusCallback(pibc, pibsc, NULL /* FIXME */, 0); 435 if(FAILED(hres)) 436 return hres; 437 438 hres = IMoniker_IsSystemMoniker(pimkReference, &mksys); 439 if(SUCCEEDED(hres) && mksys != MKSYS_URLMONIKER) 440 WARN("sysmk = %x\n", mksys); 441 442 /* FIXME: What is it for? */ 443 CreateBindCtx(0, &bctx); 444 hres = IMoniker_GetDisplayName(pimkReference, bctx, NULL, &name); 445 IBindCtx_Release(bctx); 446 if(SUCCEEDED(hres)) { 447 TRACE("got display name %s\n", debugstr_w(name)); 448 CoTaskMemFree(name); 449 } 450 451 return IMoniker_BindToStorage(pimkReference, pibc, NULL, &IID_IUnknown, &obj); 452 } 453 454 /*********************************************************************** 455 * HlinkClone (HLINK.@) 456 */ 457 HRESULT WINAPI HlinkClone(IHlink *hlink, REFIID riid, IHlinkSite *hls, 458 DWORD site_data, void **obj) 459 { 460 IMoniker *mk, *clone_mk = NULL; 461 WCHAR *loc, *name = NULL; 462 HRESULT hres; 463 464 if(!hlink || !riid || !obj) 465 return E_INVALIDARG; 466 467 *obj = NULL; 468 469 hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &mk, &loc); 470 if(FAILED(hres)) 471 return hres; 472 473 if(mk) { 474 IStream *strm; 475 LARGE_INTEGER lgint; 476 477 hres = CreateStreamOnHGlobal(NULL, TRUE, &strm); 478 if(FAILED(hres)) { 479 IMoniker_Release(mk); 480 goto cleanup; 481 } 482 483 hres = OleSaveToStream((IPersistStream*)mk, strm); 484 if(FAILED(hres)) { 485 IStream_Release(strm); 486 IMoniker_Release(mk); 487 goto cleanup; 488 } 489 IMoniker_Release(mk); 490 491 lgint.QuadPart = 0; 492 hres = IStream_Seek(strm, lgint, STREAM_SEEK_SET, NULL); 493 if(FAILED(hres)) { 494 IStream_Release(strm); 495 goto cleanup; 496 } 497 498 hres = OleLoadFromStream(strm, &IID_IMoniker, (void**)&clone_mk); 499 IStream_Release(strm); 500 if(FAILED(hres)) 501 goto cleanup; 502 } 503 504 hres = IHlink_GetFriendlyName(hlink, HLFNAMEF_DEFAULT, &name); 505 if(FAILED(hres)) 506 goto cleanup; 507 508 hres = HlinkCreateFromMoniker(clone_mk, loc, name, hls, site_data, NULL, 509 &IID_IHlink, obj); 510 511 cleanup: 512 if(clone_mk) 513 IMoniker_Release(clone_mk); 514 CoTaskMemFree(loc); 515 CoTaskMemFree(name); 516 return hres; 517 } 518 519 static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface, 520 REFIID riid, LPVOID *ppvObj) 521 { 522 CFImpl *This = impl_from_IClassFactory(iface); 523 524 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj); 525 526 *ppvObj = NULL; 527 528 if (IsEqualIID(riid, &IID_IUnknown) || 529 IsEqualIID(riid, &IID_IClassFactory)) 530 { 531 *ppvObj = &This->IClassFactory_iface; 532 return S_OK; 533 } 534 535 TRACE("-- E_NOINTERFACE\n"); 536 return E_NOINTERFACE; 537 } 538 539 static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface) 540 { 541 return 2; 542 } 543 544 static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface) 545 { 546 return 1; 547 } 548 549 static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface, 550 LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject) 551 { 552 CFImpl *This = impl_from_IClassFactory(iface); 553 554 TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject); 555 556 *ppvObject = NULL; 557 558 return This->lpfnCI(pUnkOuter, riid, ppvObject); 559 } 560 561 static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock) 562 { 563 FIXME("%p %d\n", iface, fLock); 564 return E_NOTIMPL; 565 } 566 567 static const IClassFactoryVtbl hlcfvt = 568 { 569 HLinkCF_fnQueryInterface, 570 HLinkCF_fnAddRef, 571 HLinkCF_fnRelease, 572 HLinkCF_fnCreateInstance, 573 HLinkCF_fnLockServer 574 }; 575 576 static CFImpl HLink_cf = { { &hlcfvt }, HLink_Constructor }; 577 static CFImpl HLinkBrowseContext_cf = { { &hlcfvt }, HLinkBrowseContext_Constructor }; 578 579 /*********************************************************************** 580 * DllGetClassObject (HLINK.@) 581 */ 582 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) 583 { 584 IClassFactory *pcf = NULL; 585 586 TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); 587 588 if (!ppv) 589 return E_INVALIDARG; 590 *ppv = NULL; 591 592 if (IsEqualIID(rclsid, &CLSID_StdHlink)) 593 pcf = &HLink_cf.IClassFactory_iface; 594 else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext)) 595 pcf = &HLinkBrowseContext_cf.IClassFactory_iface; 596 else 597 return CLASS_E_CLASSNOTAVAILABLE; 598 599 return IClassFactory_QueryInterface(pcf, iid, ppv); 600 } 601 602 /*********************************************************************** 603 * DllRegisterServer (HLINK.@) 604 */ 605 HRESULT WINAPI DllRegisterServer(void) 606 { 607 return __wine_register_resources( instance ); 608 } 609 610 /*********************************************************************** 611 * DllUnregisterServer (HLINK.@) 612 */ 613 HRESULT WINAPI DllUnregisterServer(void) 614 { 615 return __wine_unregister_resources( instance ); 616 } 617