[PATCH 0/8] MR9667: msado15: Add _Recordset Supports and Index implementation.
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 216 +++++++++++++++++++++++++++++++-------- 1 file changed, 173 insertions(+), 43 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index ffe3b2168b3..7857ebe150c 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2651,9 +2651,162 @@ static HRESULT WINAPI recordset_NextRecordset( _Recordset *iface, VARIANT *recor return E_NOTIMPL; } +static BOOL recordset_get_prop( struct recordset *recordset, + const GUID *prop_set, DWORD propid, VARIANT *v ) +{ + HRESULT hr = E_FAIL; + int i, j; + + for (i = 0; i < recordset->prop_count; i++) + { + if (!IsEqualGUID( &recordset->prop[i].guidPropertySet, prop_set )) continue; + + for (j=0; j < recordset->prop[i].cProperties; j++) + { + if (recordset->prop[i].rgProperties[j].dwStatus == DBPROPSTATUS_OK && + recordset->prop[i].rgProperties[j].dwPropertyID == propid) + { + *v = recordset->prop[i].rgProperties[j].vValue; + break; + } + } + if (j != recordset->prop[i].cProperties) break; + } + if (i == recordset->prop_count) return FALSE; + + if (IsEqualGUID( prop_set, &DBPROPSET_ROWSET )) + { + switch (propid) + { + case DBPROP_UPDATABILITY: + hr = VariantChangeType( v, v, 0, VT_I4 ); + break; + case DBPROP_CANHOLDROWS: + case DBPROP_CANSCROLLBACKWARDS: + case DBPROP_IRowsetLocate: + case DBPROP_IRowsetScroll: + case DBPROP_IRowsetUpdate: + case DBPROP_IRowsetResynch: + case DBPROP_IConnectionPointContainer: + case DBPROP_IRowsetFind: + case DBPROP_IRowsetIndex: + case DBPROP_IRowsetCurrentIndex: + hr = VariantChangeType( v, v, 0, VT_BOOL ); + break; + } + } + return SUCCEEDED( hr ); +} + static HRESULT WINAPI recordset_Supports( _Recordset *iface, CursorOptionEnum cursor_options, VARIANT_BOOL *ret ) { - FIXME( "%p, %08x, %p\n", iface, cursor_options, ret ); + struct recordset *recordset = impl_from_Recordset( iface ); + VARIANT v; + + TRACE( "%p, %08x, %p\n", iface, cursor_options, ret ); + + if (!ret) return MAKE_ADO_HRESULT( adErrInvalidArgument ); + if (cursor_options & ~(adHoldRecords | adMovePrevious | adAddNew | adDelete | + adUpdate | adBookmark | adApproxPosition | adUpdateBatch | + adResync | adNotify | adFind | adSeek | adIndex)) + { + FIXME( "unsupported cursor_options: %x\n", cursor_options ); + *ret = VARIANT_FALSE; + return S_OK; + } + + if ((cursor_options & adHoldRecords) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_CANHOLDROWS, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adMovePrevious) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adBookmark) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetLocate, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adApproxPosition) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetScroll, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adUpdateBatch) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetUpdate, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adResync) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetResynch, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adNotify) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IConnectionPointContainer, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adFind) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetFind, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adSeek) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetIndex, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adIndex) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_IRowsetCurrentIndex, &v ) || + !V_BOOL(&v))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adAddNew) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_UPDATABILITY, &v ) || + !(V_I4(&v) & DBPROPVAL_UP_INSERT))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adDelete) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_UPDATABILITY, &v ) || + !(V_I4(&v) & DBPROPVAL_UP_DELETE))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + if ((cursor_options & adUpdate) && + (!recordset_get_prop( recordset, &DBPROPSET_ROWSET, DBPROP_UPDATABILITY, &v ) || + !(V_I4(&v) & DBPROPVAL_UP_CHANGE))) + { + *ret = VARIANT_FALSE; + return S_OK; + } + *ret = VARIANT_TRUE; return S_OK; } @@ -3087,44 +3240,6 @@ static void init_bookmark( struct recordset *recordset ) CoTaskMemFree( colinfo ); } -static BOOL recordset_get_prop( struct recordset *recordset, - const GUID *prop_set, DWORD propid, VARIANT *v ) -{ - HRESULT hr = E_FAIL; - int i, j; - - for (i = 0; i < recordset->prop_count; i++) - { - if (!IsEqualGUID( &recordset->prop[i].guidPropertySet, prop_set )) continue; - - for (j=0; j < recordset->prop[i].cProperties; j++) - { - if (recordset->prop[i].rgProperties[j].dwStatus == DBPROPSTATUS_OK && - recordset->prop[i].rgProperties[j].dwPropertyID == propid) - { - *v = recordset->prop[i].rgProperties[j].vValue; - break; - } - } - if (j != recordset->prop[i].cProperties) break; - } - if (i == recordset->prop_count) return FALSE; - - if (IsEqualGUID( prop_set, &DBPROPSET_ROWSET )) - { - switch (propid) - { - case DBPROP_UPDATABILITY: - hr = VariantChangeType( v, v, 0, VT_I4 ); - break; - case DBPROP_IRowsetUpdate: - hr = VariantChangeType( v, v, 0, VT_BOOL ); - break; - } - } - return SUCCEEDED( hr ); -} - static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, IUnknown *unk) { struct recordset *recordset = impl_from_ADORecordsetConstruction( iface ); @@ -3146,13 +3261,28 @@ static HRESULT WINAPI rsconstruction_put_Rowset(ADORecordsetConstruction *iface, if (SUCCEEDED(hr)) { DBPROPIDSET propidset; - DBPROPID propid[2]; + DBPROPID propid[17]; propidset.guidPropertySet = DBPROPSET_ROWSET; - propidset.cPropertyIDs = 2; + propidset.cPropertyIDs = ARRAY_SIZE( propid ); propidset.rgPropertyIDs = propid; - propid[0] = DBPROP_UPDATABILITY; - propid[1] = DBPROP_IRowsetUpdate; + propid[0] = DBPROP_OTHERUPDATEDELETE; + propid[1] = DBPROP_OTHERINSERT; + propid[2] = DBPROP_CANHOLDROWS; + propid[3] = DBPROP_CANSCROLLBACKWARDS; + propid[4] = DBPROP_UPDATABILITY; + propid[5] = DBPROP_IRowsetLocate; + propid[6] = DBPROP_IRowsetScroll; + propid[7] = DBPROP_IRowsetUpdate; + propid[8] = DBPROP_IRowsetResynch; + propid[9] = DBPROP_IConnectionPointContainer; + propid[10] = DBPROP_BOOKMARKSKIPPED; + propid[11] = DBPROP_IRowsetFind; + propid[12] = DBPROP_IRowsetRefresh; + propid[13] = DBPROP_LOCKMODE; + propid[14] = DBPROP_IRowsetIndex; + propid[15] = DBPROP_IRowsetCurrentIndex; + propid[16] = DBPROP_REMOVEDELETED; hr = IRowsetInfo_GetProperties( rowset_info, 1, &propidset, &recordset->prop_count, &recordset->prop); IRowsetInfo_Release( rowset_info ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/tests/msado15.c | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 3754e32b823..e3815ada6fc 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1610,6 +1610,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) LockTypeEnum lock_type; ADO_LONGPTR size; DataTypeEnum type; + VARIANT_BOOL b; hr = CoCreateInstance( &CLSID_Recordset, NULL, CLSCTX_INPROC_SERVER, &IID__Recordset, (void **)&recordset ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -1625,6 +1626,11 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); ok( state == adStateClosed, "state = %ld\n", state ); + b = VARIANT_TRUE; + hr = _Recordset_Supports( recordset, adHoldRecords, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + testrowset.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; testrowset.IRowsetInfo_iface.lpVtbl = &rowset_info; testrowset.IColumnsInfo_iface.lpVtbl = &column_info; @@ -1672,6 +1678,62 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ok( hr == S_OK, "got %08lx\n", hr ); ok( lock_type == adLockBatchOptimistic, "lock_type = %d\n", lock_type ); + hr = _Recordset_Supports( recordset, adHoldRecords, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adMovePrevious, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adAddNew, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adDelete, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adUpdate, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adBookmark, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adApproxPosition, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adUpdateBatch, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adResync, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adNotify, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adFind, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adSeek, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adIndex, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_FALSE, "b = %x\n", b); + + hr = _Recordset_Supports( recordset, adHoldRecords | adMovePrevious, &b ); + ok( hr == S_OK, "got %08lx\n", hr); + ok( b == VARIANT_TRUE, "b = %x\n", b); + count = -1; SET_EXPECT( column_info_GetColumnInfo ); hr = Fields_get_Count( fields, &count ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- include/msado15_backcompat.idl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/msado15_backcompat.idl b/include/msado15_backcompat.idl index 0171ce492bf..0e21e4028e7 100644 --- a/include/msado15_backcompat.idl +++ b/include/msado15_backcompat.idl @@ -260,19 +260,19 @@ typedef [uuid(0000052f-0000-0010-8000-00aa006d2ea4)] enum CursorLocationEnum typedef [uuid(0000051c-0000-0010-8000-00aa006d2ea4)] enum CursorOptionEnum { - adHoldRecords = 256, - adMovePrevious = 512, - adBookmark = 8192, - adApproxPosition = 16384, - adUpdateBatch = 65536, - adResync = 131072, - adNotify = 262144, - adFind = 524288, - adSeek = 4194304, - adIndex = 8388608, - adAddNew = 16778240, - adDelete = 16779264, - adUpdate = 16809984 + adHoldRecords = 0x100, + adMovePrevious = 0x200, + adBookmark = 0x2000, + adApproxPosition = 0x4000, + adUpdateBatch = 0x10000, + adResync = 0x20000, + adNotify = 0x40000, + adFind = 0x80000, + adSeek = 0x400000, + adIndex = 0x800000, + adAddNew = 0x1000400, + adDelete = 0x1000800, + adUpdate = 0x1008000 } CursorOptionEnum; typedef [uuid(00000540-0000-0010-8000-00aa006d2ea4)] enum MarshalOptionsEnum -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- include/dbs.idl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/dbs.idl b/include/dbs.idl index 0f132fbc629..2d266b98b7a 100644 --- a/include/dbs.idl +++ b/include/dbs.idl @@ -999,6 +999,18 @@ typedef enum tagDBBOOKMARK { cpp_quote("#define STD_BOOKMARKLENGTH 1") +typedef DWORD DBINDEX_COL_ORDER; + +enum DBINDEX_COL_ORDERENUM { + DBINDEX_COL_ORDER_ASC, + DBINDEX_COL_ORDER_DESC +}; + +typedef struct tagDBINDEXCOLUMNDESC { + DBID *pColumnID; + DBINDEX_COL_ORDER eIndexColOrder; +} DBINDEXCOLUMNDESC; + typedef struct tagDBCOLUMNDESC { LPOLESTR pwszTypeName; ITypeInfo *pTypeInfo; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- include/Makefile.in | 1 + include/oledb.idl | 1 + include/rstind.idl | 82 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/rstind.idl diff --git a/include/Makefile.in b/include/Makefile.in index b2807b5e3b4..51212b26793 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -709,6 +709,7 @@ SOURCES = \ rstchg.idl \ rstfnd.idl \ rstidn.idl \ + rstind.idl \ rstinf.idl \ rstloc.idl \ rstnot.idl \ diff --git a/include/oledb.idl b/include/oledb.idl index c2e0f91f8f7..360935e2528 100644 --- a/include/oledb.idl +++ b/include/oledb.idl @@ -87,6 +87,7 @@ typedef LONG_PTR DB_LRESERVE; #include "rstchg.idl" #include "rstupd.idl" #include "rstidn.idl" +#include "rstind.idl" #include "mulres.idl" #include "transact.idl" #include "trnjoi.idl" diff --git a/include/rstind.idl b/include/rstind.idl new file mode 100644 index 00000000000..a8939d6dbba --- /dev/null +++ b/include/rstind.idl @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2025 Piotr Caban + * + * 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 + */ + +#if 0 +#pragma makedep install +#endif + +[ + local, + object, + uuid(0c733a82-2a1c-11ce-ade5-00aa0044773d), + pointer_default(unique) +] +interface IRowsetIndex : IUnknown +{ + typedef DWORD DBSEEK; + + enum DBSEEKENUM + { + DBSEEK_INVALID = 0x0, + DBSEEK_FIRSTEQ = 0x1, + DBSEEK_LASTEQ = 0x2, + DBSEEK_AFTEREQ = 0x4, + DBSEEK_AFTER = 0x8, + DBSEEK_BEFOREEQ = 0x10, + DBSEEK_BEFORE = 0x20 + }; + + cpp_quote("#define DBSEEK_GE DBSEEK_AFTEREQ") + cpp_quote("#define DBSEEK_GT DBSEEK_AFTER") + cpp_quote("#define DBSEEK_LE DBSEEK_BEFOREEQ") + cpp_quote("#define DBSEEK_LT DBSEEK_BEFORE") + + typedef DWORD DBRANGE; + + enum DBRANGEENUM { + DBRANGE_INCLUSIVESTART = 0x0, + DBRANGE_INCLUSIVEEND = 0x0, + DBRANGE_EXCLUSIVESTART = 0x1, + DBRANGE_EXCLUSIVEEND = 0x2, + DBRANGE_EXCLUDENULLS = 0x4, + DBRANGE_PREFIX = 0x8, + DBRANGE_MATCH = 0x10 + }; + + enum DBRANGEENUM20 { + DBRANGE_MATCH_N_SHIFT = 0x18, + DBRANGE_MATCH_N_MASK = 0xff, + }; + + HRESULT GetIndexInfo([in, out] DBORDINAL *pcKeyColumns, + [out, size_is(,*pcKeyColumns)] DBINDEXCOLUMNDESC **prgIndexColumnDesc, + [in, out] ULONG *pcIndexPropertySets, + [out, size_is(,*pcIndexPropertySets)] DBPROPSET **prgIndexPropertySets); + + HRESULT Seek([in] HACCESSOR hAccessor, + [in] DBORDINAL cKeyValues, + [in] void *pData, + [in] DBSEEK dwSeekOptions); + + HRESULT SetRange([in] HACCESSOR hAccessor, + [in] DBORDINAL cStartKeyColumns, + [in] void *pStartData, + [in] DBORDINAL cEndKeyColumns, + [in] void *pEndData, + [in] DBRANGE dwRangeOptions); +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- include/Makefile.in | 1 + include/oledb.idl | 1 + include/rstcridx.idl | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 include/rstcridx.idl diff --git a/include/Makefile.in b/include/Makefile.in index 51212b26793..e0987cead85 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -707,6 +707,7 @@ SOURCES = \ rpcsal.h \ rstbas.idl \ rstchg.idl \ + rstcridx.idl \ rstfnd.idl \ rstidn.idl \ rstind.idl \ diff --git a/include/oledb.idl b/include/oledb.idl index 360935e2528..ff3512f3b26 100644 --- a/include/oledb.idl +++ b/include/oledb.idl @@ -88,6 +88,7 @@ typedef LONG_PTR DB_LRESERVE; #include "rstupd.idl" #include "rstidn.idl" #include "rstind.idl" +#include "rstcridx.idl" #include "mulres.idl" #include "transact.idl" #include "trnjoi.idl" diff --git a/include/rstcridx.idl b/include/rstcridx.idl new file mode 100644 index 00000000000..aa7d3c30b4b --- /dev/null +++ b/include/rstcridx.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 Piotr Caban + * + * 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 + */ + +#if 0 +#pragma makedep install +#endif + +[ + local, + object, + uuid(0c733abd-2a1c-11ce-ade5-00aa0044773d), + pointer_default(unique) +] +interface IRowsetCurrentIndex : IRowsetIndex +{ + HRESULT GetIndex([out] DBID **ppIndexID); + + HRESULT SetIndex([in] DBID *pIndexID); +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 30 ++++++++- dlls/msado15/tests/msado15.c | 114 +++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 7857ebe150c..78015b9a3ba 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -99,6 +99,7 @@ struct recordset IRowsetExactScroll *rowset_es; IRowsetChange *rowset_change; IAccessor *accessor; + IRowsetCurrentIndex *rowset_cur_idx; EditModeEnum editmode; HROW current_row; struct @@ -1640,6 +1641,9 @@ static void close_recordset( struct recordset *recordset ) if ( recordset->rowset_change && recordset->rowset_change != NO_INTERFACE ) IRowsetChange_Release( recordset->rowset_change ); recordset->rowset_change = NULL; + if ( recordset->rowset_cur_idx && recordset->rowset_cur_idx != NO_INTERFACE ) + IRowsetCurrentIndex_Release( recordset->rowset_cur_idx ); + recordset->rowset_cur_idx = NULL; for (i = 0; i < recordset->fields.count; i++) { @@ -2943,8 +2947,30 @@ static HRESULT WINAPI recordset_Seek( _Recordset *iface, VARIANT key_values, See static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index ) { - FIXME( "%p, %s\n", iface, debugstr_w(index) ); - return E_NOTIMPL; + struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr; + DBID dbid; + + TRACE( "%p, %s\n", iface, debugstr_w(index) ); + + if (!recordset->rowset_cur_idx) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetCurrentIndex, (void **)&recordset->rowset_cur_idx ); + if (FAILED(hr) || !recordset->rowset_cur_idx) + recordset->rowset_cur_idx = NO_INTERFACE; + } + if (recordset->rowset_cur_idx == NO_INTERFACE) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + cache_release( recordset ); + + memset( &dbid, 0, sizeof(dbid) ); + dbid.eKind = DBKIND_NAME; + dbid.uName.pwszName = index; + hr = IRowsetCurrentIndex_SetIndex( recordset->rowset_cur_idx, &dbid ); + if (FAILED(hr)) return hr; + + return _Recordset_MoveFirst( iface ); } static HRESULT WINAPI recordset_get_Index( _Recordset *iface, BSTR *index ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index e3815ada6fc..910a1f13899 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -87,6 +87,7 @@ DEFINE_EXPECT(rowset_view_CreateView); DEFINE_EXPECT(view_chapter_OpenViewChapter); DEFINE_EXPECT(view_filter_SetFilter); DEFINE_EXPECT(chaptered_rowset_ReleaseChapter); +DEFINE_EXPECT(rowset_current_index_SetIndex); static BOOL is_bof( _Recordset *recordset ) { @@ -563,6 +564,7 @@ struct test_rowset IAccessor IAccessor_iface; IRowsetView IRowsetView_iface; IChapteredRowset IChapteredRowset_iface; + IRowsetCurrentIndex IRowsetCurrentIndex_iface; LONG refs; IViewChapter IViewChapter_iface; @@ -614,6 +616,11 @@ static inline struct test_rowset *impl_from_IChapteredRowset( IChapteredRowset * return CONTAINING_RECORD( iface, struct test_rowset, IChapteredRowset_iface ); } +static inline struct test_rowset *impl_from_IRowsetCurrentIndex( IRowsetCurrentIndex *iface ) +{ + return CONTAINING_RECORD( iface, struct test_rowset, IRowsetCurrentIndex_iface ); +} + static inline struct test_rowset *impl_from_IViewChapter( IViewChapter *iface ) { return CONTAINING_RECORD( iface, struct test_rowset, IViewChapter_iface ); @@ -1173,6 +1180,75 @@ static const struct IChapteredRowsetVtbl chaptered_rowset = chaptered_rowset_ReleaseChapter }; +static HRESULT WINAPI rowset_current_index_QueryInterface(IRowsetCurrentIndex *iface, REFIID riid, void **obj) +{ + struct test_rowset *rowset = impl_from_IRowsetCurrentIndex( iface ); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, obj); +} + +static ULONG WINAPI rowset_current_index_AddRef(IRowsetCurrentIndex *iface) +{ + struct test_rowset *rowset = impl_from_IRowsetCurrentIndex( iface ); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); +} + +static ULONG WINAPI rowset_current_index_Release(IRowsetCurrentIndex *iface) +{ + struct test_rowset *rowset = impl_from_IRowsetCurrentIndex( iface ); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); +} + +static HRESULT WINAPI rowset_current_index_GetIndexInfo(IRowsetCurrentIndex *iface, + DBORDINAL *pcKeyColumns, DBINDEXCOLUMNDESC **prgIndexColumnDesc, + ULONG *pcIndexPropertySets, DBPROPSET **prgIndexPropertySets) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_current_index_Seek(IRowsetCurrentIndex *iface, + HACCESSOR hAccessor, DBORDINAL cKeyValues, void *pData, DBSEEK dwSeekOptions) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_current_index_SetRange(IRowsetCurrentIndex *iface, + HACCESSOR hAccessor, DBORDINAL cStartKeyColumns, void *pStartData, + DBORDINAL cEndKeyColumns, void *pEndData, DBRANGE dwRangeOptions) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_current_index_GetIndex(IRowsetCurrentIndex *iface, DBID **ppIndexID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_current_index_SetIndex(IRowsetCurrentIndex *iface, DBID *pIndexID) +{ + CHECK_EXPECT(rowset_current_index_SetIndex); + + ok(pIndexID != NULL, "pIndexID = NULL\n"); + ok(pIndexID->eKind == DBKIND_NAME, "eKind = %ld\n", pIndexID->eKind); + ok(!wcscmp(pIndexID->uName.pwszName, L"test"), "pwszName = %s\n", wine_dbgstr_w(pIndexID->uName.pwszName)); + return S_OK; +} + +static const struct IRowsetCurrentIndexVtbl rowset_current_index = +{ + rowset_current_index_QueryInterface, + rowset_current_index_AddRef, + rowset_current_index_Release, + rowset_current_index_GetIndexInfo, + rowset_current_index_Seek, + rowset_current_index_SetRange, + rowset_current_index_GetIndex, + rowset_current_index_SetIndex +}; + static HRESULT WINAPI view_chapter_QueryInterface(IViewChapter *iface, REFIID riid, void **obj) { struct test_rowset *rowset = impl_from_IViewChapter( iface ); @@ -1348,6 +1424,11 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri { *obj = &rowset->IChapteredRowset_iface; } + else if (IsEqualIID(riid, &IID_IRowsetIndex) || + IsEqualIID(riid, &IID_IRowsetCurrentIndex)) + { + *obj = &rowset->IRowsetCurrentIndex_iface; + } else if (IsEqualIID(riid, &UKN_INTERFACE)) { trace("Unknown interface\n"); @@ -1611,6 +1692,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) ADO_LONGPTR size; DataTypeEnum type; VARIANT_BOOL b; + BSTR bstr; hr = CoCreateInstance( &CLSID_Recordset, NULL, CLSCTX_INPROC_SERVER, &IID__Recordset, (void **)&recordset ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -1638,6 +1720,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) testrowset.IAccessor_iface.lpVtbl = &accessor; testrowset.IRowsetView_iface.lpVtbl = &rowset_view; testrowset.IChapteredRowset_iface.lpVtbl = &chaptered_rowset; + testrowset.IRowsetCurrentIndex_iface.lpVtbl = &rowset_current_index; testrowset.refs = 1; testrowset.IViewChapter_iface.lpVtbl = &view_chapter; testrowset.IViewFilter_iface.lpVtbl = &view_filter; @@ -1865,6 +1948,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) else CHECK_CALLED( rowset_GetRowsAt ); ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr ); + bstr = SysAllocString( L"test" ); + SET_EXPECT( rowset_current_index_SetIndex ); if (!exact_scroll) { SET_EXPECT( rowset_RestartPosition ); @@ -1875,8 +1960,36 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) SET_EXPECT( rowset_GetRowsAt ); SET_EXPECT( rowset_GetData ); } + hr = _Recordset_put_Index( recordset, bstr ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_current_index_SetIndex ); + if (!exact_scroll) + { + CHECK_CALLED( rowset_RestartPosition ); + CHECK_CALLED( rowset_GetNextRows ); + } + else + { + CHECK_CALLED( rowset_GetRowsAt ); + CHECK_CALLED( rowset_GetData ); + } + SysFreeString( bstr ); + + SET_EXPECT( rowset_ReleaseRows ); + if (!exact_scroll) + { + SET_EXPECT( rowset_RestartPosition ); + SET_EXPECT( rowset_GetNextRows ); + } + else + { + SET_EXPECT( rowset_AddRefRows ); + SET_EXPECT( rowset_GetRowsAt ); + SET_EXPECT( rowset_GetData ); + } hr = _Recordset_MoveFirst( recordset ); ok( hr == S_OK, "got %08lx\n", hr); + CHECK_CALLED( rowset_ReleaseRows ); if (!exact_scroll) { CHECK_CALLED( rowset_RestartPosition ); @@ -1884,6 +1997,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) } else { + CHECK_CALLED( rowset_AddRefRows ); CHECK_CALLED( rowset_GetRowsAt ); CHECK_CALLED( rowset_GetData ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msado15/recordset.c | 31 +++++++++++++++++++++++++++++-- dlls/msado15/tests/msado15.c | 19 +++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 78015b9a3ba..ae7289527f9 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2975,8 +2975,35 @@ static HRESULT WINAPI recordset_put_Index( _Recordset *iface, BSTR index ) static HRESULT WINAPI recordset_get_Index( _Recordset *iface, BSTR *index ) { - FIXME( "%p, %p\n", iface, index ); - return E_NOTIMPL; + struct recordset *recordset = impl_from_Recordset( iface ); + HRESULT hr; + DBID *dbid; + + TRACE( "%p, %p\n", iface, index ); + + if (!index) return MAKE_ADO_HRESULT( adErrInvalidArgument ); + + if (!recordset->rowset_cur_idx) + { + hr = IRowset_QueryInterface( recordset->row_set, &IID_IRowsetCurrentIndex, (void **)&recordset->rowset_cur_idx ); + if (FAILED(hr) || !recordset->rowset_cur_idx) + recordset->rowset_cur_idx = NO_INTERFACE; + } + if (recordset->rowset_cur_idx == NO_INTERFACE) + return MAKE_ADO_HRESULT( adErrFeatureNotAvailable ); + + hr = IRowsetCurrentIndex_GetIndex( recordset->rowset_cur_idx, &dbid ); + if (FAILED(hr)) return hr; + + if (dbid->eKind == DBKIND_GUID_NAME || dbid->eKind == DBKIND_NAME) + { + *index = SysAllocString( dbid->uName.pwszName ); + CoTaskMemFree( dbid->uName.pwszName ); + } + else + *index = NULL; + CoTaskMemFree( dbid ); + return S_OK; } static HRESULT WINAPI recordset_Save( _Recordset *iface, VARIANT destination, PersistFormatEnum persist_format ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 910a1f13899..02228237e1f 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -87,6 +87,7 @@ DEFINE_EXPECT(rowset_view_CreateView); DEFINE_EXPECT(view_chapter_OpenViewChapter); DEFINE_EXPECT(view_filter_SetFilter); DEFINE_EXPECT(chaptered_rowset_ReleaseChapter); +DEFINE_EXPECT(rowset_current_index_GetIndex); DEFINE_EXPECT(rowset_current_index_SetIndex); static BOOL is_bof( _Recordset *recordset ) @@ -1223,8 +1224,15 @@ static HRESULT WINAPI rowset_current_index_SetRange(IRowsetCurrentIndex *iface, static HRESULT WINAPI rowset_current_index_GetIndex(IRowsetCurrentIndex *iface, DBID **ppIndexID) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(rowset_current_index_GetIndex); + ok(ppIndexID != NULL, "ppIndexID = NULL\n"); + + *ppIndexID = CoTaskMemAlloc(sizeof(**ppIndexID)); + memset(*ppIndexID, 0, sizeof(**ppIndexID)); + (*ppIndexID)->eKind = DBKIND_NAME; + (*ppIndexID)->uName.pwszName = CoTaskMemAlloc(sizeof(L"abc")); + wcscpy((*ppIndexID)->uName.pwszName, L"abc"); + return S_OK; } static HRESULT WINAPI rowset_current_index_SetIndex(IRowsetCurrentIndex *iface, DBID *pIndexID) @@ -1948,6 +1956,13 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) else CHECK_CALLED( rowset_GetRowsAt ); ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr ); + SET_EXPECT( rowset_current_index_GetIndex ); + hr = _Recordset_get_Index( recordset, &bstr ); + ok( hr == S_OK, "got %08lx\n", hr ); + CHECK_CALLED( rowset_current_index_GetIndex ); + ok( !wcscmp( bstr, L"abc"), "bstr = %s\n", wine_dbgstr_w(bstr) ); + SysFreeString( bstr ); + bstr = SysAllocString( L"test" ); SET_EXPECT( rowset_current_index_SetIndex ); if (!exact_scroll) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9667
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)