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

Last change on this file since 8266 was 7926, checked in by sandervl, 24 years ago

Wine 20020215 resync

File size: 20.0 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
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
25DEFAULT_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 */
33struct 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
65typedef struct HGLOBALStreamImpl HGLOBALStreamImpl;
66
67/*
68 * Method definition for the StgStreamImpl class.
69 */
70HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
71 HGLOBAL hGlobal,
72 BOOL fDeleteOnRelease);
73
74void HGLOBALStreamImpl_Destroy(
75 HGLOBALStreamImpl* This);
76
77void HGLOBALStreamImpl_OpenBlockChain(
78 HGLOBALStreamImpl* This);
79
80HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
81 IStream* iface,
82 REFIID riid, /* [in] */
83 void** ppvObject); /* [iid_is][out] */
84
85ULONG WINAPI HGLOBALStreamImpl_AddRef(
86 IStream* iface);
87
88ULONG WINAPI HGLOBALStreamImpl_Release(
89 IStream* iface);
90
91HRESULT WINAPI HGLOBALStreamImpl_Read(
92 IStream* iface,
93 void* pv, /* [length_is][size_is][out] */
94 ULONG cb, /* [in] */
95 ULONG* pcbRead); /* [out] */
96
97HRESULT WINAPI HGLOBALStreamImpl_Write(
98 IStream* iface,
99 const void* pv, /* [size_is][in] */
100 ULONG cb, /* [in] */
101 ULONG* pcbWritten); /* [out] */
102
103HRESULT WINAPI HGLOBALStreamImpl_Seek(
104 IStream* iface,
105 LARGE_INTEGER dlibMove, /* [in] */
106 DWORD dwOrigin, /* [in] */
107 ULARGE_INTEGER* plibNewPosition); /* [out] */
108
109HRESULT WINAPI HGLOBALStreamImpl_SetSize(
110 IStream* iface,
111 ULARGE_INTEGER libNewSize); /* [in] */
112
113HRESULT 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
120HRESULT WINAPI HGLOBALStreamImpl_Commit(
121 IStream* iface,
122 DWORD grfCommitFlags); /* [in] */
123
124HRESULT WINAPI HGLOBALStreamImpl_Revert(
125 IStream* iface);
126
127HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
128 IStream* iface,
129 ULARGE_INTEGER libOffset, /* [in] */
130 ULARGE_INTEGER cb, /* [in] */
131 DWORD dwLockType); /* [in] */
132
133HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
134 IStream* iface,
135 ULARGE_INTEGER libOffset, /* [in] */
136 ULARGE_INTEGER cb, /* [in] */
137 DWORD dwLockType); /* [in] */
138
139HRESULT WINAPI HGLOBALStreamImpl_Stat(
140 IStream* iface,
141 STATSTG* pstatstg, /* [out] */
142 DWORD grfStatFlag); /* [in] */
143
144HRESULT WINAPI HGLOBALStreamImpl_Clone(
145 IStream* iface,
146 IStream** ppstm); /* [out] */
147
148
149/*
150 * Virtual function table for the HGLOBALStreamImpl class.
151 */
152static 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 */
174HRESULT 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 */
197HRESULT 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 */
232HGLOBALStreamImpl* 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 beginning.
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 */
286void 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 */
309HRESULT 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 */
358ULONG 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 */
372ULONG 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 */
403HRESULT 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 */
474HRESULT 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 */
548HRESULT 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 */
628HRESULT 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 */
664HRESULT 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 */
749HRESULT 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 */
764HRESULT 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 */
778HRESULT 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 */
795HRESULT 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 */
812HRESULT 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
828HRESULT WINAPI HGLOBALStreamImpl_Clone(
829 IStream* iface,
830 IStream** ppstm) /* [out] */
831{
832 FIXME("not implemented!\n");
833 return E_NOTIMPL;
834}
Note: See TracBrowser for help on using the repository browser.