[PATCH 2/4] combase: Move default memory stream implementation.

Nikolay Sivov nsivov at codeweavers.com
Wed Sep 2 06:14:47 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/combase/Makefile.in     |   1 +
 dlls/combase/combase.spec    |   4 +-
 dlls/combase/hglobalstream.c | 455 +++++++++++++++++++++++
 dlls/ole32/Makefile.in       |   1 -
 dlls/ole32/hglobalstream.c   | 684 -----------------------------------
 dlls/ole32/ole32.spec        |   4 +-
 6 files changed, 460 insertions(+), 689 deletions(-)
 create mode 100644 dlls/combase/hglobalstream.c
 delete mode 100644 dlls/ole32/hglobalstream.c

diff --git a/dlls/combase/Makefile.in b/dlls/combase/Makefile.in
index ebf86708bbc..5af77584055 100644
--- a/dlls/combase/Makefile.in
+++ b/dlls/combase/Makefile.in
@@ -9,6 +9,7 @@ C_SRCS = \
 	apartment.c \
 	combase.c \
 	errorinfo.c \
+	hglobalstream.c \
 	malloc.c \
 	marshal.c \
 	roapi.c \
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec
index 50b58419bc5..9d9b34640be 100644
--- a/dlls/combase/combase.spec
+++ b/dlls/combase/combase.spec
@@ -174,7 +174,7 @@
 @ stdcall CoWaitForMultipleHandles(long long long ptr ptr)
 @ stub CoWaitForMultipleObjects
 @ stdcall CreateErrorInfo(ptr)
-@ stdcall CreateStreamOnHGlobal(ptr long ptr) ole32.CreateStreamOnHGlobal
+@ stdcall CreateStreamOnHGlobal(ptr long ptr)
 @ stub DcomChannelSetHResult
 @ stdcall DllDebugObjectRPCHook(long ptr)
 @ stdcall DllGetActivationFactory(ptr ptr)
@@ -185,7 +185,7 @@
 @ stub GetCatalogHelper
 @ stdcall GetErrorInfo(long ptr)
 @ stub GetFuncDescs
-@ stdcall GetHGlobalFromStream(ptr ptr) ole32.GetHGlobalFromStream
+@ stdcall GetHGlobalFromStream(ptr ptr)
 @ stub GetHookInterface
 @ stdcall GetRestrictedErrorInfo(ptr)
 @ stdcall HACCEL_UserFree(ptr ptr)
