[PATCH 5/6] ole32: Implement IOleCache2_UpdateCache().

Huw Davies <[email protected]>
Newsgroups gmane.comp.emulators.wine.patches
Message-ID <[email protected]>
Signed-off-by: Huw Davies <[email protected]>
---
 dlls/ole32/datacache.c  | 141 ++++++++++++--
 dlls/ole32/tests/ole2.c | 480 +++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 540 insertions(+), 81 deletions(-)

diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c
index 7a19a171e5..2c5e45134e 100644
--- a/dlls/ole32/datacache.c
+++ b/dlls/ole32/datacache.c
@@ -961,12 +961,33 @@ static HBITMAP synthesize_bitmap( HGLOBAL dib )
     return ret;
 }
 
+static HENHMETAFILE synthesize_emf( HMETAFILEPICT data )
+{
+    METAFILEPICT *pict;
+    HENHMETAFILE emf = 0;
+    UINT size;
+    void *bits;
+
+    if (!(pict = GlobalLock( data ))) return 0;
+
+    size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
+    if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
+    {
+        GetMetaFileBitsEx( pict->hMF, size, bits );
+        emf = SetWinMetaFileBits( size, bits, NULL, pict );
+        HeapFree( GetProcessHeap(), 0, bits );
+    }
+
+    GlobalUnlock( data );
+    return emf;
+}
+
 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
                                       const FORMATETC *formatetc,
                                       STGMEDIUM *stgmedium,
                                       BOOL fRelease)
 {
-    STGMEDIUM dib_copy;
+    STGMEDIUM copy;
 
     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
@@ -981,11 +1002,19 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
 
     if (formatetc->cfFormat == CF_BITMAP)
     {
-        dib_copy.tymed = TYMED_HGLOBAL;
-        dib_copy.u.hGlobal = synthesize_dib( stgmedium->u.hBitmap );
-        dib_copy.pUnkForRelease = NULL;
+        copy.tymed = TYMED_HGLOBAL;
+        copy.u.hGlobal = synthesize_dib( stgmedium->u.hBitmap );
+        copy.pUnkForRelease = NULL;
+        if (fRelease) ReleaseStgMedium(stgmedium);
+        stgmedium = &copy;
+        fRelease = TRUE;
+    }
+    else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE)
+    {
+        copy.tymed = TYMED_ENHMF;
+        copy.u.hEnhMetaFile = synthesize_emf( stgmedium->u.hMetaFilePict );
         if (fRelease) ReleaseStgMedium(stgmedium);
-        stgmedium = &dib_copy;
+        stgmedium = &copy;
         fRelease = TRUE;
     }
 
@@ -2381,14 +2410,102 @@ static HRESULT WINAPI DataCache_IOleCache2_SetData(
     return OLE_E_BLANK;
 }
 
