[OLE32] Sync with Wine 3.0. CORE-14225
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 20 Jan 2018 11:57:25 +0000 (12:57 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 20 Jan 2018 11:57:25 +0000 (12:57 +0100)
12 files changed:
dll/win32/ole32/compobj.c
dll/win32/ole32/compobj_private.h
dll/win32/ole32/datacache.c
dll/win32/ole32/enumx.c
dll/win32/ole32/enumx.h
dll/win32/ole32/hglobalstream.c
dll/win32/ole32/rpc.c
dll/win32/ole32/stg_prop.c
dll/win32/ole32/storage32.c
dll/win32/ole32/storage32.h
dll/win32/ole32/usrmarshal.c
media/doc/README.WINE

index cdadd0f..fd912d4 100644 (file)
@@ -1702,12 +1702,6 @@ HWND apartment_getwindow(const struct apartment *apt)
     return apt->win;
 }
 
-void apartment_joinmta(void)
-{
-    apartment_addref(MTA);
-    COM_CurrentInfo()->apt = MTA;
-}
-
 static void COM_TlsDestroy(void)
 {
     struct oletls *info = NtCurrentTeb()->ReservedForOle;
@@ -1812,6 +1806,40 @@ HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
     return S_OK;
 }
 
+HRESULT enter_apartment( struct oletls *info, DWORD model )
+{
+    HRESULT hr = S_OK;
+
+    if (!info->apt)
+    {
+        if (!apartment_get_or_create( model ))
+            return E_OUTOFMEMORY;
+    }
+    else if (!apartment_is_model( info->apt, model ))
+    {
+        WARN( "Attempt to change threading model of this apartment from %s to %s\n",
+              info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
+              model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
+        return RPC_E_CHANGED_MODE;
+    }
+    else
+        hr = S_FALSE;
+
+    info->inits++;
+
+    return hr;
+}
+
+void leave_apartment( struct oletls *info )
+{
+    if (!--info->inits)
+    {
+        if (info->ole_inits)
+            WARN( "Uninitializing apartment while Ole is still initialized\n" );
+        apartment_release( info->apt );
+        info->apt = NULL;
+    }
+}
 
 /******************************************************************************
  *             CoInitialize    [OLE32.@]
@@ -1870,8 +1898,7 @@ HRESULT WINAPI CoInitialize(LPVOID lpReserved)
 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
 {
   struct oletls *info = COM_CurrentInfo();
-  HRESULT hr = S_OK;
-  APARTMENT *apt;
+  HRESULT hr;
 
   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
 
@@ -1900,24 +1927,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoIni
   if (info->spy)
       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
 
-  if (!(apt = info->apt))
-  {
-    apt = apartment_get_or_create(dwCoInit);
-    if (!apt) return E_OUTOFMEMORY;
-  }
-  else if (!apartment_is_model(apt, dwCoInit))
-  {
-    /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
-       code then we are probably using the wrong threading model to implement that API. */
-    ERR("Attempt to change threading model of this apartment from %s to %s\n",
-        apt->multi_threaded ? "multi-threaded" : "apartment threaded",
-        dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
-    return RPC_E_CHANGED_MODE;
-  }
-  else
-    hr = S_FALSE;
-
-  info->inits++;
+  hr = enter_apartment( info, dwCoInit );
 
   if (info->spy)
       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
@@ -1964,13 +1974,7 @@ void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
     return;
   }
 
-  if (!--info->inits)
-  {
-    if (info->ole_inits)
-      WARN("uninitializing apartment while Ole is still initialized\n");
-    apartment_release(info->apt);
-    info->apt = NULL;
-  }
+  leave_apartment( info );
 
   /*
    * Decrease the reference count.
index 672b394..c1739f5 100644 (file)
@@ -233,8 +233,8 @@ static inline HRESULT apartment_getoxid(const struct apartment *apt, OXID *oxid)
 }
 HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN;
 HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN;
-void apartment_joinmta(void) DECLSPEC_HIDDEN;
-
+HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN;
+void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN;
 
 /* DCOM messages used by the apartment window (not compatible with native) */
 #define DM_EXECUTERPC   (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */
index 8c3fe48..e369776 100644 (file)
@@ -64,7 +64,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;
@@ -86,8 +87,6 @@ typedef struct DataCacheEntry
   struct list entry;
   /* format of this entry */
   FORMATETC fmtetc;
-  /* the clipboard format of the data */
-  CLIPFORMAT data_cf;
   /* cached data */
   STGMEDIUM stgmedium;
   /*
@@ -295,10 +294,10 @@ static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FOR
     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
     {
         /* FIXME: also compare DVTARGETDEVICEs */
-        if ((!cache_entry->fmtetc.cfFormat || !fmt.cfFormat || (fmt.cfFormat == cache_entry->fmtetc.cfFormat)) &&
+        if ((fmt.cfFormat == cache_entry->fmtetc.cfFormat) &&
             (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
             (fmt.lindex == cache_entry->fmtetc.lindex) &&
-            (!cache_entry->fmtetc.tymed || !fmt.tymed || (fmt.tymed == cache_entry->fmtetc.tymed)))
+            ((fmt.tymed == cache_entry->fmtetc.tymed) || !cache_entry->fmtetc.cfFormat)) /* tymed is ignored for view caching */
             return cache_entry;
     }
     return NULL;
@@ -307,19 +306,23 @@ static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FOR
 /* checks that the clipformat and tymed are valid and returns an error if they
 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
 * DataCache_Draw */
