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 -#include -#include -#include -#include - -#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