From: Piotr Caban piotr@codeweavers.com
--- include/dbs.idl | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/include/dbs.idl b/include/dbs.idl index 2833550b1e1..86729abc4b1 100644 --- a/include/dbs.idl +++ b/include/dbs.idl @@ -991,3 +991,16 @@ typedef enum tagDBBOOKMARK { } DBBOOKMARK;
cpp_quote("#define STD_BOOKMARKLENGTH 1") + +typedef struct tagDBCOLUMNDESC { + LPOLESTR pwszTypeName; + ITypeInfo *pTypeInfo; + [size_is(cPropertySets)] DBPROPSET *rgPropertySets; + CLSID *pclsid; + ULONG cPropertySets; + DBLENGTH ulColumnSize; + DBID dbcid; + DBTYPE wType; + BYTE bPrecision; + BYTE bScale; +} DBCOLUMNDESC;
From: Piotr Caban piotr@codeweavers.com
--- include/dbs.idl | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/include/dbs.idl b/include/dbs.idl index 86729abc4b1..881d256e1c6 100644 --- a/include/dbs.idl +++ b/include/dbs.idl @@ -543,6 +543,9 @@ cpp_quote("DEFINE_DBGUID(DBPROPSET_SESSIONALL, 0xc8b522c7, 0x5cf3, 0x11ce cpp_quote("DEFINE_DBGUID(DBPROPSET_DBINITALL, 0xc8b522ca, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);") cpp_quote("DEFINE_DBGUID(DBPROPSET_PROPERTIESINERROR, 0xc8b522d4, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);")
+cpp_quote("DEFINE_DBGUID(DBCOL_SELFCOLUMNS, 0xc8b52231, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);") +cpp_quote("DEFINE_DBGUID(DBCOL_SPECIALCOL, 0xc8b52232, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);") + cpp_quote("DEFINE_DBID(DB_NULLID, DB_NULLGUID, 0, 0);") cpp_quote("DEFINE_DBID(DBCOLUMN_IDNAME, DBCIDGUID, DBKIND_GUID_PROPID, 2);") cpp_quote("DEFINE_DBID(DBCOLUMN_NAME, DBCIDGUID, DBKIND_GUID_PROPID, 3);")
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index 10e2eb47740..837d0e3625f 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -1088,6 +1088,8 @@ static HRESULT WINAPI fields__Append( Fields *iface, BSTR name, DataTypeEnum typ
TRACE( "%p, %s, %u, %Id, %d\n", fields, debugstr_w(name), type, size, attr );
+ if (fields_get_recordset(fields)->state != adStateClosed) return MAKE_ADO_HRESULT( adErrIllegalOperation ); + memset( &colinfo, 0, sizeof(colinfo) ); colinfo.pwszName = name; colinfo.wType = type;
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 );
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/recordset.c | 101 ++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 55 deletions(-)
diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index cf1dff337af..d74593ba956 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -32,12 +32,33 @@
WINE_DEFAULT_DEBUG_CHANNEL(msado15);
+struct recordset; + +struct field +{ + Field Field_iface; + ISupportErrorInfo ISupportErrorInfo_iface; + Properties Properties_iface; + LONG refs; + WCHAR *name; + DataTypeEnum type; + LONG defined_size; + LONG attrs; + LONG index; + unsigned char prec; + unsigned char scale; + struct recordset *recordset; + + /* Field Properties */ + VARIANT optimize; +}; + struct fields { Fields Fields_iface; ISupportErrorInfo ISupportErrorInfo_iface; LONG refs; - Field **field; + struct field **field; ULONG count; ULONG allocated; }; @@ -67,25 +88,6 @@ struct recordset HACCESSOR *haccessors; };
-struct field -{ - Field Field_iface; - ISupportErrorInfo ISupportErrorInfo_iface; - Properties Properties_iface; - LONG refs; - WCHAR *name; - DataTypeEnum type; - LONG defined_size; - LONG attrs; - LONG index; - unsigned char prec; - unsigned char scale; - struct recordset *recordset; - - /* Field Properties */ - VARIANT optimize; -}; - static inline struct field *impl_from_Field( Field *iface ) { return CONTAINING_RECORD( iface, struct field, Field_iface ); @@ -809,25 +811,22 @@ static struct PropertiesVtbl field_properties_vtbl = field_props_get_Item };
-static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *recordset, Field **obj ) +static HRESULT Field_create( const WCHAR *name, LONG index, struct recordset *recordset, struct field **field ) { - struct field *field; - - if (!(field = calloc( 1, sizeof(*field) ))) return E_OUTOFMEMORY; - field->Field_iface.lpVtbl = &field_vtbl; - field->ISupportErrorInfo_iface.lpVtbl = &field_supporterrorinfo_vtbl; - field->Properties_iface.lpVtbl = &field_properties_vtbl; - field->refs = 1; - if (!(field->name = wcsdup( name ))) + if (!(*field = calloc( 1, sizeof(**field) ))) return E_OUTOFMEMORY; + (*field)->Field_iface.lpVtbl = &field_vtbl; + (*field)->ISupportErrorInfo_iface.lpVtbl = &field_supporterrorinfo_vtbl; + (*field)->Properties_iface.lpVtbl = &field_properties_vtbl; + (*field)->refs = 1; + if (!((*field)->name = wcsdup( name ))) { - free( field ); + free( *field ); return E_OUTOFMEMORY; } - field->index = index; - field->recordset = recordset; + (*field)->index = index; + (*field)->recordset = recordset;
- *obj = &field->Field_iface; - TRACE( "returning iface %p\n", *obj ); + TRACE( "returning field %p\n", *field ); return S_OK; }
@@ -995,14 +994,7 @@ static HRESULT map_index( struct fields *fields, VARIANT *index, ULONG *ret )
for (i = 0; i < fields->count; i++) { - BSTR name; - BOOL match; - HRESULT hr; - - if ((hr = Field_get_Name( fields->field[i], &name )) != S_OK) return hr; - match = !wcsicmp( V_BSTR( index ), name ); - SysFreeString( name ); - if (match) + if (!wcsicmp( V_BSTR(index), fields->field[i]->name )) { *ret = i; return S_OK; @@ -1038,8 +1030,8 @@ static HRESULT WINAPI fields_get_Item( Fields *iface, VARIANT index, Field **obj
if ((hr = map_index( fields, &index, &i )) != S_OK) return hr;
- Field_AddRef( fields->field[i] ); - *obj = fields->field[i]; + Field_AddRef( &fields->field[i]->Field_iface ); + *obj = &fields->field[i]->Field_iface; return S_OK; }
@@ -1047,7 +1039,7 @@ static BOOL resize_fields( struct fields *fields, ULONG count ) { if (count > fields->allocated) { - Field **tmp; + struct field **tmp; ULONG new_size = max( count, fields->allocated * 2 ); if (!(tmp = realloc( fields->field, new_size * sizeof(*tmp) ))) return FALSE; fields->field = tmp; @@ -1060,20 +1052,20 @@ static BOOL resize_fields( struct fields *fields, ULONG count )
static HRESULT append_field( struct fields *fields, const DBCOLUMNINFO *info ) { - Field *field; + struct field *field; HRESULT hr;
hr = Field_create( info->pwszName, fields->count, fields_get_recordset(fields), &field ); if (hr != S_OK) return hr; - Field_put_Type( field, info->wType ); - Field_put_DefinedSize( field, info->ulColumnSize ); - if (info->dwFlags != adFldUnspecified) Field_put_Attributes( field, info->dwFlags ); - Field_put_Precision( field, info->bPrecision ); - Field_put_NumericScale( field, info->bScale ); + field->type = info->wType; + field->defined_size = info->ulColumnSize; + if (info->dwFlags != adFldUnspecified) field->attrs = info->dwFlags; + field->prec = info->bPrecision; + field->scale = info->bScale;
if (!(resize_fields( fields, fields->count + 1 ))) { - Field_Release( field ); + Field_Release( &field->Field_iface ); return E_OUTOFMEMORY; }
@@ -1272,9 +1264,8 @@ static void close_recordset( struct recordset *recordset )
for (i = 0; i < col_count; i++) { - struct field *field = impl_from_Field( recordset->fields.field[i] ); - field->recordset = NULL; - Field_Release(&field->Field_iface); + recordset->fields.field[i]->recordset = NULL; + Field_Release(&recordset->fields.field[i]->Field_iface);
if (recordset->haccessors) IAccessor_ReleaseAccessor(accessor, recordset->haccessors[i], NULL);
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/msado15_private.h | 2 +- dlls/msado15/recordset.c | 35 ++++++++- dlls/msado15/rowset.c | 125 ++++++++++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 4 deletions(-)
diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h index f91e83bda38..a15c185adc0 100644 --- a/dlls/msado15/msado15_private.h +++ b/dlls/msado15/msado15_private.h @@ -26,7 +26,7 @@ HRESULT Connection_create( void ** ); HRESULT Recordset_create( void ** ); HRESULT Stream_create( void ** );
-HRESULT create_mem_rowset( IUnknown ** ); +HRESULT create_mem_rowset( int, const DBCOLUMNINFO *, IUnknown ** );
typedef enum tid_t { ADORecordsetConstruction_tid, diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c index d74593ba956..a41023e03ef 100644 --- a/dlls/msado15/recordset.c +++ b/dlls/msado15/recordset.c @@ -2178,15 +2178,48 @@ static HRESULT WINAPI recordset_Open( _Recordset *iface, VARIANT source, VARIANT
if (get_column_count(recordset)) { + DBCOLUMNINFO *info; + int i; + if (recordset->active_connection) { FIXME("adding new table\n"); return E_NOTIMPL; }
- hr = create_mem_rowset(&rowset); + info = calloc(recordset->fields.count + 1, sizeof(*info)); + if (!info) + return E_OUTOFMEMORY; + + info[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK | DBCOLUMNFLAGS_ISFIXEDLENGTH; + info[0].ulColumnSize = sizeof(unsigned int); + info[0].wType = DBTYPE_UI4; + info[0].bPrecision = 10; + info[0].bScale = 255; + info[0].columnid.eKind = DBKIND_GUID_PROPID; + info[0].columnid.uGuid.guid = DBCOL_SPECIALCOL; + info[0].columnid.uName.ulPropid = 2 /* PROPID_DBBMK_BOOKMARK */; + + for (i = 1; i <= recordset->fields.count; i++) + { + struct field *field = recordset->fields.field[i - 1]; + + info[i].pwszName = field->name; + info[i].iOrdinal = i; + info[i].dwFlags = field->attrs; + info[i].ulColumnSize = field->defined_size; + info[i].wType = field->type; + info[i].bPrecision = field->prec; + info[i].bScale = field->scale; + info[i].columnid.eKind = DBKIND_NAME; + info[i].columnid.uName.pwszName = field->name; + } + + hr = create_mem_rowset(recordset->fields.count + 1, info, &rowset); + free(info); if (FAILED(hr)) return hr; + hr = ADORecordsetConstruction_put_Rowset(&recordset->ADORecordsetConstruction_iface, rowset); IUnknown_Release(rowset); return hr; diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 1193cc88326..030d5c64742 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -27,7 +27,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(msado15); struct rowset { IRowset IRowset_iface; + IColumnsInfo IColumnsInfo_iface; LONG refs; + + int columns_cnt; + DBCOLUMNINFO *columns; + OLECHAR *columns_buf; };
static inline struct rowset *impl_from_IRowset(IRowset *iface) @@ -35,6 +40,11 @@ static inline struct rowset *impl_from_IRowset(IRowset *iface) return CONTAINING_RECORD(iface, struct rowset, IRowset_iface); }
+static inline struct rowset *impl_from_IColumnsInfo(IColumnsInfo *iface) +{ + return CONTAINING_RECORD(iface, struct rowset, IColumnsInfo_iface); +} + static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void **ppv) { struct rowset *rowset = impl_from_IRowset(iface); @@ -47,6 +57,10 @@ static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void ** { *ppv = &rowset->IRowset_iface; } + else if(IsEqualGUID(&IID_IColumnsInfo, riid)) + { + *ppv = &rowset->IColumnsInfo_iface; + }
if(*ppv) { @@ -79,6 +93,8 @@ static ULONG WINAPI rowset_Release(IRowset *iface) { TRACE("destroying %p\n", rowset);
+ CoTaskMemFree(rowset->columns); + CoTaskMemFree(rowset->columns_buf); free(rowset); } return refs; @@ -139,16 +155,121 @@ static const struct IRowsetVtbl rowset_vtbl = rowset_RestartPosition };
-HRESULT create_mem_rowset(IUnknown **ret) +static HRESULT WINAPI columns_info_QueryInterface(IColumnsInfo *iface, REFIID riid, void **out) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_QueryInterface(&rowset->IRowset_iface, riid, out); +} + +static ULONG WINAPI columns_info_AddRef(IColumnsInfo *iface) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_AddRef(&rowset->IRowset_iface); +} + +static ULONG WINAPI columns_info_Release(IColumnsInfo *iface) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + return IRowset_Release(&rowset->IRowset_iface); +} + +static HRESULT copy_column_info(DBCOLUMNINFO **dest, const DBCOLUMNINFO *src, int count, OLECHAR **buf) +{ + size_t len; + int i; + + *dest = CoTaskMemAlloc(sizeof(**dest) * count); + if (!*dest) + return E_OUTOFMEMORY; + memcpy(*dest, src, sizeof(**dest) * count); + + len = 0; + for (i = 0; i < count; i++) + { + if (src[i].pwszName) len += wcslen(src[i].pwszName) + 1; + if (src[i].columnid.eKind == DBKIND_GUID_NAME || src[i].columnid.eKind == DBKIND_NAME || + src[i].columnid.eKind == DBKIND_PGUID_NAME) + len += wcslen(src[i].columnid.uName.pwszName) + 1; + } + *buf = CoTaskMemAlloc(sizeof(**buf) * len); + if (!*buf) + { + CoTaskMemFree(*dest); + *dest = NULL; + return E_OUTOFMEMORY; + } + len = 0; + for (i = 0; i < count; i++) + { + if (src[i].pwszName) + { + wcscpy(*buf + len, src[i].pwszName); + (*dest)[i].pwszName = *buf + len; + len += wcslen(src[i].pwszName) + 1; + } + if (src[i].columnid.eKind == DBKIND_GUID_NAME || src[i].columnid.eKind == DBKIND_NAME || + src[i].columnid.eKind == DBKIND_PGUID_NAME) + { + wcscpy(*buf + len, src[i].columnid.uName.pwszName); + (*dest)[i].columnid.uName.pwszName = *buf + len; + len += wcslen(src[i].columnid.uName.pwszName) + 1; + } + } + return S_OK; +} + +static HRESULT WINAPI columns_info_GetColumnInfo(IColumnsInfo *iface, + DBORDINAL *columns, DBCOLUMNINFO **colinfo, OLECHAR **strbuf) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + + TRACE("%p, %p, %p, %p\n", rowset, columns, colinfo, strbuf); + + if (!columns || !colinfo || !strbuf) + return E_INVALIDARG; + + *columns = rowset->columns_cnt; + return copy_column_info(colinfo, rowset->columns, rowset->columns_cnt, strbuf); +} + +static HRESULT WINAPI columns_info_MapColumnIDs(IColumnsInfo *iface, + DBORDINAL column_ids, const DBID *dbids, DBORDINAL *columns) +{ + struct rowset *rowset = impl_from_IColumnsInfo(iface); + + FIXME("%p, %Iu, %p, %p\n", rowset, column_ids, dbids, columns); + return E_NOTIMPL; +} + +static struct IColumnsInfoVtbl columns_info_vtbl = +{ + columns_info_QueryInterface, + columns_info_AddRef, + columns_info_Release, + columns_info_GetColumnInfo, + columns_info_MapColumnIDs +}; + +HRESULT create_mem_rowset(int count, const DBCOLUMNINFO *info, IUnknown **ret) { struct rowset *rowset; + HRESULT hr;
- rowset = malloc(sizeof(*rowset)); + rowset = calloc(1, sizeof(*rowset)); if (!rowset) return E_OUTOFMEMORY;
rowset->IRowset_iface.lpVtbl = &rowset_vtbl; + rowset->IColumnsInfo_iface.lpVtbl = &columns_info_vtbl; rowset->refs = 1;
+ rowset->columns_cnt = count; + hr = copy_column_info(&rowset->columns, info, count, &rowset->columns_buf); + if (FAILED(hr)) + { + IRowset_Release(&rowset->IRowset_iface); + return E_OUTOFMEMORY; + } + *ret = (IUnknown *)&rowset->IRowset_iface; return S_OK; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/rowset.c | 139 +++++++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 29 deletions(-)
diff --git a/dlls/msado15/rowset.c b/dlls/msado15/rowset.c index 030d5c64742..c6c301a0ce3 100644 --- a/dlls/msado15/rowset.c +++ b/dlls/msado15/rowset.c @@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msado15);
struct rowset { - IRowset IRowset_iface; + IRowsetExactScroll IRowsetExactScroll_iface; IColumnsInfo IColumnsInfo_iface; LONG refs;
@@ -35,9 +35,9 @@ struct rowset OLECHAR *columns_buf; };
-static inline struct rowset *impl_from_IRowset(IRowset *iface) +static inline struct rowset *impl_from_IRowsetExactScroll(IRowsetExactScroll *iface) { - return CONTAINING_RECORD(iface, struct rowset, IRowset_iface); + return CONTAINING_RECORD(iface, struct rowset, IRowsetExactScroll_iface); }
static inline struct rowset *impl_from_IColumnsInfo(IColumnsInfo *iface) @@ -45,17 +45,20 @@ static inline struct rowset *impl_from_IColumnsInfo(IColumnsInfo *iface) return CONTAINING_RECORD(iface, struct rowset, IColumnsInfo_iface); }
-static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void **ppv) +static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID riid, void **ppv) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
TRACE("%p, %s, %p\n", rowset, debugstr_guid(riid), ppv);
*ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid) || - IsEqualGUID(&IID_IRowset, riid)) + IsEqualGUID(&IID_IRowset, riid) || + IsEqualGUID(&IID_IRowsetLocate, riid) || + IsEqualGUID(&IID_IRowsetScroll, riid) || + IsEqualGUID(&IID_IRowsetExactScroll, riid)) { - *ppv = &rowset->IRowset_iface; + *ppv = &rowset->IRowsetExactScroll_iface; } else if(IsEqualGUID(&IID_IColumnsInfo, riid)) { @@ -72,9 +75,9 @@ static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID riid, void ** return E_NOINTERFACE; }
-static ULONG WINAPI rowset_AddRef(IRowset *iface) +static ULONG WINAPI rowset_AddRef(IRowsetExactScroll *iface) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); LONG refs = InterlockedIncrement(&rowset->refs);
TRACE("%p new refcount %ld\n", rowset, refs); @@ -82,9 +85,9 @@ static ULONG WINAPI rowset_AddRef(IRowset *iface) return refs; }
-static ULONG WINAPI rowset_Release(IRowset *iface) +static ULONG WINAPI rowset_Release(IRowsetExactScroll *iface) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); LONG refs = InterlockedDecrement(&rowset->refs);
TRACE("%p new refcount %ld\n", rowset, refs); @@ -100,50 +103,121 @@ static ULONG WINAPI rowset_Release(IRowset *iface) return refs; }
-static HRESULT WINAPI rowset_AddRefRows(IRowset *iface, DBCOUNTITEM count, +static HRESULT WINAPI rowset_AddRefRows(IRowsetExactScroll *iface, DBCOUNTITEM count, const HROW rows[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(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) +static HRESULT WINAPI rowset_GetData(IRowsetExactScroll *iface, HROW row, HACCESSOR accessor, void *data) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
FIXME("%p, %Id, %Id, %p\n", rowset, row, accessor, data); return E_NOTIMPL; }
-static HRESULT WINAPI rowset_GetNextRows(IRowset *iface, HCHAPTER reserved, +static HRESULT WINAPI rowset_GetNextRows(IRowsetExactScroll *iface, HCHAPTER reserved, DBROWOFFSET offset, DBROWCOUNT count, DBCOUNTITEM *obtained, HROW **rows) { - struct rowset *rowset = impl_from_IRowset( iface ); + struct rowset *rowset = impl_from_IRowsetExactScroll( 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[], +static HRESULT WINAPI rowset_ReleaseRows(IRowsetExactScroll *iface, DBCOUNTITEM count, const HROW rows[], DBROWOPTIONS options[], DBREFCOUNT ref_counts[], DBROWSTATUS status[]) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(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) +static HRESULT WINAPI rowset_RestartPosition(IRowsetExactScroll *iface, HCHAPTER reserved) { - struct rowset *rowset = impl_from_IRowset(iface); + struct rowset *rowset = impl_from_IRowsetExactScroll(iface);
FIXME("%p, %Id\n", rowset, reserved); return E_NOTIMPL; }
-static const struct IRowsetVtbl rowset_vtbl = +static HRESULT WINAPI rowset_Compare(IRowsetExactScroll *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, + const BYTE *pBookmark1, DBBKMARK cbBookmark2, const BYTE *pBookmark2, DBCOMPARE *pComparison) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Iu, %p, %Iu, %p, %p\n", rowset, hReserved, cbBookmark1, + pBookmark1, cbBookmark2, pBookmark2, pComparison); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetRowsAt(IRowsetExactScroll *iface, HWATCHREGION hReserved1, + HCHAPTER hReserved2, DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset, + DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Id, %Iu, %p, %Id, %Id, %p, %p\n", rowset, hReserved1, hReserved2, + cbBookmark, pBookmark, lRowsOffset, cRows, pcRowsObtained, prghRows); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetRowsByBookmark(IRowsetExactScroll *iface, HCHAPTER hReserved, + DBCOUNTITEM cRows, const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[], + HROW rghRows[], DBROWSTATUS rgRowStatus[]) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Id, %p, %p, %p, %p\n", rowset, hReserved, cRows, + rgcbBookmarks, rgpBookmarks, rghRows, rgRowStatus); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_Hash(IRowsetExactScroll *iface, HCHAPTER hReserved, + DBBKMARK cBookmarks, const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[], + DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[]) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Iu, %p, %p, %p, %p\n", rowset, hReserved, cBookmarks, + rgcbBookmarks, rgpBookmarks, rgHashedValues, rgBookmarkStatus); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetApproximatePosition(IRowsetExactScroll *iface, HCHAPTER reserved, + DBBKMARK cnt, const BYTE *bookmarks, DBCOUNTITEM *position, DBCOUNTITEM *rows) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Iu, %p, %p, %p\n", rowset, reserved, cnt, bookmarks, position, rows); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetRowsAtRatio(IRowsetExactScroll *iface, HWATCHREGION reserved1, HCHAPTER reserved2, + DBCOUNTITEM numerator, DBCOUNTITEM Denominator, DBROWCOUNT rows_cnt, DBCOUNTITEM *obtained, HROW **rows) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Id, %Iu, %Iu, %Id, %p, %p\n", rowset, reserved1, reserved2, + numerator, Denominator, rows_cnt, obtained, rows); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_GetExactPosition(IRowsetExactScroll *iface, HCHAPTER chapter, + DBBKMARK bookmark_cnt, const BYTE *bookmarks, DBCOUNTITEM *position, DBCOUNTITEM *rows) +{ + struct rowset *rowset = impl_from_IRowsetExactScroll(iface); + + FIXME("%p, %Id, %Iu, %p, %p, %p\n", rowset, chapter, bookmark_cnt, bookmarks, position, rows); + return E_NOTIMPL; +} + +static const struct IRowsetExactScrollVtbl rowset_vtbl = { rowset_QueryInterface, rowset_AddRef, @@ -152,25 +226,32 @@ static const struct IRowsetVtbl rowset_vtbl = rowset_GetData, rowset_GetNextRows, rowset_ReleaseRows, - rowset_RestartPosition + rowset_RestartPosition, + rowset_Compare, + rowset_GetRowsAt, + rowset_GetRowsByBookmark, + rowset_Hash, + rowset_GetApproximatePosition, + rowset_GetRowsAtRatio, + rowset_GetExactPosition };
static HRESULT WINAPI columns_info_QueryInterface(IColumnsInfo *iface, REFIID riid, void **out) { struct rowset *rowset = impl_from_IColumnsInfo(iface); - return IRowset_QueryInterface(&rowset->IRowset_iface, riid, out); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, out); }
static ULONG WINAPI columns_info_AddRef(IColumnsInfo *iface) { struct rowset *rowset = impl_from_IColumnsInfo(iface); - return IRowset_AddRef(&rowset->IRowset_iface); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); }
static ULONG WINAPI columns_info_Release(IColumnsInfo *iface) { struct rowset *rowset = impl_from_IColumnsInfo(iface); - return IRowset_Release(&rowset->IRowset_iface); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); }
static HRESULT copy_column_info(DBCOLUMNINFO **dest, const DBCOLUMNINFO *src, int count, OLECHAR **buf) @@ -258,7 +339,7 @@ HRESULT create_mem_rowset(int count, const DBCOLUMNINFO *info, IUnknown **ret) rowset = calloc(1, sizeof(*rowset)); if (!rowset) return E_OUTOFMEMORY;
- rowset->IRowset_iface.lpVtbl = &rowset_vtbl; + rowset->IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; rowset->IColumnsInfo_iface.lpVtbl = &columns_info_vtbl; rowset->refs = 1;
@@ -266,10 +347,10 @@ HRESULT create_mem_rowset(int count, const DBCOLUMNINFO *info, IUnknown **ret) hr = copy_column_info(&rowset->columns, info, count, &rowset->columns_buf); if (FAILED(hr)) { - IRowset_Release(&rowset->IRowset_iface); + IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); return E_OUTOFMEMORY; }
- *ret = (IUnknown *)&rowset->IRowset_iface; + *ret = (IUnknown *)&rowset->IRowsetExactScroll_iface; return S_OK; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/msado15/tests/msado15.c | 181 ++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 3 deletions(-)
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 1ad269afa11..4c974396727 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -38,7 +38,10 @@ static char mdbpath[MAX_PATH]; static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
#define SET_EXPECT(func) \ - expect_ ## func = TRUE + do { \ + called_ ## func = FALSE; \ + expect_ ## func = TRUE; \ + } while(0)
#define CHECK_EXPECT2(func) \ do { \ @@ -68,6 +71,7 @@ DEFINE_EXPECT(rowset_QI_IRowset); DEFINE_EXPECT(rowset_QI_IRowsetExactScroll); DEFINE_EXPECT(rowset_QI_IRowsetInfo); DEFINE_EXPECT(rowset_QI_IColumnsInfo); +DEFINE_EXPECT(rowset_QI_IRowsetChange); DEFINE_EXPECT(rowset_QI_IDBAsynchStatus); DEFINE_EXPECT(rowset_QI_IAccessor); DEFINE_EXPECT(rowset_info_GetProperties); @@ -76,6 +80,10 @@ DEFINE_EXPECT(rowset_GetNextRows); DEFINE_EXPECT(rowset_ReleaseRows); DEFINE_EXPECT(rowset_GetRowsAt); DEFINE_EXPECT(rowset_GetExactPosition); +DEFINE_EXPECT(rowset_change_InsertRow); +DEFINE_EXPECT(accessor_AddRefAccessor); +DEFINE_EXPECT(accessor_CreateAccessor); +DEFINE_EXPECT(accessor_ReleaseAccessor);
static BOOL is_bof( _Recordset *recordset ) { @@ -508,6 +516,8 @@ struct test_rowset IRowsetExactScroll IRowsetExactScroll_iface; IRowsetInfo IRowsetInfo_iface; IColumnsInfo IColumnsInfo_iface; + IRowsetChange IRowsetChange_iface; + IAccessor IAccessor_iface; LONG refs; BOOL exact_scroll; }; @@ -527,6 +537,16 @@ static inline struct test_rowset *impl_from_IColumnsInfo( IColumnsInfo *iface ) return CONTAINING_RECORD( iface, struct test_rowset, IColumnsInfo_iface ); }
+static inline struct test_rowset *impl_from_IRowsetChange( IRowsetChange *iface ) +{ + return CONTAINING_RECORD( iface, struct test_rowset, IRowsetChange_iface ); +} + +static inline struct test_rowset *impl_from_IAccessor( IAccessor *iface ) +{ + return CONTAINING_RECORD( iface, struct test_rowset, IAccessor_iface ); +} + static HRESULT WINAPI rowset_info_QueryInterface(IRowsetInfo *iface, REFIID riid, void **obj) { struct test_rowset *rowset = impl_from_IRowsetInfo( iface ); @@ -647,6 +667,133 @@ static const struct IColumnsInfoVtbl column_info = column_info_MapColumnIDs, };
+static HRESULT WINAPI rowset_change_QueryInterface(IRowsetChange *iface, REFIID riid, void **obj) +{ + struct test_rowset *rowset = impl_from_IRowsetChange( iface ); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, obj); +} + +static ULONG WINAPI rowset_change_AddRef(IRowsetChange *iface) +{ + struct test_rowset *rowset = impl_from_IRowsetChange( iface ); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); +} + +static ULONG WINAPI rowset_change_Release(IRowsetChange *iface) +{ + struct test_rowset *rowset = impl_from_IRowsetChange( iface ); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); +} + +static HRESULT WINAPI rowset_change_DeleteRows(IRowsetChange *iface, HCHAPTER reserved, + DBCOUNTITEM count, const HROW rows[], DBROWSTATUS status[]) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_change_SetData(IRowsetChange *iface, + HROW row, HACCESSOR accessor, void *data) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI rowset_change_InsertRow(IRowsetChange *iface, + HCHAPTER reserved, HACCESSOR accessor, void *data, HROW *row) +{ + CHECK_EXPECT(rowset_change_InsertRow); + ok(!reserved, "reserved = %Id\n", reserved); + ok(accessor == 1, "accessor = %Id\n", accessor); + ok(!data, "data = %p\n", data); + ok(row != NULL, "row = NULL\n"); + + *row = 10; + return S_OK; +} + +static const struct IRowsetChangeVtbl rowset_change = +{ + rowset_change_QueryInterface, + rowset_change_AddRef, + rowset_change_Release, + rowset_change_DeleteRows, + rowset_change_SetData, + rowset_change_InsertRow +}; + +static HRESULT WINAPI accessor_QueryInterface(IAccessor *iface, REFIID riid, void **obj) +{ + struct test_rowset *rowset = impl_from_IAccessor( iface ); + return IRowsetExactScroll_QueryInterface(&rowset->IRowsetExactScroll_iface, riid, obj); +} + +static ULONG WINAPI accessor_AddRef(IAccessor *iface) +{ + struct test_rowset *rowset = impl_from_IAccessor( iface ); + return IRowsetExactScroll_AddRef(&rowset->IRowsetExactScroll_iface); +} + +static ULONG WINAPI accessor_Release(IAccessor *iface) +{ + struct test_rowset *rowset = impl_from_IAccessor( iface ); + return IRowsetExactScroll_Release(&rowset->IRowsetExactScroll_iface); +} + +static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, + HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) +{ + CHECK_EXPECT2(accessor_AddRefAccessor); + ok(hAccessor == 1, "hAccessor = %Id\n", hAccessor); + ok(pcRefCount != NULL, "pcRefCount == NULL\n"); + + *pcRefCount = 2; + return S_OK; +} + +static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS dwAccessorFlags, + DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBLENGTH cbRowSize, + HACCESSOR *phAccessor, DBBINDSTATUS rgStatus[]) +{ + CHECK_EXPECT(accessor_CreateAccessor); + ok(dwAccessorFlags == DBACCESSOR_ROWDATA, "dwAccessorFlags = %lx\n", dwAccessorFlags); + ok(cBindings == 0, "cBindings = %Iu\n", cBindings); + ok(cbRowSize == 0, "cbRowSize = %Iu\n", cbRowSize); + ok(phAccessor != NULL, "pHAccessor = NULL\n"); + ok(!rgStatus, "rgStatus != NULL\n"); + + *phAccessor = 1; + return S_OK; +} + +static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, + DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings, DBBINDING **prgBindings) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, + HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) +{ + CHECK_EXPECT2(accessor_ReleaseAccessor); + ok(hAccessor == 1, "hAccessor = %Id\n", hAccessor); + + if (pcRefCount) *pcRefCount = 1; + return S_OK; +} + +static const struct IAccessorVtbl accessor = +{ + accessor_QueryInterface, + accessor_AddRef, + accessor_Release, + accessor_AddRefAccessor, + accessor_CreateAccessor, + accessor_GetBindings, + accessor_ReleaseAccessor +}; + static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID riid, void **obj) { struct test_rowset *rowset = impl_from_IRowsetExactScroll( iface ); @@ -677,6 +824,11 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri CHECK_EXPECT(rowset_QI_IColumnsInfo); *obj = &rowset->IColumnsInfo_iface; } + else if (IsEqualIID(riid, &IID_IRowsetChange)) + { + CHECK_EXPECT(rowset_QI_IRowsetChange); + *obj = &rowset->IRowsetChange_iface; + } else if (IsEqualIID(riid, &IID_IDBAsynchStatus)) { CHECK_EXPECT(rowset_QI_IDBAsynchStatus); @@ -685,7 +837,7 @@ static HRESULT WINAPI rowset_QueryInterface(IRowsetExactScroll *iface, REFIID ri else if (IsEqualIID(riid, &IID_IAccessor)) { CHECK_EXPECT(rowset_QI_IAccessor); - return E_NOINTERFACE; + *obj = &rowset->IAccessor_iface; } else if (IsEqualIID(riid, &UKN_INTERFACE)) { @@ -874,7 +1026,7 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) HRESULT hr; LONG count, state; unsigned char prec, scale; - VARIANT index; + VARIANT index, missing; ADO_LONGPTR size; DataTypeEnum type;
@@ -895,6 +1047,8 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) testrowset.IRowsetExactScroll_iface.lpVtbl = &rowset_vtbl; testrowset.IRowsetInfo_iface.lpVtbl = &rowset_info; testrowset.IColumnsInfo_iface.lpVtbl = &column_info; + testrowset.IRowsetChange_iface.lpVtbl = &rowset_change; + testrowset.IAccessor_iface.lpVtbl = &accessor; testrowset.refs = 1; testrowset.exact_scroll = exact_scroll;
@@ -988,11 +1142,32 @@ static void test_ADORecordsetConstruction(BOOL exact_scroll) else todo_wine CHECK_CALLED( rowset_GetRowsAt ); ok( hr == MAKE_ADO_HRESULT(adErrNoCurrentRecord), "got %08lx\n", hr );
+ V_VT( &missing ) = VT_ERROR; + V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND; + SET_EXPECT(rowset_QI_IRowsetChange); + SET_EXPECT(rowset_QI_IAccessor); + SET_EXPECT(accessor_CreateAccessor); + SET_EXPECT(accessor_AddRefAccessor); + SET_EXPECT(rowset_change_InsertRow); + SET_EXPECT(accessor_ReleaseAccessor); + hr = _Recordset_AddNew( recordset, missing, missing ); + ok( hr == S_OK, "got %08lx\n", hr ); + todo_wine CHECK_CALLED(rowset_QI_IRowsetChange); + todo_wine CHECK_CALLED(rowset_QI_IAccessor); + todo_wine CHECK_CALLED(accessor_CreateAccessor); + todo_wine CHECK_CALLED(accessor_AddRefAccessor); + todo_wine CHECK_CALLED(rowset_change_InsertRow); + todo_wine CHECK_CALLED(accessor_ReleaseAccessor); + Fields_Release(fields); ADORecordsetConstruction_Release(construct); + SET_EXPECT( rowset_ReleaseRows ); SET_EXPECT( rowset_QI_IAccessor ); + SET_EXPECT(accessor_ReleaseAccessor); ok( !_Recordset_Release( recordset ), "_Recordset not released\n" ); + todo_wine CHECK_CALLED(rowset_ReleaseRows ); todo_wine CHECK_CALLED( rowset_QI_IAccessor ); + todo_wine CHECK_CALLED(accessor_ReleaseAccessor); ok( testrowset.refs == 1, "got %ld\n", testrowset.refs ); }