[PATCH 2/5] msado15: Implement _Recordset_get_Fields.

Hans Leidekker hans at codeweavers.com
Wed Dec 11 10:18:26 CST 2019


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/msado15/recordset.c     | 202 ++++++++++++++++++++++++++++++++++-
 dlls/msado15/tests/msado15.c |  66 +++++++++++-
 2 files changed, 263 insertions(+), 5 deletions(-)

diff --git a/dlls/msado15/recordset.c b/dlls/msado15/recordset.c
index 84adec406f..f520a87807 100644
--- a/dlls/msado15/recordset.c
+++ b/dlls/msado15/recordset.c
@@ -31,12 +31,190 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msado15);
 
+struct fields;
 struct recordset
 {
-    _Recordset  Recordset_iface;
-    LONG        refs;
+    _Recordset     Recordset_iface;
+    LONG           refs;
+    struct fields *fields;
 };
 
+struct fields
+{
+    Fields              Fields_iface;
+    LONG                refs;
+    struct recordset   *recordset;
+};
+
+static inline struct fields *impl_from_Fields( Fields *iface )
+{
+    return CONTAINING_RECORD( iface, struct fields, Fields_iface );
+}
+
+static ULONG WINAPI fields_AddRef( Fields *iface )
+{
+    struct fields *fields = impl_from_Fields( iface );
+    LONG refs = InterlockedIncrement( &fields->refs );
+    TRACE( "%p new refcount %d\n", fields, refs );
+    return refs;
+}
+
+static ULONG WINAPI fields_Release( Fields *iface )
+{
+    struct fields *fields = impl_from_Fields( iface );
+    LONG refs = InterlockedDecrement( &fields->refs );
+    TRACE( "%p new refcount %d\n", fields, refs );
+    if (!refs)
+    {
+        if (fields->recordset) _Recordset_Release( &fields->recordset->Recordset_iface );
+        WARN( "not destroying %p\n", fields );
+        return InterlockedIncrement( &fields->refs );
+    }
+    return refs;
+}
+
+static HRESULT WINAPI fields_QueryInterface( Fields *iface, REFIID riid, void **obj )
+{
+    TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
+
+    if (IsEqualGUID( riid, &IID_Fields ) || IsEqualGUID( riid, &IID_IDispatch ) ||
+        IsEqualGUID( riid, &IID_IUnknown ))
+    {
+        *obj = iface;
+    }
+    else
+    {
+        FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
+        return E_NOINTERFACE;
+    }
+    fields_AddRef( iface );
+    return S_OK;
+}
+
+static HRESULT WINAPI fields_GetTypeInfoCount( Fields *iface, UINT *count )
+{
+    FIXME( "%p, %p\n", iface, count );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_GetTypeInfo( Fields *iface, UINT index, LCID lcid, ITypeInfo **info )
+{
+    FIXME( "%p, %u, %u, %p\n", iface, index, lcid, info );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_GetIDsOfNames( Fields *iface, REFIID riid, LPOLESTR *names, UINT count,
+                                            LCID lcid, DISPID *dispid )
+{
+    FIXME( "%p, %s, %p, %u, %u, %p\n", iface, debugstr_guid(riid), names, count, lcid, dispid );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Invoke( Fields *iface, DISPID member, REFIID riid, LCID lcid, WORD flags,
+                                     DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep_info, UINT *arg_err )
+{
+    FIXME( "%p, %d, %s, %d, %d, %p, %p, %p, %p\n", iface, member, debugstr_guid(riid), lcid, flags, params,
+           result, excep_info, arg_err );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_get_Count( Fields *iface, LONG *count )
+{
+    FIXME( "%p, %p\n", iface, count );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields__NewEnum( Fields *iface, IUnknown **obj )
+{
+    FIXME( "%p, %p\n", iface, obj );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Refresh( Fields *iface )
+{
+    FIXME( "%p\n", iface );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_get_Item( Fields *iface, VARIANT index, Field **obj )
+{
+    FIXME( "%p, %s, %p\n", iface, debugstr_variant(&index), obj );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields__Append( Fields *iface, BSTR name, DataTypeEnum type, LONG size, FieldAttributeEnum attr )
+{
+    FIXME( "%p, %s, %u, %d, %d\n", iface, debugstr_w(name), type, size, attr );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Delete( Fields *iface, VARIANT index )
+{
+    FIXME( "%p, %s\n", iface, debugstr_variant(&index) );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Append( Fields *iface, BSTR name, DataTypeEnum type, LONG size, FieldAttributeEnum attr,
+                                     VARIANT value )
+{
+    TRACE( "%p, %s, %u, %d, %d, %s\n", iface, debugstr_w(name), type, size, attr, debugstr_variant(&value) );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Update( Fields *iface )
+{
+    FIXME( "%p\n", iface );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_Resync( Fields *iface, ResyncEnum resync_values )
+{
+    FIXME( "%p, %u\n", iface, resync_values );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fields_CancelUpdate( Fields *iface )
+{
+    FIXME( "%p\n", iface );
+    return E_NOTIMPL;
+}
+
+static const struct FieldsVtbl fields_vtbl =
+{
+    fields_QueryInterface,
+    fields_AddRef,
+    fields_Release,
+    fields_GetTypeInfoCount,
+    fields_GetTypeInfo,
+    fields_GetIDsOfNames,
+    fields_Invoke,
+    fields_get_Count,
+    fields__NewEnum,
+    fields_Refresh,
+    fields_get_Item,
+    fields__Append,
+    fields_Delete,
+    fields_Append,
+    fields_Update,
+    fields_Resync,
+    fields_CancelUpdate
+};
+
+static HRESULT fields_create( struct recordset *recordset, struct fields **ret )
+{
+    struct fields *fields;
+
+    if (!(fields = heap_alloc_zero( sizeof(*fields) ))) return E_OUTOFMEMORY;
+    fields->Fields_iface.lpVtbl = &fields_vtbl;
+    fields->refs = 1;
+    fields->recordset = recordset;
+    _Recordset_AddRef( &fields->recordset->Recordset_iface );
+
+    *ret = fields;
+    TRACE( "returning %p\n", *ret );
+    return S_OK;
+}
+
 static inline struct recordset *impl_from_Recordset( _Recordset *iface )
 {
     return CONTAINING_RECORD( iface, struct recordset, Recordset_iface );
@@ -58,6 +236,7 @@ static ULONG WINAPI recordset_Release( _Recordset *iface )
     if (!refs)
     {
         TRACE( "destroying %p\n", recordset );
+        recordset->fields->recordset = NULL;
         heap_free( recordset );
     }
     return refs;
@@ -199,8 +378,23 @@ static HRESULT WINAPI recordset_get_EOF( _Recordset *iface, VARIANT_BOOL *eof )
 
 static HRESULT WINAPI recordset_get_Fields( _Recordset *iface, Fields **obj )
 {
-    FIXME( "%p, %p\n", iface, obj );
-    return E_NOTIMPL;
+    struct recordset *recordset = impl_from_Recordset( iface );
+    HRESULT hr;
+
+    TRACE( "%p, %p\n", recordset, obj );
+
+    if (recordset->fields)
+    {
+        /* yes, this adds a reference to the recordset instead of the fields object */
+        _Recordset_AddRef( &recordset->Recordset_iface );
+        *obj = &recordset->fields->Fields_iface;
+        return S_OK;
+    }
+
+    if ((hr = fields_create( recordset, &recordset->fields )) != S_OK) return hr;
+
+    *obj = &recordset->fields->Fields_iface;
+    return S_OK;
 }
 
 static HRESULT WINAPI recordset_get_LockType( _Recordset *iface, LockTypeEnum *lock_type )
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c
index 3f297f4ce2..e6371b8392 100644
--- a/dlls/msado15/tests/msado15.c
+++ b/dlls/msado15/tests/msado15.c
@@ -25,6 +25,69 @@
 
 #define MAKE_ADO_HRESULT( err ) MAKE_HRESULT( SEVERITY_ERROR, FACILITY_CONTROL, err )
 
+static LONG get_refs_fields( Fields *fields )
+{
+    Fields_AddRef( fields );
+    return Fields_Release( fields );
+}
+
+static LONG get_refs_recordset( _Recordset *recordset )
+{
+    _Recordset_AddRef( recordset );
+    return _Recordset_Release( recordset );
+}
+
+static void test_Recordset(void)
+{
+    _Recordset *recordset;
+    Fields *fields, *fields2;
+    LONG refs, count;
+    HRESULT hr;
+
+    hr = CoCreateInstance( &CLSID_Recordset, NULL, CLSCTX_INPROC_SERVER, &IID__Recordset, (void **)&recordset );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* handing out fields object increases recordset refcount */
+    refs = get_refs_recordset( recordset );
+    ok( refs == 1, "got %d\n", refs );
+    hr = _Recordset_get_Fields( recordset, &fields );
+    ok( hr == S_OK, "got %08x\n", hr );
+    refs = get_refs_recordset( recordset );
+    ok( refs == 2, "got %d\n", refs );
+    refs = get_refs_fields( fields );
+    ok( refs == 1, "got %d\n", refs );
+
+    /* releasing fields object decreases recordset refcount, but fields refcount doesn't drop to zero */
+    Fields_Release( fields );
+    refs = get_refs_recordset( recordset );
+    ok( refs == 1, "got %d\n", refs );
+    refs = get_refs_fields( fields );
+    ok( refs == 1, "got %d\n", refs );
+
+    /* calling get_Fields again returns the same object with the same refcount and increases recordset refcount  */
+    hr = _Recordset_get_Fields( recordset, &fields2 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    refs = get_refs_recordset( recordset );
+    ok( refs == 2, "got %d\n", refs );
+    refs = get_refs_fields( fields2 );
+    ok( refs == 1, "got %d\n", refs );
+    ok( fields2 == fields, "expected same object\n" );
+    refs = Fields_Release( fields2 );
+    ok( refs == 1, "got %d\n", refs );
+
+    count = -1;
+    hr = Fields_get_Count( fields2, &count );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+    todo_wine ok( !count, "got %d\n", count );
+
+    refs = _Recordset_Release( recordset );
+    ok( !refs, "got %d\n", refs );
+
+    /* fields object still has a reference */
+    refs = Fields_Release( fields2 );
+    ok( refs == 1, "got %d\n", refs );
+}
+
 static HRESULT str_to_byte_array( const char *data, VARIANT *ret )
 {
     SAFEARRAY *vector;
@@ -342,7 +405,8 @@ if (0)   /* Crashes on windows */
 START_TEST(msado15)
 {
     CoInitialize( NULL );
-    test_Stream();
     test_Connection();
+    test_Recordset();
+    test_Stream();
     CoUninitialize();
 }
-- 
2.20.1




More information about the wine-devel mailing list