mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 12:54:13 +00:00
Implemented CreateStreamOnHGLOBAL.
This commit is contained in:
parent
5c385be532
commit
4f8b5a85c4
4 changed files with 784 additions and 11 deletions
|
@ -12,6 +12,7 @@ C_SRCS = \
|
|||
compositemoniker.c \
|
||||
filemoniker.c \
|
||||
guid.c \
|
||||
hglobalstream.c \
|
||||
ifs.c \
|
||||
itemmoniker.c \
|
||||
moniker.c \
|
||||
|
|
782
ole/hglobalstream.c
Normal file
782
ole/hglobalstream.c
Normal file
|
@ -0,0 +1,782 @@
|
|||
/*
|
||||
* HGLOBAL Stream implementation
|
||||
*
|
||||
* This file contains the implementation of the stream interface
|
||||
* for streams contained suported by an HGLOBAL pointer.
|
||||
*
|
||||
* Copyright 1999 Francis Beaudet
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "objbase.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(ole)
|
||||
|
||||
/****************************************************************************
|
||||
* HGLOBALStreamImpl definition.
|
||||
*
|
||||
* This class imlements the IStream inteface and represents a stream
|
||||
* supported by an HGLOBAL pointer.
|
||||
*/
|
||||
struct HGLOBALStreamImpl
|
||||
{
|
||||
ICOM_VTABLE(IStream) *lpvtbl; /* Needs to be the first item in the stuct
|
||||
* since we want to cast this in a IStream pointer */
|
||||
|
||||
/*
|
||||
* Reference count
|
||||
*/
|
||||
ULONG ref;
|
||||
|
||||
/*
|
||||
* Support for the stream
|
||||
*/
|
||||
HGLOBAL supportHandle;
|
||||
|
||||
/*
|
||||
* This flag is TRUE if the HGLOBAL is destroyed when the stream
|
||||
* is finally released.
|
||||
*/
|
||||
BOOL deleteOnRelease;
|
||||
|
||||
/*
|
||||
* Helper variable that contains the size of the stream
|
||||
*/
|
||||
ULARGE_INTEGER streamSize;
|
||||
|
||||
/*
|
||||
* This is the current position of the cursor in the stream
|
||||
*/
|
||||
ULARGE_INTEGER currentPosition;
|
||||
};
|
||||
|
||||
typedef struct HGLOBALStreamImpl HGLOBALStreamImpl;
|
||||
|
||||
/*
|
||||
* Method definition for the StgStreamImpl class.
|
||||
*/
|
||||
HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
|
||||
HGLOBAL hGlobal,
|
||||
BOOL fDeleteOnRelease);
|
||||
|
||||
void HGLOBALStreamImpl_Destroy(
|
||||
HGLOBALStreamImpl* This);
|
||||
|
||||
void HGLOBALStreamImpl_OpenBlockChain(
|
||||
HGLOBALStreamImpl* This);
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
|
||||
IStream* iface,
|
||||
REFIID riid, /* [in] */
|
||||
void** ppvObject); /* [iid_is][out] */
|
||||
|
||||
ULONG WINAPI HGLOBALStreamImpl_AddRef(
|
||||
IStream* iface);
|
||||
|
||||
ULONG WINAPI HGLOBALStreamImpl_Release(
|
||||
IStream* iface);
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Read(
|
||||
IStream* iface,
|
||||
void* pv, /* [length_is][size_is][out] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbRead); /* [out] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
IStream* iface,
|
||||
const void* pv, /* [size_is][in] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbWritten); /* [out] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Seek(
|
||||
IStream* iface,
|
||||
LARGE_INTEGER dlibMove, /* [in] */
|
||||
DWORD dwOrigin, /* [in] */
|
||||
ULARGE_INTEGER* plibNewPosition); /* [out] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_SetSize(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libNewSize); /* [in] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
|
||||
IStream* iface,
|
||||
IStream* pstm, /* [unique][in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
ULARGE_INTEGER* pcbRead, /* [out] */
|
||||
ULARGE_INTEGER* pcbWritten); /* [out] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Commit(
|
||||
IStream* iface,
|
||||
DWORD grfCommitFlags); /* [in] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Revert(
|
||||
IStream* iface);
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libOffset, /* [in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
DWORD dwLockType); /* [in] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libOffset, /* [in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
DWORD dwLockType); /* [in] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Stat(
|
||||
IStream* iface,
|
||||
STATSTG* pstatstg, /* [out] */
|
||||
DWORD grfStatFlag); /* [in] */
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Clone(
|
||||
IStream* iface,
|
||||
IStream** ppstm); /* [out] */
|
||||
|
||||
|
||||
/*
|
||||
* Virtual function table for the HGLOBALStreamImpl class.
|
||||
*/
|
||||
static ICOM_VTABLE(IStream) HGLOBALStreamImpl_Vtbl =
|
||||
{
|
||||
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.61]
|
||||
*/
|
||||
HRESULT WINAPI CreateStreamOnHGlobal(
|
||||
HGLOBAL hGlobal,
|
||||
BOOL fDeleteOnRelease,
|
||||
LPSTREAM* ppstm)
|
||||
{
|
||||
HGLOBALStreamImpl* newStream;
|
||||
|
||||
newStream = HGLOBALStreamImpl_Construct(hGlobal,
|
||||
fDeleteOnRelease);
|
||||
|
||||
if (newStream!=NULL)
|
||||
{
|
||||
return IUnknown_QueryInterface((IUnknown*)newStream,
|
||||
&IID_IStream,
|
||||
(void**)ppstm);
|
||||
}
|
||||
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** HGLOBALStreamImpl implementation
|
||||
*/
|
||||
|
||||
/***
|
||||
* This is the constructor for the HGLOBALStreamImpl class.
|
||||
*
|
||||
* Params:
|
||||
* hGlobal - Handle that will support the stream. can be NULL.
|
||||
* fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
|
||||
* when the IStream object is destroyed.
|
||||
*/
|
||||
HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
|
||||
HGLOBAL hGlobal,
|
||||
BOOL fDeleteOnRelease)
|
||||
{
|
||||
HGLOBALStreamImpl* newStream;
|
||||
|
||||
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
|
||||
|
||||
if (newStream!=0)
|
||||
{
|
||||
/*
|
||||
* Set-up the virtual function table and reference count.
|
||||
*/
|
||||
newStream->lpvtbl = &HGLOBALStreamImpl_Vtbl;
|
||||
newStream->ref = 0;
|
||||
|
||||
/*
|
||||
* Initialize the support.
|
||||
*/
|
||||
newStream->supportHandle = hGlobal;
|
||||
newStream->deleteOnRelease = fDeleteOnRelease;
|
||||
|
||||
/*
|
||||
* This method will allocate a handle if one is not supplied.
|
||||
*/
|
||||
if (newStream->supportHandle == NULL)
|
||||
{
|
||||
newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the stream at the begining.
|
||||
*/
|
||||
newStream->currentPosition.HighPart = 0;
|
||||
newStream->currentPosition.LowPart = 0;
|
||||
|
||||
/*
|
||||
* Initialize the size of the stream to the size of the handle.
|
||||
*/
|
||||
newStream->streamSize.HighPart = 0;
|
||||
newStream->streamSize.LowPart = GlobalSize(newStream->supportHandle);
|
||||
}
|
||||
|
||||
return newStream;
|
||||
}
|
||||
|
||||
/***
|
||||
* This is the destructor of the HGLOBALStreamImpl class.
|
||||
*
|
||||
* This method will clean-up all the resources used-up by the given HGLOBALStreamImpl
|
||||
* class. The pointer passed-in to this function will be freed and will not
|
||||
* be valid anymore.
|
||||
*/
|
||||
void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This)
|
||||
{
|
||||
/*
|
||||
* Release the HGlobal if the constructor asked for that.
|
||||
*/
|
||||
if (This->deleteOnRelease)
|
||||
{
|
||||
GlobalFree(This->supportHandle);
|
||||
This->supportHandle=0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, free the memory used-up by the class.
|
||||
*/
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
/***
|
||||
* This implements the IUnknown method QueryInterface for this
|
||||
* class
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
|
||||
IStream* iface,
|
||||
REFIID riid, /* [in] */
|
||||
void** ppvObject) /* [iid_is][out] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
/*
|
||||
* Perform a sanity check on the parameters.
|
||||
*/
|
||||
if (ppvObject==0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
/*
|
||||
* Initialize the return parameter.
|
||||
*/
|
||||
*ppvObject = 0;
|
||||
|
||||
/*
|
||||
* Compare the riid with the interface IDs implemented by this object.
|
||||
*/
|
||||
if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
|
||||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
|
||||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that we obtained an interface.
|
||||
*/
|
||||
if ((*ppvObject)==0)
|
||||
return E_NOINTERFACE;
|
||||
|
||||
/*
|
||||
* Query Interface always increases the reference count by one when it is
|
||||
* successful
|
||||
*/
|
||||
HGLOBALStreamImpl_AddRef(iface);
|
||||
|
||||
return S_OK;;
|
||||
}
|
||||
|
||||
/***
|
||||
* This implements the IUnknown method AddRef for this
|
||||
* class
|
||||
*/
|
||||
ULONG WINAPI HGLOBALStreamImpl_AddRef(
|
||||
IStream* iface)
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
This->ref++;
|
||||
|
||||
return This->ref;
|
||||
}
|
||||
|
||||
/***
|
||||
* This implements the IUnknown method Release for this
|
||||
* class
|
||||
*/
|
||||
ULONG WINAPI HGLOBALStreamImpl_Release(
|
||||
IStream* iface)
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
ULONG newRef;
|
||||
|
||||
This->ref--;
|
||||
|
||||
newRef = This->ref;
|
||||
|
||||
/*
|
||||
* If the reference count goes down to 0, perform suicide.
|
||||
*/
|
||||
if (newRef==0)
|
||||
{
|
||||
HGLOBALStreamImpl_Destroy(This);
|
||||
}
|
||||
|
||||
return newRef;
|
||||
}
|
||||
|
||||
/***
|
||||
* 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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Read(
|
||||
IStream* iface,
|
||||
void* pv, /* [length_is][size_is][out] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbRead) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
void* supportBuffer;
|
||||
ULONG bytesReadBuffer;
|
||||
ULONG bytesToReadFromBuffer;
|
||||
|
||||
/*
|
||||
* If the caller is not interested in the nubmer of bytes read,
|
||||
* we use another buffer to avoid "if" statements in the code.
|
||||
*/
|
||||
if (pcbRead==0)
|
||||
pcbRead = &bytesReadBuffer;
|
||||
|
||||
/*
|
||||
* Using the known size of the stream, calculate the number of bytes
|
||||
* to read from the block chain
|
||||
*/
|
||||
bytesToReadFromBuffer = MIN( This->streamSize.LowPart - This->currentPosition.LowPart, cb);
|
||||
|
||||
/*
|
||||
* Lock the buffer in position and copy the data.
|
||||
*/
|
||||
supportBuffer = GlobalLock(This->supportHandle);
|
||||
|
||||
memcpy(pv, supportBuffer+This->currentPosition.LowPart, bytesToReadFromBuffer);
|
||||
|
||||
/*
|
||||
* Move the current position to the new position
|
||||
*/
|
||||
This->currentPosition.LowPart+=bytesToReadFromBuffer;
|
||||
|
||||
/*
|
||||
* Return the number of bytes read.
|
||||
*/
|
||||
*pcbRead = bytesToReadFromBuffer;
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
GlobalUnlock(This->supportHandle);
|
||||
|
||||
/*
|
||||
* The function returns S_OK if the buffer was filled completely
|
||||
* it returns S_FALSE if the end of the stream is reached before the
|
||||
* buffer is filled
|
||||
*/
|
||||
if(*pcbRead == cb)
|
||||
return S_OK;
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/***
|
||||
* 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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Write(
|
||||
IStream* iface,
|
||||
const void* pv, /* [size_is][in] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbWritten) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
void* supportBuffer;
|
||||
ULARGE_INTEGER newSize;
|
||||
ULONG bytesWritten = 0;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
newSize.HighPart = 0;
|
||||
newSize.LowPart = This->currentPosition.LowPart + cb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify if we need to grow the stream
|
||||
*/
|
||||
if (newSize.LowPart > This->streamSize.LowPart)
|
||||
{
|
||||
/* grow stream */
|
||||
HGLOBALStreamImpl_SetSize(iface, newSize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the buffer in position and copy the data.
|
||||
*/
|
||||
supportBuffer = GlobalLock(This->supportHandle);
|
||||
|
||||
memcpy(supportBuffer+This->currentPosition.LowPart, pv, cb);
|
||||
|
||||
/*
|
||||
* Move the current position to the new position
|
||||
*/
|
||||
This->currentPosition.LowPart+=cb;
|
||||
|
||||
/*
|
||||
* Return the number of bytes read.
|
||||
*/
|
||||
*pcbWritten = cb;
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
GlobalUnlock(This->supportHandle);
|
||||
|
||||
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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Seek(
|
||||
IStream* iface,
|
||||
LARGE_INTEGER dlibMove, /* [in] */
|
||||
DWORD dwOrigin, /* [in] */
|
||||
ULARGE_INTEGER* plibNewPosition) /* [out] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
ULARGE_INTEGER newPosition;
|
||||
|
||||
/*
|
||||
* The caller is allowed to pass in NULL as the new position return value.
|
||||
* If it happens, we assign it to a dynamic variable to avoid special cases
|
||||
* in the code below.
|
||||
*/
|
||||
if (plibNewPosition == 0)
|
||||
{
|
||||
plibNewPosition = &newPosition;
|
||||
}
|
||||
|
||||
/*
|
||||
* The file pointer is moved depending on the given "function"
|
||||
* parameter.
|
||||
*/
|
||||
switch (dwOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET:
|
||||
plibNewPosition->HighPart = 0;
|
||||
plibNewPosition->LowPart = 0;
|
||||
break;
|
||||
case STREAM_SEEK_CUR:
|
||||
*plibNewPosition = This->currentPosition;
|
||||
break;
|
||||
case STREAM_SEEK_END:
|
||||
*plibNewPosition = This->streamSize;
|
||||
break;
|
||||
default:
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't support files with offsets of 64 bits.
|
||||
*/
|
||||
assert(dlibMove.HighPart == 0);
|
||||
|
||||
/*
|
||||
* Check if we end-up before the beginning of the file. That should trigger an
|
||||
* error.
|
||||
*/
|
||||
if ( (dlibMove.LowPart<0) && (plibNewPosition->LowPart < (ULONG)(-dlibMove.LowPart)) )
|
||||
{
|
||||
/*
|
||||
* I don't know what error to send there.
|
||||
*/
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
plibNewPosition->LowPart += dlibMove.LowPart;
|
||||
This->currentPosition = *plibNewPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/***
|
||||
* 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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_SetSize(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libNewSize) /* [in] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
/*
|
||||
* As documented.
|
||||
*/
|
||||
if (libNewSize.HighPart != 0)
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
|
||||
if (This->streamSize.LowPart == libNewSize.LowPart)
|
||||
return S_OK;
|
||||
|
||||
/*
|
||||
* Re allocate the HGlobal to fit the new size of the stream.
|
||||
*/
|
||||
This->supportHandle = GlobalReAlloc(This->supportHandle,
|
||||
libNewSize.LowPart,
|
||||
0);
|
||||
|
||||
This->streamSize.LowPart = libNewSize.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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* Sanity check
|
||||
*/
|
||||
if ( pstm == 0 )
|
||||
return STG_E_INVALIDPOINTER;
|
||||
|
||||
totalBytesRead.LowPart = totalBytesRead.HighPart = 0;
|
||||
totalBytesWritten.LowPart = totalBytesWritten.HighPart = 0;
|
||||
|
||||
/*
|
||||
* use stack to store data temporarly
|
||||
* there is surely more performant way of doing it, for now this basic
|
||||
* implementation will do the job
|
||||
*/
|
||||
while ( cb.LowPart > 0 )
|
||||
{
|
||||
if ( cb.LowPart >= 128 )
|
||||
copySize = 128;
|
||||
else
|
||||
copySize = cb.LowPart;
|
||||
|
||||
HGLOBALStreamImpl_Read(iface, tmpBuffer, 128, &bytesRead);
|
||||
|
||||
totalBytesRead.LowPart += bytesRead;
|
||||
|
||||
HGLOBALStreamImpl_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
|
||||
|
||||
totalBytesWritten.LowPart += bytesWritten;
|
||||
|
||||
/*
|
||||
* Check that read & write operations were succesfull
|
||||
*/
|
||||
if ( (bytesRead != copySize) && (bytesWritten != copySize) )
|
||||
{
|
||||
hr = STG_E_MEDIUMFULL;
|
||||
break;
|
||||
}
|
||||
|
||||
cb.LowPart = cb.LowPart - copySize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update number of bytes read and written
|
||||
*/
|
||||
if (pcbRead)
|
||||
{
|
||||
pcbRead->LowPart = totalBytesRead.LowPart;
|
||||
pcbRead->HighPart = totalBytesRead.HighPart;
|
||||
}
|
||||
|
||||
if (pcbWritten)
|
||||
{
|
||||
pcbWritten->LowPart = totalBytesWritten.LowPart;
|
||||
pcbWritten->HighPart = totalBytesWritten.HighPart;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libOffset, /* [in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
DWORD dwLockType) /* [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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Stat(
|
||||
IStream* iface,
|
||||
STATSTG* pstatstg, /* [out] */
|
||||
DWORD grfStatFlag) /* [in] */
|
||||
{
|
||||
HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
|
||||
|
||||
memset(pstatstg, 0, sizeof(STATSTG));
|
||||
|
||||
pstatstg->pwcsName = NULL;
|
||||
pstatstg->type = STGTY_STREAM;
|
||||
pstatstg->cbSize = This->streamSize;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI HGLOBALStreamImpl_Clone(
|
||||
IStream* iface,
|
||||
IStream** ppstm) /* [out] */
|
||||
{
|
||||
FIXME(ole, "not implemented!\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
|
@ -273,15 +273,6 @@ HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CreateStreamOnHGlobal [OLE32.61]
|
||||
*/
|
||||
HRESULT WINAPI CreateStreamOnHGlobal (HGLOBAL hGlobal, BOOL fDeleteOnRelease, LPSTREAM* ppstm)
|
||||
{
|
||||
FIXME(ole,"(%x,%x,%p), stub!\n", hGlobal, fDeleteOnRelease, ppstm);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* OleSave [OLE32.124]
|
||||
*/
|
||||
|
|
|
@ -169,7 +169,7 @@ HRESULT WINAPI StgStreamImpl_QueryInterface(
|
|||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStream)) == 0)
|
||||
else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
|
||||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
|
@ -644,7 +644,6 @@ HRESULT WINAPI StgStreamImpl_CopyTo(
|
|||
ULARGE_INTEGER* pcbRead, /* [out] */
|
||||
ULARGE_INTEGER* pcbWritten) /* [out] */
|
||||
{
|
||||
StgStreamImpl* const This=(StgStreamImpl*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
BYTE tmpBuffer[128];
|
||||
ULONG bytesRead, bytesWritten, copySize;
|
||||
|
|
Loading…
Reference in a new issue