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