ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

stg_stream.c
Go to the documentation of this file.
00001 /*
00002  * Compound Storage (32 bit version)
00003  * Stream implementation
00004  *
00005  * This file contains the implementation of the stream interface
00006  * for streams contained in a compound storage.
00007  *
00008  * Copyright 1999 Francis Beaudet
00009  * Copyright 1999 Thuy Nguyen
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00024  */
00025 
00026 #include <assert.h>
00027 #include <stdlib.h>
00028 #include <stdarg.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 
00032 #define COBJMACROS
00033 #define NONAMELESSUNION
00034 #define NONAMELESSSTRUCT
00035 
00036 #include "windef.h"
00037 #include "winbase.h"
00038 #include "winerror.h"
00039 #include "winternl.h"
00040 #include "wine/debug.h"
00041 
00042 #include "storage32.h"
00043 
00044 WINE_DEFAULT_DEBUG_CHANNEL(storage);
00045 
00046 
00047 /***
00048  * This is the destructor of the StgStreamImpl class.
00049  *
00050  * This method will clean-up all the resources used-up by the given StgStreamImpl
00051  * class. The pointer passed-in to this function will be freed and will not
00052  * be valid anymore.
00053  */
00054 static void StgStreamImpl_Destroy(StgStreamImpl* This)
00055 {
00056   TRACE("(%p)\n", This);
00057 
00058   /*
00059    * Release the reference we are holding on the parent storage.
00060    * IStorage_Release((IStorage*)This->parentStorage);
00061    *
00062    * No, don't do this. Some apps call IStorage_Release without
00063    * calling IStream_Release first. If we grab a reference the
00064    * file is not closed, and the app fails when it tries to
00065    * reopen the file (Easy-PC, for example). Just inform the
00066    * storage that we have closed the stream
00067    */
00068 
00069   if(This->parentStorage) {
00070 
00071     StorageBaseImpl_RemoveStream(This->parentStorage, This);
00072 
00073   }
00074 
00075   This->parentStorage = 0;
00076 
00077   /*
00078    * Finally, free the memory used-up by the class.
00079    */
00080   HeapFree(GetProcessHeap(), 0, This);
00081 }
00082 
00083 /***
00084  * This implements the IUnknown method QueryInterface for this
00085  * class
00086  */
00087 static HRESULT WINAPI StgStreamImpl_QueryInterface(
00088           IStream*     iface,
00089           REFIID         riid,        /* [in] */
00090           void**         ppvObject)   /* [iid_is][out] */
00091 {
00092   StgStreamImpl* const This=(StgStreamImpl*)iface;
00093 
00094   /*
00095    * Perform a sanity check on the parameters.
00096    */
00097   if (ppvObject==0)
00098     return E_INVALIDARG;
00099 
00100   /*
00101    * Initialize the return parameter.
00102    */
00103   *ppvObject = 0;
00104 
00105   /*
00106    * Compare the riid with the interface IDs implemented by this object.
00107    */
00108   if (IsEqualIID(&IID_IUnknown, riid) ||
00109       IsEqualIID(&IID_IPersist, riid) ||
00110       IsEqualIID(&IID_IPersistStream, riid) ||
00111       IsEqualIID(&IID_ISequentialStream, riid) ||
00112       IsEqualIID(&IID_IStream, riid))
00113   {
00114     *ppvObject = This;
00115   }
00116 
00117   /*
00118    * Check that we obtained an interface.
00119    */
00120   if ((*ppvObject)==0)
00121     return E_NOINTERFACE;
00122 
00123   /*
00124    * Query Interface always increases the reference count by one when it is
00125    * successful
00126    */
00127   IStream_AddRef(iface);
00128 
00129   return S_OK;
00130 }
00131 
00132 /***
00133  * This implements the IUnknown method AddRef for this
00134  * class
00135  */
00136 static ULONG WINAPI StgStreamImpl_AddRef(
00137         IStream* iface)
00138 {
00139   StgStreamImpl* const This=(StgStreamImpl*)iface;
00140   return InterlockedIncrement(&This->ref);
00141 }
00142 
00143 /***
00144  * This implements the IUnknown method Release for this
00145  * class
00146  */
00147 static ULONG WINAPI StgStreamImpl_Release(
00148         IStream* iface)
00149 {
00150   StgStreamImpl* const This=(StgStreamImpl*)iface;
00151 
00152   ULONG ref;
00153 
00154   ref = InterlockedDecrement(&This->ref);
00155 
00156   /*
00157    * If the reference count goes down to 0, perform suicide.
00158    */
00159   if (ref==0)
00160   {
00161     StgStreamImpl_Destroy(This);
00162   }
00163 
00164   return ref;
00165 }
00166 
00167 /***
00168  * This method is part of the ISequentialStream interface.
00169  *
00170  * It reads a block of information from the stream at the current
00171  * position. It then moves the current position at the end of the
00172  * read block
00173  *
00174  * See the documentation of ISequentialStream for more info.
00175  */
00176 static HRESULT WINAPI StgStreamImpl_Read(
00177           IStream*     iface,
00178           void*          pv,        /* [length_is][size_is][out] */
00179           ULONG          cb,        /* [in] */
00180           ULONG*         pcbRead)   /* [out] */
00181 {
00182   StgStreamImpl* const This=(StgStreamImpl*)iface;
00183 
00184   ULONG bytesReadBuffer;
00185   HRESULT res;
00186 
00187   TRACE("(%p, %p, %d, %p)\n",
00188     iface, pv, cb, pcbRead);
00189 
00190   if (!This->parentStorage)
00191   {
00192     WARN("storage reverted\n");
00193     return STG_E_REVERTED;
00194   }
00195 
00196   /*
00197    * If the caller is not interested in the number of bytes read,
00198    * we use another buffer to avoid "if" statements in the code.
00199    */
00200   if (pcbRead==0)
00201     pcbRead = &bytesReadBuffer;
00202 
00203   res = StorageBaseImpl_StreamReadAt(This->parentStorage,
00204                                      This->dirEntry,
00205                                      This->currentPosition,
00206                                      cb,
00207                                      pv,
00208                                      pcbRead);
00209 
00210   if (SUCCEEDED(res))
00211   {
00212     /*
00213      * Advance the pointer for the number of positions read.
00214      */
00215     This->currentPosition.u.LowPart += *pcbRead;
00216   }
00217 
00218   TRACE("<-- %08x\n", res);
00219   return res;
00220 }
00221 
00222 /***
00223  * This method is part of the ISequentialStream interface.
00224  *
00225  * It writes a block of information to the stream at the current
00226  * position. It then moves the current position at the end of the
00227  * written block. If the stream is too small to fit the block,
00228  * the stream is grown to fit.
00229  *
00230  * See the documentation of ISequentialStream for more info.
00231  */
00232 static HRESULT WINAPI StgStreamImpl_Write(
00233               IStream*     iface,
00234           const void*    pv,          /* [size_is][in] */
00235           ULONG          cb,          /* [in] */
00236           ULONG*         pcbWritten)  /* [out] */
00237 {
00238   StgStreamImpl* const This=(StgStreamImpl*)iface;
00239 
00240   ULONG bytesWritten = 0;
00241   HRESULT res;
00242 
00243   TRACE("(%p, %p, %d, %p)\n",
00244     iface, pv, cb, pcbWritten);
00245 
00246   /*
00247    * Do we have permission to write to this stream?
00248    */
00249   switch(STGM_ACCESS_MODE(This->grfMode))
00250   {
00251   case STGM_WRITE:
00252   case STGM_READWRITE:
00253       break;
00254   default:
00255       WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode));
00256       return STG_E_ACCESSDENIED;
00257   }
00258 
00259   if (!pv)
00260     return STG_E_INVALIDPOINTER;
00261 
00262   if (!This->parentStorage)
00263   {
00264     WARN("storage reverted\n");
00265     return STG_E_REVERTED;
00266   }
00267  
00268   /*
00269    * If the caller is not interested in the number of bytes written,
00270    * we use another buffer to avoid "if" statements in the code.
00271    */
00272   if (pcbWritten == 0)
00273     pcbWritten = &bytesWritten;
00274 
00275   /*
00276    * Initialize the out parameter
00277    */
00278   *pcbWritten = 0;
00279 
00280   if (cb == 0)
00281   {
00282     TRACE("<-- S_OK, written 0\n");
00283     return S_OK;
00284   }
00285 
00286   res = StorageBaseImpl_StreamWriteAt(This->parentStorage,
00287                                       This->dirEntry,
00288                                       This->currentPosition,
00289                                       cb,
00290                                       pv,
00291                                       pcbWritten);
00292 
00293   /*
00294    * Advance the position pointer for the number of positions written.
00295    */
00296   This->currentPosition.u.LowPart += *pcbWritten;
00297 
00298   if (SUCCEEDED(res))
00299     res = StorageBaseImpl_Flush(This->parentStorage);
00300 
00301   TRACE("<-- S_OK, written %u\n", *pcbWritten);
00302   return res;
00303 }
00304 
00305 /***
00306  * This method is part of the IStream interface.
00307  *
00308  * It will move the current stream pointer according to the parameters
00309  * given.
00310  *
00311  * See the documentation of IStream for more info.
00312  */
00313 static HRESULT WINAPI StgStreamImpl_Seek(
00314           IStream*      iface,
00315           LARGE_INTEGER   dlibMove,         /* [in] */
00316           DWORD           dwOrigin,         /* [in] */
00317           ULARGE_INTEGER* plibNewPosition) /* [out] */
00318 {
00319   StgStreamImpl* const This=(StgStreamImpl*)iface;
00320 
00321   ULARGE_INTEGER newPosition;
00322   DirEntry currentEntry;
00323   HRESULT hr;
00324 
00325   TRACE("(%p, %d, %d, %p)\n",
00326     iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
00327 
00328   /*
00329    * fail if the stream has no parent (as does windows)
00330    */
00331 
00332   if (!This->parentStorage)
00333   {
00334     WARN("storage reverted\n");
00335     return STG_E_REVERTED;
00336   }
00337 
00338   /*
00339    * The caller is allowed to pass in NULL as the new position return value.
00340    * If it happens, we assign it to a dynamic variable to avoid special cases
00341    * in the code below.
00342    */
00343   if (plibNewPosition == 0)
00344   {
00345     plibNewPosition = &newPosition;
00346   }
00347 
00348   /*
00349    * The file pointer is moved depending on the given "function"
00350    * parameter.
00351    */
00352   switch (dwOrigin)
00353   {
00354     case STREAM_SEEK_SET:
00355       plibNewPosition->u.HighPart = 0;
00356       plibNewPosition->u.LowPart  = 0;
00357       break;
00358     case STREAM_SEEK_CUR:
00359       *plibNewPosition = This->currentPosition;
00360       break;
00361     case STREAM_SEEK_END:
00362       hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, This->dirEntry, &currentEntry);
00363       if (FAILED(hr)) return hr;
00364       *plibNewPosition = currentEntry.size;
00365       break;
00366     default:
00367       WARN("invalid dwOrigin %d\n", dwOrigin);
00368       return STG_E_INVALIDFUNCTION;
00369   }
00370 
00371   plibNewPosition->QuadPart += dlibMove.QuadPart;
00372 
00373   /*
00374    * tell the caller what we calculated
00375    */
00376   This->currentPosition = *plibNewPosition;
00377 
00378   return S_OK;
00379 }
00380 
00381 /***
00382  * This method is part of the IStream interface.
00383  *
00384  * It will change the size of a stream.
00385  *
00386  * See the documentation of IStream for more info.
00387  */
00388 static HRESULT WINAPI StgStreamImpl_SetSize(
00389                      IStream*      iface,
00390                      ULARGE_INTEGER  libNewSize)   /* [in] */
00391 {
00392   StgStreamImpl* const This=(StgStreamImpl*)iface;
00393 
00394   HRESULT      hr;
00395 
00396   TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
00397 
00398   if(!This->parentStorage)
00399   {
00400     WARN("storage reverted\n");
00401     return STG_E_REVERTED;
00402   }
00403 
00404   /*
00405    * As documented.
00406    */
00407   if (libNewSize.u.HighPart != 0)
00408   {
00409     WARN("invalid value for libNewSize.u.HighPart %d\n", libNewSize.u.HighPart);
00410     return STG_E_INVALIDFUNCTION;
00411   }
00412 
00413   /*
00414    * Do we have permission?
00415    */
00416   if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
00417   {
00418     WARN("access denied\n");
00419     return STG_E_ACCESSDENIED;
00420   }
00421 
00422   hr = StorageBaseImpl_StreamSetSize(This->parentStorage, This->dirEntry, libNewSize);
00423 
00424   if (SUCCEEDED(hr))
00425     hr = StorageBaseImpl_Flush(This->parentStorage);
00426 
00427   return hr;
00428 }
00429 
00430 /***
00431  * This method is part of the IStream interface.
00432  *
00433  * It will copy the 'cb' Bytes to 'pstm' IStream.
00434  *
00435  * See the documentation of IStream for more info.
00436  */
00437 static HRESULT WINAPI StgStreamImpl_CopyTo(
00438                     IStream*      iface,
00439                     IStream*      pstm,         /* [unique][in] */
00440                     ULARGE_INTEGER  cb,           /* [in] */
00441                     ULARGE_INTEGER* pcbRead,      /* [out] */
00442                     ULARGE_INTEGER* pcbWritten)   /* [out] */
00443 {
00444   StgStreamImpl* const This=(StgStreamImpl*)iface;
00445   HRESULT        hr = S_OK;
00446   BYTE           tmpBuffer[128];
00447   ULONG          bytesRead, bytesWritten, copySize;
00448   ULARGE_INTEGER totalBytesRead;
00449   ULARGE_INTEGER totalBytesWritten;
00450 
00451   TRACE("(%p, %p, %d, %p, %p)\n",
00452     iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
00453 
00454   /*
00455    * Sanity check
00456    */
00457 
00458   if (!This->parentStorage)
00459   {
00460     WARN("storage reverted\n");
00461     return STG_E_REVERTED;
00462   }
00463 
00464   if ( pstm == 0 )
00465     return STG_E_INVALIDPOINTER;
00466 
00467   totalBytesRead.QuadPart = 0;
00468   totalBytesWritten.QuadPart = 0;
00469 
00470   while ( cb.QuadPart > 0 )
00471   {
00472     if ( cb.QuadPart >= sizeof(tmpBuffer) )
00473       copySize = sizeof(tmpBuffer);
00474     else
00475       copySize = cb.u.LowPart;
00476 
00477     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
00478 
00479     totalBytesRead.QuadPart += bytesRead;
00480 
00481     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
00482 
00483     totalBytesWritten.QuadPart += bytesWritten;
00484 
00485     /*
00486      * Check that read & write operations were successful
00487      */
00488     if (bytesRead != bytesWritten)
00489     {
00490       hr = STG_E_MEDIUMFULL;
00491       WARN("medium full\n");
00492       break;
00493     }
00494 
00495     if (bytesRead!=copySize)
00496       cb.QuadPart = 0;
00497     else
00498       cb.QuadPart -= bytesRead;
00499   }
00500 
00501   if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
00502   if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
00503 
00504   return hr;
00505 }
00506 
00507 /***
00508  * This method is part of the IStream interface.
00509  *
00510  * For streams contained in structured storages, this method
00511  * does nothing. This is what the documentation tells us.
00512  *
00513  * See the documentation of IStream for more info.
00514  */
00515 static HRESULT WINAPI StgStreamImpl_Commit(
00516           IStream*      iface,
00517           DWORD           grfCommitFlags)  /* [in] */
00518 {
00519   StgStreamImpl* const This=(StgStreamImpl*)iface;
00520 
00521   if (!This->parentStorage)
00522   {
00523     WARN("storage reverted\n");
00524     return STG_E_REVERTED;
00525   }
00526 
00527   return StorageBaseImpl_Flush(This->parentStorage);
00528 }
00529 
00530 /***
00531  * This method is part of the IStream interface.
00532  *
00533  * For streams contained in structured storages, this method
00534  * does nothing. This is what the documentation tells us.
00535  *
00536  * See the documentation of IStream for more info.
00537  */
00538 static HRESULT WINAPI StgStreamImpl_Revert(
00539           IStream* iface)
00540 {
00541   return S_OK;
00542 }
00543 
00544 static HRESULT WINAPI StgStreamImpl_LockRegion(
00545                     IStream*     iface,
00546                     ULARGE_INTEGER libOffset,   /* [in] */
00547                     ULARGE_INTEGER cb,          /* [in] */
00548                     DWORD          dwLockType)  /* [in] */
00549 {
00550   StgStreamImpl* const This=(StgStreamImpl*)iface;
00551 
00552   if (!This->parentStorage)
00553   {
00554     WARN("storage reverted\n");
00555     return STG_E_REVERTED;
00556   }
00557 
00558   FIXME("not implemented!\n");
00559   return E_NOTIMPL;
00560 }
00561 
00562 static HRESULT WINAPI StgStreamImpl_UnlockRegion(
00563                       IStream*     iface,
00564                       ULARGE_INTEGER libOffset,   /* [in] */
00565                       ULARGE_INTEGER cb,          /* [in] */
00566                       DWORD          dwLockType)  /* [in] */
00567 {
00568   StgStreamImpl* const This=(StgStreamImpl*)iface;
00569 
00570   if (!This->parentStorage)
00571   {
00572     WARN("storage reverted\n");
00573     return STG_E_REVERTED;
00574   }
00575 
00576   FIXME("not implemented!\n");
00577   return E_NOTIMPL;
00578 }
00579 
00580 /***
00581  * This method is part of the IStream interface.
00582  *
00583  * This method returns information about the current
00584  * stream.
00585  *
00586  * See the documentation of IStream for more info.
00587  */
00588 static HRESULT WINAPI StgStreamImpl_Stat(
00589           IStream*     iface,
00590           STATSTG*       pstatstg,     /* [out] */
00591           DWORD          grfStatFlag)  /* [in] */
00592 {
00593   StgStreamImpl* const This=(StgStreamImpl*)iface;
00594 
00595   DirEntry     currentEntry;
00596   HRESULT      hr;
00597 
00598   TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
00599 
00600   /*
00601    * if stream has no parent, return STG_E_REVERTED
00602    */
00603 
00604   if (!This->parentStorage)
00605   {
00606     WARN("storage reverted\n");
00607     return STG_E_REVERTED;
00608   }
00609 
00610   /*
00611    * Read the information from the directory entry.
00612    */
00613   hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
00614                          This->dirEntry,
00615                          &currentEntry);
00616 
00617   if (SUCCEEDED(hr))
00618   {
00619     StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
00620                      pstatstg,
00621                      &currentEntry,
00622                      grfStatFlag);
00623 
00624     pstatstg->grfMode = This->grfMode;
00625 
00626     /* In simple create mode cbSize is the current pos */
00627     if((This->parentStorage->openFlags & STGM_SIMPLE) && This->parentStorage->create)
00628       pstatstg->cbSize = This->currentPosition;
00629 
00630     return S_OK;
00631   }
00632 
00633   WARN("failed to read entry\n");
00634   return hr;
00635 }
00636 
00637 /***
00638  * This method is part of the IStream interface.
00639  *
00640  * This method returns a clone of the interface that allows for
00641  * another seek pointer
00642  *
00643  * See the documentation of IStream for more info.
00644  *
00645  * I am not totally sure what I am doing here but I presume that this
00646  * should be basically as simple as creating a new stream with the same
00647  * parent etc and positioning its seek cursor.
00648  */
00649 static HRESULT WINAPI StgStreamImpl_Clone(
00650                    IStream*     iface,
00651                    IStream**    ppstm) /* [out] */
00652 {
00653   StgStreamImpl* const This=(StgStreamImpl*)iface;
00654   HRESULT hres;
00655   StgStreamImpl* new_stream;
00656   LARGE_INTEGER seek_pos;
00657 
00658   TRACE("%p %p\n", This, ppstm);
00659 
00660   /*
00661    * Sanity check
00662    */
00663 
00664   if (!This->parentStorage)
00665     return STG_E_REVERTED;
00666 
00667   if ( ppstm == 0 )
00668     return STG_E_INVALIDPOINTER;
00669 
00670   new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry);
00671 
00672   if (!new_stream)
00673     return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
00674 
00675   *ppstm = (IStream*) new_stream;
00676   IStream_AddRef(*ppstm);
00677 
00678   seek_pos.QuadPart = This->currentPosition.QuadPart;
00679 
00680   hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
00681 
00682   assert (SUCCEEDED(hres));
00683 
00684   return S_OK;
00685 }
00686 
00687 /*
00688  * Virtual function table for the StgStreamImpl class.
00689  */
00690 static const IStreamVtbl StgStreamImpl_Vtbl =
00691 {
00692     StgStreamImpl_QueryInterface,
00693     StgStreamImpl_AddRef,
00694     StgStreamImpl_Release,
00695     StgStreamImpl_Read,
00696     StgStreamImpl_Write,
00697     StgStreamImpl_Seek,
00698     StgStreamImpl_SetSize,
00699     StgStreamImpl_CopyTo,
00700     StgStreamImpl_Commit,
00701     StgStreamImpl_Revert,
00702     StgStreamImpl_LockRegion,
00703     StgStreamImpl_UnlockRegion,
00704     StgStreamImpl_Stat,
00705     StgStreamImpl_Clone
00706 };
00707 
00708 /******************************************************************************
00709 ** StgStreamImpl implementation
00710 */
00711 
00712 /***
00713  * This is the constructor for the StgStreamImpl class.
00714  *
00715  * Params:
00716  *    parentStorage - Pointer to the storage that contains the stream to open
00717  *    dirEntry      - Index of the directory entry that points to this stream.
00718  */
00719 StgStreamImpl* StgStreamImpl_Construct(
00720         StorageBaseImpl* parentStorage,
00721     DWORD            grfMode,
00722     DirRef           dirEntry)
00723 {
00724   StgStreamImpl* newStream;
00725 
00726   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
00727 
00728   if (newStream!=0)
00729   {
00730     /*
00731      * Set-up the virtual function table and reference count.
00732      */
00733     newStream->lpVtbl    = &StgStreamImpl_Vtbl;
00734     newStream->ref       = 0;
00735 
00736     newStream->parentStorage = parentStorage;
00737 
00738     /*
00739      * We want to nail-down the reference to the storage in case the
00740      * stream out-lives the storage in the client application.
00741      *
00742      * -- IStorage_AddRef((IStorage*)newStream->parentStorage);
00743      *
00744      * No, don't do this. Some apps call IStorage_Release without
00745      * calling IStream_Release first. If we grab a reference the
00746      * file is not closed, and the app fails when it tries to
00747      * reopen the file (Easy-PC, for example)
00748      */
00749 
00750     newStream->grfMode = grfMode;
00751     newStream->dirEntry = dirEntry;
00752 
00753     /*
00754      * Start the stream at the beginning.
00755      */
00756     newStream->currentPosition.u.HighPart = 0;
00757     newStream->currentPosition.u.LowPart = 0;
00758 
00759     /* add us to the storage's list of active streams */
00760     StorageBaseImpl_AddStream(parentStorage, newStream);
00761   }
00762 
00763   return newStream;
00764 }

Generated on Thu May 24 2012 04:26:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.