source: trunk/src/ole32/hglobalstream.cpp@ 1036

Last change on this file since 1036 was 1033, checked in by davidr, 26 years ago

Ported remaining files pertaining to OLE32 from WINE

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