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