From b44b1afb813634b7e4da9cf79cd4e393a355f3ca Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sat, 20 Jan 2018 12:58:03 +0100 Subject: [PATCH] [OLE32_WINETEST] Sync with Wine 3.0. CORE-14225 --- .../rostests/winetests/ole32/hglobalstream.c | 230 --- modules/rostests/winetests/ole32/marshal.c | 8 +- modules/rostests/winetests/ole32/ole2.c | 1649 +++++++++++++++-- modules/rostests/winetests/ole32/usrmarshal.c | 201 +- 4 files changed, 1631 insertions(+), 457 deletions(-) diff --git a/modules/rostests/winetests/ole32/hglobalstream.c b/modules/rostests/winetests/ole32/hglobalstream.c index 8789623869c..9974cd32005 100644 --- a/modules/rostests/winetests/ole32/hglobalstream.c +++ b/modules/rostests/winetests/ole32/hglobalstream.c @@ -2,7 +2,6 @@ * Stream on HGLOBAL Tests * * Copyright 2006 Robert Shearman (for CodeWeavers) - * Copyright 2016 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -501,240 +500,11 @@ static void test_freed_hglobal(void) IStream_Release(pStream); } -static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos) -{ - HRESULT hr; - STATSTG stat; - LARGE_INTEGER offset; - ULARGE_INTEGER newpos; - - *hmem = 0; - *size = *pos = -1; - - hr = GetHGlobalFromStream(stream, hmem); - ok(hr == S_OK, "unexpected %#x\n", hr); - - memset(&stat, 0x55, sizeof(stat)); - hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT); - ok(hr == S_OK, "unexpected %#x\n", hr); - ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type); - ok(!stat.pwcsName, "unexpected %p\n", stat.pwcsName); - ok(IsEqualIID(&stat.clsid, &GUID_NULL), "unexpected %s\n", wine_dbgstr_guid(&stat.clsid)); - ok(!stat.cbSize.HighPart, "unexpected %#x\n", stat.cbSize.HighPart); - *size = stat.cbSize.LowPart; - - offset.QuadPart = 0; - hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &newpos); - ok(hr == S_OK, "unexpected %#x\n", hr); - ok(!newpos.HighPart, "unexpected %#x\n", newpos.HighPart); - *pos = newpos.LowPart; -} - -static void test_IStream_Clone(void) -{ - static const char hello[] = "Hello World!"; - char buf[32]; - HRESULT hr; - IStream *stream, *clone; - HGLOBAL orig_hmem, hmem, hmem_clone; - ULARGE_INTEGER newsize; - LARGE_INTEGER offset; - int size, pos, ret; - - /* test simple case for Clone */ - orig_hmem = GlobalAlloc(GMEM_MOVEABLE, 0); - ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); - hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); - ok(hr == S_OK, "unexpected %#x\n", hr); - - hr = GetHGlobalFromStream(stream, NULL); - ok(hr == E_INVALIDARG, "unexpected %#x\n", hr); - - hr = GetHGlobalFromStream(NULL, &hmem); - ok(hr == E_INVALIDARG, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem == orig_hmem, "handles should match\n"); - ok(size == 0, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - hr = IStream_Clone(stream, &clone); - ok(hr == S_OK, "unexpected %#x\n", hr); - - hr = IStream_Write(stream, hello, sizeof(hello), NULL); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(size == 13, "unexpected %d\n", size); - ok(pos == 13, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 13, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - buf[0] = 0; - hr = IStream_Read(clone, buf, sizeof(buf), NULL); - ok(hr == S_OK, "unexpected %#x\n", hr); - ok(!strcmp(buf, hello), "wrong stream contents\n"); - - newsize.QuadPart = 0x8000; - hr = IStream_SetSize(stream, newsize); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(hmem == orig_hmem, "unexpected %p\n", hmem); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 13, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 13, "unexpected %d\n", pos); - - IStream_Release(clone); - IStream_Release(stream); - - /* exploit GMEM_FIXED forced move for the same base streams */ - orig_hmem = GlobalAlloc(GMEM_FIXED, 1); - ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); - hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); - ok(hr == S_OK, "unexpected %#x\n", hr); - - hr = IStream_Clone(stream, &clone); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(size == 1, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 1, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - newsize.QuadPart = 0x8000; - hr = IStream_SetSize(stream, newsize); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(hmem != orig_hmem, "unexpected %p\n", hmem); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - IStream_Release(stream); - IStream_Release(clone); - - /* exploit GMEM_FIXED forced move for different base streams */ - orig_hmem = GlobalAlloc(GMEM_FIXED, 1); - ok(orig_hmem != 0, "unexpected %p\n", orig_hmem); - hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream); - ok(hr == S_OK, "unexpected %#x\n", hr); - - hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &clone); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(size == 1, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 1, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - newsize.QuadPart = 0x8000; - hr = IStream_SetSize(stream, newsize); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(hmem != orig_hmem, "unexpected %p\n", hmem); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone != hmem, "handles should not match\n"); - ok(size == 1, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - IStream_Release(stream); - /* releasing clone leads to test termination under windows - IStream_Release(clone); - */ - - /* test Release for a being cloned stream */ - hr = CreateStreamOnHGlobal(0, TRUE, &stream); - ok(hr == S_OK, "unexpected %#x\n", hr); - - hr = IStream_Clone(stream, &clone); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(stream, &hmem, &size, &pos); - ok(hmem != 0, "unexpected %p\n", hmem); - ok(size == 0, "unexpected %d\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - ret = IStream_Release(stream); - ok(ret == 0, "unexpected %d\n", ret); - - newsize.QuadPart = 0x8000; - hr = IStream_SetSize(clone, newsize); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 0, "unexpected %d\n", pos); - - hr = IStream_Write(clone, hello, sizeof(hello), NULL); - ok(hr == S_OK, "unexpected %#x\n", hr); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 13, "unexpected %d\n", pos); - - offset.QuadPart = 0; - hr = IStream_Seek(clone, offset, STREAM_SEEK_SET, NULL); - ok(hr == S_OK, "unexpected %#x\n", hr); - - buf[0] = 0; - hr = IStream_Read(clone, buf, sizeof(buf), NULL); - ok(hr == S_OK, "unexpected %#x\n", hr); - ok(!strcmp(buf, hello), "wrong stream contents\n"); - - stream_info(clone, &hmem_clone, &size, &pos); - ok(hmem_clone == hmem, "handles should match\n"); - ok(size == 0x8000, "unexpected %#x\n", size); - ok(pos == 32, "unexpected %d\n", pos); - - ret = IStream_Release(clone); - ok(ret == 0, "unexpected %d\n", ret); -} - START_TEST(hglobalstream) { HRESULT hr; IStream *pStream; - test_IStream_Clone(); - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); ok_ole_success(hr, "CreateStreamOnHGlobal"); diff --git a/modules/rostests/winetests/ole32/marshal.c b/modules/rostests/winetests/ole32/marshal.c index 10564cd536b..2a29e66efeb 100644 --- a/modules/rostests/winetests/ole32/marshal.c +++ b/modules/rostests/winetests/ole32/marshal.c @@ -2955,6 +2955,12 @@ static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid) hr = CoDisconnectObject((IUnknown *)iface, 0); ok(hr == S_OK, "got %08x\n", hr); + /* Initialize and uninitialize the apartment to show that we + * remain in the autojoined mta */ + hr = pCoInitializeEx( NULL, COINIT_MULTITHREADED ); + ok( hr == S_FALSE, "got %08x\n", hr ); + CoUninitialize(); + return S_OK; } @@ -3736,7 +3742,7 @@ START_TEST(marshal) argc = winetest_get_mainargs( &argv ); if (argc > 2 && (!strcmp(argv[2], "-Embedding"))) { - pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + pCoInitializeEx(NULL, COINIT_MULTITHREADED); test_register_local_server(); CoUninitialize(); diff --git a/modules/rostests/winetests/ole32/ole2.c b/modules/rostests/winetests/ole32/ole2.c index 288517c7d97..d6dafc0f630 100644 --- a/modules/rostests/winetests/ole32/ole2.c +++ b/modules/rostests/winetests/ole32/ole2.c @@ -2,6 +2,7 @@ * Object Linking and Embedding Tests * * Copyright 2005 Robert Shearman + * Copyright 2017 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -56,9 +57,15 @@ DEFINE_GUID(CLSID_Picture_EnhMetafile,0x319,0,0,0xc0,0,0,0,0,0,0,0x46); DEFINE_EXPECT(Storage_Stat); DEFINE_EXPECT(Storage_OpenStream_CompObj); +DEFINE_EXPECT(Storage_OpenStream_OlePres); DEFINE_EXPECT(Storage_SetClass); DEFINE_EXPECT(Storage_CreateStream_CompObj); +DEFINE_EXPECT(Storage_CreateStream_OlePres); DEFINE_EXPECT(Storage_OpenStream_Ole); +DEFINE_EXPECT(Storage_DestroyElement); + +static const CLSID *Storage_SetClass_CLSID; +static int Storage_DestroyElement_limit; static IPersistStorage OleObjectPersistStg; static IOleCache *cache; @@ -95,6 +102,7 @@ struct expected_method { const char *method; unsigned int flags; + FORMATETC fmt; }; static const struct expected_method *expected_method_list; @@ -107,6 +115,8 @@ static HRESULT g_QIFailsWith; static UINT cf_test_1, cf_test_2, cf_test_3; +static FORMATETC *g_dataobject_fmts; + /**************************************************************************** * PresentationDataHeader * @@ -123,7 +133,8 @@ typedef struct PresentationDataHeader * DWORD length; * CHAR format_name[length]; (null-terminated) */ - DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ + DWORD tdSize; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD) + then there are tdSize - sizeof(DWORD) more bytes before dvAspect */ DVASPECT dvAspect; DWORD lindex; DWORD advf; @@ -133,27 +144,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 inline void 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 { \ @@ -162,6 +189,64 @@ 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 const BYTE dib[] = +{ + 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) ); + ptr = GlobalLock( U(med)->hGlobal ); + memcpy( ptr, dib, sizeof(dib) ); + 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 void create_emf(STGMEDIUM *med) +{ + HDC hdc = CreateEnhMetaFileW(NULL, NULL, NULL, NULL); + + Rectangle(hdc, 0, 0, 150, 300); + med->tymed = TYMED_ENHMF; + U(med)->hEnhMetaFile = CloseEnhMetaFile(hdc); + med->pUnkForRelease = NULL; +} + +static void create_mfpict(STGMEDIUM *med) +{ + METAFILEPICT *mf; + HDC hdc = CreateMetaFileW(NULL); + + Rectangle(hdc, 0, 0, 100, 200); + + med->tymed = TYMED_MFPICT; + U(med)->hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); + mf = GlobalLock(U(med)->hMetaFilePict); + mf->mm = MM_ANISOTROPIC; + mf->xExt = 100; + mf->yExt = 200; + mf->hMF = CloseMetaFile(hdc); + GlobalUnlock(U(med)->hMetaFilePict); + med->pUnkForRelease = NULL; +} + static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv) { CHECK_EXPECTED_METHOD("OleObject_QueryInterface"); @@ -1213,7 +1298,7 @@ static void test_OleLoad(IStorage *pStorage) break; } - header.unknown3 = 4; + header.tdSize = sizeof(header.tdSize); header.dvAspect = DVASPECT_CONTENT; header.lindex = -1; header.advf = 1 << i; @@ -1368,13 +1453,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( @@ -1386,12 +1498,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( @@ -1550,7 +1666,7 @@ static void test_data_cache(void) IOleCache2 *pOleCache; IOleCache *olecache; IStorage *pStorage; - IUnknown *unk; + IUnknown *unk, *unk2; IPersistStorage *pPS; IViewObject *pViewObject; IOleCacheControl *pOleCacheControl; @@ -1584,9 +1700,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[] = @@ -1594,7 +1710,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 }, @@ -1641,10 +1756,12 @@ static void test_data_cache(void) ok(hr == S_OK, "got 0x%08x\n", hr); hr = IUnknown_QueryInterface(unk, &IID_IOleCache2, (void**)&pOleCache); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { + hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void**)&unk2); + ok(hr == S_OK, "got 0x%08x\n", hr); ok(unk == (IUnknown*)olecache, "got %p, expected %p\n", olecache, unk); ok(unk == (IUnknown*)pOleCache, "got %p, expected %p\n", pOleCache, unk); -} + ok(unk == unk2, "got %p, expected %p\n", unk2, unk); + IUnknown_Release(unk2); IOleCache2_Release(pOleCache); IOleCache_Release(olecache); IUnknown_Release(unk); @@ -1860,18 +1977,14 @@ todo_wine { DeleteDC(hdcMem); - todo_wine { hr = IOleCache2_InitCache(pOleCache, &DataObject); ok(hr == CACHE_E_NOCACHE_UPDATED, "IOleCache_InitCache should have returned CACHE_E_NOCACHE_UPDATED instead of 0x%08x\n", hr); - } IPersistStorage_Release(pPS); IViewObject_Release(pViewObject); IOleCache2_Release(pOleCache); - todo_wine { CHECK_NO_EXTRA_METHODS(); - } hr = CreateDataCache(NULL, &CLSID_NULL, &IID_IOleCache2, (LPVOID *)&pOleCache); ok_ole_success(hr, "CreateDataCache"); @@ -1939,21 +2052,17 @@ todo_wine { IStorage_Release(pStorage); } - 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[] = +static BYTE file_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 }; @@ -1973,27 +2082,15 @@ static IStorage *create_storage( int num ) ok( hr == S_OK, "got %08x\n", hr); if (num == 1) /* Set biXPelsPerMeter = 0 */ { - dib[0x26] = 0; - dib[0x27] = 0; + file_dib[0x26] = 0; + file_dib[0x27] = 0; } - hr = IStream_Write( stm, dib, sizeof(dib), &written ); + hr = IStream_Write( stm, file_dib, sizeof(file_dib), &written ); ok( hr == S_OK, "got %08x\n", hr); IStream_Release( stm ); 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; @@ -2043,7 +2140,7 @@ static void test_data_cache_dib_contents_stream(int num) "got %lu\n", GlobalSize( U(med).hGlobal ) ); ptr = GlobalLock( U(med).hGlobal ); - expect_info = *(BITMAPINFOHEADER *)(dib + sizeof(BITMAPFILEHEADER)); + expect_info = *(BITMAPINFOHEADER *)(file_dib + sizeof(BITMAPFILEHEADER)); if (expect_info.biXPelsPerMeter == 0 || expect_info.biYPelsPerMeter == 0) { HDC hdc = GetDC( 0 ); @@ -2052,8 +2149,8 @@ static void test_data_cache_dib_contents_stream(int num) ReleaseDC( 0, hdc ); } ok( !memcmp( ptr, &expect_info, sizeof(expect_info) ), "mismatch\n" ); - ok( !memcmp( ptr + sizeof(expect_info), dib + sizeof(BITMAPFILEHEADER) + sizeof(expect_info), - sizeof(dib) - sizeof(BITMAPFILEHEADER) - sizeof(expect_info) ), "mismatch\n" ); + ok( !memcmp( ptr + sizeof(expect_info), file_dib + sizeof(BITMAPFILEHEADER) + sizeof(expect_info), + sizeof(file_dib) - sizeof(BITMAPFILEHEADER) - sizeof(expect_info) ), "mismatch\n" ); GlobalUnlock( U(med).hGlobal ); ReleaseStgMedium( &med ); @@ -2103,7 +2200,7 @@ static void check_dib_size( HGLOBAL h, int cx, int cy ) GlobalUnlock( h ); } -static void test_data_cache_bitmap(void) +static void test_data_cache_cache(void) { HRESULT hr; IOleCache2 *cache; @@ -2118,6 +2215,13 @@ static void test_data_cache_bitmap(void) {{ CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, 0, NULL, 0 }, {{ CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, 0, NULL, 0 } }; + STATDATA view_caching[] = + { + {{ 0, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, 0, NULL, 0 }, + {{ 0, 0, DVASPECT_THUMBNAIL, -1, TYMED_HGLOBAL }, 0, NULL, 0 }, + {{ 0, 0, DVASPECT_DOCPRINT, -1, TYMED_HGLOBAL }, 0, NULL, 0 }, + {{ CF_METAFILEPICT, 0, DVASPECT_ICON, -1, TYMED_MFPICT }, 0, NULL, 0 } + }; hr = CreateDataCache( NULL, &CLSID_NULL, &IID_IOleCache2, (void **)&cache ); ok( hr == S_OK, "got %08x\n", hr ); @@ -2194,9 +2298,7 @@ static void test_data_cache_bitmap(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 ); @@ -2218,8 +2320,7 @@ static void test_data_cache_bitmap(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 ); @@ -2240,6 +2341,79 @@ static void test_data_cache_bitmap(void) check_dib_size( U(med).hGlobal, 2, 1 ); ReleaseStgMedium( &med ); + /* uncache everything */ + hr = IOleCache2_Uncache( cache, conn ); + ok( hr == S_OK, "got %08x\n", hr ); + + /* view caching */ + fmt.cfFormat = 0; + fmt.tymed = TYMED_ENHMF; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == S_OK, "got %08x\n", hr ); + view_caching[0].dwConnection = conn; + + fmt.tymed = TYMED_HGLOBAL; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == CACHE_S_SAMECACHE, "got %08x\n", hr ); + + fmt.dwAspect = DVASPECT_THUMBNAIL; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == S_OK, "got %08x\n", hr ); + view_caching[1].dwConnection = conn; + + fmt.dwAspect = DVASPECT_DOCPRINT; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == S_OK, "got %08x\n", hr ); + view_caching[2].dwConnection = conn; + + /* DVASPECT_ICON view cache gets mapped to CF_METAFILEPICT */ + fmt.dwAspect = DVASPECT_ICON; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == S_OK, "got %08x\n", hr ); + view_caching[3].dwConnection = conn; + + check_enum_cache( cache, view_caching, 4 ); + + /* uncache everything */ + hr = IOleCache2_Uncache( cache, view_caching[3].dwConnection ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = IOleCache2_Uncache( cache, view_caching[2].dwConnection ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = IOleCache2_Uncache( cache, view_caching[1].dwConnection ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = IOleCache2_Uncache( cache, view_caching[0].dwConnection ); + ok( hr == S_OK, "got %08x\n", hr ); + + /* Only able to set cfFormat == CF_METAFILEPICT (or == 0, see above) for DVASPECT_ICON */ + fmt.dwAspect = DVASPECT_ICON; + fmt.cfFormat = CF_DIB; + fmt.tymed = TYMED_HGLOBAL; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == DV_E_FORMATETC, "got %08x\n", hr ); + fmt.cfFormat = CF_BITMAP; + fmt.tymed = TYMED_GDI; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == DV_E_FORMATETC, "got %08x\n", hr ); + fmt.cfFormat = CF_ENHMETAFILE; + fmt.tymed = TYMED_ENHMF; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == DV_E_FORMATETC, "got %08x\n", hr ); + fmt.cfFormat = CF_METAFILEPICT; + fmt.tymed = TYMED_MFPICT; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == S_OK, "got %08x\n", hr ); + + /* uncache everything */ + hr = IOleCache2_Uncache( cache, conn ); + ok( hr == S_OK, "got %08x\n", hr ); + + /* tymed == 0 */ + fmt.cfFormat = CF_ENHMETAFILE; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.tymed = 0; + hr = IOleCache2_Cache( cache, &fmt, 0, &conn ); + ok( hr == DV_E_TYMED, "got %08x\n", hr ); + IDataObject_Release( data ); IOleCache2_Release( cache ); } @@ -2404,111 +2578,412 @@ static void test_data_cache_initnew(void) IOleCache2_Release( cache ); } -static void test_default_handler(void) +static void test_data_cache_updatecache( void ) { HRESULT hr; - IOleObject *pObject; - IRunnableObject *pRunnableObject; - IOleClientSite *pClientSite; - IDataObject *pDataObject; - SIZEL sizel; - DWORD dwStatus; - CLSID clsid; - LPOLESTR pszUserType; - LOGPALETTE palette; - DWORD dwAdvConn; - IMoniker *pMoniker; - FORMATETC fmtetc; - IOleInPlaceObject *pInPlaceObj; - IEnumOLEVERB *pEnumVerbs; - DWORD dwRegister; - static const WCHAR wszUnknown[] = {'U','n','k','n','o','w','n',0}; - static const WCHAR wszHostName[] = {'W','i','n','e',' ','T','e','s','t',' ','P','r','o','g','r','a','m',0}; - static const WCHAR wszDelim[] = {'!',0}; + IOleCache2 *cache; + FORMATETC fmt; + DWORD conn[4]; - static const struct expected_method methods_embeddinghelper[] = + static const struct expected_method methods_dib[] = { - { "OleObject_QueryInterface", 0 }, - { "OleObject_AddRef", 0 }, - { "OleObject_QueryInterface", 0 }, - { "OleObject_QueryInterface", TEST_TODO }, - { "OleObject_QueryInterface", 0 }, - { "OleObject_QueryInterface", 0 }, - { "OleObject_QueryInterface", TEST_OPTIONAL }, /* Win95/98/NT4 */ - { "OleObject_Release", TEST_TODO }, - { "WINE_EXTRA", TEST_OPTIONAL }, - { NULL, 0 } + { "DataObject_GetData", 0, { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } }, + { "DataObject_GetData", 0, { CF_BITMAP, NULL, DVASPECT_CONTENT, -1, TYMED_GDI } }, + { NULL } }; - hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IOleObject, (void **)&pObject); - ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance should have failed with REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + 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_initcache[] = + { + { "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_empty[] = + { + { NULL } + }; - hr = OleCreateDefaultHandler(&CLSID_WineTest, NULL, &IID_IOleObject, (void **)&pObject); - ok_ole_success(hr, "OleCreateDefaultHandler"); + 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 } + }; - hr = IOleObject_QueryInterface(pObject, &IID_IOleInPlaceObject, (void **)&pInPlaceObj); - ok(hr == E_NOINTERFACE, "IOleObject_QueryInterface(&IID_IOleInPlaceObject) should return E_NOINTERFACE instead of 0x%08x\n", hr); + static FORMATETC dib_fmt[] = + { + { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + { 0 } + }; - hr = IOleObject_Advise(pObject, &AdviseSink, &dwAdvConn); - ok_ole_success(hr, "IOleObject_Advise"); + hr = CreateDataCache( NULL, &CLSID_WineTestOld, &IID_IOleCache2, (void **)&cache ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = IOleObject_Close(pObject, OLECLOSE_NOSAVE); - ok_ole_success(hr, "IOleObject_Close"); + /* No cache slots */ + g_dataobject_fmts = NULL; + expected_method_list = NULL; - /* FIXME: test IOleObject_EnumAdvise */ + hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = IOleObject_EnumVerbs(pObject, &pEnumVerbs); - ok(hr == REGDB_E_CLASSNOTREG, "IOleObject_EnumVerbs should have returned REGDB_E_CLASSNOTREG instead of 0x%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 = IOleObject_GetClientSite(pObject, &pClientSite); - ok_ole_success(hr, "IOleObject_GetClientSite"); + hr = IOleCache2_Cache( cache, &fmt, 0, &conn[0] ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = IOleObject_SetClientSite(pObject, pClientSite); - ok_ole_success(hr, "IOleObject_SetClientSite"); + expected_method_list = methods_dib; - hr = IOleObject_GetClipboardData(pObject, 0, &pDataObject); - ok(hr == OLE_E_NOTRUNNING, - "IOleObject_GetClipboardData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", - hr); + hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL ); + ok( hr == CACHE_E_NOCACHE_UPDATED, "got %08x\n", hr ); - hr = IOleObject_GetExtent(pObject, DVASPECT_CONTENT, &sizel); - ok(hr == OLE_E_BLANK, "IOleObject_GetExtent should have returned OLE_E_BLANK instead of 0x%08x\n", - hr); + CHECK_NO_EXTRA_METHODS(); - hr = IOleObject_GetMiscStatus(pObject, DVASPECT_CONTENT, &dwStatus); - ok(hr == REGDB_E_CLASSNOTREG, "IOleObject_GetMiscStatus should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + /* Now with a dib available */ + g_dataobject_fmts = dib_fmt; + expected_method_list = methods_dib; - hr = IOleObject_GetUserClassID(pObject, &clsid); - ok_ole_success(hr, "IOleObject_GetUserClassID"); - ok(IsEqualCLSID(&clsid, &CLSID_WineTest), "clsid != CLSID_WineTest\n"); + hr = IOleCache2_UpdateCache( cache, &DataObject, UPDFCACHE_ALL, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = IOleObject_GetUserType(pObject, USERCLASSTYPE_FULL, &pszUserType); - todo_wine { - ok_ole_success(hr, "IOleObject_GetUserType"); - ok(!lstrcmpW(pszUserType, wszUnknown), "Retrieved user type was wrong\n"); - } + /* Add an EMF cache slot */ + fmt.cfFormat = CF_ENHMETAFILE; + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_ENHMF; - hr = IOleObject_InitFromData(pObject, NULL, TRUE, 0); - ok(hr == OLE_E_NOTRUNNING, "IOleObject_InitFromData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + hr = IOleCache2_Cache( cache, &fmt, 0, &conn[1] ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = IOleObject_IsUpToDate(pObject); - ok(hr == OLE_E_NOTRUNNING, "IOleObject_IsUpToDate should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + g_dataobject_fmts = dib_fmt; + expected_method_list = methods_dib_emf; - palette.palNumEntries = 1; - palette.palVersion = 2; - memset(&palette.palPalEntry[0], 0, sizeof(palette.palPalEntry[0])); - hr = IOleObject_SetColorScheme(pObject, &palette); - ok(hr == OLE_E_NOTRUNNING, "IOleObject_SetColorScheme should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + /* 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 ); - sizel.cx = sizel.cy = 0; - hr = IOleObject_SetExtent(pObject, DVASPECT_CONTENT, &sizel); - ok(hr == OLE_E_NOTRUNNING, "IOleObject_SetExtent should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + CHECK_NO_EXTRA_METHODS(); - hr = IOleObject_SetHostNames(pObject, wszHostName, NULL); - ok_ole_success(hr, "IOleObject_SetHostNames"); + /* Replace the emf slot with a wmf */ + hr = IOleCache2_Uncache( cache, conn[1] ); + ok( hr == S_OK, "got %08x\n", hr ); - hr = CreateItemMoniker(wszDelim, wszHostName, &pMoniker); - ok_ole_success(hr, "CreateItemMoniker"); + 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(); + + expected_method_list = methods_initcache; + + hr = IOleCache2_InitCache( cache, &DataObject ); + ok( hr == S_OK, "got %08x\n", hr ); + + CHECK_NO_EXTRA_METHODS(); + + IOleCache2_Release( cache ); +} + +static void test_default_handler(void) +{ + HRESULT hr; + IOleObject *pObject; + IRunnableObject *pRunnableObject; + IOleClientSite *pClientSite; + IDataObject *pDataObject; + SIZEL sizel; + DWORD dwStatus; + CLSID clsid; + LPOLESTR pszUserType; + LOGPALETTE palette; + DWORD dwAdvConn; + IMoniker *pMoniker; + FORMATETC fmtetc; + IOleInPlaceObject *pInPlaceObj; + IEnumOLEVERB *pEnumVerbs; + DWORD dwRegister; + static const WCHAR wszUnknown[] = {'U','n','k','n','o','w','n',0}; + static const WCHAR wszHostName[] = {'W','i','n','e',' ','T','e','s','t',' ','P','r','o','g','r','a','m',0}; + static const WCHAR wszDelim[] = {'!',0}; + + static const struct expected_method methods_embeddinghelper[] = + { + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_QueryInterface", TEST_TODO }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_QueryInterface", TEST_OPTIONAL }, /* Win95/98/NT4 */ + { "OleObject_Release", TEST_TODO }, + { "WINE_EXTRA", TEST_OPTIONAL }, + { NULL, 0 } + }; + + hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IOleObject, (void **)&pObject); + ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance should have failed with REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + + hr = OleCreateDefaultHandler(&CLSID_WineTest, NULL, &IID_IOleObject, (void **)&pObject); + ok_ole_success(hr, "OleCreateDefaultHandler"); + + hr = IOleObject_QueryInterface(pObject, &IID_IOleInPlaceObject, (void **)&pInPlaceObj); + ok(hr == E_NOINTERFACE, "IOleObject_QueryInterface(&IID_IOleInPlaceObject) should return E_NOINTERFACE instead of 0x%08x\n", hr); + + hr = IOleObject_Advise(pObject, &AdviseSink, &dwAdvConn); + ok_ole_success(hr, "IOleObject_Advise"); + + hr = IOleObject_Close(pObject, OLECLOSE_NOSAVE); + ok_ole_success(hr, "IOleObject_Close"); + + /* FIXME: test IOleObject_EnumAdvise */ + + hr = IOleObject_EnumVerbs(pObject, &pEnumVerbs); + ok(hr == REGDB_E_CLASSNOTREG, "IOleObject_EnumVerbs should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + + hr = IOleObject_GetClientSite(pObject, &pClientSite); + ok_ole_success(hr, "IOleObject_GetClientSite"); + + hr = IOleObject_SetClientSite(pObject, pClientSite); + ok_ole_success(hr, "IOleObject_SetClientSite"); + + hr = IOleObject_GetClipboardData(pObject, 0, &pDataObject); + ok(hr == OLE_E_NOTRUNNING, + "IOleObject_GetClipboardData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", + hr); + + hr = IOleObject_GetExtent(pObject, DVASPECT_CONTENT, &sizel); + ok(hr == OLE_E_BLANK, "IOleObject_GetExtent should have returned OLE_E_BLANK instead of 0x%08x\n", + hr); + + hr = IOleObject_GetMiscStatus(pObject, DVASPECT_CONTENT, &dwStatus); + ok(hr == REGDB_E_CLASSNOTREG, "IOleObject_GetMiscStatus should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + + hr = IOleObject_GetUserClassID(pObject, &clsid); + ok_ole_success(hr, "IOleObject_GetUserClassID"); + ok(IsEqualCLSID(&clsid, &CLSID_WineTest), "clsid != CLSID_WineTest\n"); + + hr = IOleObject_GetUserType(pObject, USERCLASSTYPE_FULL, &pszUserType); + todo_wine { + ok_ole_success(hr, "IOleObject_GetUserType"); + ok(!lstrcmpW(pszUserType, wszUnknown), "Retrieved user type was wrong\n"); + } + + hr = IOleObject_InitFromData(pObject, NULL, TRUE, 0); + ok(hr == OLE_E_NOTRUNNING, "IOleObject_InitFromData should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + + hr = IOleObject_IsUpToDate(pObject); + ok(hr == OLE_E_NOTRUNNING, "IOleObject_IsUpToDate should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + + palette.palNumEntries = 1; + palette.palVersion = 2; + memset(&palette.palPalEntry[0], 0, sizeof(palette.palPalEntry[0])); + hr = IOleObject_SetColorScheme(pObject, &palette); + ok(hr == OLE_E_NOTRUNNING, "IOleObject_SetColorScheme should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + + sizel.cx = sizel.cy = 0; + hr = IOleObject_SetExtent(pObject, DVASPECT_CONTENT, &sizel); + ok(hr == OLE_E_NOTRUNNING, "IOleObject_SetExtent should have returned OLE_E_NOTRUNNING instead of 0x%08x\n", hr); + + hr = IOleObject_SetHostNames(pObject, wszHostName, NULL); + ok_ole_success(hr, "IOleObject_SetHostNames"); + + hr = CreateItemMoniker(wszDelim, wszHostName, &pMoniker); + ok_ole_success(hr, "CreateItemMoniker"); hr = IOleObject_SetMoniker(pObject, OLEWHICHMK_CONTAINER, pMoniker); ok_ole_success(hr, "IOleObject_SetMoniker"); IMoniker_Release(pMoniker); @@ -2764,9 +3239,12 @@ static void test_OleDraw(void) ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); } +static const WCHAR olepres0W[] = {2,'O','l','e','P','r','e','s','0','0','0',0}; static const WCHAR comp_objW[] = {1,'C','o','m','p','O','b','j',0}; static IStream *comp_obj_stream; static IStream *ole_stream; +static IStream *olepres_stream; +static IStream *contents_stream; static HRESULT WINAPI Storage_QueryInterface(IStorage *iface, REFIID riid, void **ppvObject) { @@ -2792,18 +3270,40 @@ static HRESULT WINAPI Storage_CreateStream(IStorage *iface, LPCOLESTR pwcsName, LARGE_INTEGER pos = {{0}}; HRESULT hr; - CHECK_EXPECT(Storage_CreateStream_CompObj); - ok(!lstrcmpW(pwcsName, comp_objW), "pwcsName = %s\n", wine_dbgstr_w(pwcsName)); - todo_wine ok(grfMode == (STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode); + if (!lstrcmpW(pwcsName, comp_objW)) + { + CHECK_EXPECT(Storage_CreateStream_CompObj); + *ppstm = comp_obj_stream; + + todo_wine ok(grfMode == (STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode); + } + else if (!lstrcmpW(pwcsName, olepres0W)) + { + CHECK_EXPECT(Storage_CreateStream_OlePres); + *ppstm = olepres_stream; + + todo_wine ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode); + } + else + { +todo_wine + ok(0, "unexpected stream name %s\n", wine_dbgstr_w(pwcsName)); +#if 0 /* FIXME: return NULL once Wine is fixed */ + *ppstm = NULL; + return E_NOTIMPL; +#else + *ppstm = contents_stream; +#endif + } + ok(!reserved1, "reserved1 = %x\n", reserved1); ok(!reserved2, "reserved2 = %x\n", reserved2); ok(!!ppstm, "ppstm = NULL\n"); - *ppstm = comp_obj_stream; - IStream_AddRef(comp_obj_stream); - hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL); + IStream_AddRef(*ppstm); + hr = IStream_Seek(*ppstm, pos, STREAM_SEEK_SET, NULL); ok(hr == S_OK, "IStream_Seek returned %x\n", hr); - hr = IStream_SetSize(comp_obj_stream, size); + hr = IStream_SetSize(*ppstm, size); ok(hr == S_OK, "IStream_SetSize returned %x\n", hr); return S_OK; } @@ -2830,6 +3330,15 @@ static HRESULT WINAPI Storage_OpenStream(IStorage *iface, LPCOLESTR pwcsName, vo return S_OK; }else if(!lstrcmpW(pwcsName, ole1W)) { CHECK_EXPECT(Storage_OpenStream_Ole); + + if (!ole_stream) + { + ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READ), "grfMode = %x\n", grfMode); + + *ppstm = NULL; + return STG_E_FILENOTFOUND; + } + ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode); *ppstm = ole_stream; @@ -2837,6 +3346,16 @@ static HRESULT WINAPI Storage_OpenStream(IStorage *iface, LPCOLESTR pwcsName, vo hr = IStream_Seek(ole_stream, pos, STREAM_SEEK_SET, NULL); ok(hr == S_OK, "IStream_Seek returned %x\n", hr); return S_OK; + + }else if(!lstrcmpW(pwcsName, olepres0W)) { + CHECK_EXPECT(Storage_OpenStream_OlePres); + ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode); + + *ppstm = olepres_stream; + IStream_AddRef(olepres_stream); + hr = IStream_Seek(olepres_stream, pos, STREAM_SEEK_SET, NULL); + ok(hr == S_OK, "IStream_Seek returned %x\n", hr); + return S_OK; } ok(0, "unexpected call to OpenStream: %s\n", wine_dbgstr_w(pwcsName)); @@ -2887,8 +3406,20 @@ static HRESULT WINAPI Storage_EnumElements(IStorage *iface, DWORD reserved1, voi static HRESULT WINAPI Storage_DestroyElement(IStorage *iface, LPCOLESTR pwcsName) { - ok(0, "unexpected call to DestroyElement\n"); - return E_NOTIMPL; + char name[32]; + int stream_n, cmp; + + CHECK_EXPECT2(Storage_DestroyElement); + cmp = CompareStringW(LOCALE_NEUTRAL, 0, pwcsName, 8, olepres0W, 8); + ok(cmp == CSTR_EQUAL, + "unexpected call to DestroyElement(%s)\n", wine_dbgstr_w(pwcsName)); + + WideCharToMultiByte(CP_ACP, 0, pwcsName, -1, name, sizeof(name), NULL, NULL); + stream_n = atol(name + 8); + if (stream_n <= Storage_DestroyElement_limit) + return S_OK; + + return STG_E_FILENOTFOUND; } static HRESULT WINAPI Storage_RenameElement(IStorage *iface, LPCOLESTR pwcsOldName, LPCOLESTR pwcsNewName) @@ -2906,7 +3437,8 @@ static HRESULT WINAPI Storage_SetElementTimes(IStorage *iface, LPCOLESTR pwcsNam static HRESULT WINAPI Storage_SetClass(IStorage *iface, REFCLSID clsid) { CHECK_EXPECT(Storage_SetClass); - ok(IsEqualIID(clsid, &CLSID_WineTest), "clsid = %s\n", wine_dbgstr_guid(clsid)); + ok(IsEqualIID(clsid, Storage_SetClass_CLSID), "expected %s, got %s\n", + wine_dbgstr_guid(Storage_SetClass_CLSID), wine_dbgstr_guid(clsid)); return S_OK; } @@ -3121,6 +3653,787 @@ static void test_OleDoAutoConvert(void) RegCloseKey(root); } +/* 1x1 pixel bmp */ +static const unsigned char bmpimage[] = +{ + 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b, + 0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00, + 0x00,0x00 +}; + +static const unsigned char mf_blank_bits[] = +{ + 0x01,0x00,0x09,0x00,0x00,0x03,0x0c,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00 +}; + +static void test_data_cache_save(void) +{ + static const WCHAR contentsW[] = { 'C','o','n','t','e','n','t','s',0 }; + HRESULT hr; + ILockBytes *ilb; + IStorage *doc; + IStream *stm; + IOleCache2 *cache; + IPersistStorage *stg; + DWORD clipformat[2]; + PresentationDataHeader hdr; + + hr = CreateILockBytesOnHGlobal(0, TRUE, &ilb); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = StgCreateDocfileOnILockBytes(ilb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &doc); + ok(hr == S_OK, "unexpected %#x\n", hr); + + ILockBytes_Release(ilb); + + hr = IStorage_SetClass(doc, &CLSID_WineTest); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IStorage_CreateStream(doc, contentsW, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IStream_Write(stm, bmpimage, sizeof(bmpimage), NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + IStream_Release(stm); + + hr = IStorage_CreateStream(doc, olepres0W, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + ok(hr == S_OK, "unexpected %#x\n", hr); + + clipformat[0] = -1; + clipformat[1] = CF_METAFILEPICT; + hr = IStream_Write(stm, clipformat, sizeof(clipformat), NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hdr.tdSize = sizeof(hdr.tdSize); + hdr.dvAspect = DVASPECT_CONTENT; + hdr.lindex = -1; + hdr.advf = ADVF_PRIMEFIRST; + hdr.unknown7 = 0; + hdr.dwObjectExtentX = 0; + hdr.dwObjectExtentY = 0; + hdr.dwSize = sizeof(mf_blank_bits); + hr = IStream_Write(stm, &hdr, sizeof(hdr), NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IStream_Write(stm, mf_blank_bits, sizeof(mf_blank_bits), NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + + IStream_Release(stm); + + hr = CreateDataCache(NULL, &CLSID_NULL, &IID_IUnknown, (void **)&cache); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void **)&stg); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IPersistStorage_Load(stg, doc); + ok(hr == S_OK, "unexpected %#x\n", hr); + + IStorage_Release(doc); + + hr = IPersistStorage_IsDirty(stg); + ok(hr == S_FALSE, "unexpected %#x\n", hr); + + ole_stream = NULL; + hr = CreateStreamOnHGlobal(NULL, TRUE, &olepres_stream); + ok(hr == S_OK, "unexpected %#x\n", hr); + + /* FIXME: remove this stream once Wine is fixed */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &contents_stream); + ok(hr == S_OK, "unexpected %#x\n", hr); + + SET_EXPECT(Storage_CreateStream_OlePres); + SET_EXPECT(Storage_OpenStream_OlePres); + SET_EXPECT(Storage_OpenStream_Ole); + SET_EXPECT(Storage_DestroyElement); + Storage_DestroyElement_limit = 50; + Storage_SetClass_CLSID = &CLSID_NULL; + trace("IPersistStorage_Save:\n"); + hr = IPersistStorage_Save(stg, &Storage, FALSE); + ok(hr == S_OK, "unexpected %#x\n", hr); + CHECK_CALLED(Storage_CreateStream_OlePres); +todo_wine + CHECK_CALLED(Storage_OpenStream_OlePres); +todo_wine + CHECK_CALLED(Storage_OpenStream_Ole); +todo_wine + CHECK_CALLED(Storage_DestroyElement); + + IStream_Release(olepres_stream); + IStream_Release(contents_stream); + + IPersistStorage_Release(stg); + IOleCache2_Release(cache); +} + +#define MAX_STREAM 16 + +struct stream_def +{ + const char *name; + int cf; + DVASPECT dvAspect; + ADVF advf; + const void *data; + size_t data_size; +}; + +struct storage_def +{ + const CLSID *clsid; + int stream_count; + struct stream_def stream[MAX_STREAM]; +}; + +static const struct storage_def stg_def_0 = +{ + &CLSID_NULL, 1, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }} +}; +static const struct storage_def stg_def_0_saved = +{ + &CLSID_NULL, 0, {{ 0 }} +}; +static const struct storage_def stg_def_1 = +{ + &CLSID_NULL, 2, + {{ "Contents", -1, 0, 0, NULL, 0 }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_1_saved = +{ + &CLSID_NULL, 1, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_2 = +{ + &CLSID_ManualResetEvent, 2, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_2_saved = +{ + &CLSID_NULL, 1, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_3 = +{ + &CLSID_NULL, 5, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, ADVF_PRIMEFIRST, mf_blank_bits, sizeof(mf_blank_bits) }, + { "\2OlePres002", CF_DIB, DVASPECT_CONTENT, ADVF_PRIMEFIRST, bmpimage, sizeof(bmpimage) }, + { "MyStream", -1, 0, 0, "Hello World!", 13 }} +}; +static const struct storage_def stg_def_3_saved = +{ + &CLSID_NULL, 3, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, ADVF_PRIMEFIRST, mf_blank_bits, sizeof(mf_blank_bits) }, + { "\2OlePres002", CF_DIB, DVASPECT_CONTENT, ADVF_PRIMEFIRST, bmpimage, sizeof(bmpimage) }} +}; +static const struct storage_def stg_def_4 = +{ + &CLSID_Picture_EnhMetafile, 5, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, ADVF_PRIMEFIRST, mf_blank_bits, sizeof(mf_blank_bits) }, + { "\2OlePres002", CF_DIB, DVASPECT_CONTENT, ADVF_PRIMEFIRST, bmpimage, sizeof(bmpimage) }, + { "MyStream", -1, 0, 0, "Hello World!", 13 }} +}; +static const struct storage_def stg_def_4_saved = +{ + &CLSID_NULL, 1, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_5 = +{ + &CLSID_Picture_Dib, 5, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }, + { "\2OlePres002", CF_DIB, DVASPECT_CONTENT, ADVF_PRIMEFIRST, bmpimage, sizeof(bmpimage) }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, ADVF_PRIMEFIRST, mf_blank_bits, sizeof(mf_blank_bits) }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }, + { "MyStream", -1, 0, 0, "Hello World!", 13 }} +}; +static const struct storage_def stg_def_5_saved = +{ + &CLSID_NULL, 1, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_6 = +{ + &CLSID_Picture_Metafile, 5, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, ADVF_PRIMEFIRST, mf_blank_bits, sizeof(mf_blank_bits) }, + { "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }, + { "\2OlePres002", CF_DIB, DVASPECT_CONTENT, ADVF_PRIMEFIRST, bmpimage, sizeof(bmpimage) }, + { "MyStream", -1, 0, 0, "Hello World!", 13 }} +}; +static const struct storage_def stg_def_6_saved = +{ + &CLSID_NULL, 1, + {{ "\2OlePres000", 0, DVASPECT_ICON, ADVF_PRIMEFIRST | ADVF_ONLYONCE, NULL, 0 }} +}; +static const struct storage_def stg_def_7 = +{ + &CLSID_Picture_Dib, 1, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }} +}; +static const struct storage_def stg_def_7_saved = +{ + &CLSID_NULL, 0, {{ 0 }} +}; +static const struct storage_def stg_def_8 = +{ + &CLSID_Picture_Metafile, 1, + {{ "Contents", -1, 0, 0, mf_blank_bits, sizeof(mf_blank_bits) }} +}; +static const struct storage_def stg_def_8_saved = +{ + &CLSID_NULL, 0, {{ 0 }} +}; +static const struct storage_def stg_def_9 = +{ + &CLSID_Picture_EnhMetafile, 1, + {{ "Contents", -1, 0, 0, bmpimage, sizeof(bmpimage) }} +}; +static const struct storage_def stg_def_9_saved = +{ + &CLSID_NULL, 0, {{ 0 }} +}; + +static int read_clipformat(IStream *stream) +{ + HRESULT hr; + ULONG bytes; + int length, clipformat = -2; + + hr = IStream_Read(stream, &length, sizeof(length), &bytes); + if (hr != S_OK || bytes != sizeof(length)) + return -2; + if (length == 0) + return 0; + if (length == -1) + { + hr = IStream_Read(stream, &clipformat, sizeof(clipformat), &bytes); + if (hr != S_OK || bytes != sizeof(clipformat)) + return -2; + } + else + ok(0, "unhandled clipformat length %d\n", length); + + return clipformat; +} + +static void check_storage_contents(IStorage *stg, const struct storage_def *stg_def, + int *enumerated_streams, int *matched_streams) +{ + HRESULT hr; + IEnumSTATSTG *enumstg; + IStream *stream; + STATSTG stat; + int i, seen_stream[MAX_STREAM] = { 0 }; + + if (winetest_debug > 1) + trace("check_storage_contents:\n=============================================\n"); + + *enumerated_streams = 0; + *matched_streams = 0; + + hr = IStorage_Stat(stg, &stat, STATFLAG_NONAME); + ok(hr == S_OK, "unexpected %#x\n", hr); + ok(IsEqualCLSID(stg_def->clsid, &stat.clsid), "expected %s, got %s\n", + wine_dbgstr_guid(stg_def->clsid), wine_dbgstr_guid(&stat.clsid)); + + hr = IStorage_EnumElements(stg, 0, NULL, 0, &enumstg); + ok(hr == S_OK, "unexpected %#x\n", hr); + + for (;;) + { + ULONG bytes; + int clipformat = -1; + PresentationDataHeader header; + char name[32]; + BYTE data[1024]; + + memset(&header, 0, sizeof(header)); + + hr = IEnumSTATSTG_Next(enumstg, 1, &stat, NULL); + if(hr == S_FALSE) break; + ok(hr == S_OK, "unexpected %#x\n", hr); + + if (winetest_debug > 1) + trace("name %s, type %u, size %d, clsid %s\n", + wine_dbgstr_w(stat.pwcsName), stat.type, stat.cbSize.u.LowPart, wine_dbgstr_guid(&stat.clsid)); + + ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type); + + WideCharToMultiByte(CP_ACP, 0, stat.pwcsName, -1, name, sizeof(name), NULL, NULL); + + hr = IStorage_OpenStream(stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream); + ok(hr == S_OK, "unexpected %#x\n", hr); + + if (!memcmp(name, "\2OlePres", 7)) + { + clipformat = read_clipformat(stream); + + hr = IStream_Read(stream, &header, sizeof(header), &bytes); + ok(hr == S_OK, "unexpected %#x\n", hr); + ok(bytes >= 24, "read %u bytes\n", bytes); + + if (winetest_debug > 1) + trace("header: tdSize %#x, dvAspect %#x, lindex %#x, advf %#x, unknown7 %#x, dwObjectExtentX %#x, dwObjectExtentY %#x, dwSize %#x\n", + header.tdSize, header.dvAspect, header.lindex, header.advf, header.unknown7, + header.dwObjectExtentX, header.dwObjectExtentY, header.dwSize); + } + + memset(data, 0, sizeof(data)); + hr = IStream_Read(stream, data, sizeof(data), &bytes); + ok(hr == S_OK, "unexpected %#x\n", hr); + if (winetest_debug > 1) + trace("stream data (%u bytes): %02x %02x %02x %02x\n", bytes, data[0], data[1], data[2], data[3]); + + for (i = 0; i < stg_def->stream_count; i++) + { + if (seen_stream[i]) continue; + + if (winetest_debug > 1) + trace("%s/%s, %d/%d, %d/%d, %d/%d\n", + stg_def->stream[i].name, name, + stg_def->stream[i].cf, clipformat, + stg_def->stream[i].dvAspect, header.dvAspect, + stg_def->stream[i].advf, header.advf); + + if (!strcmp(stg_def->stream[i].name, name) && + stg_def->stream[i].cf == clipformat && + stg_def->stream[i].dvAspect == header.dvAspect && + stg_def->stream[i].advf == header.advf && + stg_def->stream[i].data_size <= bytes && + (!stg_def->stream[i].data_size || + (!memcmp(stg_def->stream[i].data, data, min(stg_def->stream[i].data_size, bytes))))) + { + if (winetest_debug > 1) + trace("stream %d matches def stream %d\n", *enumerated_streams, i); + seen_stream[i] = 1; + *matched_streams += 1; + } + } + + CoTaskMemFree(stat.pwcsName); + IStream_Release(stream); + + *enumerated_streams += 1; + } +} + +static IStorage *create_storage_from_def(const struct storage_def *stg_def) +{ + HRESULT hr; + IStorage *stg; + IStream *stm; + int i; + + hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &stg); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IStorage_SetClass(stg, stg_def->clsid); + ok(hr == S_OK, "unexpected %#x\n", hr); + + for (i = 0; i < stg_def->stream_count; i++) + { + WCHAR name[32]; + + MultiByteToWideChar(CP_ACP, 0, stg_def->stream[i].name, -1, name, 32); + hr = IStorage_CreateStream(stg, name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + ok(hr == S_OK, "unexpected %#x\n", hr); + + if (stg_def->stream[i].cf != -1) + { + int clipformat[2]; + PresentationDataHeader hdr; + + if (stg_def->stream[i].cf) + { + clipformat[0] = -1; + clipformat[1] = stg_def->stream[i].cf; + hr = IStream_Write(stm, clipformat, sizeof(clipformat), NULL); + } + else + { + clipformat[0] = 0; + hr = IStream_Write(stm, &clipformat[0], sizeof(clipformat[0]), NULL); + } + ok(hr == S_OK, "unexpected %#x\n", hr); + + hdr.tdSize = sizeof(hdr.tdSize); + hdr.dvAspect = stg_def->stream[i].dvAspect; + hdr.lindex = -1; + hdr.advf = stg_def->stream[i].advf; + hdr.unknown7 = 0; + hdr.dwObjectExtentX = 0; + hdr.dwObjectExtentY = 0; + hdr.dwSize = stg_def->stream[i].data_size; + hr = IStream_Write(stm, &hdr, sizeof(hdr), NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + } + + if (stg_def->stream[i].data_size) + { + hr = IStream_Write(stm, stg_def->stream[i].data, stg_def->stream[i].data_size, NULL); + ok(hr == S_OK, "unexpected %#x\n", hr); + } + + IStream_Release(stm); + } + + return stg; +} + +static const BYTE dib_inf[] = +{ + 0x42, 0x4d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x36, 0x00, 0x00, 0x00 +}; + +static const BYTE mf_rec[] = +{ + 0xd7, 0xcd, 0xc6, 0x9a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x16, 0x00, 0x2d, 0x00, 0x40, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x6a, 0x55 +}; + +static void get_stgdef(struct storage_def *stg_def, CLIPFORMAT cf, STGMEDIUM *stg_med, int stm_idx) +{ + BYTE *data; + int data_size; + METAFILEPICT *mfpict; + HDC hdc; + + switch (cf) + { + case CF_DIB: + data_size = sizeof(dib); + if (!strcmp(stg_def->stream[stm_idx].name, "CONTENTS")) + { + data_size += sizeof(dib_inf); + data = HeapAlloc(GetProcessHeap(), 0, data_size); + memcpy(data, dib_inf, sizeof(dib_inf)); + memcpy(data + sizeof(dib_inf), dib, sizeof(dib)); + } + else + { + data = HeapAlloc(GetProcessHeap(), 0, data_size); + memcpy(data, dib, sizeof(dib)); + } + stg_def->stream[stm_idx].data = data; + stg_def->stream[stm_idx].data_size = data_size; + break; + case CF_METAFILEPICT: + mfpict = GlobalLock(U(stg_med)->hMetaFilePict); + data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); + if (!strcmp(stg_def->stream[stm_idx].name, "CONTENTS")) + { + data = HeapAlloc(GetProcessHeap(), 0, data_size + sizeof(mf_rec)); + memcpy(data, mf_rec, sizeof(mf_rec)); + GetMetaFileBitsEx(mfpict->hMF, data_size, data + sizeof(mf_rec)); + data_size += sizeof(mf_rec); + } + else + { + data = HeapAlloc(GetProcessHeap(), 0, data_size); + GetMetaFileBitsEx(mfpict->hMF, data_size, data); + } + GlobalUnlock(U(stg_med)->hMetaFilePict); + stg_def->stream[stm_idx].data_size = data_size; + stg_def->stream[stm_idx].data = data; + break; + case CF_ENHMETAFILE: + if (!strcmp(stg_def->stream[stm_idx].name, "CONTENTS")) + { + data_size = GetEnhMetaFileBits(U(stg_med)->hEnhMetaFile, 0, NULL); + data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size); + *((DWORD *)data) = sizeof(ENHMETAHEADER); + GetEnhMetaFileBits(U(stg_med)->hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER)); + memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER)); + data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER); + } + else + { + hdc = GetDC(NULL); + data_size = GetWinMetaFileBits(U(stg_med)->hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc); + data = HeapAlloc(GetProcessHeap(), 0, data_size); + GetWinMetaFileBits(U(stg_med)->hEnhMetaFile, data_size, data, MM_ANISOTROPIC, hdc); + ReleaseDC(NULL, hdc); + } + stg_def->stream[stm_idx].data_size = data_size; + stg_def->stream[stm_idx].data = data; + break; + } +} + +static void get_stgmedium(CLIPFORMAT cfFormat, STGMEDIUM *stgmedium) +{ + switch (cfFormat) + { + case CF_DIB: + create_dib(stgmedium); + break; + case CF_METAFILEPICT: + create_mfpict(stgmedium); + break; + case CF_ENHMETAFILE: + create_emf(stgmedium); + break; + default: + ok(0, "cf %x not implemented\n", cfFormat); + } +} + +#define MAX_FMTS 5 +static void test_data_cache_save_data(void) +{ + HRESULT hr; + STGMEDIUM stgmed; + ILockBytes *ilb; + IStorage *doc; + IOleCache2 *cache; + IPersistStorage *persist; + int enumerated_streams, matched_streams, i; + DWORD dummy; + struct tests_data_cache + { + FORMATETC fmts[MAX_FMTS]; + int num_fmts, num_set; + const CLSID *clsid; + struct storage_def stg_def; + }; + + static struct tests_data_cache *pdata, data[] = + { + { + { + { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 3, 3, &CLSID_WineTest, + { + &CLSID_WineTestOld, 3, { { "\2OlePres000", CF_DIB, DVASPECT_CONTENT, 0, NULL, 0 }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, 0, NULL, 0 }, + { "\2OlePres002", CF_ENHMETAFILE, DVASPECT_CONTENT, 0, NULL, 0 } } + } + }, + /* without setting data */ + { + { + { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 3, 0, &CLSID_WineTest, + { + &CLSID_WineTestOld, 3, { { "\2OlePres000", CF_DIB, DVASPECT_CONTENT, 0, NULL, 0 }, + { "\2OlePres001", CF_METAFILEPICT, DVASPECT_CONTENT, 0, NULL, 0 }, + { "\2OlePres002", CF_ENHMETAFILE, DVASPECT_CONTENT, 0, NULL, 0 } } + } + }, + /* static picture clsids */ + { + { + { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + }, + 1, 1, &CLSID_Picture_Dib, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, + }, + 1, 1, &CLSID_Picture_Metafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 1, 1, &CLSID_Picture_EnhMetafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + /* static picture clsids without setting any data */ + { + { + { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + }, + 1, 0, &CLSID_Picture_Dib, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, + }, + 1, 0, &CLSID_Picture_Metafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 1, 0, &CLSID_Picture_EnhMetafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { 0 } + } + } + }; + + /* test _Save after caching directly through _Cache + _SetData */ + for (pdata = data; pdata->clsid != NULL; pdata++) + { + hr = CreateDataCache(NULL, pdata->clsid, &IID_IOleCache2, (void **)&cache); + ok(hr == S_OK, "unexpected %#x\n", hr); + + for (i = 0; i < pdata->num_fmts; i++) + { + hr = IOleCache2_Cache(cache, &pdata->fmts[i], 0, &dummy); + ok(SUCCEEDED(hr), "unexpected %#x\n", hr); + if (i < pdata->num_set) + { + get_stgmedium(pdata->fmts[i].cfFormat, &stgmed); + get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat, &stgmed, i); + hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmed, TRUE); + ok(hr == S_OK, "unexpected %#x\n", hr); + } + } + + /* create Storage in memory where we'll save cache */ + hr = CreateILockBytesOnHGlobal(0, TRUE, &ilb); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = StgCreateDocfileOnILockBytes(ilb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &doc); + ok(hr == S_OK, "unexpected %#x\n", hr); + ILockBytes_Release(ilb); + hr = IStorage_SetClass(doc, &CLSID_WineTestOld); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void **)&persist); + ok(hr == S_OK, "unexpected %#x\n", hr); + + /* cache entries are dirty. test saving them to stg */ + trace("IPersistStorage_Save:\n"); + hr = IPersistStorage_Save(persist, doc, FALSE); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IPersistStorage_IsDirty(persist); + ok(hr == S_OK, "unexpected %#x\n", hr); + + check_storage_contents(doc, &pdata->stg_def, &enumerated_streams, &matched_streams); + ok(enumerated_streams == matched_streams, "enumerated %d != matched %d\n", + enumerated_streams, matched_streams); + ok(enumerated_streams == pdata->stg_def.stream_count, "created %d != def streams %d\n", + enumerated_streams, pdata->stg_def.stream_count); + + for (i = 0; i < pdata->num_set; i++) + HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data); + + IPersistStorage_Release(persist); + IStorage_Release(doc); + IOleCache2_Release(cache); + } +} + +static void test_data_cache_contents(void) +{ + HRESULT hr; + IStorage *doc1, *doc2; + IOleCache2 *cache; + IPersistStorage *stg; + int i, enumerated_streams, matched_streams; + static const struct + { + const struct storage_def *in; + const struct storage_def *out; + } test_data[] = + { + { &stg_def_0, &stg_def_0_saved }, + { &stg_def_1, &stg_def_1_saved }, + { &stg_def_2, &stg_def_2_saved }, + { &stg_def_3, &stg_def_3_saved }, + { &stg_def_4, &stg_def_4_saved }, + { &stg_def_5, &stg_def_5_saved }, + { &stg_def_6, &stg_def_6_saved }, + { &stg_def_7, &stg_def_7_saved }, + { &stg_def_8, &stg_def_8_saved }, + { &stg_def_9, &stg_def_9_saved }, + }; + + for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++) + { + if (winetest_debug > 1) + trace("start testing storage def %d\n", i); + + doc1 = create_storage_from_def(test_data[i].in); + if (!doc1) continue; + + enumerated_streams = matched_streams = -1; + check_storage_contents(doc1, test_data[i].in, &enumerated_streams, &matched_streams); + ok(enumerated_streams == matched_streams, "%d in: enumerated %d != matched %d\n", i, + enumerated_streams, matched_streams); + ok(enumerated_streams == test_data[i].in->stream_count, "%d: created %d != def streams %d\n", i, + enumerated_streams, test_data[i].in->stream_count); + + hr = CreateDataCache(NULL, &CLSID_NULL, &IID_IUnknown, (void **)&cache); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void **)&stg); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IPersistStorage_Load(stg, doc1); + ok(hr == S_OK, "unexpected %#x\n", hr); + + IStorage_Release(doc1); + + hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &doc2); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IPersistStorage_IsDirty(stg); +todo_wine_if(test_data[i].in == &stg_def_4 || test_data[i].in == &stg_def_8 || test_data[i].in == &stg_def_9) + ok(hr == S_FALSE, "%d: unexpected %#x\n", i, hr); + + hr = IPersistStorage_Save(stg, doc2, FALSE); + ok(hr == S_OK, "unexpected %#x\n", hr); + + IPersistStorage_Release(stg); + + enumerated_streams = matched_streams = -1; + check_storage_contents(doc2, test_data[i].out, &enumerated_streams, &matched_streams); +todo_wine_if(!(test_data[i].in == &stg_def_0 || test_data[i].in == &stg_def_1 || test_data[i].in == &stg_def_2)) + ok(enumerated_streams == matched_streams, "%d out: enumerated %d != matched %d\n", i, + enumerated_streams, matched_streams); +todo_wine_if(!(test_data[i].in == &stg_def_0 || test_data[i].in == &stg_def_5)) + ok(enumerated_streams == test_data[i].out->stream_count, "%d: saved streams %d != def streams %d\n", i, + enumerated_streams, test_data[i].out->stream_count); + + IStorage_Release(doc2); + + if (winetest_debug > 1) + trace("done testing storage def %d\n", i); + } +} + START_TEST(ole2) { DWORD dwRegister; @@ -3153,18 +4466,24 @@ START_TEST(ole2) hr = CoRevokeClassObject(dwRegister); ok_ole_success(hr, "CoRevokeClassObject"); + Storage_SetClass_CLSID = &CLSID_WineTest; + test_data_cache(); test_data_cache_dib_contents_stream( 0 ); test_data_cache_dib_contents_stream( 1 ); - test_data_cache_bitmap(); + test_data_cache_cache(); test_data_cache_init(); test_data_cache_initnew(); + test_data_cache_updatecache(); test_default_handler(); test_runnable(); test_OleRun(); test_OleLockRunning(); test_OleDraw(); test_OleDoAutoConvert(); + test_data_cache_save(); + test_data_cache_save_data(); + test_data_cache_contents(); CoUninitialize(); } diff --git a/modules/rostests/winetests/ole32/usrmarshal.c b/modules/rostests/winetests/ole32/usrmarshal.c index bc9525914ef..8576ed78f2c 100644 --- a/modules/rostests/winetests/ole32/usrmarshal.c +++ b/modules/rostests/winetests/ole32/usrmarshal.c @@ -178,31 +178,32 @@ static void test_marshal_CLIPFORMAT(void) USER_MARSHAL_CB umcb; MIDL_STUB_MESSAGE stub_msg; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; ULONG i, size; CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat"); CLIPFORMAT cf2; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); - size = CLIPFORMAT_UserSize(&umcb.Flags, 0, &cf); - ok(size == 8 + sizeof(cf_marshaled) || - broken(size == 12 + sizeof(cf_marshaled)) || /* win64 adds 4 extra (unused) bytes */ - broken(size == 8 + sizeof(cf_marshaled) - 2), /* win9x and winnt don't include the '\0' */ + size = CLIPFORMAT_UserSize(&umcb.Flags, 1, &cf); + ok(size == 12 + sizeof(cf_marshaled) || + broken(size == 16 + sizeof(cf_marshaled)), /* win64 adds 4 extra (unused) bytes */ "CLIPFORMAT: Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); memset( buffer, 0xcc, size ); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - CLIPFORMAT_UserMarshal(&umcb.Flags, buffer, &cf); - ok(*(LONG *)(buffer + 0) == WDT_REMOTE_CALL, "CLIPFORMAT: Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(LONG *)(buffer + 0)); - ok(*(DWORD *)(buffer + 4) == cf, "CLIPFORMAT: Marshaled value should be 0x%04x instead of 0x%04x\n", cf, *(DWORD *)(buffer + 4)); - ok(!memcmp(buffer + 8, cf_marshaled, min( sizeof(cf_marshaled), size-8 )), "Marshaled data differs\n"); - if (size > sizeof(cf_marshaled) + 8) /* make sure the extra bytes are not used */ - for (i = sizeof(cf_marshaled) + 8; i < size; i++) + buffer_end = CLIPFORMAT_UserMarshal(&umcb.Flags, buffer + 1, &cf); + ok(buffer_end == buffer + 12 + sizeof(cf_marshaled), "got %p buffer %p\n", buffer_end, buffer); + ok(*(LONG *)(buffer + 4) == WDT_REMOTE_CALL, "CLIPFORMAT: Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(LONG *)(buffer + 0)); + ok(*(DWORD *)(buffer + 8) == cf, "CLIPFORMAT: Marshaled value should be 0x%04x instead of 0x%04x\n", cf, *(DWORD *)(buffer + 4)); + ok(!memcmp(buffer + 12, cf_marshaled, min( sizeof(cf_marshaled), size-12 )), "Marshaled data differs\n"); + if (size > sizeof(cf_marshaled) + 12) /* make sure the extra bytes are not used */ + for (i = sizeof(cf_marshaled) + 12; i < size; i++) ok( buffer[i] == 0xcc, "buffer offset %u has been set to %x\n", i, buffer[i] ); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - CLIPFORMAT_UserUnmarshal(&umcb.Flags, buffer, &cf2); + buffer_end = CLIPFORMAT_UserUnmarshal(&umcb.Flags, buffer + 1, &cf2); + ok(buffer_end == buffer + 12 + sizeof(cf_marshaled), "got %p buffer %p\n", buffer_end, buffer); ok(cf == cf2, "CLIPFORMAT: Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); @@ -215,25 +216,27 @@ static void test_marshal_HWND(void) USER_MARSHAL_CB umcb; MIDL_STUB_MESSAGE stub_msg; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; ULONG size; HWND hwnd = GetDesktopWindow(); HWND hwnd2; wireHWND wirehwnd; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); - size = HWND_UserSize(&umcb.Flags, 0, &hwnd); - ok(size == sizeof(*wirehwnd), "Wrong size %d\n", size); + size = HWND_UserSize(&umcb.Flags, 1, &hwnd); + ok(size == 4 + sizeof(*wirehwnd), "Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HWND_UserMarshal(&umcb.Flags, buffer, &hwnd); - wirehwnd = (wireHWND)buffer; + buffer_end = HWND_UserMarshal(&umcb.Flags, buffer + 1, &hwnd); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); + wirehwnd = (wireHWND)(buffer + 4); ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehwnd->fContext); ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %x\n", hwnd, wirehwnd->u.hRemote); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HWND_UserUnmarshal(&umcb.Flags, buffer, &hwnd2); + buffer_end = HWND_UserUnmarshal(&umcb.Flags, buffer + 1, &hwnd2); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); ok(hwnd == hwnd2, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); @@ -335,7 +338,7 @@ static void test_marshal_HENHMETAFILE(void) USER_MARSHAL_CB umcb; MIDL_STUB_MESSAGE stub_msg; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; ULONG size; HENHMETAFILE hemf; HENHMETAFILE hemf2 = NULL; @@ -344,26 +347,28 @@ static void test_marshal_HENHMETAFILE(void) hemf = create_emf(); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); - size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf); - ok(size > 20, "size should be at least 20 bytes, not %d\n", size); + size = HENHMETAFILE_UserSize(&umcb.Flags, 1, &hemf); + ok(size > 24, "size should be at least 24 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf); - wirehemf = buffer; + buffer_end = HENHMETAFILE_UserMarshal(&umcb.Flags, buffer + 1, &hemf); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); + wirehemf = buffer + 4; ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); - ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf); + ok(*(DWORD *)wirehemf == (size - 0x14), "wirestgm + 0x8 should be size - 0x14 instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); - ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf); + ok(*(DWORD *)wirehemf == (size - 0x14), "wirestgm + 0xc should be size - 0x14 instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %d\n", *(DWORD *)wirehemf); /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits * at this point */ init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2); + buffer_end = HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer + 1, &hemf2); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); @@ -374,18 +379,20 @@ static void test_marshal_HENHMETAFILE(void) hemf = NULL; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); - size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf); - ok(size == 8, "size should be 8 bytes, not %d\n", size); + size = HENHMETAFILE_UserSize(&umcb.Flags, 1, &hemf); + ok(size == 12, "size should be 12 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf); - wirehemf = buffer; + buffer_end = HENHMETAFILE_UserMarshal(&umcb.Flags, buffer + 1, &hemf); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); + wirehemf = buffer + 4; ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2); + buffer_end = HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer + 1, &hemf2); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); @@ -486,12 +493,12 @@ static void test_marshal_HMETAFILEPICT(void) GlobalUnlock(hmfp); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); - size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp); - ok(size > 20, "size should be at least 20 bytes, not %d\n", size); + size = HMETAFILEPICT_UserSize(&umcb.Flags, 1, &hmfp); + ok(size > 24, "size should be at least 24 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp); - wirehmfp = buffer; + buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer + 1, &hmfp); + wirehmfp = buffer + 4; ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp); @@ -512,16 +519,16 @@ static void test_marshal_HMETAFILEPICT(void) wirehmfp += sizeof(DWORD); /* Note use (buffer_end - buffer) instead of size here, because size is an * overestimate with native */ - ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp); + ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x2c), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); - ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp); + ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x2c), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); ok(*(WORD *)wirehmfp == 1, "wirehmfp + 0x28 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp); /* ... rest of data not tested - refer to tests for GetMetaFileBits * at this point */ init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2); + HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer + 1, &hmfp2); ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); @@ -535,12 +542,13 @@ static void test_marshal_HMETAFILEPICT(void) hmfp = NULL; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); - size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp); - ok(size == 8, "size should be 8 bytes, not %d\n", size); + size = HMETAFILEPICT_UserSize(&umcb.Flags, 1, &hmfp); + ok(size == 12, "size should be 12 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp); - wirehmfp = buffer; + buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer + 1, &hmfp); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); + wirehmfp = buffer + 4; ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp); @@ -548,7 +556,8 @@ static void test_marshal_HMETAFILEPICT(void) hmfp2 = NULL; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); - HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2); + buffer_end = HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer + 1, &hmfp2); + ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer); ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); @@ -1082,23 +1091,25 @@ static void test_marshal_HDC(void) HDC hdc = GetDC(0), hdc2; USER_MARSHAL_CB umcb; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; wireHDC wirehdc; ULONG size; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); - size = HDC_UserSize(&umcb.Flags, 0, &hdc); - ok(size == sizeof(*wirehdc), "Wrong size %d\n", size); + size = HDC_UserSize(&umcb.Flags, 1, &hdc); + ok(size == 4 + sizeof(*wirehdc), "Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HDC_UserMarshal(&umcb.Flags, buffer, &hdc); - wirehdc = (wireHDC)buffer; + buffer_end = HDC_UserMarshal(&umcb.Flags, buffer + 1, &hdc); + ok(buffer_end == buffer + 4 + sizeof(*wirehdc), "got %p buffer %p\n", buffer_end, buffer); + wirehdc = (wireHDC)(buffer + 4); ok(wirehdc->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehdc->fContext); ok(wirehdc->u.hInproc == (LONG_PTR)hdc, "Marshaled value should be %p instead of %x\n", hdc, wirehdc->u.hRemote); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HDC_UserUnmarshal(&umcb.Flags, buffer, &hdc2); + buffer_end = HDC_UserUnmarshal(&umcb.Flags, buffer + 1, &hdc2); + ok(buffer_end == buffer + 4 + sizeof(*wirehdc), "got %p buffer %p\n", buffer_end, buffer); ok(hdc == hdc2, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); @@ -1114,7 +1125,7 @@ static void test_marshal_HICON(void) HICON hIcon, hIcon2; USER_MARSHAL_CB umcb; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; wireHICON wirehicon; ULONG size; @@ -1122,18 +1133,20 @@ static void test_marshal_HICON(void) ok(hIcon != 0, "CreateIcon failed\n"); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); - size = HICON_UserSize(&umcb.Flags, 0, &hIcon); - ok(size == sizeof(*wirehicon), "Wrong size %d\n", size); + size = HICON_UserSize(&umcb.Flags, 1, &hIcon); + ok(size == 4 + sizeof(*wirehicon), "Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HICON_UserMarshal(&umcb.Flags, buffer, &hIcon); - wirehicon = (wireHICON)buffer; + buffer_end = HICON_UserMarshal(&umcb.Flags, buffer + 1, &hIcon); + ok(buffer_end == buffer + 4 + sizeof(*wirehicon), "got %p buffer %p\n", buffer_end, buffer); + wirehicon = (wireHICON)(buffer + 4); ok(wirehicon->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehicon->fContext); ok(wirehicon->u.hInproc == (LONG_PTR)hIcon, "Marshaled value should be %p instead of %x\n", hIcon, wirehicon->u.hRemote); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HICON_UserUnmarshal(&umcb.Flags, buffer, &hIcon2); + buffer_end = HICON_UserUnmarshal(&umcb.Flags, buffer + 1, &hIcon2); + ok(buffer_end == buffer + 4 + sizeof(*wirehicon), "got %p buffer %p\n", buffer_end, buffer); ok(hIcon == hIcon2, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); @@ -1148,7 +1161,7 @@ static void test_marshal_HBRUSH(void) HBRUSH hBrush, hBrush2; USER_MARSHAL_CB umcb; RPC_MESSAGE rpc_msg; - unsigned char *buffer; + unsigned char *buffer, *buffer_end; LOGBRUSH logbrush; wireHBRUSH wirehbrush; ULONG size; @@ -1161,18 +1174,20 @@ static void test_marshal_HBRUSH(void) ok(hBrush != 0, "CreateBrushIndirect failed\n"); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); - size = HBRUSH_UserSize(&umcb.Flags, 0, &hBrush); - ok(size == sizeof(*wirehbrush), "Wrong size %d\n", size); + size = HBRUSH_UserSize(&umcb.Flags, 1, &hBrush); + ok(size == 4 + sizeof(*wirehbrush), "Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HBRUSH_UserMarshal(&umcb.Flags, buffer, &hBrush); - wirehbrush = (wireHBRUSH)buffer; + buffer_end = HBRUSH_UserMarshal(&umcb.Flags, buffer + 1, &hBrush); + ok(buffer_end == buffer + 4 + sizeof(*wirehbrush), "got %p buffer %p\n", buffer_end, buffer); + wirehbrush = (wireHBRUSH)(buffer + 4); ok(wirehbrush->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehbrush->fContext); ok(wirehbrush->u.hInproc == (LONG_PTR)hBrush, "Marshaled value should be %p instead of %x\n", hBrush, wirehbrush->u.hRemote); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); - HBRUSH_UserUnmarshal(&umcb.Flags, buffer, &hBrush2); + buffer_end = HBRUSH_UserUnmarshal(&umcb.Flags, buffer + 1, &hBrush2); + ok(buffer_end == buffer + 4 + sizeof(*wirehbrush), "got %p buffer %p\n", buffer_end, buffer); ok(hBrush == hBrush2, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); @@ -1181,6 +1196,69 @@ static void test_marshal_HBRUSH(void) DeleteObject(hBrush); } +static void test_marshal_HBITMAP(void) +{ + static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize); + static BYTE bmp_bits[1024]; + MIDL_STUB_MESSAGE stub_msg; + HBITMAP hBitmap, hBitmap2; + USER_MARSHAL_CB umcb; + RPC_MESSAGE rpc_msg; + unsigned char *buffer, *buffer_end; + unsigned char bitmap[1024]; + ULONG size, bitmap_size; + + hBitmap = CreateBitmap(16, 16, 1, 1, bmp_bits); + ok(hBitmap != 0, "CreateBitmap failed\n"); + size = GetObjectA(hBitmap, sizeof(bitmap), bitmap); + ok(size != 0, "GetObject failed\n"); + bitmap_size = GetBitmapBits(hBitmap, 0, NULL); + ok(bitmap_size != 0, "GetBitmapBits failed\n"); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); + size = HBITMAP_UserSize(&umcb.Flags, 1, &hBitmap); + ok(size == 0xc, "Wrong size %d\n", size); + buffer = HeapAlloc(GetProcessHeap(), 0, size + 4); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); + buffer_end = HBITMAP_UserMarshal(&umcb.Flags, buffer + 1, &hBitmap); + ok(buffer_end == buffer + 0xc, "HBITMAP_UserMarshal() returned wrong size %d\n", (LONG)(buffer_end - buffer)); + ok(*(ULONG *)(buffer + 0x4) == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", *(ULONG *)(buffer + 0x4)); + ok(*(ULONG *)(buffer + 0x8) == (ULONG)(ULONG_PTR)hBitmap, "wirestgm + 0x4 should be bitmap handle instead of 0x%08x\n", *(ULONG *)(buffer + 0x8)); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); + HBITMAP_UserUnmarshal(&umcb.Flags, buffer + 1, &hBitmap2); + ok(hBitmap2 != NULL, "Didn't unmarshal properly\n"); + HeapFree(GetProcessHeap(), 0, buffer); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); + HBITMAP_UserFree(&umcb.Flags, &hBitmap2); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HBITMAP_UserSize(&umcb.Flags, 1, &hBitmap); + ok(size == 0x10 + header_size + bitmap_size || + broken(size == 0x14 + header_size + bitmap_size), /* Windows adds 4 extra (unused) bytes */ + "Wrong size %d\n", size); + + buffer = HeapAlloc(GetProcessHeap(), 0, size + 4); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + buffer_end = HBITMAP_UserMarshal(&umcb.Flags, buffer + 1, &hBitmap); + ok(buffer_end == buffer + 0x10 + header_size + bitmap_size, "HBITMAP_UserMarshal() returned wrong size %d\n", (LONG)(buffer_end - buffer)); + ok(*(ULONG *)(buffer + 0x4) == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)buffer); + ok(*(ULONG *)(buffer + 0x8) == (ULONG)(ULONG_PTR)hBitmap, "wirestgm + 0x4 should be bitmap handle instead of 0x%08x\n", *(ULONG *)(buffer + 0x4)); + ok(*(ULONG *)(buffer + 0xc) == (ULONG)(ULONG_PTR)bitmap_size, "wirestgm + 0x8 should be bitmap size instead of 0x%08x\n", *(ULONG *)(buffer + 0x4)); + ok(!memcmp(buffer + 0x10, bitmap, header_size), "buffer mismatch\n"); + ok(!memcmp(buffer + 0x10 + header_size, bmp_bits, bitmap_size), "buffer mismatch\n"); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HBITMAP_UserUnmarshal(&umcb.Flags, buffer + 1, &hBitmap2); + ok(hBitmap2 != NULL, "Didn't unmarshal properly\n"); + HeapFree(GetProcessHeap(), 0, buffer); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + HBITMAP_UserFree(&umcb.Flags, &hBitmap2); + DeleteObject(hBitmap); +} + struct obj { IDataObject IDataObject_iface; @@ -1344,6 +1422,7 @@ START_TEST(usrmarshal) test_marshal_HDC(); test_marshal_HICON(); test_marshal_HBRUSH(); + test_marshal_HBITMAP(); test_GetDataHere_Proxy(); -- 2.17.1