xref: /reactos/dll/win32/ole32/enumx.c (revision d5b576b2)
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  */
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  */
75 ULONG WINAPI enumx_AddRef(enumx_impl *This)
76 {
77     return InterlockedIncrement(&This->ref);
78 }
79 
80 /************************************************************************
81  * enumx_Release
82  */
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  */
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  */
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  */
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  */
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  */
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  */
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