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"
32 WINE_DEFAULT_DEBUG_CHANNEL(oledb
);
34 typedef struct rowpos rowpos
;
37 IConnectionPoint IConnectionPoint_iface
;
39 IRowPositionChange
**sinks
;
45 IRowPosition IRowPosition_iface
;
46 IConnectionPointContainer IConnectionPointContainer_iface
;
50 IChapteredRowset
*chrst
;
53 DBPOSITIONFLAGS flags
;
58 static void rowposchange_cp_destroy(rowpos_cp
*);
60 static inline rowpos
*impl_from_IRowPosition(IRowPosition
*iface
)
62 return CONTAINING_RECORD(iface
, rowpos
, IRowPosition_iface
);
65 static inline rowpos
*impl_from_IConnectionPointContainer(IConnectionPointContainer
*iface
)
67 return CONTAINING_RECORD(iface
, rowpos
, IConnectionPointContainer_iface
);
70 static inline rowpos_cp
*impl_from_IConnectionPoint(IConnectionPoint
*iface
)
72 return CONTAINING_RECORD(iface
, rowpos_cp
, IConnectionPoint_iface
);
75 static HRESULT
rowpos_fireevent(rowpos
*rp
, DBREASON reason
, DBEVENTPHASE phase
)
77 BOOL cant_deny
= phase
== DBEVENTPHASE_FAILEDTODO
|| phase
== DBEVENTPHASE_SYNCHAFTER
;
81 for (i
= 0; i
< rp
->cp
.sinks_size
; i
++)
84 hr
= IRowPositionChange_OnRowPositionChange(rp
->cp
.sinks
[i
], reason
, phase
, cant_deny
);
85 if (phase
== DBEVENTPHASE_FAILEDTODO
) return DB_E_CANCELED
;
86 if (hr
!= S_OK
) return hr
;
92 static void rowpos_clearposition(rowpos
*rp
)
97 IRowset_ReleaseRows(rp
->rowset
, 1, &rp
->row
, NULL
, NULL
, NULL
);
99 IChapteredRowset_ReleaseChapter(rp
->chrst
, rp
->chapter
, NULL
);
102 rp
->row
= DB_NULL_HROW
;
103 rp
->chapter
= DB_NULL_HCHAPTER
;
104 rp
->flags
= DBPOSITION_NOROW
;
107 static HRESULT WINAPI
rowpos_QueryInterface(IRowPosition
* iface
, REFIID riid
, void **obj
)
109 rowpos
*This
= impl_from_IRowPosition(iface
);
111 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
115 if (IsEqualIID(riid
, &IID_IUnknown
) ||
116 IsEqualIID(riid
, &IID_IRowPosition
))
120 else if (IsEqualIID(riid
, &IID_IConnectionPointContainer
))
122 *obj
= &This
->IConnectionPointContainer_iface
;
126 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
127 return E_NOINTERFACE
;
130 IRowPosition_AddRef(iface
);
134 static ULONG WINAPI
rowpos_AddRef(IRowPosition
* iface
)
136 rowpos
*This
= impl_from_IRowPosition(iface
);
137 ULONG ref
= InterlockedIncrement(&This
->ref
);
138 TRACE("(%p)->(%d)\n", This
, ref
);
142 static ULONG WINAPI
rowpos_Release(IRowPosition
* iface
)
144 rowpos
*This
= impl_from_IRowPosition(iface
);
145 LONG ref
= InterlockedDecrement(&This
->ref
);
147 TRACE("(%p)->(%d)\n", This
, ref
);
151 if (This
->rowset
) IRowset_Release(This
->rowset
);
152 if (This
->chrst
) IChapteredRowset_Release(This
->chrst
);
153 rowposchange_cp_destroy(&This
->cp
);
160 static HRESULT WINAPI
rowpos_ClearRowPosition(IRowPosition
* iface
)
162 rowpos
*This
= impl_from_IRowPosition(iface
);
165 TRACE("(%p)\n", This
);
167 if (!This
->rowset
) return E_UNEXPECTED
;
169 hr
= rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_OKTODO
);
171 return rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_FAILEDTODO
);
173 hr
= rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_ABOUTTODO
);
175 return rowpos_fireevent(This
, DBREASON_ROWPOSITION_CLEARED
, DBEVENTPHASE_FAILEDTODO
);
177 rowpos_clearposition(This
);
178 This
->cleared
= TRUE
;
182 static HRESULT WINAPI
rowpos_GetRowPosition(IRowPosition
*iface
, HCHAPTER
*chapter
,
183 HROW
*row
, DBPOSITIONFLAGS
*flags
)
185 rowpos
*This
= impl_from_IRowPosition(iface
);
187 TRACE("(%p)->(%p %p %p)\n", This
, chapter
, row
, flags
);
189 *chapter
= This
->chapter
;
191 *flags
= This
->flags
;
193 if (!This
->rowset
) return E_UNEXPECTED
;
198 static HRESULT WINAPI
rowpos_GetRowset(IRowPosition
*iface
, REFIID riid
, IUnknown
**rowset
)
200 rowpos
*This
= impl_from_IRowPosition(iface
);
202 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), rowset
);
204 if (!This
->rowset
) return E_UNEXPECTED
;
205 return IRowset_QueryInterface(This
->rowset
, riid
, (void**)rowset
);
208 static HRESULT WINAPI
rowpos_Initialize(IRowPosition
*iface
, IUnknown
*rowset
)
210 rowpos
*This
= impl_from_IRowPosition(iface
);
213 TRACE("(%p)->(%p)\n", This
, rowset
);
215 if (This
->rowset
) return DB_E_ALREADYINITIALIZED
;
217 hr
= IUnknown_QueryInterface(rowset
, &IID_IRowset
, (void**)&This
->rowset
);
218 if (FAILED(hr
)) return hr
;
220 /* this one is optional */
221 IUnknown_QueryInterface(rowset
, &IID_IChapteredRowset
, (void**)&This
->chrst
);
225 static HRESULT WINAPI
rowpos_SetRowPosition(IRowPosition
*iface
, HCHAPTER chapter
,
226 HROW row
, DBPOSITIONFLAGS flags
)
228 rowpos
*This
= impl_from_IRowPosition(iface
);
232 TRACE("(%p)->(%lx %lx %d)\n", This
, chapter
, row
, flags
);
234 if (!This
->cleared
) return E_UNEXPECTED
;
236 hr
= IRowset_AddRefRows(This
->rowset
, 1, &row
, NULL
, NULL
);
237 if (FAILED(hr
)) return hr
;
241 hr
= IChapteredRowset_AddRefChapter(This
->chrst
, chapter
, NULL
);
244 IRowset_ReleaseRows(This
->rowset
, 1, &row
, NULL
, NULL
, NULL
);
249 reason
= This
->chrst
? DBREASON_ROWPOSITION_CHAPTERCHANGED
: DBREASON_ROWPOSITION_CHANGED
;
250 hr
= rowpos_fireevent(This
, reason
, DBEVENTPHASE_SYNCHAFTER
);
253 IRowset_ReleaseRows(This
->rowset
, 1, &row
, NULL
, NULL
, NULL
);
255 IChapteredRowset_ReleaseChapter(This
->chrst
, chapter
, NULL
);
256 return rowpos_fireevent(This
, reason
, DBEVENTPHASE_FAILEDTODO
);
259 rowpos_fireevent(This
, reason
, DBEVENTPHASE_DIDEVENT
);
261 /* previously set chapter and row are released with ClearRowPosition() */
262 This
->chapter
= chapter
;
265 This
->cleared
= FALSE
;
270 static const struct IRowPositionVtbl rowpos_vtbl
=
272 rowpos_QueryInterface
,
275 rowpos_ClearRowPosition
,
276 rowpos_GetRowPosition
,
279 rowpos_SetRowPosition
282 static HRESULT WINAPI
cpc_QueryInterface(IConnectionPointContainer
*iface
, REFIID riid
, void **obj
)
284 rowpos
*This
= impl_from_IConnectionPointContainer(iface
);
285 return IRowPosition_QueryInterface(&This
->IRowPosition_iface
, riid
, obj
);
288 static ULONG WINAPI
cpc_AddRef(IConnectionPointContainer
*iface
)
290 rowpos
*This
= impl_from_IConnectionPointContainer(iface
);
291 return IRowPosition_AddRef(&This
->IRowPosition_iface
);
294 static ULONG WINAPI
cpc_Release(IConnectionPointContainer
*iface
)
296 rowpos
*This
= impl_from_IConnectionPointContainer(iface
);
297 return IRowPosition_Release(&This
->IRowPosition_iface
);
300 static HRESULT WINAPI
cpc_EnumConnectionPoints(IConnectionPointContainer
*iface
, IEnumConnectionPoints
**enum_points
)
302 rowpos
*This
= impl_from_IConnectionPointContainer(iface
);
303 FIXME("(%p)->(%p): stub\n", This
, enum_points
);
307 static HRESULT WINAPI
cpc_FindConnectionPoint(IConnectionPointContainer
*iface
, REFIID riid
, IConnectionPoint
**point
)
309 rowpos
*This
= impl_from_IConnectionPointContainer(iface
);
311 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), point
);
313 if (IsEqualIID(riid
, &IID_IRowPositionChange
))
315 *point
= &This
->cp
.IConnectionPoint_iface
;
316 IConnectionPoint_AddRef(*point
);
321 FIXME("unsupported riid %s\n", debugstr_guid(riid
));
322 return CONNECT_E_NOCONNECTION
;
326 static const struct IConnectionPointContainerVtbl rowpos_cpc_vtbl
=
331 cpc_EnumConnectionPoints
,
332 cpc_FindConnectionPoint
335 static HRESULT WINAPI
rowpos_cp_QueryInterface(IConnectionPoint
*iface
, REFIID riid
, void **obj
)
337 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
338 return IConnectionPointContainer_QueryInterface(&This
->container
->IConnectionPointContainer_iface
, riid
, obj
);
341 static ULONG WINAPI
rowpos_cp_AddRef(IConnectionPoint
*iface
)
343 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
344 return IConnectionPointContainer_AddRef(&This
->container
->IConnectionPointContainer_iface
);
347 static ULONG WINAPI
rowpos_cp_Release(IConnectionPoint
*iface
)
349 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
350 return IConnectionPointContainer_Release(&This
->container
->IConnectionPointContainer_iface
);
353 static HRESULT WINAPI
rowpos_cp_GetConnectionInterface(IConnectionPoint
*iface
, IID
*iid
)
355 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
357 TRACE("(%p)->(%p)\n", This
, iid
);
359 if (!iid
) return E_POINTER
;
361 *iid
= IID_IRowPositionChange
;
365 static HRESULT WINAPI
rowpos_cp_GetConnectionPointContainer(IConnectionPoint
*iface
, IConnectionPointContainer
**container
)
367 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
369 TRACE("(%p)->(%p)\n", This
, container
);
371 if (!container
) return E_POINTER
;
373 *container
= &This
->container
->IConnectionPointContainer_iface
;
374 IConnectionPointContainer_AddRef(*container
);
378 static HRESULT WINAPI
rowpos_cp_Advise(IConnectionPoint
*iface
, IUnknown
*unksink
, DWORD
*cookie
)
380 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
381 IRowPositionChange
*sink
;
385 TRACE("(%p)->(%p %p)\n", This
, unksink
, cookie
);
387 if (!cookie
) return E_POINTER
;
389 hr
= IUnknown_QueryInterface(unksink
, &IID_IRowPositionChange
, (void**)&sink
);
392 FIXME("sink doesn't support IRowPositionChange\n");
393 return CONNECT_E_CANNOTCONNECT
;
398 for (i
= 0; i
< This
->sinks_size
; i
++)
404 if (i
== This
->sinks_size
)
406 This
->sinks_size
*= 2;
407 This
->sinks
= heap_realloc_zero(This
->sinks
, This
->sinks_size
*sizeof(*This
->sinks
));
412 This
->sinks_size
= 10;
413 This
->sinks
= heap_alloc_zero(This
->sinks_size
*sizeof(*This
->sinks
));
417 This
->sinks
[i
] = sink
;
418 if (cookie
) *cookie
= i
+ 1;
423 static HRESULT WINAPI
rowpos_cp_Unadvise(IConnectionPoint
*iface
, DWORD cookie
)
425 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
427 TRACE("(%p)->(%d)\n", This
, cookie
);
429 if (!cookie
|| cookie
> This
->sinks_size
|| !This
->sinks
[cookie
-1])
430 return CONNECT_E_NOCONNECTION
;
432 IRowPositionChange_Release(This
->sinks
[cookie
-1]);
433 This
->sinks
[cookie
-1] = NULL
;
438 static HRESULT WINAPI
rowpos_cp_EnumConnections(IConnectionPoint
*iface
, IEnumConnections
**enum_c
)
440 rowpos_cp
*This
= impl_from_IConnectionPoint(iface
);
441 FIXME("(%p)->(%p): stub\n", This
, enum_c
);
445 static const struct IConnectionPointVtbl rowpos_cp_vtbl
=
447 rowpos_cp_QueryInterface
,
450 rowpos_cp_GetConnectionInterface
,
451 rowpos_cp_GetConnectionPointContainer
,
454 rowpos_cp_EnumConnections
457 static void rowposchange_cp_init(rowpos_cp
*cp
, rowpos
*container
)
459 cp
->IConnectionPoint_iface
.lpVtbl
= &rowpos_cp_vtbl
;
460 cp
->container
= container
;
465 void rowposchange_cp_destroy(rowpos_cp
*cp
)
468 for (i
= 0; i
< cp
->sinks_size
; i
++)
471 IRowPositionChange_Release(cp
->sinks
[i
]);
473 heap_free(cp
->sinks
);
476 HRESULT
create_oledb_rowpos(IUnknown
*outer
, void **obj
)
480 TRACE("(%p, %p)\n", outer
, obj
);
484 if(outer
) return CLASS_E_NOAGGREGATION
;
486 This
= heap_alloc(sizeof(*This
));
487 if(!This
) return E_OUTOFMEMORY
;
489 This
->IRowPosition_iface
.lpVtbl
= &rowpos_vtbl
;
490 This
->IConnectionPointContainer_iface
.lpVtbl
= &rowpos_cpc_vtbl
;
494 This
->cleared
= FALSE
;
495 rowpos_clearposition(This
);
496 rowposchange_cp_init(&This
->cp
, This
);
498 *obj
= &This
->IRowPosition_iface
;