Get rid of the no longer used ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
[wine] / dlls / ole32 / hglobalstream.c
1 /*
2  * HGLOBAL Stream implementation
3  *
4  * This file contains the implementation of the stream interface
5  * for streams contained supported by an HGLOBAL pointer.
6  *
7  * Copyright 1999 Francis Beaudet
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "objbase.h"
38 #include "ole2.h"
39 #include "winerror.h"
40 #include "winreg.h"
41 #include "winternl.h"
42
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(storage);
46
47 /****************************************************************************
48  * HGLOBALStreamImpl definition.
49  *
50  * This class imlements the IStream inteface and represents a stream
51  * supported by an HGLOBAL pointer.
52  */
53 struct HGLOBALStreamImpl
54 {
55   IStreamVtbl *lpVtbl;   /* Needs to be the first item in the stuct
56                           * since we want to cast this in a IStream pointer */
57
58   /*
59    * Reference count
60    */
61   ULONG              ref;
62
63   /*
64    * Support for the stream
65    */
66   HGLOBAL supportHandle;
67
68   /*
69    * This flag is TRUE if the HGLOBAL is destroyed when the stream
70    * is finally released.
71    */
72   BOOL    deleteOnRelease;
73
74   /*
75    * Helper variable that contains the size of the stream
76    */
77   ULARGE_INTEGER     streamSize;
78
79   /*
80    * This is the current position of the cursor in the stream
81    */
82   ULARGE_INTEGER     currentPosition;
83 };
84
85 typedef struct HGLOBALStreamImpl HGLOBALStreamImpl;
86
87 /*
88  * Method definition for the StgStreamImpl class.
89  */
90 HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
91                 HGLOBAL  hGlobal,
92                 BOOL     fDeleteOnRelease);
93
94 void HGLOBALStreamImpl_Destroy(
95                 HGLOBALStreamImpl* This);
96
97 void HGLOBALStreamImpl_OpenBlockChain(
98                 HGLOBALStreamImpl* This);
99
100 HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
101                 IStream*      iface,
102                 REFIID         riid,            /* [in] */
103                 void**         ppvObject);  /* [iid_is][out] */
104
105 ULONG WINAPI HGLOBALStreamImpl_AddRef(
106                 IStream*      iface);
107
108 ULONG WINAPI HGLOBALStreamImpl_Release(
109                 IStream*      iface);
110
111 HRESULT WINAPI HGLOBALStreamImpl_Read(
112                 IStream*      iface,
113                 void*          pv,        /* [length_is][size_is][out] */
114                 ULONG          cb,        /* [in] */
115                 ULONG*         pcbRead);  /* [out] */
116
117 HRESULT WINAPI HGLOBALStreamImpl_Write(
118                 IStream*      iface,
119                 const void*    pv,          /* [size_is][in] */
120                 ULONG          cb,          /* [in] */
121                 ULONG*         pcbWritten); /* [out] */
122
123 HRESULT WINAPI HGLOBALStreamImpl_Seek(
124                 IStream*      iface,
125                 LARGE_INTEGER   dlibMove,         /* [in] */
126                 DWORD           dwOrigin,         /* [in] */
127                 ULARGE_INTEGER* plibNewPosition); /* [out] */
128
129 HRESULT WINAPI HGLOBALStreamImpl_SetSize(
130                 IStream*      iface,
131                 ULARGE_INTEGER  libNewSize);  /* [in] */
132
133 HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
134                 IStream*      iface,
135                 IStream*      pstm,         /* [unique][in] */
136                 ULARGE_INTEGER  cb,           /* [in] */
137                 ULARGE_INTEGER* pcbRead,      /* [out] */
138                 ULARGE_INTEGER* pcbWritten);  /* [out] */
139
140 HRESULT WINAPI HGLOBALStreamImpl_Commit(
141                 IStream*      iface,
142                 DWORD           grfCommitFlags); /* [in] */
143
144 HRESULT WINAPI HGLOBALStreamImpl_Revert(
145                 IStream*  iface);
146
147 HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
148                 IStream*     iface,
149                 ULARGE_INTEGER libOffset,   /* [in] */
150                 ULARGE_INTEGER cb,          /* [in] */
151                 DWORD          dwLockType); /* [in] */
152
153 HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
154                 IStream*     iface,
155                 ULARGE_INTEGER libOffset,   /* [in] */
156                 ULARGE_INTEGER cb,          /* [in] */
157                 DWORD          dwLockType); /* [in] */
158
159 HRESULT WINAPI HGLOBALStreamImpl_Stat(
160                 IStream*     iface,
161                 STATSTG*       pstatstg,     /* [out] */
162                 DWORD          grfStatFlag); /* [in] */
163
164 HRESULT WINAPI HGLOBALStreamImpl_Clone(
165                 IStream*     iface,
166                 IStream**    ppstm);       /* [out] */
167
168
169 /*
170  * Virtual function table for the HGLOBALStreamImpl class.
171  */
172 static IStreamVtbl HGLOBALStreamImpl_Vtbl =
173 {
174     HGLOBALStreamImpl_QueryInterface,
175     HGLOBALStreamImpl_AddRef,
176     HGLOBALStreamImpl_Release,
177     HGLOBALStreamImpl_Read,
178     HGLOBALStreamImpl_Write,
179     HGLOBALStreamImpl_Seek,
180     HGLOBALStreamImpl_SetSize,
181     HGLOBALStreamImpl_CopyTo,
182     HGLOBALStreamImpl_Commit,
183     HGLOBALStreamImpl_Revert,
184     HGLOBALStreamImpl_LockRegion,
185     HGLOBALStreamImpl_UnlockRegion,
186     HGLOBALStreamImpl_Stat,
187     HGLOBALStreamImpl_Clone
188 };
189
190 /***********************************************************************
191  *           CreateStreamOnHGlobal     [OLE32.@]
192  */
193 HRESULT WINAPI CreateStreamOnHGlobal(
194                 HGLOBAL   hGlobal,
195                 BOOL      fDeleteOnRelease,
196                 LPSTREAM* ppstm)
197 {
198   HGLOBALStreamImpl* newStream;
199
200   newStream = HGLOBALStreamImpl_Construct(hGlobal,
201                                           fDeleteOnRelease);
202
203   if (newStream!=NULL)
204   {
205     return IUnknown_QueryInterface((IUnknown*)newStream,
206                                    &IID_IStream,
207                                    (void**)ppstm);
208   }
209
210   return E_OUTOFMEMORY;
211 }
212
213 /***********************************************************************
214  *           GetHGlobalFromStream     [OLE32.@]
215  */
216 HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
217 {
218   HGLOBALStreamImpl* pStream;
219
220   if (pstm == NULL)
221     return E_INVALIDARG;
222
223   pStream = (HGLOBALStreamImpl*) pstm;
224
225   /*
226    * Verify that the stream object was created with CreateStreamOnHGlobal.
227    */
228   if (pStream->lpVtbl == &HGLOBALStreamImpl_Vtbl)
229     *phglobal = pStream->supportHandle;
230   else
231   {
232     *phglobal = 0;
233     return E_INVALIDARG;
234   }
235
236   return S_OK;
237 }
238
239 /******************************************************************************
240 ** HGLOBALStreamImpl implementation
241 */
242
243 /***
244  * This is the constructor for the HGLOBALStreamImpl class.
245  *
246  * Params:
247  *    hGlobal          - Handle that will support the stream. can be NULL.
248  *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
249  *                       when the IStream object is destroyed.
250  */
251 HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
252                 HGLOBAL  hGlobal,
253                 BOOL     fDeleteOnRelease)
254 {
255   HGLOBALStreamImpl* newStream;
256
257   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
258
259   if (newStream!=0)
260   {
261     /*
262      * Set-up the virtual function table and reference count.
263      */
264     newStream->lpVtbl = &HGLOBALStreamImpl_Vtbl;
265     newStream->ref    = 0;
266
267     /*
268      * Initialize the support.
269      */
270     newStream->supportHandle = hGlobal;
271     newStream->deleteOnRelease = fDeleteOnRelease;
272
273     /*
274      * This method will allocate a handle if one is not supplied.
275      */
276     if (!newStream->supportHandle)
277     {
278       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
279                                              GMEM_SHARE, 0);
280     }
281
282     /*
283      * Start the stream at the beginning.
284      */
285     newStream->currentPosition.u.HighPart = 0;
286     newStream->currentPosition.u.LowPart = 0;
287
288     /*
289      * Initialize the size of the stream to the size of the handle.
290      */
291     newStream->streamSize.u.HighPart = 0;
292     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
293   }
294
295   return newStream;
296 }
297
298 /***
299  * This is the destructor of the HGLOBALStreamImpl class.
300  *
301  * This method will clean-up all the resources used-up by the given HGLOBALStreamImpl
302  * class. The pointer passed-in to this function will be freed and will not
303  * be valid anymore.
304  */
305 void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This)
306 {
307   TRACE("(%p)\n", This);
308
309   /*
310    * Release the HGlobal if the constructor asked for that.
311    */
312   if (This->deleteOnRelease)
313   {
314     GlobalFree(This->supportHandle);
315     This->supportHandle=0;
316   }
317
318   /*
319    * Finally, free the memory used-up by the class.
320    */
321   HeapFree(GetProcessHeap(), 0, This);
322 }
323
324 /***
325  * This implements the IUnknown method QueryInterface for this
326  * class
327  */
328 HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
329                   IStream*     iface,
330                   REFIID         riid,        /* [in] */
331                   void**         ppvObject)   /* [iid_is][out] */
332 {
333   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
334
335   /*
336    * Perform a sanity check on the parameters.
337    */
338   if (ppvObject==0)
339     return E_INVALIDARG;
340
341   /*
342    * Initialize the return parameter.
343    */
344   *ppvObject = 0;
345
346   /*
347    * Compare the riid with the interface IDs implemented by this object.
348    */
349   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
350   {
351     *ppvObject = (IStream*)This;
352   }
353   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
354   {
355     *ppvObject = (IStream*)This;
356   }
357
358   /*
359    * Check that we obtained an interface.
360    */
361   if ((*ppvObject)==0)
362     return E_NOINTERFACE;
363
364   /*
365    * Query Interface always increases the reference count by one when it is
366    * successful
367    */
368   HGLOBALStreamImpl_AddRef(iface);
369
370   return S_OK;
371 }
372
373 /***
374  * This implements the IUnknown method AddRef for this
375  * class
376  */
377 ULONG WINAPI HGLOBALStreamImpl_AddRef(
378                 IStream* iface)
379 {
380   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
381
382   This->ref++;
383
384   return This->ref;
385 }
386
387 /***
388  * This implements the IUnknown method Release for this
389  * class
390  */
391 ULONG WINAPI HGLOBALStreamImpl_Release(
392                 IStream* iface)
393 {
394   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
395
396   ULONG newRef;
397
398   This->ref--;
399
400   newRef = This->ref;
401
402   /*
403    * If the reference count goes down to 0, perform suicide.
404    */
405   if (newRef==0)
406   {
407     HGLOBALStreamImpl_Destroy(This);
408   }
409
410   return newRef;
411 }
412
413 /***
414  * This method is part of the ISequentialStream interface.
415  *
416  * If reads a block of information from the stream at the current
417  * position. It then moves the current position at the end of the
418  * read block
419  *
420  * See the documentation of ISequentialStream for more info.
421  */
422 HRESULT WINAPI HGLOBALStreamImpl_Read(
423                   IStream*     iface,
424                   void*          pv,        /* [length_is][size_is][out] */
425                   ULONG          cb,        /* [in] */
426                   ULONG*         pcbRead)   /* [out] */
427 {
428   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
429
430   void* supportBuffer;
431   ULONG bytesReadBuffer;
432   ULONG bytesToReadFromBuffer;
433
434   TRACE("(%p, %p, %ld, %p)\n", iface,
435         pv, cb, pcbRead);
436
437   /*
438    * If the caller is not interested in the nubmer of bytes read,
439    * we use another buffer to avoid "if" statements in the code.
440    */
441   if (pcbRead==0)
442     pcbRead = &bytesReadBuffer;
443
444   /*
445    * Using the known size of the stream, calculate the number of bytes
446    * to read from the block chain
447    */
448   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
449
450   /*
451    * Lock the buffer in position and copy the data.
452    */
453   supportBuffer = GlobalLock(This->supportHandle);
454
455   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
456
457   /*
458    * Move the current position to the new position
459    */
460   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
461
462   /*
463    * Return the number of bytes read.
464    */
465   *pcbRead = bytesToReadFromBuffer;
466
467   /*
468    * Cleanup
469    */
470   GlobalUnlock(This->supportHandle);
471
472   /*
473    * The function returns S_OK if the buffer was filled completely
474    * it returns S_FALSE if the end of the stream is reached before the
475    * buffer is filled
476    */
477   if(*pcbRead == cb)
478     return S_OK;
479
480   return S_FALSE;
481 }
482
483 /***
484  * This method is part of the ISequentialStream interface.
485  *
486  * It writes a block of information to the stream at the current
487  * position. It then moves the current position at the end of the
488  * written block. If the stream is too small to fit the block,
489  * the stream is grown to fit.
490  *
491  * See the documentation of ISequentialStream for more info.
492  */
493 HRESULT WINAPI HGLOBALStreamImpl_Write(
494                   IStream*     iface,
495                   const void*    pv,          /* [size_is][in] */
496                   ULONG          cb,          /* [in] */
497                   ULONG*         pcbWritten)  /* [out] */
498 {
499   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
500
501   void*          supportBuffer;
502   ULARGE_INTEGER newSize;
503   ULONG          bytesWritten = 0;
504
505   TRACE("(%p, %p, %ld, %p)\n", iface,
506         pv, cb, pcbWritten);
507
508   /*
509    * If the caller is not interested in the number of bytes written,
510    * we use another buffer to avoid "if" statements in the code.
511    */
512   if (pcbWritten == 0)
513     pcbWritten = &bytesWritten;
514
515   if (cb == 0)
516   {
517     return S_OK;
518   }
519   else
520   {
521     newSize.u.HighPart = 0;
522     newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
523   }
524
525   /*
526    * Verify if we need to grow the stream
527    */
528   if (newSize.u.LowPart > This->streamSize.u.LowPart)
529   {
530     /* grow stream */
531    IStream_SetSize(iface, newSize);
532   }
533
534   /*
535    * Lock the buffer in position and copy the data.
536    */
537   supportBuffer = GlobalLock(This->supportHandle);
538
539   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
540
541   /*
542    * Move the current position to the new position
543    */
544   This->currentPosition.u.LowPart+=cb;
545
546   /*
547    * Return the number of bytes read.
548    */
549   *pcbWritten = cb;
550
551   /*
552    * Cleanup
553    */
554   GlobalUnlock(This->supportHandle);
555
556   return S_OK;
557 }
558
559 /***
560  * This method is part of the IStream interface.
561  *
562  * It will move the current stream pointer according to the parameters
563  * given.
564  *
565  * See the documentation of IStream for more info.
566  */
567 HRESULT WINAPI HGLOBALStreamImpl_Seek(
568                   IStream*      iface,
569                   LARGE_INTEGER   dlibMove,         /* [in] */
570                   DWORD           dwOrigin,         /* [in] */
571                   ULARGE_INTEGER* plibNewPosition) /* [out] */
572 {
573   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
574
575   ULARGE_INTEGER newPosition;
576
577   TRACE("(%p, %lx%08lx, %ld, %p)\n", iface, dlibMove.u.HighPart,
578         dlibMove.u.LowPart, dwOrigin, plibNewPosition);
579
580   /*
581    * The file pointer is moved depending on the given "function"
582    * parameter.
583    */
584   switch (dwOrigin)
585   {
586     case STREAM_SEEK_SET:
587       newPosition.u.HighPart = 0;
588       newPosition.u.LowPart = 0;
589       break;
590     case STREAM_SEEK_CUR:
591       newPosition = This->currentPosition;
592       break;
593     case STREAM_SEEK_END:
594       newPosition = This->streamSize;
595       break;
596     default:
597       return STG_E_INVALIDFUNCTION;
598   }
599
600   /*
601    * Move the actual file pointer
602    * If the file pointer ends-up after the end of the stream, the next Write operation will
603    * make the file larger. This is how it is documented.
604    */
605   newPosition.QuadPart = RtlLargeIntegerAdd(newPosition.QuadPart, dlibMove.QuadPart);
606   if (newPosition.QuadPart < 0) return STG_E_INVALIDFUNCTION;
607
608   if (plibNewPosition) *plibNewPosition = newPosition;
609   This->currentPosition = newPosition;
610
611   return S_OK;
612 }
613
614 /***
615  * This method is part of the IStream interface.
616  *
617  * It will change the size of a stream.
618  *
619  * TODO: Switch from small blocks to big blocks and vice versa.
620  *
621  * See the documentation of IStream for more info.
622  */
623 HRESULT WINAPI HGLOBALStreamImpl_SetSize(
624                                      IStream*      iface,
625                                      ULARGE_INTEGER  libNewSize)   /* [in] */
626 {
627   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
628   HGLOBAL supportHandle;
629
630   TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart);
631
632   /*
633    * As documented.
634    */
635   if (libNewSize.u.HighPart != 0)
636     return STG_E_INVALIDFUNCTION;
637
638   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
639     return S_OK;
640
641   /*
642    * Re allocate the HGlobal to fit the new size of the stream.
643    */
644   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
645
646   if (supportHandle == 0)
647     return STG_E_MEDIUMFULL;
648
649   This->supportHandle = supportHandle;
650   This->streamSize.u.LowPart = libNewSize.u.LowPart;
651
652   return S_OK;
653 }
654
655 /***
656  * This method is part of the IStream interface.
657  *
658  * It will copy the 'cb' Bytes to 'pstm' IStream.
659  *
660  * See the documentation of IStream for more info.
661  */
662 HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
663                                     IStream*      iface,
664                                     IStream*      pstm,         /* [unique][in] */
665                                     ULARGE_INTEGER  cb,           /* [in] */
666                                     ULARGE_INTEGER* pcbRead,      /* [out] */
667                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
668 {
669   HRESULT        hr = S_OK;
670   BYTE           tmpBuffer[128];
671   ULONG          bytesRead, bytesWritten, copySize;
672   ULARGE_INTEGER totalBytesRead;
673   ULARGE_INTEGER totalBytesWritten;
674
675   TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm,
676         cb.u.LowPart, pcbRead, pcbWritten);
677
678   /*
679    * Sanity check
680    */
681   if ( pstm == 0 )
682     return STG_E_INVALIDPOINTER;
683
684   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
685   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
686
687   /*
688    * use stack to store data temporarly
689    * there is surely more performant way of doing it, for now this basic
690    * implementation will do the job
691    */
692   while ( cb.u.LowPart > 0 )
693   {
694     if ( cb.u.LowPart >= 128 )
695       copySize = 128;
696     else
697       copySize = cb.u.LowPart;
698
699     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
700
701     totalBytesRead.u.LowPart += bytesRead;
702
703     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
704
705     totalBytesWritten.u.LowPart += bytesWritten;
706
707     /*
708      * Check that read & write operations were succesfull
709      */
710     if (bytesRead != bytesWritten)
711     {
712       hr = STG_E_MEDIUMFULL;
713       break;
714     }
715
716     if (bytesRead!=copySize)
717       cb.u.LowPart = 0;
718     else
719       cb.u.LowPart -= bytesRead;
720   }
721
722   /*
723    * Update number of bytes read and written
724    */
725   if (pcbRead)
726   {
727     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
728     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
729   }
730
731   if (pcbWritten)
732   {
733     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
734     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
735   }
736   return hr;
737 }
738
739 /***
740  * This method is part of the IStream interface.
741  *
742  * For streams supported by HGLOBALS, this function does nothing.
743  * This is what the documentation tells us.
744  *
745  * See the documentation of IStream for more info.
746  */
747 HRESULT WINAPI HGLOBALStreamImpl_Commit(
748                   IStream*      iface,
749                   DWORD         grfCommitFlags)  /* [in] */
750 {
751   return S_OK;
752 }
753
754 /***
755  * This method is part of the IStream interface.
756  *
757  * For streams supported by HGLOBALS, this function does nothing.
758  * This is what the documentation tells us.
759  *
760  * See the documentation of IStream for more info.
761  */
762 HRESULT WINAPI HGLOBALStreamImpl_Revert(
763                   IStream* iface)
764 {
765   return S_OK;
766 }
767
768 /***
769  * This method is part of the IStream interface.
770  *
771  * For streams supported by HGLOBALS, this function does nothing.
772  * This is what the documentation tells us.
773  *
774  * See the documentation of IStream for more info.
775  */
776 HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
777                   IStream*       iface,
778                   ULARGE_INTEGER libOffset,   /* [in] */
779                   ULARGE_INTEGER cb,          /* [in] */
780                   DWORD          dwLockType)  /* [in] */
781 {
782   return S_OK;
783 }
784
785 /*
786  * This method is part of the IStream interface.
787  *
788  * For streams supported by HGLOBALS, this function does nothing.
789  * This is what the documentation tells us.
790  *
791  * See the documentation of IStream for more info.
792  */
793 HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
794                   IStream*       iface,
795                   ULARGE_INTEGER libOffset,   /* [in] */
796                   ULARGE_INTEGER cb,          /* [in] */
797                   DWORD          dwLockType)  /* [in] */
798 {
799   return S_OK;
800 }
801
802 /***
803  * This method is part of the IStream interface.
804  *
805  * This method returns information about the current
806  * stream.
807  *
808  * See the documentation of IStream for more info.
809  */
810 HRESULT WINAPI HGLOBALStreamImpl_Stat(
811                   IStream*     iface,
812                   STATSTG*     pstatstg,     /* [out] */
813                   DWORD        grfStatFlag)  /* [in] */
814 {
815   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
816
817   memset(pstatstg, 0, sizeof(STATSTG));
818
819   pstatstg->pwcsName = NULL;
820   pstatstg->type     = STGTY_STREAM;
821   pstatstg->cbSize   = This->streamSize;
822
823   return S_OK;
824 }
825
826 HRESULT WINAPI HGLOBALStreamImpl_Clone(
827                   IStream*     iface,
828                   IStream**    ppstm) /* [out] */
829 {
830   ULARGE_INTEGER dummy;
831   LARGE_INTEGER offset;
832   HRESULT hr;
833   HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
834   TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart);
835   hr=CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm);
836   if(FAILED(hr))
837     return hr;
838   offset.QuadPart=(LONGLONG)This->currentPosition.QuadPart;
839   HGLOBALStreamImpl_Seek(*ppstm,offset,STREAM_SEEK_SET,&dummy);
840   return S_OK;
841 }