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