-static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
+static HRESULT check_valid_formatetc( const FORMATETC *fmt )
 {
-    if (!cfFormat || !tymed ||
-        (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
-        (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
-        (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
-        (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
+    /* DVASPECT_ICON must be CF_METAFILEPICT */
+    if (fmt->dwAspect == DVASPECT_ICON && fmt->cfFormat != CF_METAFILEPICT)
+        return DV_E_FORMATETC;
+
+    if (!fmt->cfFormat ||
+        (fmt->cfFormat == CF_METAFILEPICT && fmt->tymed == TYMED_MFPICT) ||
+        (fmt->cfFormat == CF_BITMAP && fmt->tymed == TYMED_GDI) ||
+        (fmt->cfFormat == CF_DIB && fmt->tymed == TYMED_HGLOBAL) ||
+        (fmt->cfFormat == CF_ENHMETAFILE && fmt->tymed == TYMED_ENHMF))
         return S_OK;
-    else if (tymed == TYMED_HGLOBAL)
+    else if (fmt->tymed == TYMED_HGLOBAL)
         return CACHE_S_FORMATETC_NOTSUPPORTED;
     else
     {
-        WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
+        WARN("invalid clipformat/tymed combination: %d/%d\n", fmt->cfFormat, fmt->tymed);
         return DV_E_TYMED;
     }
 }
@@ -332,7 +335,6 @@ static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD
     hr = copy_formatetc(&entry->fmtetc, fmt);
     if (FAILED(hr)) return FALSE;
 
-    entry->data_cf = 0;
     entry->stgmedium.tymed = TYMED_NULL;
     entry->stgmedium.pUnkForRelease = NULL;
     entry->stream = NULL;
@@ -353,7 +355,7 @@ static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc
     DWORD id = automatic ? 1 : This->last_cache_id;
     DataCacheEntry *entry;
 
-    hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
+    hr = check_valid_formatetc( formatetc );
     if (FAILED(hr))
         return hr;
     if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
@@ -454,6 +456,10 @@ static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
     hr = IStream_Read(stream, &length, sizeof(length), &read);
     if (hr != S_OK || read != sizeof(length))
         return DV_E_CLIPFORMAT;
+    if (!length) {
+        /* No clipboard format present */
+        return S_OK;
+    }
     if (length == -1)
     {
         DWORD cf;
@@ -483,11 +489,16 @@ static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
 {
     DWORD length;
     HRESULT hr;
+    char format_name[256];
 
     if (clipformat < 0xc000)
         length = -1;
     else
-        length = GetClipboardFormatNameA(clipformat, NULL, 0);
+    {
+        length = GetClipboardFormatNameA(clipformat, format_name, sizeof(format_name));
+        /* If there is a clipboard format name, we need to include its terminating \0 */
+        if (length) length++;
+    }
     hr = IStream_Write(stream, &length, sizeof(length), NULL);
     if (FAILED(hr))
         return hr;
@@ -498,12 +509,7 @@ static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
     }
     else
     {
-        char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
-        if (!format_name)
-            return E_OUTOFMEMORY;
-        GetClipboardFormatNameA(clipformat, format_name, length);
         hr = IStream_Write(stream, format_name, length, NULL);
-        HeapFree(GetProcessHeap(), 0, format_name);
     }
     return hr;
 }
@@ -618,7 +624,6 @@ static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
     GlobalUnlock( hmfpict );
     if (SUCCEEDED( hr ))
     {
-        cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
         cache_entry->stgmedium.tymed = TYMED_MFPICT;
         cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
     }
@@ -703,7 +708,6 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
 
     GlobalUnlock( hglobal );
 
-    cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
     cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
     cache_entry->stgmedium.u.hGlobal = hglobal;
 
@@ -756,112 +760,273 @@ static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
     return hr;
 }
 
-static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
-                                           IStorage *storage, IStream **stream)
+static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header)
 {
-    WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
-        '0' + (cache_entry->stream_number / 100) % 10,
-        '0' + (cache_entry->stream_number / 10) % 10,
-        '0' + cache_entry->stream_number % 10, 0};
-
-    /* FIXME: cache the created stream in This? */
-    return IStorage_CreateStream(storage, wszName,
-                                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
-                                 0, 0, stream);
+    if (entry->fmtetc.ptd)
+        FIXME("ptd not serialized\n");
+    header->tdSize = sizeof(header->tdSize);
+    header->dvAspect = entry->fmtetc.dwAspect;
+    header->lindex = entry->fmtetc.lindex;
+    header->advf = entry->advise_flags;
+    header->unknown7 = 0;
+    header->dwObjectExtentX = 0;
+    header->dwObjectExtentY = 0;
+    header->dwSize = 0;
 }
 
-static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
-                                   BOOL same_as_load)
+static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream)
 {
-    PresentationDataHeader header;
-    HRESULT hr;
-    IStream *pres_stream;
-    void *data = NULL;
-
-    TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
+    HRESULT hr = S_OK;
+    int data_size = 0;
+    BITMAPINFO *bmi = NULL;
 
-    hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
-    if (FAILED(hr))
-        return hr;
+    if (entry->stgmedium.tymed != TYMED_NULL)
+    {
+        data_size = GlobalSize(entry->stgmedium.u.hGlobal);
+        bmi = GlobalLock(entry->stgmedium.u.hGlobal);
+    }
 
-    hr = write_clipformat(pres_stream, cache_entry->data_cf);
-    if (FAILED(hr))
-        return hr;
+    if (!contents)
+    {
+        PresentationDataHeader header;
 
-    if (cache_entry->fmtetc.ptd)
-        FIXME("ptd not serialized\n");
-    header.unknown3 = 4;
-    header.dvAspect = cache_entry->fmtetc.dwAspect;
-    header.lindex = cache_entry->fmtetc.lindex;
-    header.advf = cache_entry->advise_flags;
-    header.unknown7 = 0;
-    header.dwObjectExtentX = 0;
-    header.dwObjectExtentY = 0;
-    header.dwSize = 0;
-
-    /* size the data */
-    switch (cache_entry->data_cf)
-    {
-        case CF_METAFILEPICT:
+        init_stream_header(entry, &header);
+        hr = write_clipformat(stream, entry->fmtetc.cfFormat);
+        if (FAILED(hr)) goto end;
+        if (data_size)
         {
-            if (cache_entry->stgmedium.tymed != TYMED_NULL)
+            header.dwSize = data_size;
+            /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
+            if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0)
             {
-                const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
-                if (!mfpict)
-                {
-                    IStream_Release(pres_stream);
-                    return DV_E_STGMEDIUM;
-                }
-                header.dwObjectExtentX = mfpict->xExt;
-                header.dwObjectExtentY = mfpict->yExt;
-                header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
-                GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
+                header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter);
+                header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter);
+            }
+            else
+            {
+                HDC hdc = GetDC(0);
+                header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
+                header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
+                ReleaseDC(0, hdc);
             }
-            break;
         }
-        default:
-            break;
+        hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
+        if (hr == S_OK && data_size)
+            hr = IStream_Write(stream, bmi, data_size, NULL);
     }
-
-    /*
-     * Write the header.
-     */
-    hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
-                       NULL);
-    if (FAILED(hr))
+    else if(data_size)
     {
-        IStream_Release(pres_stream);
-        return hr;
+        BITMAPFILEHEADER bmp_fhdr;
+
+        bmp_fhdr.bfType = 0x4d42;
+        bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER);
+        bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0;
+        bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER);
+        hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL);
+        if (hr == S_OK)
+            hr = IStream_Write(stream, bmi, data_size, NULL);
     }
 
-    /* get the data */
-    switch (cache_entry->data_cf)
+end:
+    if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal);
+    return hr;
+}
+
+#include <pshpack2.h>
+struct meta_placeable
+{
+    DWORD key;
+    WORD hwmf;
+    WORD bounding_box[4];
+    WORD inch;
+    DWORD reserved;
+    WORD checksum;
+};
+#include <poppack.h>
+
+static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream)
+{
+    HRESULT hr = S_OK;
+    int data_size = 0;
+    void *data = NULL;
+    METAFILEPICT *mfpict = NULL;
+
+    if (!contents)
     {
-        case CF_METAFILEPICT:
+        PresentationDataHeader header;
+
+        init_stream_header(entry, &header);
+        hr = write_clipformat(stream, entry->fmtetc.cfFormat);
+        if (FAILED(hr)) return hr;
+        if (entry->stgmedium.tymed != TYMED_NULL)
         {
-            if (cache_entry->stgmedium.tymed != TYMED_NULL)
+            mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
+            if (!mfpict)
+                return DV_E_STGMEDIUM;
+            data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
+            header.dwObjectExtentX = mfpict->xExt;
+            header.dwObjectExtentY = mfpict->yExt;
+            header.dwSize = data_size;
+            data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
+            if (!data)
             {
-                const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
-                if (!mfpict)
-                {
-                    IStream_Release(pres_stream);
-                    return DV_E_STGMEDIUM;
-                }
-                data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
-                GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
-                GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
+                GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
+                return E_OUTOFMEMORY;
             }
-            break;
+            GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
+            GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
         }
-        default:
-            break;
+        hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
+        if (hr == S_OK && data_size)
+            hr = IStream_Write(stream, data, data_size, NULL);
+        HeapFree(GetProcessHeap(), 0, data);
     }
+    else if (entry->stgmedium.tymed != TYMED_NULL)
+    {
+        struct meta_placeable meta_place_rec;
+        WORD *check;
 
-    if (data)
-        hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
-    HeapFree(GetProcessHeap(), 0, data);
+        mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
+        if (!mfpict)
+            return DV_E_STGMEDIUM;
+        data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
+        data = HeapAlloc(GetProcessHeap(), 0, data_size);
+        if (!data)
+        {
+            GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
+            return E_OUTOFMEMORY;
+        }
+        GetMetaFileBitsEx(mfpict->hMF, data_size, data);
+
+        /* units are in 1/8th of a point (1 point is 1/72th of an inch) */
+        meta_place_rec.key = 0x9ac6cdd7;
+        meta_place_rec.hwmf = 0;
+        meta_place_rec.inch = 576;
+        meta_place_rec.bounding_box[0] = 0;
+        meta_place_rec.bounding_box[1] = 0;
+        meta_place_rec.bounding_box[2] = 0;
+        meta_place_rec.bounding_box[3] = 0;
+        meta_place_rec.checksum = 0;
+        meta_place_rec.reserved = 0;
+
+        /* These values are rounded down so MulDiv won't do the right thing */
+        meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540;
+        meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540;
+        GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
+
+        for (check = (WORD *)&meta_place_rec; check != (WORD *)&meta_place_rec.checksum; check++)
+            meta_place_rec.checksum ^= *check;
+        hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL);
+        if (hr == S_OK && data_size)
+            hr = IStream_Write(stream, data, data_size, NULL);
+        HeapFree(GetProcessHeap(), 0, data);
+    }
+
+    return hr;
+}
+
+static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream)
+{
+    HRESULT hr = S_OK;
+    int data_size = 0;
+    BYTE *data;
+
+    if (!contents)
+    {
+        PresentationDataHeader header;
+        METAFILEPICT *mfpict;
+        HDC hdc = GetDC(0);
+
+        init_stream_header(entry, &header);
+        hr = write_clipformat(stream, entry->fmtetc.cfFormat);
+        if (FAILED(hr))
+        {
+            ReleaseDC(0, hdc);
+            return hr;
+        }
+        data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc);
+        header.dwSize = data_size;
+        data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
+        if (!data)
+        {
+            ReleaseDC(0, hdc);
+            return E_OUTOFMEMORY;
+        }
+        GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc);
+        ReleaseDC(0, hdc);
+        mfpict = (METAFILEPICT *)data;
+        header.dwObjectExtentX = mfpict->xExt;
+        header.dwObjectExtentY = mfpict->yExt;
+        hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
+        if (hr == S_OK && data_size)
+            hr = IStream_Write(stream, data, data_size, NULL);
+        HeapFree(GetProcessHeap(), 0, data);
+    }
+    else if (entry->stgmedium.tymed != TYMED_NULL)
+    {
+        data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL);
+        data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size);
+        if (!data) return E_OUTOFMEMORY;
+        *((DWORD *)data) = sizeof(ENHMETAHEADER);
+        GetEnhMetaFileBits(entry->stgmedium.u.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);
+        hr = IStream_Write(stream, data, data_size, NULL);
+        HeapFree(GetProcessHeap(), 0, data);
+    }
 
