[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