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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

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