-    IStream_Release(pres_stream);
+    return hr;
+}
+
+static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
+static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage,
+                             BOOL contents, IStream **stream)
+{
+    WCHAR pres[] = {2,'O','l','e','P','r','e','s',
+        '0' + (cache_entry->stream_number / 100) % 10,
+        '0' + (cache_entry->stream_number / 10) % 10,
+        '0' + cache_entry->stream_number % 10, 0};
+    const WCHAR *name;
+
+    if (contents)
+        name = CONTENTS;
+    else
+        name = pres;
+
+    return IStorage_CreateStream(storage, name,
+                                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+                                 0, 0, stream);
+}
+
+static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
+                                   BOOL same_as_load)
+{
+    HRESULT hr;
+    IStream *stream;
+    BOOL contents = (cache_entry->id == 1);
+
+    TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
+
+    hr = create_stream(cache_entry, storage, contents, &stream);
+    if (FAILED(hr))
+        return hr;
+
+    switch (cache_entry->fmtetc.cfFormat)
+    {
+    case CF_DIB:
+        hr = save_dib(cache_entry, contents, stream);
+        break;
+    case CF_METAFILEPICT:
+        hr = save_mfpict(cache_entry, contents, stream);
+        break;
+    case CF_ENHMETAFILE:
+        hr = save_emf(cache_entry, contents, stream);
+        break;
+    default:
+        FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat);
+    }
+
+    IStream_Release(stream);
     return hr;
 }
 
@@ -904,12 +1069,12 @@ static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
     return S_OK;
 }
 
-static HGLOBAL synthesize_dib( HBITMAP bm )
+static HRESULT synthesize_dib( HBITMAP bm, STGMEDIUM *med )
 {
     HDC hdc = GetDC( 0 );
     BITMAPINFOHEADER header;
     BITMAPINFO *bmi;
-    HGLOBAL ret = 0;
+    HRESULT hr = E_FAIL;
     DWORD header_size;
 
     memset( &header, 0, sizeof(header) );
@@ -917,34 +1082,64 @@ static HGLOBAL synthesize_dib( HBITMAP bm )
     if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
 
     header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
-    if (!(ret = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
-    bmi = GlobalLock( ret );
+    if (!(med->u.hGlobal = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
+    bmi = GlobalLock( med->u.hGlobal );
     memset( bmi, 0, header_size );
     memcpy( bmi, &header, header.biSize );
     GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
-    GlobalUnlock( ret );
+    GlobalUnlock( med->u.hGlobal );
+    med->tymed = TYMED_HGLOBAL;
+    med->pUnkForRelease = NULL;
+    hr = S_OK;
 
 done:
     ReleaseDC( 0, hdc );
-    return ret;
+    return hr;
 }
 
-static HBITMAP synthesize_bitmap( HGLOBAL dib )
+static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med )
 {
-    HBITMAP ret = 0;
+    HRESULT hr = E_FAIL;
     BITMAPINFO *bmi;
     HDC hdc = GetDC( 0 );
 
     if ((bmi = GlobalLock( dib )))
     {
         /* FIXME: validate data size */
-        ret = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
-                              (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
-                              bmi, DIB_RGB_COLORS );
+        med->u.hBitmap = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
+                                         (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
+                                         bmi, DIB_RGB_COLORS );
         GlobalUnlock( dib );
+        med->tymed = TYMED_GDI;
+        med->pUnkForRelease = NULL;
+        hr = S_OK;
     }
     ReleaseDC( 0, hdc );
-    return ret;
+    return hr;
+}
+
+static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med )
+{
+    METAFILEPICT *pict;
+    HRESULT hr = E_FAIL;
+    UINT size;
+    void *bits;
+
+    if (!(pict = GlobalLock( data ))) return hr;
+
+    size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
+    if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
+    {
+        GetMetaFileBitsEx( pict->hMF, size, bits );
+        med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict );
+        HeapFree( GetProcessHeap(), 0, bits );
+        med->tymed = TYMED_ENHMF;
+        med->pUnkForRelease = NULL;
+        hr = S_OK;
+    }
+
+    GlobalUnlock( data );
+    return hr;
 }
 
 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
@@ -952,7 +1147,8 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
                                       STGMEDIUM *stgmedium,
                                       BOOL fRelease)
 {
-    STGMEDIUM dib_copy;
+    STGMEDIUM copy;
+    HRESULT hr;
 
     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
@@ -964,15 +1160,21 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
 
     cache_entry->dirty = TRUE;
     ReleaseStgMedium(&cache_entry->stgmedium);
-    cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
 
     if (formatetc->cfFormat == CF_BITMAP)
     {
-        dib_copy.tymed = TYMED_HGLOBAL;
-        dib_copy.u.hGlobal = synthesize_dib( stgmedium->u.hBitmap );
-        dib_copy.pUnkForRelease = NULL;
+        hr = synthesize_dib( stgmedium->u.hBitmap, &copy );
+        if (FAILED(hr)) return hr;
         if (fRelease) ReleaseStgMedium(stgmedium);
-        stgmedium = &dib_copy;
+        stgmedium = &copy;
+        fRelease = TRUE;
+    }
+    else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE)
+    {
+        hr = synthesize_emf( stgmedium->u.hMetaFilePict, &copy );
+        if (FAILED(hr)) return hr;
+        if (fRelease) ReleaseStgMedium(stgmedium);
+        stgmedium = &copy;
         fRelease = TRUE;
     }
 
@@ -982,8 +1184,7 @@ static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
         return S_OK;
     }
     else
-        return copy_stg_medium(cache_entry->data_cf,
-                               &cache_entry->stgmedium, stgmedium);
+        return copy_stg_medium(cache_entry->fmtetc.cfFormat, &cache_entry->stgmedium, stgmedium);
 }
 
 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, FORMATETC *fmt, STGMEDIUM *stgmedium)
@@ -998,19 +1199,14 @@ static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, FORMATETC *fm
         return OLE_E_BLANK;
 
     if (fmt->cfFormat == CF_BITMAP)
-    {
-        stgmedium->tymed = TYMED_GDI;
-        stgmedium->u.hBitmap = synthesize_bitmap( cache_entry->stgmedium.u.hGlobal );
-        stgmedium->pUnkForRelease = NULL;
-        return S_OK;
-    }
-    return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
+        return synthesize_bitmap( cache_entry->stgmedium.u.hGlobal, stgmedium );
+
+    return copy_stg_medium(cache_entry->fmtetc.cfFormat, stgmedium, &cache_entry->stgmedium);
 }
 
 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
 {
     ReleaseStgMedium(&cache_entry->stgmedium);
-    cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
     return S_OK;
 }
 
