xref: /reactos/dll/win32/hlink/browse_ctx.c (revision c2c66aff)
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 HRESULT WINAPI IHlinkBC_Register(IHlinkBrowseContext* iface,
99         DWORD dwReserved, IUnknown *piunk, IMoniker *pimk, DWORD *pdwRegister)
100 {
101     static const WCHAR szIdent[] = {'W','I','N','E','H','L','I','N','K',0};
102     HlinkBCImpl  *This = impl_from_IHlinkBrowseContext(iface);
103     IMoniker *mon;
104     IMoniker *composite;
105     IRunningObjectTable *ROT;
106     HRESULT hr;
107 
108     FIXME("(%p)->(%i %p %p %p)\n", This, dwReserved, piunk, pimk, pdwRegister);
109 
110     hr = CreateItemMoniker(NULL, szIdent, &mon);
111     if (FAILED(hr))
112         return hr;
113     CreateGenericComposite(mon, pimk, &composite);
114 
115     GetRunningObjectTable(0, &ROT);
116     IRunningObjectTable_Register(ROT, 0, piunk, composite, pdwRegister);
117 
118     IRunningObjectTable_Release(ROT);
119     IMoniker_Release(composite);
120     IMoniker_Release(mon);
121 
122     return S_OK;
123 }
124 
125 static HRESULT WINAPI IHlinkBC_GetObject(IHlinkBrowseContext* face,
126         IMoniker *pimk, BOOL fBindifRootRegistered, IUnknown **ppiunk)
127 {
128     FIXME("\n");
129     return E_NOTIMPL;
130 }
131 
132 static HRESULT WINAPI IHlinkBC_Revoke(IHlinkBrowseContext* iface,
133         DWORD dwRegister)
134 {
135     HRESULT r;
136     IRunningObjectTable *ROT;
137     HlinkBCImpl  *This = impl_from_IHlinkBrowseContext(iface);
138 
139     FIXME("(%p)->(%i)\n", This, dwRegister);
140 
141     GetRunningObjectTable(0, &ROT);
142     r = IRunningObjectTable_Revoke(ROT, dwRegister);
143     IRunningObjectTable_Release(ROT);
144 
145     return r;
146 }
147 
148 static HRESULT WINAPI IHlinkBC_SetBrowseWindowInfo(IHlinkBrowseContext* iface,
149         HLBWINFO *phlbwi)
150 {
151     HlinkBCImpl  *This = impl_from_IHlinkBrowseContext(iface);
152     TRACE("(%p)->(%p)\n", This, phlbwi);
153 
154     if(!phlbwi)
155         return E_INVALIDARG;
156 
157     heap_free(This->BrowseWindowInfo);
158     This->BrowseWindowInfo = heap_alloc(phlbwi->cbSize);
159     memcpy(This->BrowseWindowInfo, phlbwi, phlbwi->cbSize);
160 
161     return S_OK;
162 }
163 
164 static HRESULT WINAPI IHlinkBC_GetBrowseWindowInfo(IHlinkBrowseContext* iface,
165         HLBWINFO *phlbwi)
166 {
167     HlinkBCImpl  *This = impl_from_IHlinkBrowseContext(iface);
168     TRACE("(%p)->(%p)\n", This, phlbwi);
169 
170     if(!phlbwi)
171         return E_INVALIDARG;
172 
173     if(!This->BrowseWindowInfo)
174         phlbwi->cbSize = 0;
175     else
176         memcpy(phlbwi, This->BrowseWindowInfo, This->BrowseWindowInfo->cbSize);
177 
178     return S_OK;
179 }
180 
181 static HRESULT WINAPI IHlinkBC_SetInitialHlink(IHlinkBrowseContext* iface,
182         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
183 {
184     HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface);
185     struct link_entry *link;
186 
187     TRACE("(%p)->(%p %s %s)\n", This, pimkTarget, debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName));
188 
189     if (!list_empty(&This->links))
190         return CO_E_ALREADYINITIALIZED;
191 
192     link = heap_alloc(sizeof(struct link_entry));
193     if (!link) return E_OUTOFMEMORY;
194 
195     HlinkCreateFromMoniker(pimkTarget, pwzLocation, pwzFriendlyName, NULL,
196             0, NULL, &IID_IHlink, (void**)&link->link);
197 
198     list_add_head(&This->links, &link->entry);
199     This->current = LIST_ENTRY(list_head(&This->links), struct link_entry, entry);
200     return S_OK;
201 }
202 
203 static HRESULT WINAPI IHlinkBC_OnNavigateHlink(IHlinkBrowseContext *iface,
204         DWORD grfHLNF, IMoniker* pmkTarget, LPCWSTR pwzLocation, LPCWSTR
205         pwzFriendlyName, ULONG *puHLID)
206 {
207     HlinkBCImpl  *This = impl_from_IHlinkBrowseContext(iface);
208 
209     FIXME("(%p)->(%i %p %s %s %p)\n", This, grfHLNF, pmkTarget,
210             debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID);
211 
212     return S_OK;
213 }
214 
215 static struct link_entry *context_get_entry(HlinkBCImpl *ctxt, ULONG hlid)
216 {
217     struct list *entry;
218 
219     switch (hlid)
220     {
221     case HLID_PREVIOUS:
222         entry = list_prev(&ctxt->links, &ctxt->current->entry);
223         break;
224     case HLID_NEXT:
225         entry = list_next(&ctxt->links, &ctxt->current->entry);
226         break;
227     case HLID_CURRENT:
228         entry = &ctxt->current->entry;
229         break;
230     case HLID_STACKBOTTOM:
231         entry = list_tail(&ctxt->links);
232         break;
233     case HLID_STACKTOP:
234         entry = list_head(&ctxt->links);
235         break;
236     default:
237         WARN("unknown id 0x%x\n", hlid);
238         entry = NULL;
239     }
240 
241     return entry ? LIST_ENTRY(entry, struct link_entry, entry) : NULL;
242 }
243 
244 static HRESULT WINAPI IHlinkBC_UpdateHlink(IHlinkBrowseContext* iface,
245         ULONG hlid, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name)
246 {
247     HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface);
248     struct link_entry *entry = context_get_entry(This, hlid);
249     IHlink *link;
250     HRESULT hr;
251 
252     TRACE("(%p)->(0x%x %p %s %s)\n", This, hlid, target, debugstr_w(location), debugstr_w(friendly_name));
253 
254     if (!entry)
255         return E_INVALIDARG;
256 
257     hr = HlinkCreateFromMoniker(target, location, friendly_name, NULL, 0, NULL, &IID_IHlink, (void**)&link);
258     if (FAILED(hr))
259         return hr;
260 
261     IHlink_Release(entry->link);
262     entry->link = link;
263 
264     return S_OK;
265 }
266 
267 static HRESULT WINAPI IHlinkBC_EnumNavigationStack( IHlinkBrowseContext *iface,
268         DWORD dwReserved, DWORD grfHLFNAMEF, IEnumHLITEM** ppienumhlitem)
269 {
270     FIXME("\n");
271     return E_NOTIMPL;
272 }
273 
274 static HRESULT WINAPI IHlinkBC_QueryHlink( IHlinkBrowseContext* iface,
275         DWORD grfHLONG, ULONG uHLID)
276 {
277     FIXME("\n");
278     return E_NOTIMPL;
279 }
280 
281 static HRESULT WINAPI IHlinkBC_GetHlink(IHlinkBrowseContext* iface, ULONG hlid, IHlink **ret)
282 {
283     HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface);
284     struct link_entry *link;
285 
286     TRACE("(%p)->(0x%x %p)\n", This, hlid, ret);
287 
288     link = context_get_entry(This, hlid);
289     if (!link)
290         return E_FAIL;
291 
292     *ret = link->link;
293     IHlink_AddRef(*ret);
294 
295     return S_OK;
296 }
297 
298 static HRESULT WINAPI IHlinkBC_SetCurrentHlink(IHlinkBrowseContext* iface, ULONG hlid)
299 {
300     HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface);
301     struct link_entry *link;
302 
303     TRACE("(%p)->(0x%08x)\n", This, hlid);
304 
305     link = context_get_entry(This, hlid);
306     if (!link)
307         return E_FAIL;
308 
309     This->current = link;
310     return S_OK;
311 }
312 
313 static HRESULT WINAPI IHlinkBC_Clone( IHlinkBrowseContext* iface,
314         IUnknown* piunkOuter, REFIID riid, IUnknown** ppiunkOjb)
315 {
316     FIXME("\n");
317     return E_NOTIMPL;
318 }
319 
320 static HRESULT WINAPI IHlinkBC_Close(IHlinkBrowseContext* iface,
321         DWORD reserved)
322 {
323     FIXME("\n");
324     return E_NOTIMPL;
325 }
326 
327 static const IHlinkBrowseContextVtbl hlvt =
328 {
329     IHlinkBC_fnQueryInterface,
330     IHlinkBC_fnAddRef,
331     IHlinkBC_fnRelease,
332     IHlinkBC_Register,
333     IHlinkBC_GetObject,
334     IHlinkBC_Revoke,
335     IHlinkBC_SetBrowseWindowInfo,
336     IHlinkBC_GetBrowseWindowInfo,
337     IHlinkBC_SetInitialHlink,
338     IHlinkBC_OnNavigateHlink,
339     IHlinkBC_UpdateHlink,
340     IHlinkBC_EnumNavigationStack,
341     IHlinkBC_QueryHlink,
342     IHlinkBC_GetHlink,
343     IHlinkBC_SetCurrentHlink,
344     IHlinkBC_Clone,
345     IHlinkBC_Close
346 };
347 
348 HRESULT HLinkBrowseContext_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
349 {
350     HlinkBCImpl * hl;
351 
352     TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
353     *ppv = NULL;
354 
355     if (pUnkOuter)
356         return CLASS_E_NOAGGREGATION;
357 
358     hl = heap_alloc_zero(sizeof(HlinkBCImpl));
359     if (!hl)
360         return E_OUTOFMEMORY;
361 
362     hl->ref = 1;
363     hl->IHlinkBrowseContext_iface.lpVtbl = &hlvt;
364     list_init(&hl->links);
365     hl->current = NULL;
366 
367     *ppv = hl;
368     return S_OK;
369 }
370