[PATCH 4/4] ole32: Synthesize dibs or bitmaps as appropriate.

Huw Davies huw at codeweavers.com
Tue May 23 07:11:42 CDT 2017


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/ole32/datacache.c  | 86 +++++++++++++++++++++++++++++++++++++++++++++----
 dlls/ole32/tests/ole2.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 163 insertions(+), 7 deletions(-)

diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c
index d850a34182..420711a1e4 100644
--- a/dlls/ole32/datacache.c
+++ b/dlls/ole32/datacache.c
@@ -297,13 +297,21 @@ static void DataCache_Destroy(
 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
 {
     DataCacheEntry *cache_entry;
+    FORMATETC fmt = *formatetc;
+
+    if (fmt.cfFormat == CF_BITMAP)
+    {
+        fmt.cfFormat = CF_DIB;
+        fmt.tymed = TYMED_HGLOBAL;
+    }
+
     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
     {
         /* FIXME: also compare DVTARGETDEVICEs */
-        if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
-            (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
-            (formatetc->lindex == cache_entry->fmtetc.lindex) &&
-            (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
+        if ((!cache_entry->fmtetc.cfFormat || !fmt.cfFormat || (fmt.cfFormat == cache_entry->fmtetc.cfFormat)) &&
+            (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
+            (fmt.lindex == cache_entry->fmtetc.lindex) &&
+            (!cache_entry->fmtetc.tymed || !fmt.tymed || (fmt.tymed == cache_entry->fmtetc.tymed)))
             return cache_entry;
     }
     return NULL;
@@ -901,11 +909,56 @@ static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
     return S_OK;
 }
 
+static HGLOBAL synthesize_dib( HBITMAP bm )
+{
+    HDC hdc = GetDC( 0 );
+    BITMAPINFOHEADER header;
+    BITMAPINFO *bmi;
+    HGLOBAL ret = 0;
+    DWORD header_size;
+
+    memset( &header, 0, sizeof(header) );
+    header.biSize = sizeof(header);
+    if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
+
+    header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
+    if (!(ret = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
+    bmi = GlobalLock( ret );
+    memset( bmi, 0, header_size );
+    memcpy( bmi, &header, header.biSize );
+    GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
+    GlobalUnlock( ret );
+
+done:
+    ReleaseDC( 0, hdc );
+    return ret;
+}
+
+static HBITMAP synthesize_bitmap( HGLOBAL dib )
+{
+    HBITMAP ret = 0;
+    BITMAPINFO *bmi;
+    HDC hdc = GetDC( 0 );
+
+    if ((bmi = GlobalLock( dib )))
+    {
+        /* FIXME: validate data size */
+        ret = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
+                              (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
+                              bmi, DIB_RGB_COLORS );
+        GlobalUnlock( dib );
+    }
+    ReleaseDC( 0, hdc );
+    return ret;
+}
+
 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
                                       const FORMATETC *formatetc,
-                                      const STGMEDIUM *stgmedium,
+                                      STGMEDIUM *stgmedium,
                                       BOOL fRelease)
 {
+    STGMEDIUM dib_copy;
+
     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
         stgmedium->tymed == TYMED_NULL)
@@ -917,6 +970,17 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
     cache_entry->dirty = TRUE;
     ReleaseStgMedium(&cache_entry->stgmedium);
     cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
+
+    if (formatetc->cfFormat == CF_BITMAP)
+    {
+        dib_copy.tymed = TYMED_HGLOBAL;
+        dib_copy.u.hGlobal = synthesize_dib( stgmedium->u.hBitmap );
+        dib_copy.pUnkForRelease = NULL;
+        if (fRelease) ReleaseStgMedium(stgmedium);
+        stgmedium = &dib_copy;
+        fRelease = TRUE;
+    }
+
     if (fRelease)
     {
         cache_entry->stgmedium = *stgmedium;
@@ -927,7 +991,7 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
                                &cache_entry->stgmedium, stgmedium);
 }
 
-static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
+static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, FORMATETC *fmt, STGMEDIUM *stgmedium)
 {
     if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->stream)
     {
@@ -937,6 +1001,14 @@ static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *st
     }
     if (cache_entry->stgmedium.tymed == TYMED_NULL)
         return OLE_E_BLANK;
+
+    if (fmt->cfFormat == CF_BITMAP)
+    {
+        stgmedium->tymed = TYMED_GDI;
+        stgmedium->u.hBitmap = synthesize_bitmap( cache_entry->stgmedium.u.hGlobal );
+        stgmedium->pUnkForRelease = NULL;
+        return S_OK;
+    }
     return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
 }
 
@@ -1109,7 +1181,7 @@ static HRESULT WINAPI DataCache_GetData(
     if (!cache_entry)
         return OLE_E_BLANK;
 
-    return DataCacheEntry_GetData(cache_entry, pmedium);
+    return DataCacheEntry_GetData(cache_entry, pformatetcIn, pmedium);
 }
 
 static HRESULT WINAPI DataCache_GetDataHere(
diff --git a/dlls/ole32/tests/ole2.c b/dlls/ole32/tests/ole2.c
index 0102ca0f48..394371b03c 100644
--- a/dlls/ole32/tests/ole2.c
+++ b/dlls/ole32/tests/ole2.c
@@ -1993,6 +1993,18 @@ 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;
@@ -2083,12 +2095,33 @@ static void test_data_cache_dib_contents_stream(int num)
     IUnknown_Release( unk );
 }
 
+static void check_bitmap_size( HBITMAP h, int cx, int cy )
+{
+    BITMAP bm;
+
+    GetObjectW( h, sizeof(bm), &bm );
+    ok( bm.bmWidth == cx, "got %d expect %d\n", bm.bmWidth, cx );
+    ok( bm.bmHeight == cy, "got %d expect %d\n", bm.bmHeight, cy );
+}
+
+static void check_dib_size( HGLOBAL h, int cx, int cy )
+{
+    BITMAPINFO *info;
+
+    info = GlobalLock( h );
+    ok( info->bmiHeader.biWidth == cx, "got %d expect %d\n", info->bmiHeader.biWidth, cx );
+    ok( info->bmiHeader.biHeight == cy, "got %d expect %d\n", info->bmiHeader.biHeight, cy );
+    GlobalUnlock( h );
+}
+
 static void test_data_cache_bitmap(void)
 {
     HRESULT hr;
     IOleCache2 *cache;
+    IDataObject *data;
     FORMATETC fmt;
     DWORD conn;
+    STGMEDIUM med;
     STATDATA expect[] =
     {
         {{ CF_DIB,          0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, 0, NULL, 0 },
@@ -2165,6 +2198,57 @@ static void test_data_cache_bitmap(void)
 
     check_enum_cache( cache, expect, 2 );
 
+    /* Try setting a 1x1 bitmap */
+    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;
+
+    hr = IOleCache2_SetData( cache, &fmt, &med, TRUE );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = IDataObject_GetData( data, &fmt, &med );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( med.tymed == TYMED_GDI, "got %d\n", med.tymed );
+    check_bitmap_size( U(med).hBitmap, 1, 1 );
+    ReleaseStgMedium( &med );
+
+    fmt.cfFormat = CF_DIB;
+    fmt.tymed = TYMED_HGLOBAL;
+    hr = IDataObject_GetData( data, &fmt, &med );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( med.tymed == TYMED_HGLOBAL, "got %d\n", med.tymed );
+    check_dib_size( U(med).hGlobal, 1, 1 );
+    ReleaseStgMedium( &med );
+
+    /* Now set a 2x1 dib */
+    fmt.cfFormat = CF_DIB;
+    fmt.tymed = TYMED_HGLOBAL;
+    med.tymed = TYMED_HGLOBAL;
+    U(med).hGlobal = create_dib();
+
+    hr = IOleCache2_SetData( cache, &fmt, &med, TRUE );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    fmt.cfFormat = CF_BITMAP;
+    fmt.tymed = TYMED_GDI;
+    hr = IDataObject_GetData( data, &fmt, &med );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( med.tymed == TYMED_GDI, "got %d\n", med.tymed );
+    check_bitmap_size( U(med).hBitmap, 2, 1 );
+    ReleaseStgMedium( &med );
+
+    fmt.cfFormat = CF_DIB;
+    fmt.tymed = TYMED_HGLOBAL;
+    hr = IDataObject_GetData( data, &fmt, &med );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( med.tymed == TYMED_HGLOBAL, "got %d\n", med.tymed );
+    check_dib_size( U(med).hGlobal, 2, 1 );
+    ReleaseStgMedium( &med );
+
+    IDataObject_Release( data );
     IOleCache2_Release( cache );
 }
 
-- 
2.12.0




More information about the wine-patches mailing list