diff --git a/dlls/combase/hglobalstream.c b/dlls/combase/hglobalstream.c
new file mode 100644
index 00000000000..5cbb280fd5e
--- /dev/null
+++ b/dlls/combase/hglobalstream.c
@@ -0,0 +1,455 @@
+/*
+ * HGLOBAL Stream implementation
+ *
+ * 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "objbase.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(storage);
+
+struct handle_wrapper
+{
+    LONG ref;
+    HGLOBAL hglobal;
+    ULONG size;
+    BOOL delete_on_release;
+};
+
+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);
+        HeapFree(GetProcessHeap(), 0, handle);
+    }
+}
+
+static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
+{
+    struct handle_wrapper *handle;
+
+    handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle));
+    if (!handle) return NULL;
+
+    /* allocate a handle if one is not supplied */
+    if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0);
+    if (!hglobal)
+    {
+        HeapFree(GetProcessHeap(), 0, handle);
+        return NULL;
+    }
+    handle->ref = 1;
+    handle->hglobal = hglobal;
+    handle->size = GlobalSize(hglobal);
+    handle->delete_on_release = delete_on_release;
+
+    return handle;
+}
+
+struct hglobal_stream
+{
+    IStream IStream_iface;
+    LONG ref;
+
+    struct handle_wrapper *handle;
+    ULARGE_INTEGER position;
+};
+
+static inline struct hglobal_stream *impl_from_IStream(IStream *iface)
+{
+    return CONTAINING_RECORD(iface, struct hglobal_stream, IStream_iface);
+}
+
+static const IStreamVtbl hglobalstreamvtbl;
+
+static struct hglobal_stream *hglobalstream_construct(void)
+{
+    struct hglobal_stream *object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
+
+    if (object)
+    {
+        object->IStream_iface.lpVtbl = &hglobalstreamvtbl;
+        object->ref = 1;
+    }
+    return object;
+}
+
+static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj)
+{
+    if (!obj)
+        return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, riid) ||
+        IsEqualIID(&IID_ISequentialStream, riid) ||
+        IsEqualIID(&IID_IStream, riid))
+    {
+        *obj = iface;
+        IStream_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI stream_AddRef(IStream *iface)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    return InterlockedIncrement(&stream->ref);
+}
+
+static ULONG WINAPI stream_Release(IStream *iface)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    ULONG ref = InterlockedDecrement(&stream->ref);
+
+    if (!ref)
+    {
+        handle_release(stream->handle);
+        HeapFree(GetProcessHeap(), 0, stream);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *read_len)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    ULONG dummy, len;
+    char *buffer;
+
+    TRACE("%p, %p, %d, %p\n", iface, pv, cb, read_len);
+
+    if (!read_len)
+        read_len = &dummy;
+
+    len = min(stream->handle->size - stream->position.u.LowPart, cb);
+
+    buffer = GlobalLock(stream->handle->hglobal);
+    if (!buffer)
+    {
+        WARN("Failed to lock hglobal %p\n", stream->handle->hglobal);
+        *read_len = 0;
+        return S_OK;
+    }
+
+    memcpy(pv, buffer + stream->position.u.LowPart, len);
+    stream->position.u.LowPart += len;
+
+    *read_len = len;
+
+    GlobalUnlock(stream->handle->hglobal);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *written)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    ULARGE_INTEGER size;
+    ULONG dummy = 0;
+    char *buffer;
+
+    TRACE("%p, %p, %d, %p\n", iface, pv, cb, written);
+
+    if (!written)
+        written = &dummy;
+
+    if (!cb)
+        goto out;
+
+    *written = 0;
+
+    size.u.HighPart = 0;
+    size.u.LowPart = stream->position.u.LowPart + cb;
+
+    if (size.u.LowPart > stream->handle->size)
+    {
+        /* grow stream */
+        HRESULT hr = IStream_SetSize(iface, size);
+        if (FAILED(hr))
+        {
+            ERR("IStream_SetSize failed with error 0x%08x\n", hr);
+            return hr;
+        }
+    }
+
+    buffer = GlobalLock(stream->handle->hglobal);
+    if (!buffer)
+    {
+        WARN("write to invalid hglobal %p\n", stream->handle->hglobal);
+        return S_OK;
+    }
+
+    memcpy(buffer + stream->position.u.LowPart, pv, cb);
+    stream->position.u.LowPart += cb;
+
+    GlobalUnlock(stream->handle->hglobal);
+
+out:
+    *written = cb;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin,
+        ULARGE_INTEGER *pos)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    ULARGE_INTEGER position = stream->position;
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %s, %d, %p\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, pos);
+
+    switch (origin)
+    {
+        case STREAM_SEEK_SET:
+            position.QuadPart = 0;
+            break;
+        case STREAM_SEEK_CUR:
+            break;
+        case STREAM_SEEK_END:
+            position.QuadPart = stream->handle->size;
+            break;
+        default:
+            hr = STG_E_SEEKERROR;
+            goto end;
+    }
+
+    position.u.HighPart = 0;
+    position.u.LowPart += move.QuadPart;
+
+    if (move.u.LowPart >= 0x80000000 && position.u.LowPart >= move.u.LowPart)
+    {
+        /* We tried to seek backwards and went past the start. */
+        hr = STG_E_SEEKERROR;
+        goto end;
+    }
+
+    stream->position = position;
+
+end:
+    if (pos) *pos = stream->position;
+
+    return hr;
+}
+
+static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+    HGLOBAL hglobal;
+
+    TRACE("%p, %s\n", iface, wine_dbgstr_longlong(size.QuadPart));
+
+    if (stream->handle->size == size.u.LowPart)
+        return S_OK;
+
+    hglobal = GlobalReAlloc(stream->handle->hglobal, size.u.LowPart, GMEM_MOVEABLE);
+    if (!hglobal)
+        return E_OUTOFMEMORY;
+
+    stream->handle->hglobal = hglobal;
+    stream->handle->size = size.u.LowPart;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER cb,
+        ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
+{
+    ULARGE_INTEGER total_read, total_written;
+    HRESULT hr = S_OK;
+    BYTE buffer[128];
+
+    TRACE("%p, %p, %d, %p, %p\n", iface, dest, cb.u.LowPart, read_len, written);
+
+    if (!dest)
+        return STG_E_INVALIDPOINTER;
+
+    total_read.QuadPart = 0;
+    total_written.QuadPart = 0;
+
+    while (cb.QuadPart > 0)
+    {
+        ULONG chunk_size = chunk_size = cb.QuadPart >= sizeof(buffer) ? sizeof(buffer) : cb.u.LowPart;
+        ULONG chunk_read, chunk_written;
+
+        hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
+        if (FAILED(hr))
+            break;
+
+        total_read.QuadPart += chunk_read;
+
+        if (chunk_read)
+        {
+            hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
+            if (FAILED(hr))
+                break;
+
+            total_written.QuadPart += chunk_written;
+        }
+
+        if (chunk_read != chunk_size)
+            cb.QuadPart = 0;
+        else
+            cb.QuadPart -= chunk_read;
+    }
+
+    if (read_len)
+        read_len->QuadPart = total_read.QuadPart;
+    if (written)
+        written->QuadPart = total_written.QuadPart;
+
+    return hr;
+}
+
+static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Revert(IStream *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
+        ULARGE_INTEGER len, DWORD lock_type)
+{
+    return STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset,
+        ULARGE_INTEGER len, DWORD lock_type)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD flags)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface);
+
+    memset(pstatstg, 0, sizeof(STATSTG));
+
+    pstatstg->pwcsName = NULL;
+    pstatstg->type = STGTY_STREAM;
+    pstatstg->cbSize.QuadPart = stream->handle->size;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI stream_Clone(IStream *iface, IStream **ppstm)
+{
+    struct hglobal_stream *stream = impl_from_IStream(iface), *clone;
+    ULARGE_INTEGER dummy;
+    LARGE_INTEGER offset;
+
+    TRACE("%p, %p\n", iface, ppstm);
+
+    *ppstm = NULL;
+
+    clone = hglobalstream_construct();
+    if (!clone) return E_OUTOFMEMORY;
+
+    *ppstm = &clone->IStream_iface;
+    handle_addref(stream->handle);
+    clone->handle = stream->handle;
+
+    offset.QuadPart = (LONGLONG)stream->position.QuadPart;
+    IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
+    return S_OK;
+}
+
+static const IStreamVtbl hglobalstreamvtbl =
+{
+    stream_QueryInterface,
+    stream_AddRef,
+    stream_Release,
+    stream_Read,
+    stream_Write,
+    stream_Seek,
+    stream_SetSize,
+    stream_CopyTo,
+    stream_Commit,
+    stream_Revert,
+    stream_LockRegion,
+    stream_UnlockRegion,
+    stream_Stat,
+    stream_Clone
+};
+
+/***********************************************************************
+ *           CreateStreamOnHGlobal     (combase.@)
+ */
+HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL delete_on_release, IStream **stream)
+{
+    struct hglobal_stream *object;
+
+    if (!stream)
+        return E_INVALIDARG;
+
+    object = hglobalstream_construct();
+    if (!object) return E_OUTOFMEMORY;
+
+    object->handle = handle_create(hGlobal, delete_on_release);
+    if (!object->handle)
+    {
+        HeapFree(GetProcessHeap(), 0, object);
+        return E_OUTOFMEMORY;
+    }
+
+    *stream = &object->IStream_iface;
+
+    return S_OK;
+}
+
+/***********************************************************************
+ *           GetHGlobalFromStream     (combase.@)
+ */
+HRESULT WINAPI GetHGlobalFromStream(IStream *stream, HGLOBAL *phglobal)
+{
+    struct hglobal_stream *object;
+
+    if (!stream || !phglobal)
+        return E_INVALIDARG;
+
+    object = impl_from_IStream(stream);
+
+    if (object->IStream_iface.lpVtbl == &hglobalstreamvtbl)
+        *phglobal = object->handle->hglobal;
+    else
+    {
+        *phglobal = 0;
+        return E_INVALIDARG;
+    }
+
+    return S_OK;
+}
diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in
index 89807b94ef0..bb06faebe49 100644
--- a/dlls/ole32/Makefile.in
+++ b/dlls/ole32/Makefile.in
@@ -21,7 +21,6 @@ C_SRCS = \
 	filemoniker.c \
 	ftmarshal.c \
 	git.c \
