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