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