-	hglobalstream.c \
 	itemmoniker.c \
 	marshal.c \
 	memlockbytes.c \
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
deleted file mode 100644
index 4cfedd66a1b..00000000000
--- a/dlls/ole32/hglobalstream.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * HGLOBAL Stream implementation
- *
- * This file contains the implementation of the stream interface
- * 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
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#define COBJMACROS
-#define NONAMELESSUNION
-
-#include "windef.h"
-#include "winbase.h"
-#include "winuser.h"
-#include "objbase.h"
-#include "ole2.h"
-#include "winerror.h"
-#include "winternl.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(storage);
-
-struct handle_wrapper
-{
-    LONG ref;
-    HGLOBAL hglobal;
-    ULONG size;
-    BOOL delete_on_release;
-};
-
-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);
-        HeapFree(GetProcessHeap(), 0, handle);
-    }
-}
-
-static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
-{
-    struct handle_wrapper *handle;
-
-    handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle));
-    if (!handle) return NULL;
-
-    /* allocate a handle if one is not supplied */
-    if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0);
-    if (!hglobal)
-    {
-        HeapFree(GetProcessHeap(), 0, handle);
-        return NULL;
-    }
-    handle->ref = 1;
-    handle->hglobal = hglobal;
-    handle->size = GlobalSize(hglobal);
-    handle->delete_on_release = delete_on_release;
-
-    return handle;
-}
-
-/****************************************************************************
- * HGLOBALStreamImpl definition.
- *
- * This class implements the IStream interface and represents a stream
- * supported by an HGLOBAL pointer.
- */
-typedef struct
-{
-  IStream IStream_iface;
-  LONG ref;
-
-  struct handle_wrapper *handle;
-
-  /* current position of the cursor */
-  ULARGE_INTEGER currentPosition;
-} HGLOBALStreamImpl;
-
-static inline HGLOBALStreamImpl *impl_from_IStream(IStream *iface)
-{
-  return CONTAINING_RECORD(iface, HGLOBALStreamImpl, IStream_iface);
-}
-
-static const IStreamVtbl HGLOBALStreamImplVtbl;
-
-static HGLOBALStreamImpl *hglobalstream_construct(void)
-{
-    HGLOBALStreamImpl *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
-
-    if (This)
-    {
-        This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
-        This->ref = 1;
-        This->handle = NULL;
-        This->currentPosition.QuadPart = 0;
-    }
-    return This;
-}
-
-static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
-		  IStream*     iface,
-		  REFIID         riid,	      /* [in] */
-		  void**         ppvObject)   /* [iid_is][out] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-
-  if (ppvObject==0)
-    return E_INVALIDARG;
-
-  *ppvObject = 0;
-
-  if (IsEqualIID(&IID_IUnknown, riid) ||
-      IsEqualIID(&IID_ISequentialStream, riid) ||
-      IsEqualIID(&IID_IStream, riid))
-  {
-    *ppvObject = &This->IStream_iface;
-  }
-
-  if ((*ppvObject)==0)
-    return E_NOINTERFACE;
-
-  IStream_AddRef(iface);
-
-  return S_OK;
-}
-
-static ULONG WINAPI HGLOBALStreamImpl_AddRef(IStream* iface)
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-  return InterlockedIncrement(&This->ref);
-}
-
-static ULONG WINAPI HGLOBALStreamImpl_Release(
-		IStream* iface)
-{
-  HGLOBALStreamImpl* This= impl_from_IStream(iface);
-  ULONG ref = InterlockedDecrement(&This->ref);
-
-  if (!ref)
-  {
-    handle_release(This->handle);
-    HeapFree(GetProcessHeap(), 0, This);
-  }
-
-  return ref;
-}
-
-/***
- * This method is part of the ISequentialStream interface.
- *
- * If reads a block of information from the stream at the current
- * position. It then moves the current position at the end of the
- * read block
- *
- * See the documentation of ISequentialStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Read(
-		  IStream*     iface,
-		  void*          pv,        /* [length_is][size_is][out] */
-		  ULONG          cb,        /* [in] */
-		  ULONG*         pcbRead)   /* [out] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-
-  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->handle->size - This->currentPosition.u.LowPart, cb);
-
-  /*
-   * Lock the buffer in position and copy the data.
-   */
-  supportBuffer = GlobalLock(This->handle->hglobal);
-  if (!supportBuffer)
-  {
-      WARN("read from invalid hglobal %p\n", This->handle->hglobal);
-      *pcbRead = 0;
-      return S_OK;
-  }
-
-  memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
-
-  /*
-   * Move the current position to the new position
-   */
-  This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
-
-  /*
-   * Return the number of bytes read.
-   */
-  *pcbRead = bytesToReadFromBuffer;
-
-  /*
-   * Cleanup
-   */
-  GlobalUnlock(This->handle->hglobal);
-
-  /*
-   * Always returns S_OK even if the end of the stream is reached before the
-   * buffer is filled
-   */
-
-  return S_OK;
-}
-
-/***
- * This method is part of the ISequentialStream interface.
- *
- * It writes a block of information to the stream at the current
- * position. It then moves the current position at the end of the
- * written block. If the stream is too small to fit the block,
- * the stream is grown to fit.
- *
- * See the documentation of ISequentialStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Write(
-	          IStream*     iface,
-		  const void*    pv,          /* [size_is][in] */
-		  ULONG          cb,          /* [in] */
-		  ULONG*         pcbWritten)  /* [out] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-
-  void*          supportBuffer;
-  ULARGE_INTEGER newSize;
-  ULONG          bytesWritten = 0;
-
-  TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten);
-
-  /*
-   * 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->handle->size)
-  {
-    /* 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->handle->hglobal);
-  if (!supportBuffer)
-  {
-      WARN("write to invalid hglobal %p\n", This->handle->hglobal);
-      return S_OK;
-  }
-
-  memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
-
-  /*
-   * Move the current position to the new position
-   */
-  This->currentPosition.u.LowPart+=cb;
-
-  /*
-   * Cleanup
-   */
-  GlobalUnlock(This->handle->hglobal);
-
-out:
-  /*
-   * Return the number of bytes read.
-   */
-  *pcbWritten = cb;
-
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * It will move the current stream pointer according to the parameters
- * given.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Seek(
-		  IStream*      iface,
-		  LARGE_INTEGER   dlibMove,         /* [in] */
-		  DWORD           dwOrigin,         /* [in] */
-		  ULARGE_INTEGER* plibNewPosition) /* [out] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-
-  ULARGE_INTEGER newPosition = This->currentPosition;
-  HRESULT hr = S_OK;
-
-  TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart,
-	dlibMove.u.LowPart, dwOrigin, plibNewPosition);
-
-  /*
-   * The file pointer is moved depending on the given "function"
-   * parameter.
-   */
-  switch (dwOrigin)
-  {
-    case STREAM_SEEK_SET:
-      newPosition.u.HighPart = 0;
-      newPosition.u.LowPart = 0;
-      break;
-    case STREAM_SEEK_CUR:
-      break;
-    case STREAM_SEEK_END:
-      newPosition.QuadPart = This->handle->size;
-      break;
-    default:
-      hr = STG_E_SEEKERROR;
-      goto end;
-  }
-
-  /*
-   * Move the actual file pointer
-   * If the file pointer ends-up after the end of the stream, the next Write operation will
-   * make the file larger. This is how it is documented.
-   */
-  newPosition.u.HighPart = 0;
-  newPosition.u.LowPart += dlibMove.QuadPart;
-
-  if (dlibMove.u.LowPart >= 0x80000000 &&
-      newPosition.u.LowPart >= dlibMove.u.LowPart)
-  {
-    /* We tried to seek backwards and went past the start. */
-    hr = STG_E_SEEKERROR;
-    goto end;
-  }
-
-  This->currentPosition = newPosition;
-
-end:
-  if (plibNewPosition) *plibNewPosition = This->currentPosition;
-
-  return hr;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * It will change the size of a stream.
- *
- * TODO: Switch from small blocks to big blocks and vice versa.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_SetSize(
-				     IStream*      iface,
-				     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
-   */
-
-  if (This->handle->size == libNewSize.u.LowPart)
-    return S_OK;
-
-  /*
-   * Re allocate the HGlobal to fit the new size of the stream.
-   */
-  supportHandle = GlobalReAlloc(This->handle->hglobal, libNewSize.u.LowPart, GMEM_MOVEABLE);
-
-  if (supportHandle == 0)
-    return E_OUTOFMEMORY;
-
-  This->handle->hglobal = supportHandle;
-  This->handle->size = libNewSize.u.LowPart;
-
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * It will copy the 'cb' Bytes to 'pstm' IStream.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
-				    IStream*      iface,
-				    IStream*      pstm,         /* [unique][in] */
-				    ULARGE_INTEGER  cb,           /* [in] */
-				    ULARGE_INTEGER* pcbRead,      /* [out] */
-				    ULARGE_INTEGER* pcbWritten)   /* [out] */
-{
-  HRESULT        hr = S_OK;
-  BYTE           tmpBuffer[128];
-  ULONG          bytesRead, bytesWritten, copySize;
-  ULARGE_INTEGER totalBytesRead;
-  ULARGE_INTEGER totalBytesWritten;
-
-  TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm,
-	cb.u.LowPart, pcbRead, pcbWritten);
-
-  if ( pstm == 0 )
-    return STG_E_INVALIDPOINTER;
-
-  totalBytesRead.QuadPart = 0;
-  totalBytesWritten.QuadPart = 0;
-
-  while ( cb.QuadPart > 0 )
-  {
-    if ( cb.QuadPart >= sizeof(tmpBuffer) )
-      copySize = sizeof(tmpBuffer);
-    else
-      copySize = cb.u.LowPart;
-
-    hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
-    if (FAILED(hr))
-        break;
-
-    totalBytesRead.QuadPart += bytesRead;
-
-    if (bytesRead)
-    {
-        hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
-        if (FAILED(hr))
-            break;
-
-        totalBytesWritten.QuadPart += bytesWritten;
-    }
-
-    if (bytesRead!=copySize)
-      cb.QuadPart = 0;
-    else
-      cb.QuadPart -= bytesRead;
-  }
-
-  if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
-  if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
-
-  return hr;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * For streams supported by HGLOBALS, this function does nothing.
- * This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Commit(
-		  IStream*      iface,
-		  DWORD         grfCommitFlags)  /* [in] */
-{
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * For streams supported by HGLOBALS, this function does nothing.
- * This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Revert(
-		  IStream* iface)
-{
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * For streams supported by HGLOBALS, this function does nothing.
- * This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
-		  IStream*       iface,
-		  ULARGE_INTEGER libOffset,   /* [in] */
-		  ULARGE_INTEGER cb,          /* [in] */
-		  DWORD          dwLockType)  /* [in] */
-{
-  return STG_E_INVALIDFUNCTION;
-}
-
-/*
- * This method is part of the IStream interface.
- *
- * For streams supported by HGLOBALS, this function does nothing.
- * This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
-		  IStream*       iface,
-		  ULARGE_INTEGER libOffset,   /* [in] */
-		  ULARGE_INTEGER cb,          /* [in] */
-		  DWORD          dwLockType)  /* [in] */
-{
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * This method returns information about the current
- * stream.
- *
- * See the documentation of IStream for more info.
- */
-static HRESULT WINAPI HGLOBALStreamImpl_Stat(
-		  IStream*     iface,
-		  STATSTG*     pstatstg,     /* [out] */
-		  DWORD        grfStatFlag)  /* [in] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface);
-
-  memset(pstatstg, 0, sizeof(STATSTG));
-
-  pstatstg->pwcsName = NULL;
-  pstatstg->type     = STGTY_STREAM;
-  pstatstg->cbSize.QuadPart = This->handle->size;
-
-  return S_OK;
-}
-
-static HRESULT WINAPI HGLOBALStreamImpl_Clone(
-		  IStream*     iface,
-		  IStream**    ppstm) /* [out] */
-{
-  HGLOBALStreamImpl* This = impl_from_IStream(iface), *clone;
-  ULARGE_INTEGER dummy;
-  LARGE_INTEGER offset;
-
-  TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->handle->delete_on_release,(long)This->currentPosition.QuadPart);
-
-  *ppstm = NULL;
-
-  clone = hglobalstream_construct();
-  if (!clone) return E_OUTOFMEMORY;
-
-  *ppstm = &clone->IStream_iface;
-  handle_addref(This->handle);
-  clone->handle = This->handle;
-
-  offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart;
-  IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
-  return S_OK;
-}
-
-static const IStreamVtbl HGLOBALStreamImplVtbl =
-{
-    HGLOBALStreamImpl_QueryInterface,
-    HGLOBALStreamImpl_AddRef,
-    HGLOBALStreamImpl_Release,
-    HGLOBALStreamImpl_Read,
-    HGLOBALStreamImpl_Write,
-    HGLOBALStreamImpl_Seek,
-    HGLOBALStreamImpl_SetSize,
-    HGLOBALStreamImpl_CopyTo,
-    HGLOBALStreamImpl_Commit,
-    HGLOBALStreamImpl_Revert,
-    HGLOBALStreamImpl_LockRegion,
-    HGLOBALStreamImpl_UnlockRegion,
-    HGLOBALStreamImpl_Stat,
-    HGLOBALStreamImpl_Clone
-};
-
-/***********************************************************************
- *           CreateStreamOnHGlobal     [OLE32.@]
- */
-HRESULT WINAPI CreateStreamOnHGlobal(
-		HGLOBAL   hGlobal,
-		BOOL      fDeleteOnRelease,
-		LPSTREAM* ppstm)
-{
-  HGLOBALStreamImpl* This;
-
-  if (!ppstm)
-    return E_INVALIDARG;
-
-  This = hglobalstream_construct();
-  if (!This) return E_OUTOFMEMORY;
-
-  This->handle = handle_create(hGlobal, fDeleteOnRelease);
-  if (!This->handle)
-  {
-      HeapFree(GetProcessHeap(), 0, This);
-      return E_OUTOFMEMORY;
-  }
-
-  *ppstm = &This->IStream_iface;
-
-  return S_OK;
-}
-
-/***********************************************************************
- *           GetHGlobalFromStream     [OLE32.@]
- */
-HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
-{
-  HGLOBALStreamImpl* pStream;
-
-  if (!pstm || !phglobal)
-    return E_INVALIDARG;
-
-  pStream = impl_from_IStream(pstm);
-
-  /*
-   * Verify that the stream object was created with CreateStreamOnHGlobal.
-   */
-  if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl)
-    *phglobal = pStream->handle->hglobal;
-  else
-  {
-    *phglobal = 0;
-    return E_INVALIDARG;
-  }
-
-  return S_OK;
-}
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index 44c03b6628c..a6f62ebfa99 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -105,7 +105,7 @@
 @ stub CreateObjrefMoniker
 @ stdcall CreateOleAdviseHolder(ptr)
 @ stdcall CreatePointerMoniker(ptr ptr)
-@ stdcall CreateStreamOnHGlobal(ptr long ptr)
+@ stdcall CreateStreamOnHGlobal(ptr long ptr) combase.CreateStreamOnHGlobal
 @ stdcall DestroyRunningObjectTable()
 @ stdcall DllDebugObjectRPCHook(long ptr) combase.DllDebugObjectRPCHook
 @ stdcall -private DllGetClassObject (ptr ptr ptr)
@@ -121,7 +121,7 @@
 @ stub GetDocumentBitStg
 @ stdcall GetErrorInfo(long ptr) combase.GetErrorInfo
 @ stdcall GetHGlobalFromILockBytes(ptr ptr)
-@ stdcall GetHGlobalFromStream(ptr ptr)
+@ stdcall GetHGlobalFromStream(ptr ptr) combase.GetHGlobalFromStream
 @ stub GetHookInterface
 @ stdcall GetRunningObjectTable(long ptr)
 @ stdcall HACCEL_UserFree(ptr ptr) combase.HACCEL_UserFree
-- 
2.28.0




More information about the wine-devel mailing list