ReactOS  0.4.14-dev-98-gb0d4763
stg_stream.c
Go to the documentation of this file.
1 /*
2  * Compound Storage (32 bit version)
3  * Stream implementation
4  *
5  * This file contains the implementation of the stream interface
6  * for streams contained in a compound storage.
7  *
8  * Copyright 1999 Francis Beaudet
9  * Copyright 1999 Thuy Nguyen
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winternl.h"
38 #include "wine/debug.h"
39 
40 #include "storage32.h"
41 
43 
44 /***
45  * This implements the IUnknown method QueryInterface for this
46  * class
47  */
49  IStream* iface,
50  REFIID riid, /* [in] */
51  void** ppvObject) /* [iid_is][out] */
52 {
54 
55  if (ppvObject==0)
56  return E_INVALIDARG;
57 
58  *ppvObject = 0;
59 
60  if (IsEqualIID(&IID_IUnknown, riid) ||
61  IsEqualIID(&IID_ISequentialStream, riid) ||
62  IsEqualIID(&IID_IStream, riid))
63  {
64  *ppvObject = &This->IStream_iface;
65  }
66  else
67  return E_NOINTERFACE;
68 
69  IStream_AddRef(iface);
70 
71  return S_OK;
72 }
73 
74 /***
75  * This implements the IUnknown method AddRef for this
76  * class
77  */
79  IStream* iface)
80 {
82  return InterlockedIncrement(&This->ref);
83 }
84 
85 /***
86  * This implements the IUnknown method Release for this
87  * class
88  */
90  IStream* iface)
91 {
94 
95  if (!ref)
96  {
97  TRACE("(%p)\n", This);
98 
99  /*
100  * Release the reference we are holding on the parent storage.
101  * IStorage_Release(&This->parentStorage->IStorage_iface);
102  *
103  * No, don't do this. Some apps call IStorage_Release without
104  * calling IStream_Release first. If we grab a reference the
105  * file is not closed, and the app fails when it tries to
106  * reopen the file (Easy-PC, for example). Just inform the
107  * storage that we have closed the stream
108  */
109 
110  if (This->parentStorage)
111  StorageBaseImpl_RemoveStream(This->parentStorage, This);
112  This->parentStorage = 0;
114  }
115 
116  return ref;
117 }
118 
119 /***
120  * This method is part of the ISequentialStream interface.
121  *
122  * It reads a block of information from the stream at the current
123  * position. It then moves the current position at the end of the
124  * read block
125  *
126  * See the documentation of ISequentialStream for more info.
127  */
129  IStream* iface,
130  void* pv, /* [length_is][size_is][out] */
131  ULONG cb, /* [in] */
132  ULONG* pcbRead) /* [out] */
133 {
135 
136  ULONG bytesReadBuffer;
137  HRESULT res;
138 
139  TRACE("(%p, %p, %d, %p)\n",
140  iface, pv, cb, pcbRead);
141 
142  if (!This->parentStorage)
143  {
144  WARN("storage reverted\n");
145  return STG_E_REVERTED;
146  }
147 
148  /*
149  * If the caller is not interested in the number of bytes read,
150  * we use another buffer to avoid "if" statements in the code.
151  */
152  if (pcbRead==0)
153  pcbRead = &bytesReadBuffer;
154 
155  res = StorageBaseImpl_StreamReadAt(This->parentStorage,
156  This->dirEntry,
157  This->currentPosition,
158  cb,
159  pv,
160  pcbRead);
161 
162  if (SUCCEEDED(res))
163  {
164  /*
165  * Advance the pointer for the number of positions read.
166  */
167  This->currentPosition.QuadPart += *pcbRead;
168  }
169 
170  TRACE("<-- %08x\n", res);
171  return res;
172 }
173 
174 /***
175  * This method is part of the ISequentialStream interface.
176  *
177  * It writes a block of information to the stream at the current
178  * position. It then moves the current position at the end of the
179  * written block. If the stream is too small to fit the block,
180  * the stream is grown to fit.
181  *
182  * See the documentation of ISequentialStream for more info.
183  */
185  IStream* iface,
186  const void* pv, /* [size_is][in] */
187  ULONG cb, /* [in] */
188  ULONG* pcbWritten) /* [out] */
189 {
191 
192  ULONG bytesWritten = 0;
193  HRESULT res;
194 
195  TRACE("(%p, %p, %d, %p)\n",
196  iface, pv, cb, pcbWritten);
197 
198  /*
199  * Do we have permission to write to this stream?
200  */
201  switch(STGM_ACCESS_MODE(This->grfMode))
202  {
203  case STGM_WRITE:
204  case STGM_READWRITE:
205  break;
206  default:
207  WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode));
208  return STG_E_ACCESSDENIED;
209  }
210 
211  if (!pv)
212  return STG_E_INVALIDPOINTER;
213 
214  if (!This->parentStorage)
215  {
216  WARN("storage reverted\n");
217  return STG_E_REVERTED;
218  }
219 
220  /*
221  * If the caller is not interested in the number of bytes written,
222  * we use another buffer to avoid "if" statements in the code.
223  */
224  if (pcbWritten == 0)
225  pcbWritten = &bytesWritten;
226 
227  /*
228  * Initialize the out parameter
229  */
230  *pcbWritten = 0;
231 
232  if (cb == 0)
233  {
234  TRACE("<-- S_OK, written 0\n");
235  return S_OK;
236  }
237 
238  res = StorageBaseImpl_StreamWriteAt(This->parentStorage,
239  This->dirEntry,
240  This->currentPosition,
241  cb,
242  pv,
243  pcbWritten);
244 
245  /*
246  * Advance the position pointer for the number of positions written.
247  */
248  This->currentPosition.QuadPart += *pcbWritten;
249 
250  if (SUCCEEDED(res))
251  res = StorageBaseImpl_Flush(This->parentStorage);
252 
253  TRACE("<-- %08x, written %u\n", res, *pcbWritten);
254  return res;
255 }
256 
257 /***
258  * This method is part of the IStream interface.
259  *
260  * It will move the current stream pointer according to the parameters
261  * given.
262  *
263  * See the documentation of IStream for more info.
264  */
266  IStream* iface,
267  LARGE_INTEGER dlibMove, /* [in] */
268  DWORD dwOrigin, /* [in] */
269  ULARGE_INTEGER* plibNewPosition) /* [out] */
270 {
272 
273  ULARGE_INTEGER newPosition;
274  DirEntry currentEntry;
275  HRESULT hr;
276 
277  TRACE("(%p, %d, %d, %p)\n",
278  iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
279 
280  /*
281  * fail if the stream has no parent (as does windows)
282  */
283 
284  if (!This->parentStorage)
285  {
286  WARN("storage reverted\n");
287  return STG_E_REVERTED;
288  }
289 
290  /*
291  * The caller is allowed to pass in NULL as the new position return value.
292  * If it happens, we assign it to a dynamic variable to avoid special cases
293  * in the code below.
294  */
295  if (plibNewPosition == 0)
296  {
297  plibNewPosition = &newPosition;
298  }
299 
300  /*
301  * The file pointer is moved depending on the given "function"
302  * parameter.
303  */
304  switch (dwOrigin)
305  {
306  case STREAM_SEEK_SET:
307  plibNewPosition->u.HighPart = 0;
308  plibNewPosition->u.LowPart = 0;
309  break;
310  case STREAM_SEEK_CUR:
311  *plibNewPosition = This->currentPosition;
312  break;
313  case STREAM_SEEK_END:
314  hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, This->dirEntry, &currentEntry);
315  if (FAILED(hr)) return hr;
316  *plibNewPosition = currentEntry.size;
317  break;
318  default:
319  WARN("invalid dwOrigin %d\n", dwOrigin);
320  return STG_E_INVALIDFUNCTION;
321  }
322 
323  plibNewPosition->QuadPart += dlibMove.QuadPart;
324 
325  /*
326  * tell the caller what we calculated
327  */
328  This->currentPosition = *plibNewPosition;
329 
330  return S_OK;
331 }
332 
333 /***
334  * This method is part of the IStream interface.
335  *
336  * It will change the size of a stream.
337  *
338  * See the documentation of IStream for more info.
339  */
341  IStream* iface,
342  ULARGE_INTEGER libNewSize) /* [in] */
343 {
345 
346  HRESULT hr;
347 
348  TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
349 
350  if(!This->parentStorage)
351  {
352  WARN("storage reverted\n");
353  return STG_E_REVERTED;
354  }
355 
356  /*
357  * As documented.
358  */
359  if (libNewSize.u.HighPart != 0)
360  {
361  WARN("invalid value for libNewSize.u.HighPart %d\n", libNewSize.u.HighPart);
362  return STG_E_INVALIDFUNCTION;
363  }
364 
365  /*
366  * Do we have permission?
367  */
368  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
369  {
370  WARN("access denied\n");
371  return STG_E_ACCESSDENIED;
372  }
373 
374  hr = StorageBaseImpl_StreamSetSize(This->parentStorage, This->dirEntry, libNewSize);
375 
376  if (SUCCEEDED(hr))
377  hr = StorageBaseImpl_Flush(This->parentStorage);
378 
379  return hr;
380 }
381 
382 /***
383  * This method is part of the IStream interface.
384  *
385  * It will copy the 'cb' Bytes to 'pstm' IStream.
386  *
387  * See the documentation of IStream for more info.
388  */
390  IStream* iface,
391  IStream* pstm, /* [unique][in] */
392  ULARGE_INTEGER cb, /* [in] */
393  ULARGE_INTEGER* pcbRead, /* [out] */
394  ULARGE_INTEGER* pcbWritten) /* [out] */
395 {
397  HRESULT hr = S_OK;
398  BYTE tmpBuffer[128];
399  ULONG bytesRead, bytesWritten, copySize;
400  ULARGE_INTEGER totalBytesRead;
401  ULARGE_INTEGER totalBytesWritten;
402 
403  TRACE("(%p, %p, %d, %p, %p)\n",
404  iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
405 
406  /*
407  * Sanity check
408  */
409 
410  if (!This->parentStorage)
411  {
412  WARN("storage reverted\n");
413  return STG_E_REVERTED;
414  }
415 
416  if ( pstm == 0 )
417  return STG_E_INVALIDPOINTER;
418 
419  totalBytesRead.QuadPart = 0;
420  totalBytesWritten.QuadPart = 0;
421 
422  while ( cb.QuadPart > 0 )
423  {
424  if ( cb.QuadPart >= sizeof(tmpBuffer) )
425  copySize = sizeof(tmpBuffer);
426  else
427  copySize = cb.u.LowPart;
428 
429  IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
430 
431  totalBytesRead.QuadPart += bytesRead;
432 
433  IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
434 
435  totalBytesWritten.QuadPart += bytesWritten;
436 
437  /*
438  * Check that read & write operations were successful
439  */
440  if (bytesRead != bytesWritten)
441  {
443  WARN("medium full\n");
444  break;
445  }
446 
447  if (bytesRead!=copySize)
448  cb.QuadPart = 0;
449  else
450  cb.QuadPart -= bytesRead;
451  }
452 
453  if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
454  if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
455 
456  return hr;
457 }
458 
459 /***
460  * This method is part of the IStream interface.
461  *
462  * For streams contained in structured storages, this method
463  * does nothing. This is what the documentation tells us.
464  *
465  * See the documentation of IStream for more info.
466  */
468  IStream* iface,
469  DWORD grfCommitFlags) /* [in] */
470 {
472 
473  if (!This->parentStorage)
474  {
475  WARN("storage reverted\n");
476  return STG_E_REVERTED;
477  }
478 
479  return StorageBaseImpl_Flush(This->parentStorage);
480 }
481 
482 /***
483  * This method is part of the IStream interface.
484  *
485  * For streams contained in structured storages, this method
486  * does nothing. This is what the documentation tells us.
487  *
488  * See the documentation of IStream for more info.
489  */
491  IStream* iface)
492 {
493  return S_OK;
494 }
495 
497  IStream* iface,
498  ULARGE_INTEGER libOffset, /* [in] */
499  ULARGE_INTEGER cb, /* [in] */
500  DWORD dwLockType) /* [in] */
501 {
503 
504  if (!This->parentStorage)
505  {
506  WARN("storage reverted\n");
507  return STG_E_REVERTED;
508  }
509 
510  FIXME("not implemented!\n");
511  return E_NOTIMPL;
512 }
513 
515  IStream* iface,
516  ULARGE_INTEGER libOffset, /* [in] */
517  ULARGE_INTEGER cb, /* [in] */
518  DWORD dwLockType) /* [in] */
519 {
521 
522  if (!This->parentStorage)
523  {
524  WARN("storage reverted\n");
525  return STG_E_REVERTED;
526  }
527 
528  FIXME("not implemented!\n");
529  return E_NOTIMPL;
530 }
531 
532 /***
533  * This method is part of the IStream interface.
534  *
535  * This method returns information about the current
536  * stream.
537  *
538  * See the documentation of IStream for more info.
539  */
541  IStream* iface,
542  STATSTG* pstatstg, /* [out] */
543  DWORD grfStatFlag) /* [in] */
544 {
546 
547  DirEntry currentEntry;
548  HRESULT hr;
549 
550  TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
551 
552  /*
553  * if stream has no parent, return STG_E_REVERTED
554  */
555 
556  if (!This->parentStorage)
557  {
558  WARN("storage reverted\n");
559  return STG_E_REVERTED;
560  }
561 
562  /*
563  * Read the information from the directory entry.
564  */
565  hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
566  This->dirEntry,
567  &currentEntry);
568 
569  if (SUCCEEDED(hr))
570  {
571  StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
572  pstatstg,
573  &currentEntry,
574  grfStatFlag);
575 
576  pstatstg->grfMode = This->grfMode;
577 
578  /* In simple create mode cbSize is the current pos */
579  if((This->parentStorage->openFlags & STGM_SIMPLE) && This->parentStorage->create)
580  pstatstg->cbSize = This->currentPosition;
581 
582  return S_OK;
583  }
584 
585  WARN("failed to read entry\n");
586  return hr;
587 }
588 
589 /***
590  * This method is part of the IStream interface.
591  *
592  * This method returns a clone of the interface that allows for
593  * another seek pointer
594  *
595  * See the documentation of IStream for more info.
596  *
597  * I am not totally sure what I am doing here but I presume that this
598  * should be basically as simple as creating a new stream with the same
599  * parent etc and positioning its seek cursor.
600  */
602  IStream* iface,
603  IStream** ppstm) /* [out] */
604 {
606  StgStreamImpl* new_stream;
607  LARGE_INTEGER seek_pos;
608 
609  TRACE("%p %p\n", This, ppstm);
610 
611  /*
612  * Sanity check
613  */
614 
615  if (!This->parentStorage)
616  return STG_E_REVERTED;
617 
618  if ( ppstm == 0 )
619  return STG_E_INVALIDPOINTER;
620 
621  new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry);
622 
623  if (!new_stream)
624  return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
625 
626  *ppstm = &new_stream->IStream_iface;
627  IStream_AddRef(*ppstm);
628 
629  seek_pos.QuadPart = This->currentPosition.QuadPart;
630 
631  return IStream_Seek(*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
632 }
633 
634 /*
635  * Virtual function table for the StgStreamImpl class.
636  */
637 static const IStreamVtbl StgStreamVtbl =
638 {
653 };
654 
655 /******************************************************************************
656 ** StgStreamImpl implementation
657 */
658 
659 /***
660  * This is the constructor for the StgStreamImpl class.
661  *
662  * Params:
663  * parentStorage - Pointer to the storage that contains the stream to open
664  * dirEntry - Index of the directory entry that points to this stream.
665  */
667  StorageBaseImpl* parentStorage,
668  DWORD grfMode,
669  DirRef dirEntry)
670 {
671  StgStreamImpl* newStream;
672 
673  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
674 
675  if (newStream)
676  {
677  /*
678  * Set-up the virtual function table and reference count.
679  */
680  newStream->IStream_iface.lpVtbl = &StgStreamVtbl;
681  newStream->ref = 0;
682 
683  newStream->parentStorage = parentStorage;
684 
685  /*
686  * We want to nail-down the reference to the storage in case the
687  * stream out-lives the storage in the client application.
688  *
689  * -- IStorage_AddRef(&newStream->parentStorage->IStorage_iface);
690  *
691  * No, don't do this. Some apps call IStorage_Release without
692  * calling IStream_Release first. If we grab a reference the
693  * file is not closed, and the app fails when it tries to
694  * reopen the file (Easy-PC, for example)
695  */
696 
697  newStream->grfMode = grfMode;
698  newStream->dirEntry = dirEntry;
699 
700  /*
701  * Start the stream at the beginning.
702  */
703  newStream->currentPosition.u.HighPart = 0;
704  newStream->currentPosition.u.LowPart = 0;
705 
706  /* add us to the storage's list of active streams */
707  StorageBaseImpl_AddStream(parentStorage, newStream);
708  }
709 
710  return newStream;
711 }
ULARGE_INTEGER currentPosition
Definition: storage32.h:455
static HRESULT StorageBaseImpl_Flush(StorageBaseImpl *This)
Definition: storage32.h:268
#define REFIID
Definition: guiddef.h:118
#define E_NOINTERFACE
Definition: winerror.h:2364
DWORD grfMode
Definition: storage32.h:445
HRESULT hr
Definition: shlfolder.c:183
#define STG_E_INVALIDPOINTER
Definition: winerror.h:2571
static HRESULT WINAPI StgStreamImpl_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
Definition: stg_stream.c:265
WINE_DEFAULT_DEBUG_CHANNEL(storage)
REFIID riid
Definition: precomp.h:44
ULARGE_INTEGER size
Definition: storage32.h:157
static HRESULT WINAPI StgStreamImpl_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
Definition: stg_stream.c:514
#define WARN(fmt,...)
Definition: debug.h:111
void StorageBaseImpl_RemoveStream(StorageBaseImpl *stg, StgStreamImpl *strm)
Definition: storage32.c:2721
#define STG_E_MEDIUMFULL
Definition: winerror.h:2581
#define STG_E_INSUFFICIENTMEMORY
Definition: winerror.h:2570
Definition: send.c:47
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
static const IStreamVtbl StgStreamVtbl
Definition: stg_stream.c:637
#define STG_E_ACCESSDENIED
Definition: winerror.h:2568
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:110
DirRef dirEntry
Definition: storage32.h:450
#define E_INVALIDARG
Definition: ddrawi.h:101
struct _LARGE_INTEGER::@2205 u
smooth NULL
Definition: ftsmooth.c:416
#define STGM_WRITE
Definition: objbase.h:917
static HRESULT WINAPI StgStreamImpl_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
Definition: stg_stream.c:340
#define STG_E_INVALIDFUNCTION
Definition: winerror.h:2564
static HRESULT WINAPI StgStreamImpl_Clone(IStream *iface, IStream **ppstm)
Definition: stg_stream.c:601
static HRESULT WINAPI StgStreamImpl_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
Definition: stg_stream.c:540
#define TRACE(s)
Definition: solgame.cpp:4
static HRESULT StorageBaseImpl_StreamSetSize(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.h:317
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static HRESULT StorageBaseImpl_StreamWriteAt(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.h:311
LONG HRESULT
Definition: typedefs.h:77
const GUID IID_IUnknown
#define WINAPI
Definition: msvc.h:8
static HRESULT WINAPI StgStreamImpl_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
Definition: stg_stream.c:496
unsigned long DWORD
Definition: ntddk_ex.h:95
static HRESULT WINAPI StgStreamImpl_Revert(IStream *iface)
Definition: stg_stream.c:490
static DWORD cb
Definition: integrity.c:41
static HRESULT WINAPI StgStreamImpl_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
Definition: stg_stream.c:128
#define InterlockedDecrement
Definition: armddk.h:52
unsigned char BYTE
Definition: mem.h:68
REFIID LPVOID * ppvObject
Definition: precomp.h:44
static ULONG WINAPI StgStreamImpl_AddRef(IStream *iface)
Definition: stg_stream.c:78
ULONG DirRef
Definition: storage32.h:139
static HRESULT WINAPI StgStreamImpl_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
Definition: stg_stream.c:184
#define STGM_READWRITE
Definition: objbase.h:918
#define STGM_ACCESS_MODE(stgm)
Definition: storage32.h:115
GLenum GLsizei GLuint GLint * bytesWritten
Definition: glext.h:11123
StorageBaseImpl * parentStorage
Definition: storage32.h:440
void StorageBaseImpl_AddStream(StorageBaseImpl *stg, StgStreamImpl *strm)
Definition: storage32.c:2715
#define S_OK
Definition: intsafe.h:59
struct _ULARGE_INTEGER::@3750 u
#define InterlockedIncrement
Definition: armddk.h:53
static HRESULT WINAPI StgStreamImpl_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
Definition: stg_stream.c:389
static HRESULT WINAPI StgStreamImpl_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
Definition: stg_stream.c:48
#define STG_E_REVERTED
Definition: winerror.h:2590
#define E_NOTIMPL
Definition: ddrawi.h:99
static HRESULT StorageBaseImpl_StreamReadAt(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.h:303
void StorageUtl_CopyDirEntryToSTATSTG(StorageBaseImpl *storage, STATSTG *destination, const DirEntry *source, int statFlags)
Definition: storage32.c:7018
GLuint res
Definition: glext.h:9613
unsigned int ULONG
Definition: retypes.h:1
IStream IStream_iface
Definition: storage32.h:429
StgStreamImpl * StgStreamImpl_Construct(StorageBaseImpl *parentStorage, DWORD grfMode, DirRef dirEntry)
Definition: stg_stream.c:666
static HRESULT StorageBaseImpl_ReadDirEntry(StorageBaseImpl *This, DirRef index, DirEntry *data)
Definition: storage32.h:290
#define STGM_SIMPLE
Definition: objbase.h:915
#define HeapFree(x, y, z)
Definition: compat.h:394
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
static sub_stream_t * impl_from_IStream(IStream *iface)
Definition: mimeole.c:182
#define SUCCEEDED(hr)
Definition: intsafe.h:57
LONGLONG QuadPart
Definition: typedefs.h:112
static HRESULT WINAPI StgStreamImpl_Commit(IStream *iface, DWORD grfCommitFlags)
Definition: stg_stream.c:467
static ULONG WINAPI StgStreamImpl_Release(IStream *iface)
Definition: stg_stream.c:89