vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / browseui / aclmulti.c
blob47547cdd1e1701ce3c10996e701b5488e417f9f0
1 /*
2 * Multisource AutoComplete list
4 * Copyright 2007 Mikolaj Zalewski
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.
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.
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "wine/debug.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "shlwapi.h"
31 #include "winerror.h"
32 #include "objbase.h"
34 #include "shlguid.h"
35 #include "shlobj.h"
37 #include "browseui.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(browseui);
41 struct ACLMultiSublist {
42 IUnknown *punk;
43 IEnumString *pEnum;
44 IACList *pACL;
47 typedef struct tagACLMulti {
48 IEnumString IEnumString_iface;
49 IACList IACList_iface;
50 IObjMgr IObjMgr_iface;
51 LONG refCount;
52 INT nObjs;
53 INT currObj;
54 struct ACLMultiSublist *objs;
55 } ACLMulti;
57 static inline ACLMulti *impl_from_IEnumString(IEnumString *iface)
59 return CONTAINING_RECORD(iface, ACLMulti, IEnumString_iface);
62 static inline ACLMulti *impl_from_IACList(IACList *iface)
64 return CONTAINING_RECORD(iface, ACLMulti, IACList_iface);
67 static inline ACLMulti *impl_from_IObjMgr(IObjMgr *iface)
69 return CONTAINING_RECORD(iface, ACLMulti, IObjMgr_iface);
72 static void release_obj(struct ACLMultiSublist *obj)
74 IUnknown_Release(obj->punk);
75 if (obj->pEnum)
76 IEnumString_Release(obj->pEnum);
77 if (obj->pACL)
78 IACList_Release(obj->pACL);
81 static HRESULT WINAPI ACLMulti_QueryInterface(IEnumString *iface, REFIID iid, LPVOID *ppvOut)
83 ACLMulti *This = impl_from_IEnumString(iface);
84 *ppvOut = NULL;
86 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumString))
88 *ppvOut = &This->IEnumString_iface;
90 else if (IsEqualIID(iid, &IID_IACList))
92 *ppvOut = &This->IACList_iface;
94 else if (IsEqualIID(iid, &IID_IObjMgr))
96 *ppvOut = &This->IObjMgr_iface;
99 if (*ppvOut)
101 IEnumString_AddRef(iface);
102 return S_OK;
105 WARN("unsupported interface: %s\n", debugstr_guid(iid));
106 return E_NOINTERFACE;
109 static ULONG WINAPI ACLMulti_AddRef(IEnumString *iface)
111 ACLMulti *This = impl_from_IEnumString(iface);
112 return InterlockedIncrement(&This->refCount);
115 static ULONG WINAPI ACLMulti_Release(IEnumString *iface)
117 ACLMulti *This = impl_from_IEnumString(iface);
118 ULONG ret;
119 int i;
121 ret = InterlockedDecrement(&This->refCount);
122 if (ret == 0)
124 for (i = 0; i < This->nObjs; i++)
125 release_obj(&This->objs[i]);
126 free(This->objs);
127 free(This);
128 BROWSEUI_refCount--;
131 return ret;
134 static HRESULT WINAPI ACLMulti_Next(IEnumString *iface, ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
136 ACLMulti *This = impl_from_IEnumString(iface);
138 TRACE("(%p, %ld, %p, %p)\n", iface, celt, rgelt, pceltFetched);
139 while (This->currObj < This->nObjs)
141 if (This->objs[This->currObj].pEnum)
143 /* native browseui 6.0 also returns only one element */
144 HRESULT ret = IEnumString_Next(This->objs[This->currObj].pEnum, 1, rgelt, pceltFetched);
145 if (ret != S_FALSE)
146 return ret;
148 This->currObj++;
151 if (pceltFetched)
152 *pceltFetched = 0;
153 *rgelt = NULL;
154 return S_FALSE;
157 static HRESULT WINAPI ACLMulti_Reset(IEnumString *iface)
159 ACLMulti *This = impl_from_IEnumString(iface);
160 int i;
162 This->currObj = 0;
163 for (i = 0; i < This->nObjs; i++)
165 if (This->objs[i].pEnum)
166 IEnumString_Reset(This->objs[i].pEnum);
168 return S_OK;
171 static HRESULT WINAPI ACLMulti_Skip(IEnumString *iface, ULONG celt)
173 /* native browseui 6.0 returns this: */
174 return E_NOTIMPL;
177 static HRESULT WINAPI ACLMulti_Clone(IEnumString *iface, IEnumString **ppOut)
179 *ppOut = NULL;
180 /* native browseui 6.0 returns this: */
181 return E_OUTOFMEMORY;
184 static const IEnumStringVtbl ACLMultiVtbl =
186 ACLMulti_QueryInterface,
187 ACLMulti_AddRef,
188 ACLMulti_Release,
190 ACLMulti_Next,
191 ACLMulti_Skip,
192 ACLMulti_Reset,
193 ACLMulti_Clone
196 static HRESULT WINAPI ACLMulti_IObjMgr_QueryInterface(IObjMgr *iface, REFIID iid, LPVOID *ppvOut)
198 ACLMulti *This = impl_from_IObjMgr(iface);
199 return IEnumString_QueryInterface(&This->IEnumString_iface, iid, ppvOut);
202 static ULONG WINAPI ACLMulti_IObjMgr_AddRef(IObjMgr *iface)
204 ACLMulti *This = impl_from_IObjMgr(iface);
205 return IEnumString_AddRef(&This->IEnumString_iface);
208 static ULONG WINAPI ACLMulti_IObjMgr_Release(IObjMgr *iface)
210 ACLMulti *This = impl_from_IObjMgr(iface);
211 return IEnumString_Release(&This->IEnumString_iface);
214 static HRESULT WINAPI ACLMulti_Append(IObjMgr *iface, IUnknown *obj)
216 ACLMulti *This = impl_from_IObjMgr(iface);
218 TRACE("(%p, %p)\n", This, obj);
219 if (obj == NULL)
220 return E_FAIL;
222 This->objs = realloc(This->objs, sizeof(This->objs[0]) * (This->nObjs+1));
223 This->objs[This->nObjs].punk = obj;
224 IUnknown_AddRef(obj);
225 if (FAILED(IUnknown_QueryInterface(obj, &IID_IEnumString, (LPVOID *)&This->objs[This->nObjs].pEnum)))
226 This->objs[This->nObjs].pEnum = NULL;
227 if (FAILED(IUnknown_QueryInterface(obj, &IID_IACList, (LPVOID *)&This->objs[This->nObjs].pACL)))
228 This->objs[This->nObjs].pACL = NULL;
229 This->nObjs++;
230 return S_OK;
233 static HRESULT WINAPI ACLMulti_Remove(IObjMgr *iface, IUnknown *obj)
235 ACLMulti *This = impl_from_IObjMgr(iface);
236 int i;
238 TRACE("(%p, %p)\n", This, obj);
239 for (i = 0; i < This->nObjs; i++)
240 if (This->objs[i].punk == obj)
242 release_obj(&This->objs[i]);
243 memmove(&This->objs[i], &This->objs[i+1], (This->nObjs-i-1)*sizeof(struct ACLMultiSublist));
244 This->nObjs--;
245 This->objs = realloc(This->objs, sizeof(This->objs[0]) * This->nObjs);
246 return S_OK;
249 return E_FAIL;
252 static const IObjMgrVtbl ACLMulti_ObjMgrVtbl =
254 ACLMulti_IObjMgr_QueryInterface,
255 ACLMulti_IObjMgr_AddRef,
256 ACLMulti_IObjMgr_Release,
258 ACLMulti_Append,
259 ACLMulti_Remove
262 static HRESULT WINAPI ACLMulti_IACList_QueryInterface(IACList *iface, REFIID iid, LPVOID *ppvOut)
264 ACLMulti *This = impl_from_IACList(iface);
265 return IEnumString_QueryInterface(&This->IEnumString_iface, iid, ppvOut);
268 static ULONG WINAPI ACLMulti_IACList_AddRef(IACList *iface)
270 ACLMulti *This = impl_from_IACList(iface);
271 return IEnumString_AddRef(&This->IEnumString_iface);
274 static ULONG WINAPI ACLMulti_IACList_Release(IACList *iface)
276 ACLMulti *This = impl_from_IACList(iface);
277 return IEnumString_Release(&This->IEnumString_iface);
280 static HRESULT WINAPI ACLMulti_Expand(IACList *iface, LPCWSTR wstr)
282 ACLMulti *This = impl_from_IACList(iface);
283 HRESULT res = S_OK;
284 int i;
286 for (i = 0; i < This->nObjs; i++)
288 if (!This->objs[i].pACL)
289 continue;
290 res = IACList_Expand(This->objs[i].pACL, wstr);
291 /* Vista behaviour - XP would break out of the loop if res == S_OK (usually calling Expand only once) */
293 return res;
296 static const IACListVtbl ACLMulti_ACListVtbl =
298 ACLMulti_IACList_QueryInterface,
299 ACLMulti_IACList_AddRef,
300 ACLMulti_IACList_Release,
302 ACLMulti_Expand
305 HRESULT ACLMulti_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
307 ACLMulti *This;
308 if (pUnkOuter)
309 return CLASS_E_NOAGGREGATION;
311 if (!(This = calloc(1, sizeof(ACLMulti))))
312 return E_OUTOFMEMORY;
314 This->IEnumString_iface.lpVtbl = &ACLMultiVtbl;
315 This->IACList_iface.lpVtbl = &ACLMulti_ACListVtbl;
316 This->IObjMgr_iface.lpVtbl = &ACLMulti_ObjMgrVtbl;
317 This->refCount = 1;
319 TRACE("returning %p\n", This);
320 *ppOut = (IUnknown *)&This->IEnumString_iface;
321 BROWSEUI_refCount++;
322 return S_OK;