-static HRESULT WINAPI DataCache_UpdateCache(
-            IOleCache2*     iface,
-	    LPDATAOBJECT    pDataObject,
-	    DWORD           grfUpdf,
-	    LPVOID          pReserved)
+static BOOL entry_updateable( DataCacheEntry *entry, DWORD mode )
 {
-  FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
-  return E_NOTIMPL;
+    BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL;
+
+    if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE;
+
+    if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE;
+    if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE;
+    if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE;
+    if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE;
+    if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE;
+
+    return FALSE;
+}
+
+static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data,
+                                             DWORD mode, void *reserved )
+{
+    DataCache *This = impl_from_IOleCache2(iface);
+    DataCacheEntry *cache_entry;
+    STGMEDIUM med;
+    HRESULT hr = S_OK;
+    CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP };
+    FORMATETC fmt;
+    int i, slots = 0;
+    BOOL done_one = FALSE;
+
+    TRACE( "(%p %p %08x %p)\n", iface, data, mode, reserved );
+
+    LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
+    {
+        slots++;
+
+        if (!entry_updateable( cache_entry, mode ))
+        {
+            done_one = TRUE;
+            continue;
+        }
+
+        fmt = cache_entry->fmtetc;
+
+        if (fmt.cfFormat)
+        {
+            hr = IDataObject_GetData( data, &fmt, &med );
+            if (hr != S_OK && fmt.cfFormat == CF_DIB)
+            {
+                fmt.cfFormat = CF_BITMAP;
+                fmt.tymed = TYMED_GDI;
+                hr = IDataObject_GetData( data, &fmt, &med );
+            }
+            if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE)
+            {
+                fmt.cfFormat = CF_METAFILEPICT;
+                fmt.tymed = TYMED_MFPICT;
+                hr = IDataObject_GetData( data, &fmt, &med );
+            }
+            if (hr == S_OK)
+            {
+                hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
+                if (hr != S_OK) ReleaseStgMedium( &med );
+                else done_one = TRUE;
+            }
+        }
+        else
+        {
+            for (i = 0; i < sizeof(view_list) / sizeof(view_list[0]); i++)
+            {
+                fmt.cfFormat = view_list[i];
+                fmt.tymed = tymed_from_cf( fmt.cfFormat );
+                hr = IDataObject_QueryGetData( data, &fmt );
+                if (hr == S_OK)
+                {
+                    hr = IDataObject_GetData( data, &fmt, &med );
+                    if (hr == S_OK)
+                    {
+                        if (fmt.cfFormat == CF_BITMAP)
+                        {
+                            cache_entry->fmtetc.cfFormat = CF_DIB;
+                            cache_entry->fmtetc.tymed = TYMED_HGLOBAL;
+                        }
+                        else
+                        {
+                            cache_entry->fmtetc.cfFormat = fmt.cfFormat;
+                            cache_entry->fmtetc.tymed = fmt.tymed;
+                        }
+                        hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
+                        if (hr != S_OK) ReleaseStgMedium( &med );
+                        else done_one = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED;
 }
 
 static HRESULT WINAPI DataCache_DiscardCache(
diff --git a/dlls/ole32/tests/ole2.c b/dlls/ole32/tests/ole2.c
index aaee6773d8..9b96570999 100644
--- a/dlls/ole32/tests/ole2.c
+++ b/dlls/ole32/tests/ole2.c
@@ -112,6 +112,7 @@ struct expected_method
 {
     const char *method;
     unsigned int flags;
+    FORMATETC fmt;
 };
 
 static const struct expected_method *expected_method_list;
@@ -124,6 +125,8 @@ static HRESULT g_QIFailsWith;
 
 static UINT cf_test_1, cf_test_2, cf_test_3;
 
+static FORMATETC *g_dataobject_fmts;
+
 /****************************************************************************
  * PresentationDataHeader
  *
@@ -150,27 +153,43 @@ typedef struct PresentationDataHeader
     DWORD dwSize;
 } PresentationDataHeader;
 
-#define CHECK_EXPECTED_METHOD(method_name) \
-    do { \
-        trace("%s\n", method_name); \
-        ok(expected_method_list->method != NULL, "Extra method %s called\n", method_name); \
-        if (!strcmp(expected_method_list->method, "WINE_EXTRA")) \
-        { \
-            todo_wine ok(0, "Too many method calls.\n"); \
-            break; \
-        } \
-        if (expected_method_list->method) \
-        { \
-            while (expected_method_list->flags & TEST_OPTIONAL && \
-                   strcmp(expected_method_list->method, method_name) != 0) \
-                expected_method_list++; \
-            todo_wine_if (expected_method_list->flags & TEST_TODO) \
-                ok(!strcmp(expected_method_list->method, method_name), \
-                   "Expected %s to be called instead of %s\n", \
-                   expected_method_list->method, method_name); \
-            expected_method_list++; \
-        } \
-    } while(0)
+static void inline check_expected_method_fmt(const char *method_name, const FORMATETC *fmt)
+{
+    trace("%s\n", method_name);
+    ok(expected_method_list->method != NULL, "Extra method %s called\n", method_name);
+    if (!strcmp(expected_method_list->method, "WINE_EXTRA"))
+    {
+        todo_wine ok(0, "Too many method calls.\n");
+        return;
+    }
+    if (expected_method_list->method)
+    {
+        while (expected_method_list->flags & TEST_OPTIONAL &&
+               strcmp(expected_method_list->method, method_name) != 0)
+            expected_method_list++;
+        todo_wine_if (expected_method_list->flags & TEST_TODO)
+        {
+            ok(!strcmp(expected_method_list->method, method_name),
+               "Expected %s to be called instead of %s\n",
+               expected_method_list->method, method_name);
+            if (fmt)
+            {
+                ok(fmt->cfFormat == expected_method_list->fmt.cfFormat, "got cf %04x vs %04x\n",
+                   fmt->cfFormat, expected_method_list->fmt.cfFormat );
+                ok(fmt->dwAspect == expected_method_list->fmt.dwAspect, "got aspect %d vs %d\n",
+                   fmt->dwAspect, expected_method_list->fmt.dwAspect );
+                ok(fmt->lindex == expected_method_list->fmt.lindex, "got lindex %d vs %d\n",
+                   fmt->lindex, expected_method_list->fmt.lindex );
+                ok(fmt->tymed == expected_method_list->fmt.tymed, "got tymed %d vs %d\n",
+                   fmt->tymed, expected_method_list->fmt.tymed );
+            }
+        }
+        expected_method_list++;
+    }
+}
+
+#define CHECK_EXPECTED_METHOD(method_name) check_expected_method_fmt(method_name, NULL)
+#define CHECK_EXPECTED_METHOD_FMT(method_name, fmt) check_expected_method_fmt(method_name, fmt)
 
 #define CHECK_NO_EXTRA_METHODS() \
     do { \
@@ -179,6 +198,41 @@ typedef struct PresentationDataHeader
         ok(!expected_method_list->method, "Method sequence starting from %s not called\n", expected_method_list->method); \
     } while (0)
 
+/* 2 x 1 x 32 bpp dib. PelsPerMeter = 200x400 */
+static BYTE dib[] =
+{
+    0x42, 0x4d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
+
+    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00,
+    0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void create_dib( STGMEDIUM *med )
+{
+    void *ptr;
+
+    med->tymed = TYMED_HGLOBAL;
+    U(med)->hGlobal = GlobalAlloc( GMEM_MOVEABLE, sizeof(dib) - sizeof(BITMAPFILEHEADER) );
+    ptr = GlobalLock( U(med)->hGlobal );
+    memcpy( ptr, dib + sizeof(BITMAPFILEHEADER), sizeof(dib) - sizeof(BITMAPFILEHEADER) );
+    GlobalUnlock( U(med)->hGlobal );
+    med->pUnkForRelease = NULL;
+}
+
+static void create_bitmap( STGMEDIUM *med )
+{
+    med->tymed = TYMED_GDI;
+    U(med)->hBitmap = CreateBitmap( 1, 1, 1, 1, NULL );
+    med->pUnkForRelease = NULL;
+}
+
 static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv)
 {
     CHECK_EXPECTED_METHOD("OleObject_QueryInterface");
@@ -1385,13 +1439,40 @@ static ULONG WINAPI DataObject_Release(
     return 1;
 }
 
-static HRESULT WINAPI DataObject_GetData(
-        IDataObject*     iface,
-        LPFORMATETC      pformatetcIn,
-        STGMEDIUM*       pmedium)
+static inline BOOL fmtetc_equal( const FORMATETC *a, const FORMATETC *b )
 {
-    CHECK_EXPECTED_METHOD("DataObject_GetData");
-    return E_NOTIMPL;
+    /* FIXME ptd */
+    return a->cfFormat == b->cfFormat && a->dwAspect == b->dwAspect &&
+        a->lindex == b->lindex && a->tymed == b->tymed;
+
+}
+
+static HRESULT WINAPI DataObject_GetData( IDataObject *iface, FORMATETC *fmt_in,
+                                          STGMEDIUM *med )
+{
+    FORMATETC *fmt;
+
+    CHECK_EXPECTED_METHOD_FMT("DataObject_GetData", fmt_in);
+
+    for (fmt = g_dataobject_fmts; fmt && fmt->cfFormat != 0; fmt++)
+    {
+        if (fmtetc_equal( fmt_in, fmt ))
+        {
+            switch (fmt->cfFormat)
+            {
+            case CF_DIB:
+                create_dib( med );
+                return S_OK;
+            case CF_BITMAP:
+                create_bitmap( med );
+                return S_OK;
+            default:
+                trace( "unhandled fmt %d\n", fmt->cfFormat );
+            }
+        }
+    }
+
+    return S_FALSE;
 }
 
 static HRESULT WINAPI DataObject_GetDataHere(
@@ -1403,12 +1484,16 @@ static HRESULT WINAPI DataObject_GetDataHere(
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI DataObject_QueryGetData(
-        IDataObject*     iface,
-        LPFORMATETC      pformatetc)
+static HRESULT WINAPI DataObject_QueryGetData( IDataObject *iface, FORMATETC *fmt_in )
 {
-    CHECK_EXPECTED_METHOD("DataObject_QueryGetData");
-    return S_OK;
+    FORMATETC *fmt;
+
+    CHECK_EXPECTED_METHOD_FMT("DataObject_QueryGetData", fmt_in);
+
+    for (fmt = g_dataobject_fmts; fmt && fmt->cfFormat != 0; fmt++)
+        if (fmtetc_equal( fmt_in, fmt )) return S_OK;
+
+    return S_FALSE;
 }
 
 static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
@@ -1601,9 +1686,9 @@ static void test_data_cache(void)
         { "draw_continue", 1 },
         { "draw_continue", 1 },
         { "draw_continue", 1 },
-        { "DataObject_GetData", 0 },
-        { "DataObject_GetData", 0 },
-        { "DataObject_GetData", 0 },
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_THUMBNAIL, -1, TYMED_HGLOBAL} },
+        { "DataObject_GetData", 0, { CF_BITMAP,       NULL, DVASPECT_THUMBNAIL, -1, TYMED_GDI} },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_ICON,      -1, TYMED_MFPICT} },
         { NULL, 0 }
     };
     static const struct expected_method methods_cachethenrun[] =
@@ -1611,7 +1696,6 @@ static void test_data_cache(void)
         { "DataObject_DAdvise", 0 },
         { "DataObject_DAdvise", 0 },
         { "DataObject_DAdvise", 0 },
-        { "DataObject_QueryGetData", 1 }, /* called by win9x and nt4 */
         { "DataObject_DAdvise", 0 },
         { "DataObject_DUnadvise", 0 },
         { "DataObject_DUnadvise", 0 },
@@ -1961,22 +2045,6 @@ static void test_data_cache(void)
 
 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
 
-/* 2 x 1 x 32 bpp dib. PelsPerMeter = 200x400 */
-static BYTE dib[] =
-{
-    0x42, 0x4d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
-
-    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
-    0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00,
-    0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
 static IStorage *create_storage( int num )
 {
     IStorage *stg;
@@ -2001,18 +2069,6 @@ static IStorage *create_storage( int num )
     return stg;
 }
 
-static HGLOBAL create_dib( void )
-{
-    HGLOBAL h;
-    void *ptr;
-
-    h = GlobalAlloc( GMEM_MOVEABLE, sizeof(dib) - sizeof(BITMAPFILEHEADER) );
-    ptr = GlobalLock( h );
-    memcpy( ptr, dib + sizeof(BITMAPFILEHEADER), sizeof(dib) - sizeof(BITMAPFILEHEADER) );
-    GlobalUnlock( h );
-    return h;
-}
-
 static void test_data_cache_dib_contents_stream(int num)
 {
     HRESULT hr;
@@ -2220,9 +2276,7 @@ static void test_data_cache_cache(void)
     hr = IOleCache2_QueryInterface( cache, &IID_IDataObject, (void **) &data );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    med.tymed = TYMED_GDI;
-    U(med).hBitmap = CreateBitmap( 1, 1, 1, 1, NULL );
-    med.pUnkForRelease = NULL;
+    create_bitmap( &med );
 
     hr = IOleCache2_SetData( cache, &fmt, &med, TRUE );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -2244,8 +2298,7 @@ static void test_data_cache_cache(void)
     /* Now set a 2x1 dib */
     fmt.cfFormat = CF_DIB;
     fmt.tymed = TYMED_HGLOBAL;
-    med.tymed = TYMED_HGLOBAL;
-    U(med).hGlobal = create_dib();
+    create_dib( &med );
 
     hr = IOleCache2_SetData( cache, &fmt, &med, TRUE );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -2503,6 +2556,294 @@ static void test_data_cache_initnew(void)
     IOleCache2_Release( cache );
 }
 
+static void test_data_cache_updatecache( void )
+{
+    HRESULT hr;
+    IOleCache2 *cache;
+    FORMATETC fmt;
+    DWORD conn[4];
+
+    static const struct expected_method methods_dib[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData", 0, { CF_BITMAP,       NULL, DVASPECT_CONTENT, -1, TYMED_GDI } },
+        { NULL }
+    };
+
+    static const struct expected_method methods_dib_emf[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData", 0, { CF_ENHMETAFILE,  NULL, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
+        { NULL }
+    };
+    static const struct expected_method methods_dib_wmf[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
+        { NULL }
+    };
+    static const struct expected_method methods_viewcache[] =
+    {
+        { "DataObject_QueryGetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
+        { "DataObject_QueryGetData", 0, { CF_ENHMETAFILE,  NULL, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
+        { "DataObject_QueryGetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { "DataObject_QueryGetData", 0, { CF_BITMAP,       NULL, DVASPECT_CONTENT, -1, TYMED_GDI } },
+        { NULL }
+    };
+    static const struct expected_method methods_viewcache_with_dib[] =
+    {
+        { "DataObject_QueryGetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
+        { "DataObject_QueryGetData", 0, { CF_ENHMETAFILE,  NULL, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
+        { "DataObject_QueryGetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData",      0, { CF_DIB,          NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
+        { NULL }
+    };
+    static const struct expected_method methods_flags_all[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT,   -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData", 0, { CF_ENHMETAFILE,  NULL, DVASPECT_CONTENT,   -1, TYMED_ENHMF } },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT,   -1, TYMED_MFPICT } },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT,   -1, TYMED_MFPICT } },
+        { NULL }
+    };
+    static const struct expected_method methods_flags_ifblank_1[] =
+    {
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT,   -1, TYMED_MFPICT } },
+        { NULL }
+    };
+    static const struct expected_method methods_flags_ifblank_2[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT,   -1, TYMED_HGLOBAL } },
+        { "DataObject_GetData", 0, { CF_METAFILEPICT, NULL, DVASPECT_CONTENT,   -1, TYMED_MFPICT } },
+        { NULL }
+    };
+    static const struct expected_method methods_flags_normal[] =
+    {
+        { "DataObject_GetData", 0, { CF_DIB,          NULL, DVASPECT_CONTENT,   -1, TYMED_HGLOBAL } },
+        { NULL }
+    };
+    static const struct expected_method methods_empty[] =
+    {
+        { NULL }
+    };
+
+    static STATDATA view_cache[] =
+    {
+        {{ 0,          0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, 0, NULL, 0 }
+    };
+    static STATDATA view_cache_after_dib[] =
+    {
+        {{ CF_DIB,          0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, 0, NULL, 0 },
+        {{ CF_BITMAP,       0, DVASPECT_CONTENT, -1, TYMED_GDI },     0, NULL, 0 }
+    };
+
+    static FORMATETC dib_fmt[] =
+    {
+        { CF_DIB,       NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
+        { 0 }
+    };
+
+    hr = CreateDataCache( NULL, &CLSID_WineTestOld, &IID_IOleCache2, (void **)&cache );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* No cache slots */
+    g_dataobject_fmts = NULL;
+    expected_method_list = NULL;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* A dib cache slot */
+    fmt.cfFormat = CF_DIB;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_HGLOBAL;
+
+    hr = IOleCache2_Cache( cache, &fmt, 0, &conn[0] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    expected_method_list = methods_dib;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == CACHE_E_NOCACHE_UPDATED, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    /* Now with a dib available */
+    g_dataobject_fmts = dib_fmt;
+    expected_method_list = methods_dib;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* Add an EMF cache slot */
+    fmt.cfFormat = CF_ENHMETAFILE;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_ENHMF;
+
+    hr = IOleCache2_Cache( cache, &fmt, 0, &conn[1] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    g_dataobject_fmts = dib_fmt;
+    expected_method_list = methods_dib_emf;
+
+    /* Two slots to fill, only the dib will succeed */
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    /* Replace the emf slot with a wmf */
+    hr = IOleCache2_Uncache( cache, conn[1] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    fmt.cfFormat = CF_METAFILEPICT;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_MFPICT;
+
+    hr = IOleCache2_Cache( cache, &fmt, 0, &conn[1] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    g_dataobject_fmts = dib_fmt;
+    expected_method_list = methods_dib_wmf;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = IOleCache2_Uncache( cache, conn[1] );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = IOleCache2_Uncache( cache, conn[0] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* View caching */
+    fmt.cfFormat = 0;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_HGLOBAL;
+
+    hr = IOleCache2_Cache( cache, &fmt, 0, &conn[0] );
+    ok( hr == S_OK, "got %08x\n", hr );
+    view_cache[0].dwConnection = conn[0];
+
+    g_dataobject_fmts = NULL;
+    expected_method_list = methods_viewcache;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == CACHE_E_NOCACHE_UPDATED, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+    check_enum_cache( cache, view_cache, 1 );
+
+    g_dataobject_fmts = dib_fmt;
+    expected_method_list = methods_viewcache_with_dib;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+    view_cache_after_dib[0].dwConnection = view_cache_after_dib[1].dwConnection = view_cache[0].dwConnection;
+    check_enum_cache( cache, view_cache_after_dib, 2 );
+
+    hr = IOleCache2_Uncache( cache, conn[0] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* Try some different flags */
+
+    fmt.cfFormat = CF_DIB;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_HGLOBAL;
+
+    hr = IOleCache2_Cache( cache, &fmt, 0, &conn[0] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    fmt.cfFormat = CF_ENHMETAFILE;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_ENHMF;
+
+    hr = IOleCache2_Cache( cache, &fmt, ADVF_NODATA, &conn[1] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    fmt.cfFormat = CF_METAFILEPICT;
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_MFPICT;
+
+    hr = IOleCache2_Cache( cache, &fmt, ADVFCACHE_ONSAVE, &conn[2] );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    g_dataobject_fmts = dib_fmt;
+    expected_method_list = methods_flags_all;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    expected_method_list = methods_flags_all;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    expected_method_list = methods_flags_ifblank_1;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_IFBLANK , NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    hr = IOleCache2_DiscardCache( cache, DISCARDCACHE_NOSAVE );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    expected_method_list = methods_flags_ifblank_2;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_IFBLANK , NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    hr = IOleCache2_DiscardCache( cache, DISCARDCACHE_NOSAVE );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    expected_method_list = methods_flags_all;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_IFBLANK | UPDFCACHE_NODATACACHE, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    expected_method_list = methods_empty;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ONLYIFBLANK | UPDFCACHE_NORMALCACHE, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    hr = IOleCache2_DiscardCache( cache, DISCARDCACHE_NOSAVE );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    expected_method_list = methods_flags_normal;
+
+    hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ONLYIFBLANK | UPDFCACHE_NORMALCACHE, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    CHECK_NO_EXTRA_METHODS();
+
+    IOleCache2_Release( cache );
+}
+
 static void test_default_handler(void)
 {
     HRESULT hr;
@@ -3833,6 +4174,7 @@ START_TEST(ole2)
     test_data_cache_cache();
     test_data_cache_init();
     test_data_cache_initnew();
+    test_data_cache_updatecache();
     test_default_handler();
     test_runnable();
     test_OleRun();
-- 
2.12.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.