From 2e363267ebe1a6da518da6f8ac195aa56621bf76 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 23 May 2017 13:11:42 +0100 Subject: [PATCH] ole32: Synthesize dibs or bitmaps as appropriate. Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- 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 d850a341828..420711a1e4e 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 0102ca0f488..394371b03c7 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.11.4.GIT