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
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
;
38 IConnectionPoint IConnectionPoint_iface
;
40 IRowPositionChange
**sinks
;
46 IRowPosition IRowPosition_iface
;
47 IConnectionPointContainer IConnectionPointContainer_iface
;
51 IChapteredRowset
*chrst
;
54 DBPOSITIONFLAGS flags
;
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
;
82 for (i
= 0; i
< rp
->cp
.sinks_size
; 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
;
93 static void rowpos_clearposition(rowpos
*rp
)
98 IRowset_ReleaseRows(rp
->rowset
, 1, &rp
->row
, NULL
, NULL
, NULL
);
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
);
116 if (IsEqualIID(riid
, &IID_IUnknown
) ||
117 IsEqualIID(riid
, &IID_IRowPosition
))
121 else if (IsEqualIID(riid
, &IID_IConnectionPointContainer
))
123 *obj
= &This
->IConnectionPointContainer_iface
;
127 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
128 return E_NOINTERFACE
;
131 IRowPosition_AddRef(iface
);
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
);
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
);
152 if (This
->rowset
) IRowset_Release(This
->rowset
);
153 if (This
->chrst
) IChapteredRowset_Release(This
->chrst
);
154 rowposchange_cp_destroy(&This
->cp
);
161 static HRESULT WINAPI
rowpos_ClearRowPosition(IRowPosition
* iface
)
163 rowpos
*This
= impl_from_IRowPosition(iface
);
166 TRACE("(%p)\n", This
);
168 if (!This
->rowset
) return E_UNEXPECTED
;
170 hr
= rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_OKTODO
);
172 return rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_FAILEDTODO
);
174 hr
= rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_ABOUTTODO
);
176 return rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_FAILEDTODO
);
178 rowpos_clearposition(This
);
179 This
->cleared
= TRUE
;
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
;
192 *flags
= This
->flags
;
194 if (!This
->rowset
) return E_UNEXPECTED
;
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
);
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
);
226 static HRESULT WINAPI
rowpos_SetRowPosition(IRowPosition
*iface
, HCHAPTER chapter
,
227 HROW row
, DBPOSITIONFLAGS flags
)
229 rowpos
*This
= impl_from_IRowPosition(iface
);
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
;
242 hr
= IChapteredRowset_AddRefChapter(This
->chrst
, chapter
, NULL
);
245 IRowset_ReleaseRows(This
->rowset
, 1, &row
, NULL
, NULL
, NULL
);
250 reason
= This
->chrst
? DBREASON_ROWPOSITION_CHAPTERCHANGED
: DBREASON_ROWPOSITION_CHANGED
;
251 hr
= rowpos_fireevent(This
, reason
, DBEVENTPHASE_SYNCHAFTER
);
254 IRowset_ReleaseRows(This
->rowset
, 1, &row
, NULL
, NULL
, NULL
);
256 IChapteredRowset_ReleaseChapter(This
->chrst
, chapter
, NULL
);
257 return rowpos_fireevent(This
, reason
, DBEVENTPHASE_FAILEDTODO
);
260 rowpos_fireevent(This
, reason
, DBEVENTPHASE_DIDEVENT
);
262 /* previously set chapter and row are released with ClearRowPosition() */
263 This
->chapter
= chapter
;
266 This
->cleared
= FALSE
;
271 static const struct IRowPositionVtbl rowpos_vtbl
=
273 rowpos_QueryInterface
,
276 rowpos_ClearRowPosition
,
277 rowpos_GetRowPosition
,
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
);
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
);
322 FIXME("unsupported riid %s\n", debugstr_guid(riid
));
323 return CONNECT_E_NOCONNECTION
;
327 static const struct IConnectionPointContainerVtbl rowpos_cpc_vtbl
=
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
;
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
);
379 static HRESULT WINAPI
rowpos_cp_Advise(IConnectionPoint
*iface
, IUnknown
*unksink
, DWORD
*cookie
)
381 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
382 IRowPositionChange
*sink
;
386 TRACE("(%p)->(%p %p)\n", This
, unksink
, cookie
);
388 if (!cookie
) return E_POINTER
;
390 hr
= IUnknown_QueryInterface(unksink
, &IID_IRowPositionChange
, (void**)&sink
);
393 FIXME("sink doesn't support IRowPositionChange\n");
394 return CONNECT_E_CANNOTCONNECT
;
399 for (i
= 0; i
< This
->sinks_size
; i
++)
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
));
413 This
->sinks_size
= 10;
414 This
->sinks
= heap_alloc_zero(This
->sinks_size
*sizeof(*This
->sinks
));
418 This
->sinks
[i
] = sink
;
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
;
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
);
446 static const struct IConnectionPointVtbl rowpos_cp_vtbl
=
448 rowpos_cp_QueryInterface
,
451 rowpos_cp_GetConnectionInterface
,
452 rowpos_cp_GetConnectionPointContainer
,
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
;
466 void rowposchange_cp_destroy(rowpos_cp
*cp
)
469 for (i
= 0; i
< cp
->sinks_size
; i
++)
472 IRowPositionChange_Release(cp
->sinks
[i
]);
474 heap_free(cp
->sinks
);
477 HRESULT
create_oledb_rowpos(IUnknown
*outer
, void **obj
)
481 TRACE("(%p, %p)\n", outer
, obj
);
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
;
495 This
->cleared
= FALSE
;
496 rowpos_clearposition(This
);
497 rowposchange_cp_init(&This
->cp
, This
);
499 *obj
= &This
->IRowPosition_iface
;