combase: Move default memory stream implementation.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
02301d8fbc
commit
1a7dbcfd42
|
@ -9,6 +9,7 @@ C_SRCS = \
|
|||
apartment.c \
|
||||
combase.c \
|
||||
errorinfo.c \
|
||||
hglobalstream.c \
|
||||
malloc.c \
|
||||
marshal.c \
|
||||
roapi.c \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -21,7 +21,6 @@ C_SRCS = \
|
|||
filemoniker.c \
|
||||
ftmarshal.c \
|
||||
git.c \
|
||||
hglobalstream.c \
|
||||
itemmoniker.c \
|
||||
marshal.c \
|
||||
memlockbytes.c \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue