1 /*
2 * IEnum* implementation
3 *
4 * Copyright 2006 Mike McCormack
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 #define COBJMACROS
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28
29 #include "enumx.h"
30
31 #include "wine/list.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(ole);
35
36 struct tagEnumSTATPROPSETSTG_impl
37 {
38 const void *vtbl;
39 LONG ref;
40 struct list elements;
41 struct list *current;
42 ULONG elem_size;
43 GUID riid;
44 IUnknown *parent;
45 enumx_copy_cb copy_cb;
46 };
47
48 /************************************************************************
49 * enumx_QueryInterface
50 */
enumx_QueryInterface(enumx_impl * This,REFIID riid,void ** ppvObject)51 HRESULT WINAPI enumx_QueryInterface(
52 enumx_impl *This,
53 REFIID riid,
54 void** ppvObject)
55 {
56 if ( ppvObject==0 )
57 return E_INVALIDARG;
58
59 *ppvObject = 0;
60
61 if (IsEqualGUID(&IID_IUnknown, riid) ||
62 IsEqualGUID(&This->riid, riid))
63 {
64 IUnknown_AddRef(((IUnknown*)This));
65 *ppvObject = This;
66 return S_OK;
67 }
68
69 return E_NOINTERFACE;
70 }
71
72 /************************************************************************
73 * enumx_AddRef
74 */
enumx_AddRef(enumx_impl * This)75 ULONG WINAPI enumx_AddRef(enumx_impl *This)
76 {
77 return InterlockedIncrement(&This->ref);
78 }
79
80 /************************************************************************
81 * enumx_Release
82 */
enumx_Release(enumx_impl * This)83 ULONG WINAPI enumx_Release(enumx_impl *This)
84 {
85 ULONG ref;
86
87 ref = InterlockedDecrement(&This->ref);
88 if (ref == 0)
89 {
90 while (!list_empty(&This->elements))
91 {
92 struct list *x = list_head(&This->elements);
93 list_remove(x);
94 HeapFree(GetProcessHeap(), 0, x);
95 }
96 IUnknown_Release(This->parent);
97 HeapFree(GetProcessHeap(), 0, This);
98 }
99 return ref;
100 }
101
102 /************************************************************************
103 * enumx_Next
104 */
enumx_Next(enumx_impl * This,ULONG celt,void * rgelt,ULONG * pceltFetched)105 HRESULT WINAPI enumx_Next(enumx_impl *This, ULONG celt,
106 void *rgelt, ULONG *pceltFetched)
107 {
108 unsigned char *p;
109 ULONG count = 0;
110
111 TRACE("%p %u %p\n", This, celt, pceltFetched);
112
113 if (This->current == NULL)
114 This->current = list_head(&This->elements);
115 p = rgelt;
116 while (count < celt && This->current && This->current != &This->elements)
117 {
118 if (This->copy_cb)
119 This->copy_cb(This->parent, &This->current[1], p);
120 else
121 memcpy(p, &This->current[1], This->elem_size);
122 p += This->elem_size;
123 This->current = This->current->next;
124 count++;
125 }
126 if (pceltFetched)
127 *pceltFetched = count;
128 if (count < celt)
129 return S_FALSE;
130 return S_OK;
131 }
132
133 /************************************************************************
134 * enumx_Skip
135 */
enumx_Skip(enumx_impl * This,ULONG celt)136 HRESULT WINAPI enumx_Skip(enumx_impl *This, ULONG celt)
137 {
138 ULONG count = 0;
139
140 TRACE("%p %u\n", This, celt);
141
142 if (This->current == NULL)
143 This->current = list_head(&This->elements);
144
145 while (count < celt && This->current && This->current != &This->elements)
146 count++;
147
148 return S_OK;
149 }
150
151 /************************************************************************
152 * enumx_Reset
153 */
enumx_Reset(enumx_impl * This)154 HRESULT WINAPI enumx_Reset(enumx_impl *This)
155 {
156 TRACE("\n");
157
158 This->current = NULL;
159 return S_OK;
160 }
161
162 /************************************************************************
163 * enumx_fnClone
164 */
enumx_Clone(enumx_impl * iface,enumx_impl ** ppenum)165 HRESULT WINAPI enumx_Clone(
166 enumx_impl *iface,
167 enumx_impl **ppenum)
168 {
169 FIXME("\n");
170 return E_NOTIMPL;
171 }
172
173 /************************************************************************
174 * enumx_allocate
175 *
176 * Allocate a generic enumerator
177 */
enumx_allocate(REFIID riid,const void * vtbl,ULONG elem_size,IUnknown * parent,enumx_copy_cb copy_cb)178 enumx_impl *enumx_allocate(REFIID riid, const void *vtbl, ULONG elem_size,
179 IUnknown *parent, enumx_copy_cb copy_cb)
180 {
181 enumx_impl *enumx;
182
183 enumx = HeapAlloc(GetProcessHeap(), 0, sizeof *enumx);
184 if (enumx)
185 {
186 enumx->vtbl = vtbl;
187 enumx->ref = 1;
188 enumx->current = NULL;
189 enumx->elem_size = elem_size;
190 enumx->riid = *riid;
191 enumx->parent = parent;
192 enumx->copy_cb = copy_cb;
193
194 IUnknown_AddRef(parent);
195
196 list_init(&enumx->elements);
197 }
198
199 return enumx;
200 }
201
202 /************************************************************************
203 * enumx_add_element
204 *
205 * Add an element to the enumeration.
206 */
enumx_add_element(enumx_impl * enumx,const void * data)207 void *enumx_add_element(enumx_impl *enumx, const void *data)
208 {
209 struct list *element;
210
211 element = HeapAlloc(GetProcessHeap(), 0, sizeof *element + enumx->elem_size);
212 if (!element)
213 return NULL;
214 memcpy(&element[1], data, enumx->elem_size);
215 list_add_tail(&enumx->elements, element);
216 return &element[1];
217 }
218