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 "wine/debug.h" 24 #include "wine/list.h" 25 26 WINE_DEFAULT_DEBUG_CHANNEL(hlink); 27 28 struct link_entry 29 { 30 struct list entry; 31 IHlink *link; 32 }; 33 34 typedef struct 35 { 36 IHlinkBrowseContext IHlinkBrowseContext_iface; 37 LONG ref; 38 HLBWINFO* BrowseWindowInfo; 39 struct link_entry *current; 40 struct list links; 41 } HlinkBCImpl; 42 43 static inline HlinkBCImpl *impl_from_IHlinkBrowseContext(IHlinkBrowseContext *iface) 44 { 45 return CONTAINING_RECORD(iface, HlinkBCImpl, IHlinkBrowseContext_iface); 46 } 47 48 static HRESULT WINAPI IHlinkBC_fnQueryInterface( IHlinkBrowseContext *iface, 49 REFIID riid, LPVOID* ppvObj) 50 { 51 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 52 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj); 53 54 if (IsEqualIID(riid, &IID_IUnknown) || 55 IsEqualIID(riid, &IID_IHlinkBrowseContext)) 56 *ppvObj = This; 57 58 if (*ppvObj) 59 { 60 IUnknown_AddRef((IUnknown*)(*ppvObj)); 61 return S_OK; 62 } 63 return E_NOINTERFACE; 64 } 65 66 static ULONG WINAPI IHlinkBC_fnAddRef (IHlinkBrowseContext* iface) 67 { 68 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 69 ULONG refCount = InterlockedIncrement(&This->ref); 70 71 TRACE("(%p)->(count=%u)\n", This, refCount - 1); 72 73 return refCount; 74 } 75 76 static ULONG WINAPI IHlinkBC_fnRelease (IHlinkBrowseContext* iface) 77 { 78 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 79 ULONG ref = InterlockedDecrement(&This->ref); 80 81 TRACE("(%p)->(count=%u)\n", This, ref + 1); 82 83 if (!ref) 84 { 85 struct link_entry *link, *link2; 86 87 LIST_FOR_EACH_ENTRY_SAFE(link, link2, &This->links, struct link_entry, entry) 88 { 89 list_remove(&link->entry); 90 IHlink_Release(link->link); 91 heap_free(link); 92 } 93 94 heap_free(This->BrowseWindowInfo); 95 heap_free(This); 96 } 97 98 return ref; 99 } 100 101 static const WCHAR szIdent[] = {'W','I','N','E','H','L','I','N','K',0}; 102 103 static HRESULT WINAPI IHlinkBC_Register(IHlinkBrowseContext* iface, 104 DWORD dwReserved, IUnknown *piunk, IMoniker *pimk, DWORD *pdwRegister) 105 { 106 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 107 IMoniker *mon; 108 IMoniker *composite; 109 IRunningObjectTable *ROT; 110 HRESULT hr; 111 112 FIXME("(%p)->(%i %p %p %p)\n", This, dwReserved, piunk, pimk, pdwRegister); 113 114 hr = CreateItemMoniker(NULL, szIdent, &mon); 115 if (FAILED(hr)) 116 return hr; 117 CreateGenericComposite(mon, pimk, &composite); 118 119 GetRunningObjectTable(0, &ROT); 120 IRunningObjectTable_Register(ROT, 0, piunk, composite, pdwRegister); 121 122 IRunningObjectTable_Release(ROT); 123 IMoniker_Release(composite); 124 IMoniker_Release(mon); 125 126 return S_OK; 127 } 128 129 static HRESULT WINAPI IHlinkBC_GetObject(IHlinkBrowseContext* iface, 130 IMoniker *pimk, BOOL fBindifRootRegistered, IUnknown **ppiunk) 131 { 132 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 133 IMoniker *mon; 134 IMoniker *composite; 135 IRunningObjectTable *ROT; 136 HRESULT hr; 137 138 TRACE("(%p)->(%p, %d, %p)\n", This, pimk, fBindifRootRegistered, ppiunk); 139 140 hr = CreateItemMoniker(NULL, szIdent, &mon); 141 if (FAILED(hr)) return hr; 142 CreateGenericComposite(mon, pimk, &composite); 143 144 GetRunningObjectTable(0, &ROT); 145 hr = IRunningObjectTable_GetObject(ROT, composite, ppiunk); 146 147 IRunningObjectTable_Release(ROT); 148 IMoniker_Release(composite); 149 IMoniker_Release(mon); 150 151 return hr; 152 } 153 154 static HRESULT WINAPI IHlinkBC_Revoke(IHlinkBrowseContext* iface, 155 DWORD dwRegister) 156 { 157 HRESULT r; 158 IRunningObjectTable *ROT; 159 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 160 161 FIXME("(%p)->(%i)\n", This, dwRegister); 162 163 GetRunningObjectTable(0, &ROT); 164 r = IRunningObjectTable_Revoke(ROT, dwRegister); 165 IRunningObjectTable_Release(ROT); 166 167 return r; 168 } 169 170 static HRESULT WINAPI IHlinkBC_SetBrowseWindowInfo(IHlinkBrowseContext* iface, 171 HLBWINFO *phlbwi) 172 { 173 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 174 TRACE("(%p)->(%p)\n", This, phlbwi); 175 176 if(!phlbwi) 177 return E_INVALIDARG; 178 179 heap_free(This->BrowseWindowInfo); 180 This->BrowseWindowInfo = heap_alloc(phlbwi->cbSize); 181 memcpy(This->BrowseWindowInfo, phlbwi, phlbwi->cbSize); 182 183 return S_OK; 184 } 185 186 static HRESULT WINAPI IHlinkBC_GetBrowseWindowInfo(IHlinkBrowseContext* iface, 187 HLBWINFO *phlbwi) 188 { 189 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 190 TRACE("(%p)->(%p)\n", This, phlbwi); 191 192 if(!phlbwi) 193 return E_INVALIDARG; 194 195 if(!This->BrowseWindowInfo) 196 phlbwi->cbSize = 0; 197 else 198 memcpy(phlbwi, This->BrowseWindowInfo, This->BrowseWindowInfo->cbSize); 199 200 return S_OK; 201 } 202 203 static HRESULT WINAPI IHlinkBC_SetInitialHlink(IHlinkBrowseContext* iface, 204 IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName) 205 { 206 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 207 struct link_entry *link; 208 209 TRACE("(%p)->(%p %s %s)\n", This, pimkTarget, debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName)); 210 211 if (!list_empty(&This->links)) 212 return CO_E_ALREADYINITIALIZED; 213 214 link = heap_alloc(sizeof(struct link_entry)); 215 if (!link) return E_OUTOFMEMORY; 216 217 HlinkCreateFromMoniker(pimkTarget, pwzLocation, pwzFriendlyName, NULL, 218 0, NULL, &IID_IHlink, (void**)&link->link); 219 220 list_add_head(&This->links, &link->entry); 221 This->current = LIST_ENTRY(list_head(&This->links), struct link_entry, entry); 222 return S_OK; 223 } 224 225 static HRESULT WINAPI IHlinkBC_OnNavigateHlink(IHlinkBrowseContext *iface, 226 DWORD grfHLNF, IMoniker* pmkTarget, LPCWSTR pwzLocation, LPCWSTR 227 pwzFriendlyName, ULONG *puHLID) 228 { 229 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 230 231 FIXME("(%p)->(%i %p %s %s %p)\n", This, grfHLNF, pmkTarget, 232 debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); 233 234 return S_OK; 235 } 236 237 static struct link_entry *context_get_entry(HlinkBCImpl *ctxt, ULONG hlid) 238 { 239 struct list *entry; 240 241 switch (hlid) 242 { 243 case HLID_PREVIOUS: 244 entry = list_prev(&ctxt->links, &ctxt->current->entry); 245 break; 246 case HLID_NEXT: 247 entry = list_next(&ctxt->links, &ctxt->current->entry); 248 break; 249 case HLID_CURRENT: 250 entry = &ctxt->current->entry; 251 break; 252 case HLID_STACKBOTTOM: 253 entry = list_tail(&ctxt->links); 254 break; 255 case HLID_STACKTOP: 256 entry = list_head(&ctxt->links); 257 break; 258 default: 259 WARN("unknown id 0x%x\n", hlid); 260 entry = NULL; 261 } 262 263 return entry ? LIST_ENTRY(entry, struct link_entry, entry) : NULL; 264 } 265 266 static HRESULT WINAPI IHlinkBC_UpdateHlink(IHlinkBrowseContext* iface, 267 ULONG hlid, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name) 268 { 269 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 270 struct link_entry *entry = context_get_entry(This, hlid); 271 IHlink *link; 272 HRESULT hr; 273 274 TRACE("(%p)->(0x%x %p %s %s)\n", This, hlid, target, debugstr_w(location), debugstr_w(friendly_name)); 275 276 if (!entry) 277 return E_INVALIDARG; 278 279 hr = HlinkCreateFromMoniker(target, location, friendly_name, NULL, 0, NULL, &IID_IHlink, (void**)&link); 280 if (FAILED(hr)) 281 return hr; 282 283 IHlink_Release(entry->link); 284 entry->link = link; 285 286 return S_OK; 287 } 288 289 static HRESULT WINAPI IHlinkBC_EnumNavigationStack( IHlinkBrowseContext *iface, 290 DWORD dwReserved, DWORD grfHLFNAMEF, IEnumHLITEM** ppienumhlitem) 291 { 292 FIXME("\n"); 293 return E_NOTIMPL; 294 } 295 296 static HRESULT WINAPI IHlinkBC_QueryHlink( IHlinkBrowseContext* iface, 297 DWORD grfHLONG, ULONG uHLID) 298 { 299 FIXME("\n"); 300 return E_NOTIMPL; 301 } 302 303 static HRESULT WINAPI IHlinkBC_GetHlink(IHlinkBrowseContext* iface, ULONG hlid, IHlink **ret) 304 { 305 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 306 struct link_entry *link; 307 308 TRACE("(%p)->(0x%x %p)\n", This, hlid, ret); 309 310 link = context_get_entry(This, hlid); 311 if (!link) 312 return E_FAIL; 313 314 *ret = link->link; 315 IHlink_AddRef(*ret); 316 317 return S_OK; 318 } 319 320 static HRESULT WINAPI IHlinkBC_SetCurrentHlink(IHlinkBrowseContext* iface, ULONG hlid) 321 { 322 HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); 323 struct link_entry *link; 324 325 TRACE("(%p)->(0x%08x)\n", This, hlid); 326 327 link = context_get_entry(This, hlid); 328 if (!link) 329 return E_FAIL; 330 331 This->current = link; 332 return S_OK; 333 } 334 335 static HRESULT WINAPI IHlinkBC_Clone( IHlinkBrowseContext* iface, 336 IUnknown* piunkOuter, REFIID riid, IUnknown** ppiunkOjb) 337 { 338 FIXME("\n"); 339 return E_NOTIMPL; 340 } 341 342 static HRESULT WINAPI IHlinkBC_Close(IHlinkBrowseContext* iface, 343 DWORD reserved) 344 { 345 FIXME("\n"); 346 return E_NOTIMPL; 347 } 348 349 static const IHlinkBrowseContextVtbl hlvt = 350 { 351 IHlinkBC_fnQueryInterface, 352 IHlinkBC_fnAddRef, 353 IHlinkBC_fnRelease, 354 IHlinkBC_Register, 355 IHlinkBC_GetObject, 356 IHlinkBC_Revoke, 357 IHlinkBC_SetBrowseWindowInfo, 358 IHlinkBC_GetBrowseWindowInfo, 359 IHlinkBC_SetInitialHlink, 360 IHlinkBC_OnNavigateHlink, 361 IHlinkBC_UpdateHlink, 362 IHlinkBC_EnumNavigationStack, 363 IHlinkBC_QueryHlink, 364 IHlinkBC_GetHlink, 365 IHlinkBC_SetCurrentHlink, 366 IHlinkBC_Clone, 367 IHlinkBC_Close 368 }; 369 370 HRESULT HLinkBrowseContext_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) 371 { 372 HlinkBCImpl * hl; 373 374 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid)); 375 *ppv = NULL; 376 377 if (pUnkOuter) 378 return CLASS_E_NOAGGREGATION; 379 380 hl = heap_alloc_zero(sizeof(HlinkBCImpl)); 381 if (!hl) 382 return E_OUTOFMEMORY; 383 384 hl->ref = 1; 385 hl->IHlinkBrowseContext_iface.lpVtbl = &hlvt; 386 list_init(&hl->links); 387 hl->current = NULL; 388 389 *ppv = hl; 390 return S_OK; 391 } 392