@@ -1108,7 +1304,10 @@ static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
 
   if (IsEqualIID(&IID_IUnknown, riid))
   {
-    *ppvObject = iface;
+    if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */
+      *ppvObject = &this->IOleCache2_iface;
+    else
+      *ppvObject = iface;
   }
   else if (IsEqualIID(&IID_IDataObject, riid))
   {
@@ -1230,6 +1429,8 @@ static HRESULT WINAPI DataCache_GetData(
     DataCache *This = impl_from_IDataObject(iface);
     DataCacheEntry *cache_entry;
 
+    TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
+
     memset(pmedium, 0, sizeof(*pmedium));
 
     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
@@ -1561,8 +1762,6 @@ static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *s
     return add_cache_entry( This, fmt, 0, stm, contents_stream );
 }
 
-static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
-
 /************************************************************************
  * DataCache_Load (IPersistStorage)
  *
@@ -1621,35 +1820,14 @@ static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
  * our responsibility to copy the information when saving to a new
  * storage.
  */
-static HRESULT WINAPI DataCache_Save(
-            IPersistStorage* iface,
-           IStorage*        pStg,
-           BOOL             fSameAsLoad)
+static HRESULT WINAPI DataCache_Save(IPersistStorage* iface, IStorage *stg, BOOL same_as_load)
 {
     DataCache *This = impl_from_IPersistStorage(iface);
     DataCacheEntry *cache_entry;
-    BOOL dirty = FALSE;
     HRESULT hr = S_OK;
     unsigned short stream_number = 0;
 
-    TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
-
-    dirty = This->dirty;
-    if (!dirty)
-    {
-        LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
-        {
-            dirty = cache_entry->dirty;
-            if (dirty)
-                break;
-        }
-    }
-
-    /* this is a shortcut if nothing changed */
-    if (!dirty && !fSameAsLoad && This->presentationStorage)
-    {
-        return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
-    }
+    TRACE("(%p, %p, %d)\n", iface, stg, same_as_load);
 
     /* assign stream numbers to the cache entries */
     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
@@ -1665,17 +1843,17 @@ static HRESULT WINAPI DataCache_Save(
     /* write out the cache entries */
     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
     {
-        if (!fSameAsLoad || cache_entry->dirty)
+        if (!same_as_load || cache_entry->dirty)
         {
-            hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
+            hr = DataCacheEntry_Save(cache_entry, stg, same_as_load);
             if (FAILED(hr))
                 break;
 
-            cache_entry->dirty = FALSE;
+            if (same_as_load) cache_entry->dirty = FALSE;
         }
     }
 
-    This->dirty = FALSE;
+    if (same_as_load) This->dirty = FALSE;
     return hr;
 }
 
@@ -1826,7 +2004,7 @@ static HRESULT WINAPI DataCache_Draw(
 
     if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
 
-    switch (cache_entry->data_cf)
+    switch (cache_entry->fmtetc.cfFormat)
     {
       case CF_METAFILEPICT:
       {
@@ -2085,7 +2263,7 @@ static HRESULT WINAPI DataCache_GetExtent(
       continue;
 
 
-    switch (cache_entry->data_cf)
+    switch (cache_entry->fmtetc.cfFormat)
     {
       case CF_METAFILEPICT:
       {
@@ -2231,6 +2409,13 @@ static HRESULT WINAPI DataCache_Cache(
         fmt_cpy.tymed = TYMED_HGLOBAL;
     }
 
+    /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */
+    if (fmt_cpy.dwAspect == DVASPECT_ICON && fmt_cpy.cfFormat == 0)
+    {
+        fmt_cpy.cfFormat = CF_METAFILEPICT;
+        fmt_cpy.tymed = TYMED_MFPICT;
+    }
+
     *pdwConnection = 0;
 
     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
@@ -2327,12 +2512,10 @@ fail:
     return hr;
 }
 
-static HRESULT WINAPI DataCache_InitCache(
-           IOleCache2*     iface,
-           IDataObject*    pDataObject)
+static HRESULT WINAPI DataCache_InitCache( IOleCache2 *iface, IDataObject *data )
 {
-  FIXME("stub\n");
-  return E_NOTIMPL;
+    TRACE( "(%p %p)\n", iface, data );
+    return IOleCache2_UpdateCache( iface, data, UPDFCACHE_ALLBUTNODATACACHE, NULL );
 }
 
 static HRESULT WINAPI DataCache_IOleCache2_SetData(
@@ -2364,14 +2547,102 @@ static HRESULT WINAPI DataCache_IOleCache2_SetData(
     return OLE_E_BLANK;
 }
 
-static HRESULT WINAPI DataCache_UpdateCache(
-            IOleCache2*     iface,
-           LPDATAOBJECT    pDataObject,
-           DWORD           grfUpdf,
-           LPVOID          pReserved)
+static BOOL entry_updatable( DataCacheEntry *entry, DWORD mode )
 {
-  FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
-  return E_NOTIMPL;
+    BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL;
+
+    if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE;
+
+    if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE;
+    if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE;
+    if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE;
+    if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE;
+    if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE;
+
+    return FALSE;
+}
+
+static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data,
+                                             DWORD mode, void *reserved )
+{
+    DataCache *This = impl_from_IOleCache2(iface);
+    DataCacheEntry *cache_entry;
+    STGMEDIUM med;
+    HRESULT hr = S_OK;
+    CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP };
+    FORMATETC fmt;
+    int i, slots = 0;
+    BOOL done_one = FALSE;
+
+    TRACE( "(%p %p %08x %p)\n", iface, data, mode, reserved );
+
+    LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
+    {
+        slots++;
+
+        if (!entry_updatable( cache_entry, mode ))
+        {
+            done_one = TRUE;
+            continue;
+        }
+
+        fmt = cache_entry->fmtetc;
+
+        if (fmt.cfFormat)
+        {
+            hr = IDataObject_GetData( data, &fmt, &med );
+            if (hr != S_OK && fmt.cfFormat == CF_DIB)
+            {
+                fmt.cfFormat = CF_BITMAP;
+                fmt.tymed = TYMED_GDI;
+                hr = IDataObject_GetData( data, &fmt, &med );
+            }
+            if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE)
+            {
+                fmt.cfFormat = CF_METAFILEPICT;
+                fmt.tymed = TYMED_MFPICT;
+                hr = IDataObject_GetData( data, &fmt, &med );
+            }
+            if (hr == S_OK)
+            {
+                hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
+                if (hr != S_OK) ReleaseStgMedium( &med );
+                else done_one = TRUE;
+            }
+        }
+        else
+        {
+            for (i = 0; i < sizeof(view_list) / sizeof(view_list[0]); i++)
+            {
+                fmt.cfFormat = view_list[i];
+                fmt.tymed = tymed_from_cf( fmt.cfFormat );
+                hr = IDataObject_QueryGetData( data, &fmt );
+                if (hr == S_OK)
+                {
+                    hr = IDataObject_GetData( data, &fmt, &med );
+                    if (hr == S_OK)
+                    {
+                        if (fmt.cfFormat == CF_BITMAP)
+                        {
+                            cache_entry->fmtetc.cfFormat = CF_DIB;
+                            cache_entry->fmtetc.tymed = TYMED_HGLOBAL;
+                        }
+                        else
+                        {
+                            cache_entry->fmtetc.cfFormat = fmt.cfFormat;
+                            cache_entry->fmtetc.tymed = fmt.tymed;
+                        }
+                        hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
+                        if (hr != S_OK) ReleaseStgMedium( &med );
+                        else done_one = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED;
 }
 
 static HRESULT WINAPI DataCache_DiscardCache(
index 3af0cd1..7399a02 100644 (file)
@@ -30,8 +30,6 @@ struct tagEnumSTATPROPSETSTG_impl
     struct list *current;
     ULONG elem_size;
     GUID riid;
-    IUnknown *parent;
-    enumx_copy_cb copy_cb;
 };
 
 /************************************************************************
@@ -82,7 +80,6 @@ ULONG WINAPI enumx_Release(enumx_impl *This)
              list_remove(x);
              HeapFree(GetProcessHeap(), 0, x);
         }
-        IUnknown_Release(This->parent);
         HeapFree(GetProcessHeap(), 0, This);
     }
     return ref;
@@ -104,10 +101,7 @@ HRESULT WINAPI enumx_Next(enumx_impl *This, ULONG celt,
     p = rgelt;
     while (count < celt && This->current && This->current != &This->elements)
     {
-        if (This->copy_cb)
-            This->copy_cb(This->parent, &This->current[1], p);
-        else
-            memcpy(p, &This->current[1], This->elem_size);
+        memcpy(p, &This->current[1], This->elem_size);
         p += This->elem_size;
         This->current = This->current->next;
         count++;
@@ -164,8 +158,7 @@ HRESULT WINAPI enumx_Clone(
  *
  * Allocate a generic enumerator
  */
-enumx_impl *enumx_allocate(REFIID riid, const void *vtbl, ULONG elem_size,
-                           IUnknown *parent, enumx_copy_cb copy_cb)
+enumx_impl *enumx_allocate(REFIID riid, const void *vtbl, ULONG elem_size)
 {
     enumx_impl *enumx;
 
@@ -177,11 +170,6 @@ enumx_impl *enumx_allocate(REFIID riid, const void *vtbl, ULONG elem_size,
         enumx->current = NULL;
         enumx->elem_size = elem_size;
         enumx->riid = *riid;
-        enumx->parent = parent;
-        enumx->copy_cb = copy_cb;
-
-        IUnknown_AddRef(parent);
-
         list_init(&enumx->elements);
     }
 
index 6f784e1..d4347d9 100644 (file)
@@ -21,8 +21,6 @@
 
 typedef struct tagEnumSTATPROPSETSTG_impl enumx_impl;
 
-typedef void (*enumx_copy_cb)(IUnknown *parent, void *orig, void *dest);
-
 extern HRESULT WINAPI enumx_QueryInterface(enumx_impl *, REFIID, void**) DECLSPEC_HIDDEN;
 extern ULONG WINAPI enumx_AddRef(enumx_impl *) DECLSPEC_HIDDEN;
 extern ULONG WINAPI enumx_Release(enumx_impl *) DECLSPEC_HIDDEN;
@@ -30,8 +28,7 @@ extern HRESULT WINAPI enumx_Next(enumx_impl *, ULONG, void *, ULONG *) DECLSPEC_
 extern HRESULT WINAPI enumx_Skip(enumx_impl *, ULONG) DECLSPEC_HIDDEN;
 extern HRESULT WINAPI enumx_Reset(enumx_impl *) DECLSPEC_HIDDEN;
 extern HRESULT WINAPI enumx_Clone(enumx_impl *, enumx_impl **) DECLSPEC_HIDDEN;
-extern enumx_impl *enumx_allocate(REFIID, const void *, ULONG,
-                                  IUnknown *, enumx_copy_cb) DECLSPEC_HIDDEN;
+extern enumx_impl *enumx_allocate(REFIID, const void *, ULONG) DECLSPEC_HIDDEN;
 extern void *enumx_add_element(enumx_impl *, const void *) DECLSPEC_HIDDEN;
 
 #endif /* __OLE_ENUM_H__ */
index 6a82b71..732e6c6 100644 (file)
@@ -5,7 +5,6 @@
  * for streams contained supported by an HGLOBAL pointer.
  *
  * Copyright 1999 Francis Beaudet
- * 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
 
 #include "precomp.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(hglobalstream);
-
-struct handle_wrapper
-{
-    LONG ref;
-    HGLOBAL hglobal;
-    ULONG size;
-    BOOL delete_on_release;
-    CRITICAL_SECTION lock;
-};
-
-static void handle_addref(struct handle_wrapper *handle)
-{
-    InterlockedIncrement(&handle->ref);
-}
-
-static void handle_release(struct handle_wrapper *handle)
-{
-    ULONG ref = InterlockedDecrement(&handle->ref);
-
-    if (!ref)
-    {
-        if (handle->delete_on_release)
-        {
-            GlobalFree(handle->hglobal);
-            handle->hglobal = NULL;
-        }
-
-        handle->lock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection(&handle->lock);
-        HeapFree(GetProcessHeap(), 0, handle);
-    }
-}
-
-static ULONG handle_read(struct handle_wrapper *handle, ULONG *pos, void *dest, ULONG len)
-{
-    void *source;
-
-    EnterCriticalSection(&handle->lock);
-
-    if (*pos < handle->size)
-        len = min(handle->size - *pos, len);
-    else
-        len = 0;
-
-    source = GlobalLock(handle->hglobal);
-    if (source)
-    {
-        memcpy(dest, (char *)source + *pos, len);
-        *pos += len;
-        GlobalUnlock(handle->hglobal);
-    }
-    else
-    {
-        WARN("read from invalid hglobal %p\n", handle->hglobal);
-        len = 0;
-    }
-
-    LeaveCriticalSection(&handle->lock);
-    return len;
-}
-
-static ULONG handle_write(struct handle_wrapper *handle, ULONG *pos, const void *source, ULONG len)
-{
-    void *dest;
-
-    if (!len)
-        return 0;
-
-    EnterCriticalSection(&handle->lock);
-
-    if (*pos + len > handle->size)
-    {
-        HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, *pos + len, GMEM_MOVEABLE);
-        if (hglobal)
-        {
-            handle->hglobal = hglobal;
-            handle->size = *pos + len;
-        }
-        else
-        {
-            len = 0;
-            goto done;
-        }
-    }
-
-    dest = GlobalLock(handle->hglobal);
-    if (dest)
-    {
-        memcpy((char *)dest + *pos, source, len);
-        *pos += len;
-        GlobalUnlock(handle->hglobal);
-    }
-    else
-    {
-        WARN("write to invalid hglobal %p\n", handle->hglobal);
-        /* len = 0; */
-    }
-
-done:
-    LeaveCriticalSection(&handle->lock);
-    return len;
-}
-
-static HGLOBAL handle_gethglobal(struct handle_wrapper *handle)
-{
-    return handle->hglobal;
-}
-
-static HRESULT handle_setsize(struct handle_wrapper *handle, ULONG size)
-{
-    HRESULT hr = S_OK;
-
-    EnterCriticalSection(&handle->lock);
-
-    if (handle->size != size)
-    {
-        HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, size, GMEM_MOVEABLE);
-        if (hglobal)
-        {
-            handle->hglobal = hglobal;
-            handle->size = size;
-        }
-        else
-            hr = E_OUTOFMEMORY;
-    }
-
-    LeaveCriticalSection(&handle->lock);
-    return hr;
-}
-
-static ULONG handle_getsize(struct handle_wrapper *handle)
-{
-    return handle->size;
-}
-
-static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
-{
-    struct handle_wrapper *handle;
-
-    handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle));
-    if (handle)
-    {
-        handle->ref = 1;
-        handle->hglobal = hglobal;
-        handle->size = GlobalSize(hglobal);
-        handle->delete_on_release = delete_on_release;
-        InitializeCriticalSection(&handle->lock);
-        handle->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": handle_wrapper.lock");
-    }
-    return handle;
-}
+WINE_DEFAULT_DEBUG_CHANNEL(storage);
 
 /****************************************************************************
  * HGLOBALStreamImpl definition.
@@ -188,7 +36,14 @@ typedef struct
   IStream IStream_iface;
   LONG ref;
 
-  struct handle_wrapper *handle;
+  /* support for the stream */
+  HGLOBAL supportHandle;
+
+  /* if TRUE the HGLOBAL is destroyed when the stream is finally released */
+  BOOL deleteOnRelease;
+
+  /* size of the stream */
+  ULARGE_INTEGER streamSize;
 
   /* current position of the cursor */
   ULARGE_INTEGER currentPosition;
@@ -240,7 +95,12 @@ static ULONG WINAPI HGLOBALStreamImpl_Release(
 
   if (!ref)
   {
-    handle_release(This->handle);
+    if (This->deleteOnRelease)
+    {
+      GlobalFree(This->supportHandle);
+      This->supportHandle = NULL;
+    }
+
     HeapFree(GetProcessHeap(), 0, This);
   }
 
@@ -263,12 +123,59 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read(
                  ULONG*         pcbRead)   /* [out] */
 {
   HGLOBALStreamImpl* This = impl_from_IStream(iface);
-  ULONG num_bytes;
 
-  TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbRead);
+  void* supportBuffer;
+  ULONG bytesReadBuffer;
+  ULONG bytesToReadFromBuffer;
+
+  TRACE("(%p, %p, %d, %p)\n", iface,
+       pv, cb, pcbRead);
+
+  /*
+   * If the caller is not interested in the number of bytes read,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbRead==0)
+    pcbRead = &bytesReadBuffer;
+
+  /*
+   * Using the known size of the stream, calculate the number of bytes
+   * to read from the block chain
+   */
+  bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
+
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+  if (!supportBuffer)
+  {
+      WARN("read from invalid hglobal %p\n", This->supportHandle);
+      *pcbRead = 0;
+      return S_OK;
+  }
+
+  memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
 
-  num_bytes = handle_read(This->handle, &This->currentPosition.u.LowPart, pv, cb);
-  if (pcbRead) *pcbRead = num_bytes;
+  /*
+   * Move the current position to the new position
+   */
+  This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
+
+  /*
+   * Return the number of bytes read.
+   */
+  *pcbRead = bytesToReadFromBuffer;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+
+  /*
+   * Always returns S_OK even if the end of the stream is reached before the
+   * buffer is filled
+   */
 
   return S_OK;
 }
@@ -290,14 +197,71 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write(
                  ULONG*         pcbWritten)  /* [out] */
 {
   HGLOBALStreamImpl* This = impl_from_IStream(iface);
-  ULONG num_bytes;
+
+  void*          supportBuffer;
+  ULARGE_INTEGER newSize;
+  ULONG          bytesWritten = 0;
 
   TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten);
 
-  num_bytes = handle_write(This->handle, &This->currentPosition.u.LowPart, pv, cb);
-  if (pcbWritten) *pcbWritten = num_bytes;
+  /*
+   * If the caller is not interested in the number of bytes written,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbWritten == 0)
+    pcbWritten = &bytesWritten;
+
+  if (cb == 0)
+    goto out;
+
+  *pcbWritten = 0;
+
+  newSize.u.HighPart = 0;
+  newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
+
+  /*
+   * Verify if we need to grow the stream
+   */
+  if (newSize.u.LowPart > This->streamSize.u.LowPart)
+  {
+    /* grow stream */
+    HRESULT hr = IStream_SetSize(iface, newSize);
+    if (FAILED(hr))
+    {
+      ERR("IStream_SetSize failed with error 0x%08x\n", hr);
+      return hr;
+    }
+  }
+
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+  if (!supportBuffer)
+  {
+      WARN("write to invalid hglobal %p\n", This->supportHandle);
+      return S_OK;
+  }
+
+  memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
 
-  return (num_bytes < cb) ? E_OUTOFMEMORY : S_OK;
+  /*
+   * Move the current position to the new position
+   */
+  This->currentPosition.u.LowPart+=cb;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+
+out:
+  /*
+   * Return the number of bytes read.
+   */
+  *pcbWritten = cb;
+
+  return S_OK;
 }
 
 /***
@@ -335,7 +299,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek(
     case STREAM_SEEK_CUR:
       break;
     case STREAM_SEEK_END:
-      newPosition.QuadPart = handle_getsize(This->handle);
+      newPosition = This->streamSize;
       break;
     default:
       hr = STG_E_SEEKERROR;
@@ -380,13 +344,29 @@ static HRESULT WINAPI HGLOBALStreamImpl_SetSize(
                                     ULARGE_INTEGER  libNewSize)   /* [in] */
 {
   HGLOBALStreamImpl* This = impl_from_IStream(iface);
+  HGLOBAL supportHandle;
 
   TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
 
   /*
    * HighPart is ignored as shown in tests
    */
-  return handle_setsize(This->handle, libNewSize.u.LowPart);
+
+  if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
+    return S_OK;
+
+  /*
+   * Re allocate the HGlobal to fit the new size of the stream.
+   */
+  supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
+
+  if (supportHandle == 0)
+    return E_OUTOFMEMORY;
+
+  This->supportHandle = supportHandle;
+  This->streamSize.u.LowPart = libNewSize.u.LowPart;
+
+  return S_OK;
 }
 
 /***
@@ -534,49 +514,24 @@ static HRESULT WINAPI HGLOBALStreamImpl_Stat(
 
   pstatstg->pwcsName = NULL;
   pstatstg->type     = STGTY_STREAM;
-  pstatstg->cbSize.QuadPart = handle_getsize(This->handle);
+  pstatstg->cbSize   = This->streamSize;
 
   return S_OK;
 }
 
-static const IStreamVtbl HGLOBALStreamImplVtbl;
-
-static HGLOBALStreamImpl *HGLOBALStreamImpl_Create(void)
-{
-    HGLOBALStreamImpl *This;
-
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
-    if (This)
-    {
-        This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
-        This->ref = 1;
-    }
-    return This;
-}
-
 static HRESULT WINAPI HGLOBALStreamImpl_Clone(
                  IStream*     iface,
                  IStream**    ppstm) /* [out] */
 {
   HGLOBALStreamImpl* This = impl_from_IStream(iface);
-  HGLOBALStreamImpl* clone;
   ULARGE_INTEGER dummy;
   LARGE_INTEGER offset;
+  HRESULT hr;
 
-  if (!ppstm) return E_INVALIDARG;
-
-  *ppstm = NULL;
-
-  TRACE(" Cloning %p (seek position=%d)\n", iface, This->currentPosition.u.LowPart);
-
-  clone = HGLOBALStreamImpl_Create();
-  if (!clone) return E_OUTOFMEMORY;
-
-  *ppstm = &clone->IStream_iface;
-
-  handle_addref(This->handle);
-  clone->handle = This->handle;
-
+  TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart);
+  hr = CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm);
+  if(FAILED(hr))
+    return hr;
   offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart;
   IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
   return S_OK;
@@ -613,19 +568,28 @@ HRESULT WINAPI CreateStreamOnHGlobal(
   if (!ppstm)
     return E_INVALIDARG;
 
-  This = HGLOBALStreamImpl_Create();
+  This = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
   if (!This) return E_OUTOFMEMORY;
 
-  /* allocate a handle if one is not supplied */
-  if (!hGlobal)
-    hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
+  This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
+  This->ref = 1;
+
+  /* initialize the support */
+  This->supportHandle = hGlobal;
+  This->deleteOnRelease = fDeleteOnRelease;
 
-  This->handle = handle_create(hGlobal, fDeleteOnRelease);
+  /* allocate a handle if one is not supplied */
+  if (!This->supportHandle)
+    This->supportHandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
 
   /* start at the beginning */
   This->currentPosition.u.HighPart = 0;
   This->currentPosition.u.LowPart = 0;
 
+  /* initialize the size of the stream to the size of the handle */
+  This->streamSize.u.HighPart = 0;
+  This->streamSize.u.LowPart = GlobalSize(This->supportHandle);
+
   *ppstm = &This->IStream_iface;
 
   return S_OK;
@@ -638,16 +602,16 @@ HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
 {
   HGLOBALStreamImpl* pStream;
 
-  if (!pstm || !phglobal)
+  if (pstm == NULL)
     return E_INVALIDARG;
 
-  pStream = impl_from_IStream(pstm);
+  pStream = (HGLOBALStreamImpl*) pstm;
 
   /*
    * Verify that the stream object was created with CreateStreamOnHGlobal.
    */
   if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl)
-    *phglobal = handle_gethglobal(pStream->handle);
+    *phglobal = pStream->supportHandle;
   else
   {
     *phglobal = 0;
index 985c622..eb1bf5b 100644 (file)
@@ -1474,16 +1474,17 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
     else
     {
         BOOL joined = FALSE;
-        if (!COM_CurrentInfo()->apt)
+        struct oletls *info = COM_CurrentInfo();
+
+        if (!info->apt)
         {
-            apartment_joinmta();
+            enter_apartment(info, COINIT_MULTITHREADED);
             joined = TRUE;
         }
         RPC_ExecuteCall(params);
         if (joined)
         {
-            apartment_release(COM_CurrentInfo()->apt);
-            COM_CurrentInfo()->apt = NULL;
+            leave_apartment(info);
         }
     }
 
index aca47c8..a9308d6 100644 (file)
@@ -1004,18 +1004,15 @@ static HRESULT PropertyStorage_ReadDictionary(PropertyStorage_impl *This,
         if (This->codePage != CP_UNICODE)
             ptr[cbEntry - 1] = '\0';
         else
-            ((LPWSTR)ptr)[cbEntry - 1] = 0;
+            *((LPWSTR)ptr + cbEntry / sizeof(WCHAR)) = '\0';
         hr = PropertyStorage_StoreNameWithId(This, (char*)ptr, This->codePage, propid);
         if (This->codePage == CP_UNICODE)
         {
-            /* cbEntry is the number of characters */
-            cbEntry *= 2;
-
             /* Unicode entries are padded to DWORD boundaries */
             if (cbEntry % sizeof(DWORD))
                 ptr += sizeof(DWORD) - (cbEntry % sizeof(DWORD));
         }
-        ptr += cbEntry;
+        ptr += sizeof(DWORD) + cbEntry;
     }
     return hr;
 }
@@ -1056,10 +1053,6 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data,
         prop->u.bVal = *data;
         TRACE("Read byte 0x%x\n", prop->u.bVal);
         break;
-    case VT_BOOL:
-        StorageUtl_ReadWord(data, 0, (WORD*)&prop->u.boolVal);
-        TRACE("Read bool %d\n", prop->u.boolVal);
-        break;
     case VT_I2:
         StorageUtl_ReadWord(data, 0, (WORD*)&prop->u.iVal);
         TRACE("Read short %d\n", prop->u.iVal);
@@ -1078,18 +1071,6 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data,
         StorageUtl_ReadDWord(data, 0, &prop->u.ulVal);
         TRACE("Read ulong %d\n", prop->u.ulVal);
         break;
-    case VT_I8:
-        StorageUtl_ReadULargeInteger(data, 0, (ULARGE_INTEGER *)&prop->u.hVal);
-        TRACE("Read long long %s\n", wine_dbgstr_longlong(prop->u.hVal.QuadPart));
-        break;
-    case VT_UI8:
-        StorageUtl_ReadULargeInteger(data, 0, &prop->u.uhVal);
-        TRACE("Read ulong long %s\n", wine_dbgstr_longlong(prop->u.uhVal.QuadPart));
-        break;
-    case VT_R8:
-        memcpy(&prop->u.dblVal, data, sizeof(double));
-        TRACE("Read double %f\n", prop->u.dblVal);
-        break;
     case VT_LPSTR:
     {
         DWORD count;
@@ -2383,9 +2364,7 @@ static HRESULT create_EnumSTATPROPSETSTG(
 
     enumx = enumx_allocate(&IID_IEnumSTATPROPSETSTG,
                            &IEnumSTATPROPSETSTG_Vtbl,
-                           sizeof (STATPROPSETSTG),
-                           (IUnknown*)&This->base.IStorage_iface,
-                           NULL);
+                           sizeof (STATPROPSETSTG));
 
     /* add all the property set elements into a list */
     r = IStorage_EnumElements(stg, 0, NULL, 0, &penum);
@@ -2478,27 +2457,6 @@ static HRESULT WINAPI IEnumSTATPROPSTG_fnClone(
     return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum);
 }
 
-static void prop_enum_copy_cb(IUnknown *parent, void *orig, void *dest)
-{
-    PropertyStorage_impl *storage = impl_from_IPropertyStorage((IPropertyStorage*)parent);
-    STATPROPSTG *src_prop = orig;
-    STATPROPSTG *dest_prop = dest;
-    LPWSTR name;
-
-    dest_prop->propid = src_prop->propid;
-    dest_prop->vt = src_prop->vt;
-    dest_prop->lpwstrName = NULL;
-
-    if (dictionary_find(storage->propid_to_name, UlongToPtr(src_prop->propid), (void**)&name))
-    {
-        DWORD size = (strlenW(name) + 1) * sizeof(WCHAR);
-
-        dest_prop->lpwstrName = CoTaskMemAlloc(size);
-        if (!dest_prop->lpwstrName) return;
-        memcpy(dest_prop->lpwstrName, name, size);
-    }
-}
-
 static BOOL prop_enum_stat(const void *k, const void *v, void *extra, void *arg)
 {
     enumx_impl *enumx = arg;
@@ -2525,9 +2483,7 @@ static HRESULT create_EnumSTATPROPSTG(
 
     enumx = enumx_allocate(&IID_IEnumSTATPROPSTG,
                            &IEnumSTATPROPSTG_Vtbl,
-                           sizeof (STATPROPSTG),
-                           (IUnknown*)&This->IPropertyStorage_iface,
-                           prop_enum_copy_cb);
+                           sizeof (STATPROPSTG));
 
     dictionary_enumerate(This->propid_to_prop, prop_enum_stat, enumx);
 
index 6443197..6adf3c7 100644 (file)
@@ -2067,7 +2067,7 @@ static HRESULT WINAPI StorageBaseImpl_SetClass(
   HRESULT hRes;
   DirEntry currentEntry;
 
-  TRACE("(%p, %p)\n", iface, clsid);
+  TRACE("(%p, %s)\n", iface, wine_dbgstr_guid(clsid));
 
   if (This->reverted)
     return STG_E_REVERTED;
@@ -7249,6 +7249,8 @@ BlockChainStream* BlockChainStream_Construct(
   BlockChainStream* newStream;
 
   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
+  if(!newStream)
+    return NULL;
 
   newStream->parentStorage           = parentStorage;
   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
index 51be7d4..4f692fe 100644 (file)
@@ -517,20 +517,25 @@ StgStreamImpl* StgStreamImpl_Construct(
 /******************************************************************************
  * Endian conversion macros
  */
-#undef htole32
-#undef htole16
-
 #ifdef WORDS_BIGENDIAN
 
+#ifndef htole32
 #define htole32(x) RtlUlongByteSwap(x)
+#endif
+#ifndef htole16
 #define htole16(x) RtlUshortByteSwap(x)
+#endif
 #define lendian32toh(x) RtlUlongByteSwap(x)
 #define lendian16toh(x) RtlUshortByteSwap(x)
 
 #else
 
+#ifndef htole32
 #define htole32(x) (x)
+#endif
+#ifndef htole16
 #define htole16(x) (x)
+#endif
 #define lendian32toh(x) (x)
 #define lendian16toh(x) (x)
 
index 4de57fd..9a56bd0 100644 (file)
@@ -80,11 +80,11 @@ static const char* debugstr_user_flags(ULONG *pFlags)
  *  the first parameter is an unsigned long.
  *  This function is only intended to be called by the RPC runtime.
  */
-ULONG __RPC_USER CLIPFORMAT_UserSize(ULONG *pFlags, ULONG StartingSize, CLIPFORMAT *pCF)
+ULONG __RPC_USER CLIPFORMAT_UserSize(ULONG *pFlags, ULONG size, CLIPFORMAT *pCF)
 {
-    ULONG size = StartingSize;
+    TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), size, pCF);
 
-    TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, pCF);
+    ALIGN_LENGTH(size, 3);
 
     size += 8;
 
@@ -129,6 +129,8 @@ unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(ULONG *pFlags, unsigned char *
 {
     TRACE("(%s, %p, &0x%04x\n", debugstr_user_flags(pFlags), pBuffer, *pCF);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     /* only need to marshal the name if it is not a pre-defined type and
      * we are going remote */
     if ((*pCF >= 0xc000) && (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE))
@@ -191,6 +193,8 @@ unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(ULONG *pFlags, unsigned char
 
     TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, pCF);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     fContext = *(DWORD *)pBuffer;
     pBuffer += 4;
 
@@ -264,18 +268,23 @@ static ULONG handle_UserSize(ULONG *pFlags, ULONG StartingSize, HANDLE *handle)
         RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);
         return StartingSize;
     }
+
+    ALIGN_LENGTH(StartingSize, 3);
     return StartingSize + sizeof(RemotableHandle);
 }
 
 static unsigned char * handle_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle)
 {
-    RemotableHandle *remhandle = (RemotableHandle *)pBuffer;
+    RemotableHandle *remhandle;
     if (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE)
     {
         ERR("can't remote a local handle\n");
         RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);
         return pBuffer;
     }
+
+    ALIGN_POINTER(pBuffer, 3);
+    remhandle = (RemotableHandle *)pBuffer;
     remhandle->fContext = WDT_INPROC_CALL;
     remhandle->u.hInproc = (LONG_PTR)*handle;
     return pBuffer + sizeof(RemotableHandle);
@@ -283,7 +292,10 @@ static unsigned char * handle_UserMarshal(ULONG *pFlags, unsigned char *pBuffer,
 
 static unsigned char * handle_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle)
 {
-    RemotableHandle *remhandle = (RemotableHandle *)pBuffer;
+    RemotableHandle *remhandle;
+
+    ALIGN_POINTER(pBuffer, 3);
+    remhandle = (RemotableHandle *)pBuffer;
     if (remhandle->fContext != WDT_INPROC_CALL)
         RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL);
     *handle = (HANDLE)(LONG_PTR)remhandle->u.hInproc;
@@ -566,10 +578,28 @@ void __RPC_USER HGLOBAL_UserFree(ULONG *pFlags, HGLOBAL *phGlobal)
  *  the first parameter is a ULONG.
  *  This function is only intended to be called by the RPC runtime.
  */
-ULONG __RPC_USER HBITMAP_UserSize(ULONG *pFlags, ULONG StartingSize, HBITMAP *phBmp)
+ULONG __RPC_USER HBITMAP_UserSize(ULONG *flags, ULONG size, HBITMAP *bmp)
 {
-    FIXME(":stub\n");
-    return StartingSize;
+    TRACE("(%s, %d, %p)\n", debugstr_user_flags(flags), size, *bmp);
+
+    ALIGN_LENGTH(size, 3);
+
+    size += sizeof(ULONG);
+    if (LOWORD(*flags) == MSHCTX_INPROC)
+        size += sizeof(ULONG);
+    else
+    {
+        size += sizeof(ULONG);
+
+        if (*bmp)
+        {
+            size += sizeof(ULONG);
+            size += FIELD_OFFSET(userBITMAP, cbSize);
+            size += GetBitmapBits(*bmp, 0, NULL);
+        }
+    }
+
+    return size;
 }
 
 /******************************************************************************
@@ -591,10 +621,45 @@ ULONG __RPC_USER HBITMAP_UserSize(ULONG *pFlags, ULONG StartingSize, HBITMAP *ph
 *  the first parameter is a ULONG.
 *  This function is only intended to be called by the RPC runtime.
 */
-unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp)
+unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *flags, unsigned char *buffer, HBITMAP *bmp)
 {
-    FIXME(":stub\n");
-    return pBuffer;
+    TRACE("(%s, %p, %p)\n", debugstr_user_flags(flags), buffer, *bmp);
+
+    ALIGN_POINTER(buffer, 3);
+
+    if (LOWORD(*flags) == MSHCTX_INPROC)
+    {
+        *(ULONG *)buffer = WDT_INPROC_CALL;
+        buffer += sizeof(ULONG);
+        *(ULONG *)buffer = (ULONG)(ULONG_PTR)*bmp;
+        buffer += sizeof(ULONG);
+    }
+    else
+    {
+        *(ULONG *)buffer = WDT_REMOTE_CALL;
+        buffer += sizeof(ULONG);
+        *(ULONG *)buffer = (ULONG)(ULONG_PTR)*bmp;
+        buffer += sizeof(ULONG);
+
+        if (*bmp)
+        {
+            static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize);
+            BITMAP bitmap;
+            ULONG bitmap_size;
+
+            bitmap_size = GetBitmapBits(*bmp, 0, NULL);
+            *(ULONG *)buffer = bitmap_size;
+            buffer += sizeof(ULONG);
+
+            GetObjectW(*bmp, sizeof(BITMAP), &bitmap);
+            memcpy(buffer, &bitmap, header_size);
+            buffer += header_size;
+
+            GetBitmapBits(*bmp, bitmap_size, buffer);
+            buffer += bitmap_size;
+        }
+    }
+    return buffer;
 }
 
 /******************************************************************************
@@ -616,10 +681,56 @@ unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *pFlags, unsigned char *pBu
  *  the first parameter is an ULONG.
  *  This function is only intended to be called by the RPC runtime.
  */
-unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp)
+unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *flags, unsigned char *buffer, HBITMAP *bmp)
 {
-    FIXME(":stub\n");
-    return pBuffer;
+    ULONG context;
+
+    TRACE("(%s, %p, %p)\n", debugstr_user_flags(flags), buffer, bmp);
+
+    ALIGN_POINTER(buffer, 3);
+
+    context = *(ULONG *)buffer;
+    buffer += sizeof(ULONG);
+
+    if (context == WDT_INPROC_CALL)
+    {
+        *bmp = *(HBITMAP *)buffer;
+        buffer += sizeof(*bmp);
+    }
+    else if (context == WDT_REMOTE_CALL)
+    {
+        ULONG handle = *(ULONG *)buffer;
+        buffer += sizeof(ULONG);
+
+        if (handle)
+        {
+            static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize);
+            BITMAP bitmap;
+            ULONG bitmap_size;
+            unsigned char *bits;
+
+            bitmap_size = *(ULONG *)buffer;
+            buffer += sizeof(ULONG);
+            bits = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
+
+            memcpy(&bitmap, buffer, header_size);
+            buffer += header_size;
+
+            memcpy(bits, buffer, bitmap_size);
+            buffer += bitmap_size;
+
+            bitmap.bmBits = bits;
+            *bmp = CreateBitmapIndirect(&bitmap);
+
+            HeapFree(GetProcessHeap(), 0, bits);
+        }
+        else
+            *bmp = NULL;
+    }
+    else
+        RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);
+
+    return buffer;
 }
 
 /******************************************************************************
@@ -640,9 +751,12 @@ unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *pFlags, unsigned char *p
  *  which the first parameter is a ULONG.
  *  This function is only intended to be called by the RPC runtime.
  */
