xref: /reactos/dll/win32/ole32/hglobalstream.c (revision 0f5d91b7)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * HGLOBAL Stream implementation
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * This file contains the implementation of the stream interface
5c2c66affSColin Finck  * for streams contained supported by an HGLOBAL pointer.
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * Copyright 1999 Francis Beaudet
8*c0f90872SAmine Khaldi  * Copyright 2016 Dmitry Timoshkov
9c2c66affSColin Finck  *
10c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
11c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
12c2c66affSColin Finck  * License as published by the Free Software Foundation; either
13c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
16c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18c2c66affSColin Finck  * Lesser General Public License for more details.
19c2c66affSColin Finck  *
20c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
21c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
22c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23c2c66affSColin Finck  */
24c2c66affSColin Finck 
25*c0f90872SAmine Khaldi #include <assert.h>
26*c0f90872SAmine Khaldi #include <stdlib.h>
27*c0f90872SAmine Khaldi #include <stdarg.h>
28*c0f90872SAmine Khaldi #include <stdio.h>
29*c0f90872SAmine Khaldi #include <string.h>
30*c0f90872SAmine Khaldi 
31*c0f90872SAmine Khaldi #define COBJMACROS
32*c0f90872SAmine Khaldi #define NONAMELESSUNION
33*c0f90872SAmine Khaldi 
34*c0f90872SAmine Khaldi #include "windef.h"
35*c0f90872SAmine Khaldi #include "winbase.h"
36*c0f90872SAmine Khaldi #include "winuser.h"
37*c0f90872SAmine Khaldi #include "objbase.h"
38*c0f90872SAmine Khaldi #include "ole2.h"
39*c0f90872SAmine Khaldi #include "winerror.h"
40*c0f90872SAmine Khaldi #include "winternl.h"
41*c0f90872SAmine Khaldi 
42*c0f90872SAmine Khaldi #include "wine/debug.h"
43*c0f90872SAmine Khaldi 
44*c0f90872SAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(hglobalstream);
45*c0f90872SAmine Khaldi 
46*c0f90872SAmine Khaldi struct handle_wrapper
47*c0f90872SAmine Khaldi {
48*c0f90872SAmine Khaldi     LONG ref;
49*c0f90872SAmine Khaldi     HGLOBAL hglobal;
50*c0f90872SAmine Khaldi     ULONG size;
51*c0f90872SAmine Khaldi     BOOL delete_on_release;
52*c0f90872SAmine Khaldi     CRITICAL_SECTION lock;
53*c0f90872SAmine Khaldi };
54*c0f90872SAmine Khaldi 
handle_addref(struct handle_wrapper * handle)55*c0f90872SAmine Khaldi static void handle_addref(struct handle_wrapper *handle)
56*c0f90872SAmine Khaldi {
57*c0f90872SAmine Khaldi     InterlockedIncrement(&handle->ref);
58*c0f90872SAmine Khaldi }
59*c0f90872SAmine Khaldi 
handle_release(struct handle_wrapper * handle)60*c0f90872SAmine Khaldi static void handle_release(struct handle_wrapper *handle)
61*c0f90872SAmine Khaldi {
62*c0f90872SAmine Khaldi     ULONG ref = InterlockedDecrement(&handle->ref);
63*c0f90872SAmine Khaldi 
64*c0f90872SAmine Khaldi     if (!ref)
65*c0f90872SAmine Khaldi     {
66*c0f90872SAmine Khaldi         if (handle->delete_on_release)
67*c0f90872SAmine Khaldi         {
68*c0f90872SAmine Khaldi             GlobalFree(handle->hglobal);
69*c0f90872SAmine Khaldi             handle->hglobal = NULL;
70*c0f90872SAmine Khaldi         }
71*c0f90872SAmine Khaldi 
72*c0f90872SAmine Khaldi         handle->lock.DebugInfo->Spare[0] = 0;
73*c0f90872SAmine Khaldi         DeleteCriticalSection(&handle->lock);
74*c0f90872SAmine Khaldi         HeapFree(GetProcessHeap(), 0, handle);
75*c0f90872SAmine Khaldi     }
76*c0f90872SAmine Khaldi }
77*c0f90872SAmine Khaldi 
handle_read(struct handle_wrapper * handle,ULONG * pos,void * dest,ULONG len)78*c0f90872SAmine Khaldi static ULONG handle_read(struct handle_wrapper *handle, ULONG *pos, void *dest, ULONG len)
79*c0f90872SAmine Khaldi {
80*c0f90872SAmine Khaldi     void *source;
81*c0f90872SAmine Khaldi 
82*c0f90872SAmine Khaldi     EnterCriticalSection(&handle->lock);
83*c0f90872SAmine Khaldi 
84*c0f90872SAmine Khaldi     if (*pos < handle->size)
85*c0f90872SAmine Khaldi         len = min(handle->size - *pos, len);
86*c0f90872SAmine Khaldi     else
87*c0f90872SAmine Khaldi         len = 0;
88*c0f90872SAmine Khaldi 
89*c0f90872SAmine Khaldi     source = GlobalLock(handle->hglobal);
90*c0f90872SAmine Khaldi     if (source)
91*c0f90872SAmine Khaldi     {
92*c0f90872SAmine Khaldi         memcpy(dest, (char *)source + *pos, len);
93*c0f90872SAmine Khaldi         *pos += len;
94*c0f90872SAmine Khaldi         GlobalUnlock(handle->hglobal);
95*c0f90872SAmine Khaldi     }
96*c0f90872SAmine Khaldi     else
97*c0f90872SAmine Khaldi     {
98*c0f90872SAmine Khaldi         WARN("read from invalid hglobal %p\n", handle->hglobal);
99*c0f90872SAmine Khaldi         len = 0;
100*c0f90872SAmine Khaldi     }
101*c0f90872SAmine Khaldi 
102*c0f90872SAmine Khaldi     LeaveCriticalSection(&handle->lock);
103*c0f90872SAmine Khaldi     return len;
104*c0f90872SAmine Khaldi }
105*c0f90872SAmine Khaldi 
handle_write(struct handle_wrapper * handle,ULONG * pos,const void * source,ULONG len)106*c0f90872SAmine Khaldi static ULONG handle_write(struct handle_wrapper *handle, ULONG *pos, const void *source, ULONG len)
107*c0f90872SAmine Khaldi {
108*c0f90872SAmine Khaldi     void *dest;
109*c0f90872SAmine Khaldi 
110*c0f90872SAmine Khaldi     if (!len)
111*c0f90872SAmine Khaldi         return 0;
112*c0f90872SAmine Khaldi 
113*c0f90872SAmine Khaldi     EnterCriticalSection(&handle->lock);
114*c0f90872SAmine Khaldi 
115*c0f90872SAmine Khaldi     if (*pos + len > handle->size)
116*c0f90872SAmine Khaldi     {
117*c0f90872SAmine Khaldi         HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, *pos + len, GMEM_MOVEABLE);
118*c0f90872SAmine Khaldi         if (hglobal)
119*c0f90872SAmine Khaldi         {
120*c0f90872SAmine Khaldi             handle->hglobal = hglobal;
121*c0f90872SAmine Khaldi             handle->size = *pos + len;
122*c0f90872SAmine Khaldi         }
123*c0f90872SAmine Khaldi         else
124*c0f90872SAmine Khaldi         {
125*c0f90872SAmine Khaldi             len = 0;
126*c0f90872SAmine Khaldi             goto done;
127*c0f90872SAmine Khaldi         }
128*c0f90872SAmine Khaldi     }
129*c0f90872SAmine Khaldi 
130*c0f90872SAmine Khaldi     dest = GlobalLock(handle->hglobal);
131*c0f90872SAmine Khaldi     if (dest)
132*c0f90872SAmine Khaldi     {
133*c0f90872SAmine Khaldi         memcpy((char *)dest + *pos, source, len);
134*c0f90872SAmine Khaldi         *pos += len;
135*c0f90872SAmine Khaldi         GlobalUnlock(handle->hglobal);
136*c0f90872SAmine Khaldi     }
137*c0f90872SAmine Khaldi     else
138*c0f90872SAmine Khaldi     {
139*c0f90872SAmine Khaldi         WARN("write to invalid hglobal %p\n", handle->hglobal);
140*c0f90872SAmine Khaldi         /* len = 0; */
141*c0f90872SAmine Khaldi     }
142*c0f90872SAmine Khaldi 
143*c0f90872SAmine Khaldi done:
144*c0f90872SAmine Khaldi     LeaveCriticalSection(&handle->lock);
145*c0f90872SAmine Khaldi     return len;
146*c0f90872SAmine Khaldi }
147*c0f90872SAmine Khaldi 
handle_gethglobal(struct handle_wrapper * handle)148*c0f90872SAmine Khaldi static HGLOBAL handle_gethglobal(struct handle_wrapper *handle)
149*c0f90872SAmine Khaldi {
150*c0f90872SAmine Khaldi     return handle->hglobal;
151*c0f90872SAmine Khaldi }
152*c0f90872SAmine Khaldi 
handle_setsize(struct handle_wrapper * handle,ULONG size)153*c0f90872SAmine Khaldi static HRESULT handle_setsize(struct handle_wrapper *handle, ULONG size)
154*c0f90872SAmine Khaldi {
155*c0f90872SAmine Khaldi     HRESULT hr = S_OK;
156*c0f90872SAmine Khaldi 
157*c0f90872SAmine Khaldi     EnterCriticalSection(&handle->lock);
158*c0f90872SAmine Khaldi 
159*c0f90872SAmine Khaldi     if (handle->size != size)
160*c0f90872SAmine Khaldi     {
161*c0f90872SAmine Khaldi         HGLOBAL hglobal = GlobalReAlloc(handle->hglobal, size, GMEM_MOVEABLE);
162*c0f90872SAmine Khaldi         if (hglobal)
163*c0f90872SAmine Khaldi         {
164*c0f90872SAmine Khaldi             handle->hglobal = hglobal;
165*c0f90872SAmine Khaldi             handle->size = size;
166*c0f90872SAmine Khaldi         }
167*c0f90872SAmine Khaldi         else
168*c0f90872SAmine Khaldi             hr = E_OUTOFMEMORY;
169*c0f90872SAmine Khaldi     }
170*c0f90872SAmine Khaldi 
171*c0f90872SAmine Khaldi     LeaveCriticalSection(&handle->lock);
172*c0f90872SAmine Khaldi     return hr;
173*c0f90872SAmine Khaldi }
174*c0f90872SAmine Khaldi 
handle_getsize(struct handle_wrapper * handle)175*c0f90872SAmine Khaldi static ULONG handle_getsize(struct handle_wrapper *handle)
176*c0f90872SAmine Khaldi {
177*c0f90872SAmine Khaldi     return handle->size;
178*c0f90872SAmine Khaldi }
179*c0f90872SAmine Khaldi 
handle_create(HGLOBAL hglobal,BOOL delete_on_release)180*c0f90872SAmine Khaldi static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
181*c0f90872SAmine Khaldi {
182*c0f90872SAmine Khaldi     struct handle_wrapper *handle;
183*c0f90872SAmine Khaldi 
184*c0f90872SAmine Khaldi     handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle));
185*c0f90872SAmine Khaldi     if (handle)
186*c0f90872SAmine Khaldi     {
187*c0f90872SAmine Khaldi         handle->ref = 1;
188*c0f90872SAmine Khaldi         handle->hglobal = hglobal;
189*c0f90872SAmine Khaldi         handle->size = GlobalSize(hglobal);
190*c0f90872SAmine Khaldi         handle->delete_on_release = delete_on_release;
191*c0f90872SAmine Khaldi         InitializeCriticalSection(&handle->lock);
192*c0f90872SAmine Khaldi         handle->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": handle_wrapper.lock");
193*c0f90872SAmine Khaldi     }
194*c0f90872SAmine Khaldi     return handle;
195*c0f90872SAmine Khaldi }
196c2c66affSColin Finck 
197c2c66affSColin Finck /****************************************************************************
198c2c66affSColin Finck  * HGLOBALStreamImpl definition.
199c2c66affSColin Finck  *
200c2c66affSColin Finck  * This class implements the IStream interface and represents a stream
201c2c66affSColin Finck  * supported by an HGLOBAL pointer.
202c2c66affSColin Finck  */
203c2c66affSColin Finck typedef struct
204c2c66affSColin Finck {
205c2c66affSColin Finck   IStream IStream_iface;
206c2c66affSColin Finck   LONG ref;
207c2c66affSColin Finck 
208*c0f90872SAmine Khaldi   struct handle_wrapper *handle;
209c2c66affSColin Finck 
210c2c66affSColin Finck   /* current position of the cursor */
211c2c66affSColin Finck   ULARGE_INTEGER currentPosition;
212c2c66affSColin Finck } HGLOBALStreamImpl;
213c2c66affSColin Finck 
impl_from_IStream(IStream * iface)214c2c66affSColin Finck static inline HGLOBALStreamImpl *impl_from_IStream(IStream *iface)
215c2c66affSColin Finck {
216c2c66affSColin Finck   return CONTAINING_RECORD(iface, HGLOBALStreamImpl, IStream_iface);
217c2c66affSColin Finck }
218c2c66affSColin Finck 
HGLOBALStreamImpl_QueryInterface(IStream * iface,REFIID riid,void ** ppvObject)219c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
220c2c66affSColin Finck 		  IStream*     iface,
221c2c66affSColin Finck 		  REFIID         riid,	      /* [in] */
222c2c66affSColin Finck 		  void**         ppvObject)   /* [iid_is][out] */
223c2c66affSColin Finck {
224c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
225c2c66affSColin Finck 
226c2c66affSColin Finck   if (ppvObject==0)
227c2c66affSColin Finck     return E_INVALIDARG;
228c2c66affSColin Finck 
229c2c66affSColin Finck   *ppvObject = 0;
230c2c66affSColin Finck 
231c2c66affSColin Finck   if (IsEqualIID(&IID_IUnknown, riid) ||
232c2c66affSColin Finck       IsEqualIID(&IID_ISequentialStream, riid) ||
233c2c66affSColin Finck       IsEqualIID(&IID_IStream, riid))
234c2c66affSColin Finck   {
235c2c66affSColin Finck     *ppvObject = &This->IStream_iface;
236c2c66affSColin Finck   }
237c2c66affSColin Finck 
238c2c66affSColin Finck   if ((*ppvObject)==0)
239c2c66affSColin Finck     return E_NOINTERFACE;
240c2c66affSColin Finck 
241c2c66affSColin Finck   IStream_AddRef(iface);
242c2c66affSColin Finck 
243c2c66affSColin Finck   return S_OK;
244c2c66affSColin Finck }
245c2c66affSColin Finck 
HGLOBALStreamImpl_AddRef(IStream * iface)246c2c66affSColin Finck static ULONG WINAPI HGLOBALStreamImpl_AddRef(IStream* iface)
247c2c66affSColin Finck {
248c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
249c2c66affSColin Finck   return InterlockedIncrement(&This->ref);
250c2c66affSColin Finck }
251c2c66affSColin Finck 
HGLOBALStreamImpl_Release(IStream * iface)252c2c66affSColin Finck static ULONG WINAPI HGLOBALStreamImpl_Release(
253c2c66affSColin Finck 		IStream* iface)
254c2c66affSColin Finck {
255c2c66affSColin Finck   HGLOBALStreamImpl* This= impl_from_IStream(iface);
256c2c66affSColin Finck   ULONG ref = InterlockedDecrement(&This->ref);
257c2c66affSColin Finck 
258c2c66affSColin Finck   if (!ref)
259c2c66affSColin Finck   {
260*c0f90872SAmine Khaldi     handle_release(This->handle);
261c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, This);
262c2c66affSColin Finck   }
263c2c66affSColin Finck 
264c2c66affSColin Finck   return ref;
265c2c66affSColin Finck }
266c2c66affSColin Finck 
267c2c66affSColin Finck /***
268c2c66affSColin Finck  * This method is part of the ISequentialStream interface.
269c2c66affSColin Finck  *
270c2c66affSColin Finck  * If reads a block of information from the stream at the current
271c2c66affSColin Finck  * position. It then moves the current position at the end of the
272c2c66affSColin Finck  * read block
273c2c66affSColin Finck  *
274c2c66affSColin Finck  * See the documentation of ISequentialStream for more info.
275c2c66affSColin Finck  */
HGLOBALStreamImpl_Read(IStream * iface,void * pv,ULONG cb,ULONG * pcbRead)276c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Read(
277c2c66affSColin Finck 		  IStream*     iface,
278c2c66affSColin Finck 		  void*          pv,        /* [length_is][size_is][out] */
279c2c66affSColin Finck 		  ULONG          cb,        /* [in] */
280c2c66affSColin Finck 		  ULONG*         pcbRead)   /* [out] */
281c2c66affSColin Finck {
282c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
283*c0f90872SAmine Khaldi   ULONG num_bytes;
284c2c66affSColin Finck 
285*c0f90872SAmine Khaldi   TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbRead);
286c2c66affSColin Finck 
287*c0f90872SAmine Khaldi   num_bytes = handle_read(This->handle, &This->currentPosition.u.LowPart, pv, cb);
288*c0f90872SAmine Khaldi   if (pcbRead) *pcbRead = num_bytes;
289c2c66affSColin Finck 
290c2c66affSColin Finck   return S_OK;
291c2c66affSColin Finck }
292c2c66affSColin Finck 
293c2c66affSColin Finck /***
294c2c66affSColin Finck  * This method is part of the ISequentialStream interface.
295c2c66affSColin Finck  *
296c2c66affSColin Finck  * It writes a block of information to the stream at the current
297c2c66affSColin Finck  * position. It then moves the current position at the end of the
298c2c66affSColin Finck  * written block. If the stream is too small to fit the block,
299c2c66affSColin Finck  * the stream is grown to fit.
300c2c66affSColin Finck  *
301c2c66affSColin Finck  * See the documentation of ISequentialStream for more info.
302c2c66affSColin Finck  */
HGLOBALStreamImpl_Write(IStream * iface,const void * pv,ULONG cb,ULONG * pcbWritten)303c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Write(
304c2c66affSColin Finck 	          IStream*     iface,
305c2c66affSColin Finck 		  const void*    pv,          /* [size_is][in] */
306c2c66affSColin Finck 		  ULONG          cb,          /* [in] */
307c2c66affSColin Finck 		  ULONG*         pcbWritten)  /* [out] */
308c2c66affSColin Finck {
309c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
310*c0f90872SAmine Khaldi   ULONG num_bytes;
311c2c66affSColin Finck 
312c2c66affSColin Finck   TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten);
313c2c66affSColin Finck 
314*c0f90872SAmine Khaldi   num_bytes = handle_write(This->handle, &This->currentPosition.u.LowPart, pv, cb);
315*c0f90872SAmine Khaldi   if (pcbWritten) *pcbWritten = num_bytes;
316c2c66affSColin Finck 
317*c0f90872SAmine Khaldi   return (num_bytes < cb) ? E_OUTOFMEMORY : S_OK;
318c2c66affSColin Finck }
319c2c66affSColin Finck 
320c2c66affSColin Finck /***
321c2c66affSColin Finck  * This method is part of the IStream interface.
322c2c66affSColin Finck  *
323c2c66affSColin Finck  * It will move the current stream pointer according to the parameters
324c2c66affSColin Finck  * given.
325c2c66affSColin Finck  *
326c2c66affSColin Finck  * See the documentation of IStream for more info.
327c2c66affSColin Finck  */
HGLOBALStreamImpl_Seek(IStream * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)328c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Seek(
329c2c66affSColin Finck 		  IStream*      iface,
330c2c66affSColin Finck 		  LARGE_INTEGER   dlibMove,         /* [in] */
331c2c66affSColin Finck 		  DWORD           dwOrigin,         /* [in] */
332c2c66affSColin Finck 		  ULARGE_INTEGER* plibNewPosition) /* [out] */
333c2c66affSColin Finck {
334c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
335c2c66affSColin Finck 
336c2c66affSColin Finck   ULARGE_INTEGER newPosition = This->currentPosition;
337c2c66affSColin Finck   HRESULT hr = S_OK;
338c2c66affSColin Finck 
339c2c66affSColin Finck   TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart,
340c2c66affSColin Finck 	dlibMove.u.LowPart, dwOrigin, plibNewPosition);
341c2c66affSColin Finck 
342c2c66affSColin Finck   /*
343c2c66affSColin Finck    * The file pointer is moved depending on the given "function"
344c2c66affSColin Finck    * parameter.
345c2c66affSColin Finck    */
346c2c66affSColin Finck   switch (dwOrigin)
347c2c66affSColin Finck   {
348c2c66affSColin Finck     case STREAM_SEEK_SET:
349c2c66affSColin Finck       newPosition.u.HighPart = 0;
350c2c66affSColin Finck       newPosition.u.LowPart = 0;
351c2c66affSColin Finck       break;
352c2c66affSColin Finck     case STREAM_SEEK_CUR:
353c2c66affSColin Finck       break;
354c2c66affSColin Finck     case STREAM_SEEK_END:
355*c0f90872SAmine Khaldi       newPosition.QuadPart = handle_getsize(This->handle);
356c2c66affSColin Finck       break;
357c2c66affSColin Finck     default:
358c2c66affSColin Finck       hr = STG_E_SEEKERROR;
359c2c66affSColin Finck       goto end;
360c2c66affSColin Finck   }
361c2c66affSColin Finck 
362c2c66affSColin Finck   /*
363c2c66affSColin Finck    * Move the actual file pointer
364c2c66affSColin Finck    * If the file pointer ends-up after the end of the stream, the next Write operation will
365c2c66affSColin Finck    * make the file larger. This is how it is documented.
366c2c66affSColin Finck    */
367c2c66affSColin Finck   newPosition.u.HighPart = 0;
368c2c66affSColin Finck   newPosition.u.LowPart += dlibMove.QuadPart;
369c2c66affSColin Finck 
370c2c66affSColin Finck   if (dlibMove.u.LowPart >= 0x80000000 &&
371c2c66affSColin Finck       newPosition.u.LowPart >= dlibMove.u.LowPart)
372c2c66affSColin Finck   {
373c2c66affSColin Finck     /* We tried to seek backwards and went past the start. */
374c2c66affSColin Finck     hr = STG_E_SEEKERROR;
375c2c66affSColin Finck     goto end;
376c2c66affSColin Finck   }
377c2c66affSColin Finck 
378c2c66affSColin Finck   This->currentPosition = newPosition;
379c2c66affSColin Finck 
380c2c66affSColin Finck end:
381c2c66affSColin Finck   if (plibNewPosition) *plibNewPosition = This->currentPosition;
382c2c66affSColin Finck 
383c2c66affSColin Finck   return hr;
384c2c66affSColin Finck }
385c2c66affSColin Finck 
386c2c66affSColin Finck /***
387c2c66affSColin Finck  * This method is part of the IStream interface.
388c2c66affSColin Finck  *
389c2c66affSColin Finck  * It will change the size of a stream.
390c2c66affSColin Finck  *
391c2c66affSColin Finck  * TODO: Switch from small blocks to big blocks and vice versa.
392c2c66affSColin Finck  *
393c2c66affSColin Finck  * See the documentation of IStream for more info.
394c2c66affSColin Finck  */
HGLOBALStreamImpl_SetSize(IStream * iface,ULARGE_INTEGER libNewSize)395c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_SetSize(
396c2c66affSColin Finck 				     IStream*      iface,
397c2c66affSColin Finck 				     ULARGE_INTEGER  libNewSize)   /* [in] */
398c2c66affSColin Finck {
399c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
400c2c66affSColin Finck 
401c2c66affSColin Finck   TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
402c2c66affSColin Finck 
403c2c66affSColin Finck   /*
404c2c66affSColin Finck    * HighPart is ignored as shown in tests
405c2c66affSColin Finck    */
406*c0f90872SAmine Khaldi   return handle_setsize(This->handle, libNewSize.u.LowPart);
407c2c66affSColin Finck }
408c2c66affSColin Finck 
409c2c66affSColin Finck /***
410c2c66affSColin Finck  * This method is part of the IStream interface.
411c2c66affSColin Finck  *
412c2c66affSColin Finck  * It will copy the 'cb' Bytes to 'pstm' IStream.
413c2c66affSColin Finck  *
414c2c66affSColin Finck  * See the documentation of IStream for more info.
415c2c66affSColin Finck  */
HGLOBALStreamImpl_CopyTo(IStream * iface,IStream * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER * pcbRead,ULARGE_INTEGER * pcbWritten)416c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
417c2c66affSColin Finck 				    IStream*      iface,
418c2c66affSColin Finck 				    IStream*      pstm,         /* [unique][in] */
419c2c66affSColin Finck 				    ULARGE_INTEGER  cb,           /* [in] */
420c2c66affSColin Finck 				    ULARGE_INTEGER* pcbRead,      /* [out] */
421c2c66affSColin Finck 				    ULARGE_INTEGER* pcbWritten)   /* [out] */
422c2c66affSColin Finck {
423c2c66affSColin Finck   HRESULT        hr = S_OK;
424c2c66affSColin Finck   BYTE           tmpBuffer[128];
425c2c66affSColin Finck   ULONG          bytesRead, bytesWritten, copySize;
426c2c66affSColin Finck   ULARGE_INTEGER totalBytesRead;
427c2c66affSColin Finck   ULARGE_INTEGER totalBytesWritten;
428c2c66affSColin Finck 
429c2c66affSColin Finck   TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm,
430c2c66affSColin Finck 	cb.u.LowPart, pcbRead, pcbWritten);
431c2c66affSColin Finck 
432c2c66affSColin Finck   if ( pstm == 0 )
433c2c66affSColin Finck     return STG_E_INVALIDPOINTER;
434c2c66affSColin Finck 
435c2c66affSColin Finck   totalBytesRead.QuadPart = 0;
436c2c66affSColin Finck   totalBytesWritten.QuadPart = 0;
437c2c66affSColin Finck 
438c2c66affSColin Finck   while ( cb.QuadPart > 0 )
439c2c66affSColin Finck   {
440c2c66affSColin Finck     if ( cb.QuadPart >= sizeof(tmpBuffer) )
441c2c66affSColin Finck       copySize = sizeof(tmpBuffer);
442c2c66affSColin Finck     else
443c2c66affSColin Finck       copySize = cb.u.LowPart;
444c2c66affSColin Finck 
445c2c66affSColin Finck     hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
446c2c66affSColin Finck     if (FAILED(hr))
447c2c66affSColin Finck         break;
448c2c66affSColin Finck 
449c2c66affSColin Finck     totalBytesRead.QuadPart += bytesRead;
450c2c66affSColin Finck 
451c2c66affSColin Finck     if (bytesRead)
452c2c66affSColin Finck     {
453c2c66affSColin Finck         hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
454c2c66affSColin Finck         if (FAILED(hr))
455c2c66affSColin Finck             break;
456c2c66affSColin Finck 
457c2c66affSColin Finck         totalBytesWritten.QuadPart += bytesWritten;
458c2c66affSColin Finck     }
459c2c66affSColin Finck 
460c2c66affSColin Finck     if (bytesRead!=copySize)
461c2c66affSColin Finck       cb.QuadPart = 0;
462c2c66affSColin Finck     else
463c2c66affSColin Finck       cb.QuadPart -= bytesRead;
464c2c66affSColin Finck   }
465c2c66affSColin Finck 
466c2c66affSColin Finck   if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
467c2c66affSColin Finck   if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
468c2c66affSColin Finck 
469c2c66affSColin Finck   return hr;
470c2c66affSColin Finck }
471c2c66affSColin Finck 
472c2c66affSColin Finck /***
473c2c66affSColin Finck  * This method is part of the IStream interface.
474c2c66affSColin Finck  *
475c2c66affSColin Finck  * For streams supported by HGLOBALS, this function does nothing.
476c2c66affSColin Finck  * This is what the documentation tells us.
477c2c66affSColin Finck  *
478c2c66affSColin Finck  * See the documentation of IStream for more info.
479c2c66affSColin Finck  */
HGLOBALStreamImpl_Commit(IStream * iface,DWORD grfCommitFlags)480c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Commit(
481c2c66affSColin Finck 		  IStream*      iface,
482c2c66affSColin Finck 		  DWORD         grfCommitFlags)  /* [in] */
483c2c66affSColin Finck {
484c2c66affSColin Finck   return S_OK;
485c2c66affSColin Finck }
486c2c66affSColin Finck 
487c2c66affSColin Finck /***
488c2c66affSColin Finck  * This method is part of the IStream interface.
489c2c66affSColin Finck  *
490c2c66affSColin Finck  * For streams supported by HGLOBALS, this function does nothing.
491c2c66affSColin Finck  * This is what the documentation tells us.
492c2c66affSColin Finck  *
493c2c66affSColin Finck  * See the documentation of IStream for more info.
494c2c66affSColin Finck  */
HGLOBALStreamImpl_Revert(IStream * iface)495c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Revert(
496c2c66affSColin Finck 		  IStream* iface)
497c2c66affSColin Finck {
498c2c66affSColin Finck   return S_OK;
499c2c66affSColin Finck }
500c2c66affSColin Finck 
501c2c66affSColin Finck /***
502c2c66affSColin Finck  * This method is part of the IStream interface.
503c2c66affSColin Finck  *
504c2c66affSColin Finck  * For streams supported by HGLOBALS, this function does nothing.
505c2c66affSColin Finck  * This is what the documentation tells us.
506c2c66affSColin Finck  *
507c2c66affSColin Finck  * See the documentation of IStream for more info.
508c2c66affSColin Finck  */
HGLOBALStreamImpl_LockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)509c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
510c2c66affSColin Finck 		  IStream*       iface,
511c2c66affSColin Finck 		  ULARGE_INTEGER libOffset,   /* [in] */
512c2c66affSColin Finck 		  ULARGE_INTEGER cb,          /* [in] */
513c2c66affSColin Finck 		  DWORD          dwLockType)  /* [in] */
514c2c66affSColin Finck {
515c2c66affSColin Finck   return STG_E_INVALIDFUNCTION;
516c2c66affSColin Finck }
517c2c66affSColin Finck 
518c2c66affSColin Finck /*
519c2c66affSColin Finck  * This method is part of the IStream interface.
520c2c66affSColin Finck  *
521c2c66affSColin Finck  * For streams supported by HGLOBALS, this function does nothing.
522c2c66affSColin Finck  * This is what the documentation tells us.
523c2c66affSColin Finck  *
524c2c66affSColin Finck  * See the documentation of IStream for more info.
525c2c66affSColin Finck  */
HGLOBALStreamImpl_UnlockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)526c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
527c2c66affSColin Finck 		  IStream*       iface,
528c2c66affSColin Finck 		  ULARGE_INTEGER libOffset,   /* [in] */
529c2c66affSColin Finck 		  ULARGE_INTEGER cb,          /* [in] */
530c2c66affSColin Finck 		  DWORD          dwLockType)  /* [in] */
531c2c66affSColin Finck {
532c2c66affSColin Finck   return S_OK;
533c2c66affSColin Finck }
534c2c66affSColin Finck 
535c2c66affSColin Finck /***
536c2c66affSColin Finck  * This method is part of the IStream interface.
537c2c66affSColin Finck  *
538c2c66affSColin Finck  * This method returns information about the current
539c2c66affSColin Finck  * stream.
540c2c66affSColin Finck  *
541c2c66affSColin Finck  * See the documentation of IStream for more info.
542c2c66affSColin Finck  */
HGLOBALStreamImpl_Stat(IStream * iface,STATSTG * pstatstg,DWORD grfStatFlag)543c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Stat(
544c2c66affSColin Finck 		  IStream*     iface,
545c2c66affSColin Finck 		  STATSTG*     pstatstg,     /* [out] */
546c2c66affSColin Finck 		  DWORD        grfStatFlag)  /* [in] */
547c2c66affSColin Finck {
548c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
549c2c66affSColin Finck 
550c2c66affSColin Finck   memset(pstatstg, 0, sizeof(STATSTG));
551c2c66affSColin Finck 
552c2c66affSColin Finck   pstatstg->pwcsName = NULL;
553c2c66affSColin Finck   pstatstg->type     = STGTY_STREAM;
554*c0f90872SAmine Khaldi   pstatstg->cbSize.QuadPart = handle_getsize(This->handle);
555c2c66affSColin Finck 
556c2c66affSColin Finck   return S_OK;
557c2c66affSColin Finck }
558c2c66affSColin Finck 
559*c0f90872SAmine Khaldi static const IStreamVtbl HGLOBALStreamImplVtbl;
560*c0f90872SAmine Khaldi 
HGLOBALStreamImpl_Create(void)561*c0f90872SAmine Khaldi static HGLOBALStreamImpl *HGLOBALStreamImpl_Create(void)
562*c0f90872SAmine Khaldi {
563*c0f90872SAmine Khaldi     HGLOBALStreamImpl *This;
564*c0f90872SAmine Khaldi 
565*c0f90872SAmine Khaldi     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
566*c0f90872SAmine Khaldi     if (This)
567*c0f90872SAmine Khaldi     {
568*c0f90872SAmine Khaldi         This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
569*c0f90872SAmine Khaldi         This->ref = 1;
570*c0f90872SAmine Khaldi     }
571*c0f90872SAmine Khaldi     return This;
572*c0f90872SAmine Khaldi }
573*c0f90872SAmine Khaldi 
HGLOBALStreamImpl_Clone(IStream * iface,IStream ** ppstm)574c2c66affSColin Finck static HRESULT WINAPI HGLOBALStreamImpl_Clone(
575c2c66affSColin Finck 		  IStream*     iface,
576c2c66affSColin Finck 		  IStream**    ppstm) /* [out] */
577c2c66affSColin Finck {
578c2c66affSColin Finck   HGLOBALStreamImpl* This = impl_from_IStream(iface);
579*c0f90872SAmine Khaldi   HGLOBALStreamImpl* clone;
580c2c66affSColin Finck   ULARGE_INTEGER dummy;
581c2c66affSColin Finck   LARGE_INTEGER offset;
582c2c66affSColin Finck 
583*c0f90872SAmine Khaldi   if (!ppstm) return E_INVALIDARG;
584*c0f90872SAmine Khaldi 
585*c0f90872SAmine Khaldi   *ppstm = NULL;
586*c0f90872SAmine Khaldi 
587*c0f90872SAmine Khaldi   TRACE(" Cloning %p (seek position=%d)\n", iface, This->currentPosition.u.LowPart);
588*c0f90872SAmine Khaldi 
589*c0f90872SAmine Khaldi   clone = HGLOBALStreamImpl_Create();
590*c0f90872SAmine Khaldi   if (!clone) return E_OUTOFMEMORY;
591*c0f90872SAmine Khaldi 
592*c0f90872SAmine Khaldi   *ppstm = &clone->IStream_iface;
593*c0f90872SAmine Khaldi 
594*c0f90872SAmine Khaldi   handle_addref(This->handle);
595*c0f90872SAmine Khaldi   clone->handle = This->handle;
596*c0f90872SAmine Khaldi 
597c2c66affSColin Finck   offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart;
598c2c66affSColin Finck   IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
599c2c66affSColin Finck   return S_OK;
600c2c66affSColin Finck }
601c2c66affSColin Finck 
602c2c66affSColin Finck static const IStreamVtbl HGLOBALStreamImplVtbl =
603c2c66affSColin Finck {
604c2c66affSColin Finck     HGLOBALStreamImpl_QueryInterface,
605c2c66affSColin Finck     HGLOBALStreamImpl_AddRef,
606c2c66affSColin Finck     HGLOBALStreamImpl_Release,
607c2c66affSColin Finck     HGLOBALStreamImpl_Read,
608c2c66affSColin Finck     HGLOBALStreamImpl_Write,
609c2c66affSColin Finck     HGLOBALStreamImpl_Seek,
610c2c66affSColin Finck     HGLOBALStreamImpl_SetSize,
611c2c66affSColin Finck     HGLOBALStreamImpl_CopyTo,
612c2c66affSColin Finck     HGLOBALStreamImpl_Commit,
613c2c66affSColin Finck     HGLOBALStreamImpl_Revert,
614c2c66affSColin Finck     HGLOBALStreamImpl_LockRegion,
615c2c66affSColin Finck     HGLOBALStreamImpl_UnlockRegion,
616c2c66affSColin Finck     HGLOBALStreamImpl_Stat,
617c2c66affSColin Finck     HGLOBALStreamImpl_Clone
618c2c66affSColin Finck };
619c2c66affSColin Finck 
620c2c66affSColin Finck /***********************************************************************
621c2c66affSColin Finck  *           CreateStreamOnHGlobal     [OLE32.@]
622c2c66affSColin Finck  */
CreateStreamOnHGlobal(HGLOBAL hGlobal,BOOL fDeleteOnRelease,LPSTREAM * ppstm)623c2c66affSColin Finck HRESULT WINAPI CreateStreamOnHGlobal(
624c2c66affSColin Finck 		HGLOBAL   hGlobal,
625c2c66affSColin Finck 		BOOL      fDeleteOnRelease,
626c2c66affSColin Finck 		LPSTREAM* ppstm)
627c2c66affSColin Finck {
628c2c66affSColin Finck   HGLOBALStreamImpl* This;
629c2c66affSColin Finck 
630c2c66affSColin Finck   if (!ppstm)
631c2c66affSColin Finck     return E_INVALIDARG;
632c2c66affSColin Finck 
633*c0f90872SAmine Khaldi   This = HGLOBALStreamImpl_Create();
634c2c66affSColin Finck   if (!This) return E_OUTOFMEMORY;
635c2c66affSColin Finck 
6362178977bSAmine Khaldi   /* allocate a handle if one is not supplied */
637*c0f90872SAmine Khaldi   if (!hGlobal)
638*c0f90872SAmine Khaldi     hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
639*c0f90872SAmine Khaldi 
640*c0f90872SAmine Khaldi   This->handle = handle_create(hGlobal, fDeleteOnRelease);
641c2c66affSColin Finck 
642c2c66affSColin Finck   /* start at the beginning */
643c2c66affSColin Finck   This->currentPosition.u.HighPart = 0;
644c2c66affSColin Finck   This->currentPosition.u.LowPart = 0;
645c2c66affSColin Finck 
646c2c66affSColin Finck   *ppstm = &This->IStream_iface;
647c2c66affSColin Finck 
648c2c66affSColin Finck   return S_OK;
649c2c66affSColin Finck }
650c2c66affSColin Finck 
651c2c66affSColin Finck /***********************************************************************
652c2c66affSColin Finck  *           GetHGlobalFromStream     [OLE32.@]
653c2c66affSColin Finck  */
GetHGlobalFromStream(IStream * pstm,HGLOBAL * phglobal)654c2c66affSColin Finck HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
655c2c66affSColin Finck {
656c2c66affSColin Finck   HGLOBALStreamImpl* pStream;
657c2c66affSColin Finck 
658*c0f90872SAmine Khaldi   if (!pstm || !phglobal)
659c2c66affSColin Finck     return E_INVALIDARG;
660c2c66affSColin Finck 
661*c0f90872SAmine Khaldi   pStream = impl_from_IStream(pstm);
662c2c66affSColin Finck 
663c2c66affSColin Finck   /*
664c2c66affSColin Finck    * Verify that the stream object was created with CreateStreamOnHGlobal.
665c2c66affSColin Finck    */
666c2c66affSColin Finck   if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl)
667*c0f90872SAmine Khaldi     *phglobal = handle_gethglobal(pStream->handle);
668c2c66affSColin Finck   else
669c2c66affSColin Finck   {
670c2c66affSColin Finck     *phglobal = 0;
671c2c66affSColin Finck     return E_INVALIDARG;
672c2c66affSColin Finck   }
673c2c66affSColin Finck 
674c2c66affSColin Finck   return S_OK;
675c2c66affSColin Finck }
676