From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/Makefile.in | 1 + dlls/msado15/msado15_private.h | 2 + dlls/msado15/recordset.c | 31 +++++-- dlls/msado15/rowset.c | 154 +++++++++++++++++++++++++++++++++ dlls/msado15/tests/msado15.c | 15 ++++ 5 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 dlls/msado15/rowset.c
diff --git a/dlls/msado15/Makefile.in b/dlls/msado15/Makefile.in index 74fee1adea5..1209708e980 100644 --- a/dlls/msado15/Makefile.in +++ b/dlls/msado15/Makefile.in @@ -8,4 +8,5 @@ SOURCES = \ msado15_classes.idl \ msado15_tlb.idl \ recordset.c \ + rowset.c \ stream.c diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h index 2944f9fce4f..f91e83bda38 100644 --- a/dlls/msado15/msado15_private.h +++ b/dlls/msado15/msado15_private.h @@ -26,6 +26,8 @@ HRESULT Connection_create( void ** ); HRESULT Recordset_create( void ** ); HRESULT Stream_create( void ** );
+HRESULT create_mem_rowset( IUnknown ** ); + typedef enum tid_t { ADORecordsetConstruction_tid, Command_tid, diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 837d0e3625f..cf1dff337af 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2178,19 +2178,30 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
if (recordset->state == adStateOpen) return MAKE_ADO_HRESULT( adErrObjectOpen );
- if (get_column_count( recordset )) + if (V_VT(&active_connection) != VT_ERROR || V_ERROR(&active_connection) != DISP_E_PARAMNOTFOUND) { - recordset->state = adStateOpen; - return S_OK; + hr = _Recordset_put_ActiveConnection( iface, active_connection ); + if (FAILED(hr)) + return hr; }
- if (V_VT(&active_connection) != VT_ERROR || V_ERROR(&active_connection) != DISP_E_PARAMNOTFOUND) + if (get_column_count(recordset)) { - hr = _Recordset_put_ActiveConnection( iface, active_connection ); + if (recordset->active_connection) + { + FIXME("adding new table\n"); + return E_NOTIMPL; + } + + hr = create_mem_rowset(&rowset); if (FAILED(hr)) return hr; + hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); + IUnknown_Release(rowset); + return hr; } - else if (!recordset->active_connection) + + if (!recordset->active_connection) return MAKE_ADO_HRESULT( adErrInvalidConnection );
if (V_VT(&source) != VT_BSTR) @@ -2235,7 +2246,6 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); recordset->cursor_type = cursor_type; - recordset->state = adStateOpen;
IUnknown_Release(rowset);
@@ -2799,9 +2809,14 @@ static HRESULT WINAPI rsconstruction_get_Rowset(ADORecordsetConstruction *iface,
TRACE( "%p, %p\n", recordset, row_set );
+ if (!recordset->row_set) + { + *row_set = NULL; + return S_OK; + } + hr = IRowset_QueryInterface(recordset->row_set, &IID_IUnknown, (void**)row_set); if ( FAILED(hr) ) return E_FAIL; - return S_OK; }
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c new file mode 100644 index 00000000000..1193cc88326 --- /dev/null +++ b/dlls/msado15/rowset.c @@ -0,0 +1,154 @@ +/* + * Copyright 2025 Piotr Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include "oledb.h" +#include "unknwn.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msado15); + +struct rowset +{ + IRowset IRowset_iface; + LONG refs; +}; + +static inline struct rowset *impl_from_IRowset(IRowset *iface) +{ + return CONTAINING_RECORD(iface, struct rowset, IRowset_iface); +} + +static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void **ppv) +{ + struct rowset *rowset = impl_from_IRowset(iface); + + TRACE("%p, %s, %p\n", rowset, debugstr_guid(riid), ppv); + + *ppv = NULL; + if(IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IRowset, riid)) + { + *ppv = &rowset->IRowset_iface; + } + + if(*ppv) + { + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; + } + + FIXME("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv); + return E_NOINTERFACE; +} + +static ULONG WINAPI rowset_AddRef(IRowset *iface) +{ + struct rowset *rowset = impl_from_IRowset(iface); + LONG refs = InterlockedIncrement(&rowset->refs); + + TRACE("%p new refcount %ld\n", rowset, refs); + + return refs; +} + +static ULONG WINAPI rowset_Release(IRowset *iface) +{ + struct rowset *rowset = impl_from_IRowset(iface); + LONG refs = InterlockedDecrement(&rowset->refs); + + TRACE("%p new refcount %ld\n", rowset, refs); + + if (!refs) + { + TRACE("destroying %p\n", rowset); + + free(rowset); + } + return refs; +} + +static HRESULT WINAPI rowset_AddRefRows(IRowset *iface, DBCOUNTITEM count, + const HROW rows[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) +{ + struct rowset *rowset = impl_from_IRowset(iface); + + FIXME("%p, %Id, %p, %p, %p\n", rowset, count, rows, ref_counts, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetData(IRowset *iface, HROW row, HACCESSOR accessor, void *data) +{ + struct rowset *rowset = impl_from_IRowset(iface); + + FIXME("%p, %Id, %Id, %p\n", rowset, row, accessor, data); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetNextRows(IRowset *iface, HCHAPTER reserved, + DBROWOFFSET offset, DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) +{ + struct rowset *rowset = impl_from_IRowset( iface ); + + FIXME("%p, %Id, %Id, %Id, %p, %p\n", rowset, reserved, offset, count, obtained, rows); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_ReleaseRows(IRowset *iface, DBCOUNTITEM count, const HROW rows[], + DBROWOPTIONS options[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) +{ + struct rowset *rowset = impl_from_IRowset(iface); + + FIXME("%p, %Id, %p, %p, %p, %p\n", rowset, count, rows, options, ref_counts, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_RestartPosition(IRowset *iface, HCHAPTER reserved) +{ + struct rowset *rowset = impl_from_IRowset(iface); + + FIXME("%p, %Id\n", rowset, reserved); + return E_NOTIMPL; +} + +static const struct IRowsetVtbl rowset_vtbl = +{ + rowset_QueryInterface, + rowset_AddRef, + rowset_Release, + rowset_AddRefRows, + rowset_GetData, + rowset_GetNextRows, + rowset_ReleaseRows, + rowset_RestartPosition +}; + +HRESULT create_mem_rowset(IUnknown **ret) +{ + struct rowset *rowset; + + rowset = malloc(sizeof(*rowset)); + if (!rowset) return E_OUTOFMEMORY; + + rowset->IRowset_iface.lpVtbl = &rowset_vtbl; + rowset->refs = 1; + + *ret = (IUnknown *)&rowset->IRowset_iface; + return S_OK; +} diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index d81ab7da6cf..1ad269afa11 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -93,6 +93,7 @@ static BOOL is_eof( _Recordset *recordset )
static void test_Recordset(void) { + ADORecordsetConstruction *recordset_constr; _Recordset *recordset; IRunnableObject *runtime; ISupportErrorInfo *errorinfo; @@ -109,6 +110,7 @@ static void test_Recordset(void) HRESULT hr; VARIANT bookmark, filter, active; EditModeEnum editmode; + IUnknown *rowset; LONG cache_size;
hr = CoCreateInstance( &CLSID_Recordset, NULL, CLSCTX_INPROC_SERVER, &IID__Recordset, (void **)&recordset ); @@ -303,11 +305,24 @@ static void test_Recordset(void)
Properties_Release(props);
+ hr = _Recordset_QueryInterface(recordset, &IID_ADORecordsetConstruction, (void**)&recordset_constr); + ok(hr == S_OK, "failed %lx\n", hr); + rowset = (IUnknown *)0xdeadbeef; + hr = ADORecordsetConstruction_get_Rowset(recordset_constr, &rowset); + ok(hr == S_OK, "failed %08lx\n", hr); + ok(!rowset, "rowset = %p\n", rowset); + hr = _Recordset_Open( recordset, missing, missing, adOpenStatic, adLockBatchOptimistic, adCmdUnspecified ); ok( hr == S_OK, "got %08lx\n", hr ); ok( is_eof( recordset ), "not eof\n" ); ok( is_bof( recordset ), "not bof\n" );
+ hr = ADORecordsetConstruction_get_Rowset(recordset_constr, &rowset); + ok(hr == S_OK, "failed %08lx\n", hr); + ok(!!rowset, "rowset = NULL\n"); + IUnknown_Release(rowset); + ADORecordsetConstruction_Release(recordset_constr); + V_VT(&active) = VT_UNKNOWN; V_UNKNOWN(&active) = (IUnknown *)0xdeadbeef; hr = _Recordset_get_ActiveConnection( recordset, &active );