-void __RPC_USER HBITMAP_UserFree(ULONG *pFlags, HBITMAP *phBmp)
+void __RPC_USER HBITMAP_UserFree(ULONG *flags, HBITMAP *bmp)
 {
-    FIXME(":stub\n");
+    TRACE("(%s, %p)\n", debugstr_user_flags(flags), *bmp);
+
+    if (LOWORD(*flags) != MSHCTX_INPROC)
+        DeleteObject(*bmp);
 }
 
 /******************************************************************************
@@ -963,11 +1077,11 @@ void __RPC_USER HMETAFILE_UserFree(ULONG *pFlags, HMETAFILE *phmf)
 *  the first parameter is a ULONG.
 *  This function is only intended to be called by the RPC runtime.
 */
-ULONG __RPC_USER HENHMETAFILE_UserSize(ULONG *pFlags, ULONG StartingSize, HENHMETAFILE *phEmf)
+ULONG __RPC_USER HENHMETAFILE_UserSize(ULONG *pFlags, ULONG size, HENHMETAFILE *phEmf)
 {
-    ULONG size = StartingSize;
+    TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), size, *phEmf);
 
-    TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, *phEmf);
+    ALIGN_LENGTH(size, 3);
 
     size += sizeof(ULONG);
     if (LOWORD(*pFlags) == MSHCTX_INPROC)
