[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