* 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
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;
{
const char *method;
unsigned int flags;
+ FORMATETC fmt;
};
static const struct expected_method *expected_method_list;
static UINT cf_test_1, cf_test_2, cf_test_3;
+static FORMATETC *g_dataobject_fmts;
+
/****************************************************************************
* 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;
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 { \
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");
break;
}
- header.unknown3 = 4;
+ header.tdSize = sizeof(header.tdSize);
header.dvAspect = DVASPECT_CONTENT;
header.lindex = -1;
header.advf = 1 << i;
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(
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(
IOleCache2 *pOleCache;
IOleCache *olecache;
IStorage *pStorage;
- IUnknown *unk;
+ IUnknown *unk, *unk2;
IPersistStorage *pPS;
IViewObject *pViewObject;
IOleCacheControl *pOleCacheControl;
{ "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[] =
{ "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 },
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);
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");
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
};
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;
"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 );
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 );
GlobalUnlock( h );
}
-static void test_data_cache_bitmap(void)
+static void test_data_cache_cache(void)
{
HRESULT hr;
IOleCache2 *cache;
{{ 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 );
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 );
/* 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 );
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 );
}
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);
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)
{
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;
}
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;
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));
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)
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;
}
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;
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();
}
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);
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);
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;
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);
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);
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);
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);
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);
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);
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);
HICON hIcon, hIcon2;
USER_MARSHAL_CB umcb;
RPC_MESSAGE rpc_msg;
- unsigned char *buffer;
+ unsigned char *buffer, *buffer_end;
wireHICON wirehicon;
ULONG size;
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);
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;
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);
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;
test_marshal_HDC();
test_marshal_HICON();
test_marshal_HBRUSH();
+ test_marshal_HBITMAP();
test_GetDataHere_Proxy();