source: trunk/src/ole32/hglobalstream.c@ 8441

Last change on this file since 8441 was 8441, checked in by sandervl, 23 years ago

Wine resync

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