@@ -1012,6 +1126,8 @@ unsigned char * __RPC_USER HENHMETAFILE_UserMarshal(ULONG *pFlags, unsigned char
 {
     TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *phEmf);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     if (LOWORD(*pFlags) == MSHCTX_INPROC)
     {
         if (sizeof(*phEmf) == 8)
@@ -1070,6 +1186,8 @@ unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(ULONG *pFlags, unsigned ch
 
     TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, phEmf);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     fContext = *(ULONG *)pBuffer;
     pBuffer += sizeof(ULONG);
 
@@ -1155,11 +1273,11 @@ void __RPC_USER HENHMETAFILE_UserFree(ULONG *pFlags, HENHMETAFILE *phEmf)
  *  the first parameter is a ULONG.
  *  This function is only intended to be called by the RPC runtime.
  */
-ULONG __RPC_USER HMETAFILEPICT_UserSize(ULONG *pFlags, ULONG StartingSize, HMETAFILEPICT *phMfp)
+ULONG __RPC_USER HMETAFILEPICT_UserSize(ULONG *pFlags, ULONG size, HMETAFILEPICT *phMfp)
 {
-    ULONG size = StartingSize;
+    TRACE("(%s, %d, &%p)\n", debugstr_user_flags(pFlags), size, *phMfp);
 
-    TRACE("(%s, %d, &%p)\n", debugstr_user_flags(pFlags), StartingSize, *phMfp);
+    ALIGN_LENGTH(size, 3);
 
     size += sizeof(ULONG);
 
@@ -1209,6 +1327,8 @@ unsigned char * __RPC_USER HMETAFILEPICT_UserMarshal(ULONG *pFlags, unsigned cha
 {
     TRACE("(%s, %p, &%p)\n", debugstr_user_flags(pFlags), pBuffer, *phMfp);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     if (LOWORD(*pFlags) == MSHCTX_INPROC)
     {
         if (sizeof(HMETAFILEPICT) == 8)
@@ -1272,6 +1392,8 @@ unsigned char * __RPC_USER HMETAFILEPICT_UserUnmarshal(ULONG *pFlags, unsigned c
 
     TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, phMfp);
 
+    ALIGN_POINTER(pBuffer, 3);
+
     fContext = *(ULONG *)pBuffer;
     pBuffer += sizeof(ULONG);
 
@@ -1602,9 +1724,7 @@ ULONG __RPC_USER STGMEDIUM_UserSize(ULONG *pFlags, ULONG StartingSize, STGMEDIUM
     case TYMED_GDI:
         TRACE("TYMED_GDI\n");
         if (pStgMedium->u.hBitmap)
-        {
-            FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap);
-        }
+            size = HBITMAP_UserSize(pFlags, size, &pStgMedium->u.hBitmap);
         break;
     case TYMED_MFPICT:
         TRACE("TYMED_MFPICT\n");
@@ -1714,9 +1834,7 @@ unsigned char * __RPC_USER STGMEDIUM_UserMarshal(ULONG *pFlags, unsigned char *p
     case TYMED_GDI:
         TRACE("TYMED_GDI\n");
         if (pStgMedium->u.hBitmap)
-        {
-            FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap);
-        }
+            pBuffer = HBITMAP_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hBitmap);
         break;
     case TYMED_MFPICT:
         TRACE("TYMED_MFPICT\n");
@@ -1852,9 +1970,7 @@ unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(ULONG *pFlags, unsigned char
     case TYMED_GDI:
         TRACE("TYMED_GDI\n");
         if (content)
-        {
-            FIXME("not implemented for GDI object\n");
-        }
+            pBuffer = HBITMAP_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hBitmap);
         else
             pStgMedium->u.hBitmap = NULL;
         break;
index 5cc918b..4b324f3 100644 (file)
@@ -139,7 +139,7 @@ reactos/dll/win32/ntdsapi             # Synced to WineStaging-2.9
 reactos/dll/win32/objsel              # Synced to WineStaging-2.9
 reactos/dll/win32/odbc32              # Synced to WineStaging-2.9. Depends on port of Linux ODBC.
 reactos/dll/win32/odbccp32            # Synced to WineStaging-2.9
-reactos/dll/win32/ole32               # Synced to WineStaging-2.16
+reactos/dll/win32/ole32               # Synced to Wine-3.0
 reactos/dll/win32/oleacc              # Synced to WineStaging-2.9
 reactos/dll/win32/oleaut32            # Synced to WineStaging-2.16
 reactos/dll/win32/olecli32            # Synced to WineStaging-2.9