mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / oledb32 / rowpos.c
blobc922f93f908b2e8147647cafd31b9b1e7990e950
1 /* OLE DB Row Position library
3 * Copyright 2013 Nikolay Sivov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
22 #include "windef.h"
23 #include "ole2.h"
24 #include "olectl.h"
26 #include "oledb.h"
27 #include "oledberr.h"
29 #include "oledb_private.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(oledb);
35 typedef struct rowpos rowpos;
36 typedef struct
38 IConnectionPoint IConnectionPoint_iface;
39 rowpos *container;
40 IRowPositionChange **sinks;
41 DWORD sinks_size;
42 } rowpos_cp;
44 struct rowpos
46 IRowPosition IRowPosition_iface;
47 IConnectionPointContainer IConnectionPointContainer_iface;
48 LONG ref;
50 IRowset *rowset;
51 IChapteredRowset *chrst;
52 HROW row;
53 HCHAPTER chapter;
54 DBPOSITIONFLAGS flags;
55 BOOL cleared;
56 rowpos_cp cp;
59 static void rowposchange_cp_destroy(rowpos_cp*);
61 static inline rowpos *impl_from_IRowPosition(IRowPosition *iface)
63 return CONTAINING_RECORD(iface, rowpos, IRowPosition_iface);
66 static inline rowpos *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
68 return CONTAINING_RECORD(iface, rowpos, IConnectionPointContainer_iface);
71 static inline rowpos_cp *impl_from_IConnectionPoint(IConnectionPoint *iface)
73 return CONTAINING_RECORD(iface, rowpos_cp, IConnectionPoint_iface);
76 static HRESULT rowpos_fireevent(rowpos *rp, DBREASON reason, DBEVENTPHASE phase)
78 BOOL cant_deny = phase == DBEVENTPHASE_FAILEDTODO || phase == DBEVENTPHASE_SYNCHAFTER;
79 HRESULT hr = S_OK;
80 DWORD i;
82 for (i = 0; i < rp->cp.sinks_size; i++)
83 if (rp->cp.sinks[i])
85 hr = IRowPositionChange_OnRowPositionChange(rp->cp.sinks[i], reason, phase, cant_deny);
86 if (phase == DBEVENTPHASE_FAILEDTODO) return DB_E_CANCELED;
87 if (hr != S_OK) return hr;
90 return hr;
93 static void rowpos_clearposition(rowpos *rp)
95 if (!rp->cleared)
97 if (rp->rowset)
98 IRowset_ReleaseRows(rp->rowset, 1, &rp->row, NULL, NULL, NULL);
99 if (rp->chrst)
100 IChapteredRowset_ReleaseChapter(rp->chrst, rp->chapter, NULL);
103 rp->row = DB_NULL_HROW;
104 rp->chapter = DB_NULL_HCHAPTER;
105 rp->flags = DBPOSITION_NOROW;
108 static HRESULT WINAPI rowpos_QueryInterface(IRowPosition* iface, REFIID riid, void **obj)
110 rowpos *This = impl_from_IRowPosition(iface);
112 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
114 *obj = NULL;
116 if (IsEqualIID(riid, &IID_IUnknown) ||
117 IsEqualIID(riid, &IID_IRowPosition))
119 *obj = iface;
121 else if (IsEqualIID(riid, &IID_IConnectionPointContainer))
123 *obj = &This->IConnectionPointContainer_iface;
125 else
127 FIXME("interface %s not implemented\n", debugstr_guid(riid));
128 return E_NOINTERFACE;
131 IRowPosition_AddRef(iface);
132 return S_OK;
135 static ULONG WINAPI rowpos_AddRef(IRowPosition* iface)
137 rowpos *This = impl_from_IRowPosition(iface);
138 ULONG ref = InterlockedIncrement(&This->ref);
139 TRACE("(%p)->(%d)\n", This, ref);
140 return ref;
143 static ULONG WINAPI rowpos_Release(IRowPosition* iface)
145 rowpos *This = impl_from_IRowPosition(iface);
146 LONG ref = InterlockedDecrement(&This->ref);
148 TRACE("(%p)->(%d)\n", This, ref);
150 if (ref == 0)
152 if (This->rowset) IRowset_Release(This->rowset);
153 if (This->chrst) IChapteredRowset_Release(This->chrst);
154 rowposchange_cp_destroy(&This->cp);
155 heap_free(This);
158 return ref;
161 static HRESULT WINAPI rowpos_ClearRowPosition(IRowPosition* iface)
163 rowpos *This = impl_from_IRowPosition(iface);
164 HRESULT hr;
166 TRACE("(%p)\n", This);
168 if (!This->rowset) return E_UNEXPECTED;
170 hr = rowpos_fireevent(This, DBREASON_ROWPOSITION_CLEARED, DBEVENTPHASE_OKTODO);
171 if (hr != S_OK)
172 return rowpos_fireevent(This, DBREASON_ROWPOSITION_CLEARED, DBEVENTPHASE_FAILEDTODO);
174 hr = rowpos_fireevent(This, DBREASON_ROWPOSITION_CLEARED, DBEVENTPHASE_ABOUTTODO);
175 if (hr != S_OK)
176 return rowpos_fireevent(This, DBREASON_ROWPOSITION_CLEARED, DBEVENTPHASE_FAILEDTODO);
178 rowpos_clearposition(This);
179 This->cleared = TRUE;
180 return S_OK;
183 static HRESULT WINAPI rowpos_GetRowPosition(IRowPosition *iface, HCHAPTER *chapter,
184 HROW *row, DBPOSITIONFLAGS *flags)
186 rowpos *This = impl_from_IRowPosition(iface);
188 TRACE("(%p)->(%p %p %p)\n", This, chapter, row, flags);
190 *chapter = This->chapter;
191 *row = This->row;
192 *flags = This->flags;
194 if (!This->rowset) return E_UNEXPECTED;
196 return S_OK;
199 static HRESULT WINAPI rowpos_GetRowset(IRowPosition *iface, REFIID riid, IUnknown **rowset)
201 rowpos *This = impl_from_IRowPosition(iface);
203 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), rowset);
205 if (!This->rowset) return E_UNEXPECTED;
206 return IRowset_QueryInterface(This->rowset, riid, (void**)rowset);
209 static HRESULT WINAPI rowpos_Initialize(IRowPosition *iface, IUnknown *rowset)
211 rowpos *This = impl_from_IRowPosition(iface);
212 HRESULT hr;
214 TRACE("(%p)->(%p)\n", This, rowset);
216 if (This->rowset) return DB_E_ALREADYINITIALIZED;
218 hr = IUnknown_QueryInterface(rowset, &IID_IRowset, (void**)&This->rowset);
219 if (FAILED(hr)) return hr;
221 /* this one is optional */
222 IUnknown_QueryInterface(rowset, &IID_IChapteredRowset, (void**)&This->chrst);
223 return S_OK;
226 static HRESULT WINAPI rowpos_SetRowPosition(IRowPosition *iface, HCHAPTER chapter,
227 HROW row, DBPOSITIONFLAGS flags)
229 rowpos *This = impl_from_IRowPosition(iface);
230 DBREASON reason;
231 HRESULT hr;
233 TRACE("(%p)->(%lx %lx %d)\n", This, chapter, row, flags);
235 if (!This->cleared) return E_UNEXPECTED;
237 hr = IRowset_AddRefRows(This->rowset, 1, &row, NULL, NULL);
238 if (FAILED(hr)) return hr;
240 if (This->chrst)
242 hr = IChapteredRowset_AddRefChapter(This->chrst, chapter, NULL);
243 if (FAILED(hr))
245 IRowset_ReleaseRows(This->rowset, 1, &row, NULL, NULL, NULL);
246 return hr;
250 reason = This->chrst ? DBREASON_ROWPOSITION_CHAPTERCHANGED : DBREASON_ROWPOSITION_CHANGED;
251 hr = rowpos_fireevent(This, reason, DBEVENTPHASE_SYNCHAFTER);
252 if (hr != S_OK)
254 IRowset_ReleaseRows(This->rowset, 1, &row, NULL, NULL, NULL);
255 if (This->chrst)
256 IChapteredRowset_ReleaseChapter(This->chrst, chapter, NULL);
257 return rowpos_fireevent(This, reason, DBEVENTPHASE_FAILEDTODO);
259 else
260 rowpos_fireevent(This, reason, DBEVENTPHASE_DIDEVENT);
262 /* previously set chapter and row are released with ClearRowPosition() */
263 This->chapter = chapter;
264 This->row = row;
265 This->flags = flags;
266 This->cleared = FALSE;
268 return S_OK;
271 static const struct IRowPositionVtbl rowpos_vtbl =
273 rowpos_QueryInterface,
274 rowpos_AddRef,
275 rowpos_Release,
276 rowpos_ClearRowPosition,
277 rowpos_GetRowPosition,
278 rowpos_GetRowset,
279 rowpos_Initialize,
280 rowpos_SetRowPosition
283 static HRESULT WINAPI cpc_QueryInterface(IConnectionPointContainer *iface, REFIID riid, void **obj)
285 rowpos *This = impl_from_IConnectionPointContainer(iface);
286 return IRowPosition_QueryInterface(&This->IRowPosition_iface, riid, obj);
289 static ULONG WINAPI cpc_AddRef(IConnectionPointContainer *iface)
291 rowpos *This = impl_from_IConnectionPointContainer(iface);
292 return IRowPosition_AddRef(&This->IRowPosition_iface);
295 static ULONG WINAPI cpc_Release(IConnectionPointContainer *iface)
297 rowpos *This = impl_from_IConnectionPointContainer(iface);
298 return IRowPosition_Release(&This->IRowPosition_iface);
301 static HRESULT WINAPI cpc_EnumConnectionPoints(IConnectionPointContainer *iface, IEnumConnectionPoints **enum_points)
303 rowpos *This = impl_from_IConnectionPointContainer(iface);
304 FIXME("(%p)->(%p): stub\n", This, enum_points);
305 return E_NOTIMPL;
308 static HRESULT WINAPI cpc_FindConnectionPoint(IConnectionPointContainer *iface, REFIID riid, IConnectionPoint **point)
310 rowpos *This = impl_from_IConnectionPointContainer(iface);
312 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), point);
314 if (IsEqualIID(riid, &IID_IRowPositionChange))
316 *point = &This->cp.IConnectionPoint_iface;
317 IConnectionPoint_AddRef(*point);
318 return S_OK;
320 else
322 FIXME("unsupported riid %s\n", debugstr_guid(riid));
323 return CONNECT_E_NOCONNECTION;
327 static const struct IConnectionPointContainerVtbl rowpos_cpc_vtbl =
329 cpc_QueryInterface,
330 cpc_AddRef,
331 cpc_Release,
332 cpc_EnumConnectionPoints,
333 cpc_FindConnectionPoint
336 static HRESULT WINAPI rowpos_cp_QueryInterface(IConnectionPoint *iface, REFIID riid, void **obj)
338 rowpos_cp *This = impl_from_IConnectionPoint(iface);
339 return IConnectionPointContainer_QueryInterface(&This->container->IConnectionPointContainer_iface, riid, obj);
342 static ULONG WINAPI rowpos_cp_AddRef(IConnectionPoint *iface)
344 rowpos_cp *This = impl_from_IConnectionPoint(iface);
345 return IConnectionPointContainer_AddRef(&This->container->IConnectionPointContainer_iface);
348 static ULONG WINAPI rowpos_cp_Release(IConnectionPoint *iface)
350 rowpos_cp *This = impl_from_IConnectionPoint(iface);
351 return IConnectionPointContainer_Release(&This->container->IConnectionPointContainer_iface);
354 static HRESULT WINAPI rowpos_cp_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
356 rowpos_cp *This = impl_from_IConnectionPoint(iface);
358 TRACE("(%p)->(%p)\n", This, iid);
360 if (!iid) return E_POINTER;
362 *iid = IID_IRowPositionChange;
363 return S_OK;
366 static HRESULT WINAPI rowpos_cp_GetConnectionPointContainer(IConnectionPoint *iface, IConnectionPointContainer **container)
368 rowpos_cp *This = impl_from_IConnectionPoint(iface);
370 TRACE("(%p)->(%p)\n", This, container);
372 if (!container) return E_POINTER;
374 *container = &This->container->IConnectionPointContainer_iface;
375 IConnectionPointContainer_AddRef(*container);
376 return S_OK;
379 static HRESULT WINAPI rowpos_cp_Advise(IConnectionPoint *iface, IUnknown *unksink, DWORD *cookie)
381 rowpos_cp *This = impl_from_IConnectionPoint(iface);
382 IRowPositionChange *sink;
383 HRESULT hr;
384 DWORD i;
386 TRACE("(%p)->(%p %p)\n", This, unksink, cookie);
388 if (!cookie) return E_POINTER;
390 hr = IUnknown_QueryInterface(unksink, &IID_IRowPositionChange, (void**)&sink);
391 if (FAILED(hr))
393 FIXME("sink doesn't support IRowPositionChange\n");
394 return CONNECT_E_CANNOTCONNECT;
397 if (This->sinks)
399 for (i = 0; i < This->sinks_size; i++)
401 if (!This->sinks[i])
402 break;
405 if (i == This->sinks_size)
407 This->sinks_size *= 2;
408 This->sinks = heap_realloc_zero(This->sinks, This->sinks_size*sizeof(*This->sinks));
411 else
413 This->sinks_size = 10;
414 This->sinks = heap_alloc_zero(This->sinks_size*sizeof(*This->sinks));
415 i = 0;
418 This->sinks[i] = sink;
419 *cookie = i + 1;
421 return S_OK;
424 static HRESULT WINAPI rowpos_cp_Unadvise(IConnectionPoint *iface, DWORD cookie)
426 rowpos_cp *This = impl_from_IConnectionPoint(iface);
428 TRACE("(%p)->(%d)\n", This, cookie);
430 if (!cookie || cookie > This->sinks_size || !This->sinks[cookie-1])
431 return CONNECT_E_NOCONNECTION;
433 IRowPositionChange_Release(This->sinks[cookie-1]);
434 This->sinks[cookie-1] = NULL;
436 return S_OK;
439 static HRESULT WINAPI rowpos_cp_EnumConnections(IConnectionPoint *iface, IEnumConnections **enum_c)
441 rowpos_cp *This = impl_from_IConnectionPoint(iface);
442 FIXME("(%p)->(%p): stub\n", This, enum_c);
443 return E_NOTIMPL;
446 static const struct IConnectionPointVtbl rowpos_cp_vtbl =
448 rowpos_cp_QueryInterface,
449 rowpos_cp_AddRef,
450 rowpos_cp_Release,
451 rowpos_cp_GetConnectionInterface,
452 rowpos_cp_GetConnectionPointContainer,
453 rowpos_cp_Advise,
454 rowpos_cp_Unadvise,
455 rowpos_cp_EnumConnections
458 static void rowposchange_cp_init(rowpos_cp *cp, rowpos *container)
460 cp->IConnectionPoint_iface.lpVtbl = &rowpos_cp_vtbl;
461 cp->container = container;
462 cp->sinks = NULL;
463 cp->sinks_size = 0;
466 void rowposchange_cp_destroy(rowpos_cp *cp)
468 DWORD i;
469 for (i = 0; i < cp->sinks_size; i++)
471 if (cp->sinks[i])
472 IRowPositionChange_Release(cp->sinks[i]);
474 heap_free(cp->sinks);
477 HRESULT create_oledb_rowpos(IUnknown *outer, void **obj)
479 rowpos *This;
481 TRACE("(%p, %p)\n", outer, obj);
483 *obj = NULL;
485 if(outer) return CLASS_E_NOAGGREGATION;
487 This = heap_alloc(sizeof(*This));
488 if(!This) return E_OUTOFMEMORY;
490 This->IRowPosition_iface.lpVtbl = &rowpos_vtbl;
491 This->IConnectionPointContainer_iface.lpVtbl = &rowpos_cpc_vtbl;
492 This->ref = 1;
493 This->rowset = NULL;
494 This->chrst = NULL;
495 This->cleared = FALSE;
496 rowpos_clearposition(This);
497 rowposchange_cp_init(&This->cp, This);
499 *obj = &This->IRowPosition_iface;
501 return S_OK;