Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhglobalstream.c
Go to the documentation of this file.
00001 /* 00002 * HGLOBAL Stream implementation 00003 * 00004 * This file contains the implementation of the stream interface 00005 * for streams contained supported by an HGLOBAL pointer. 00006 * 00007 * Copyright 1999 Francis Beaudet 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 */ 00023 00024 #include "config.h" 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 "winuser.h" 00039 #include "objbase.h" 00040 #include "ole2.h" 00041 #include "winerror.h" 00042 #include "winternl.h" 00043 00044 #include "wine/debug.h" 00045 00046 WINE_DEFAULT_DEBUG_CHANNEL(storage); 00047 00048 /**************************************************************************** 00049 * HGLOBALStreamImpl definition. 00050 * 00051 * This class implements the IStream interface and represents a stream 00052 * supported by an HGLOBAL pointer. 00053 */ 00054 typedef struct 00055 { 00056 IStream IStream_iface; 00057 LONG ref; 00058 00059 /* support for the stream */ 00060 HGLOBAL supportHandle; 00061 00062 /* if TRUE the HGLOBAL is destroyed when the stream is finally released */ 00063 BOOL deleteOnRelease; 00064 00065 /* size of the stream */ 00066 ULARGE_INTEGER streamSize; 00067 00068 /* current position of the cursor */ 00069 ULARGE_INTEGER currentPosition; 00070 } HGLOBALStreamImpl; 00071 00072 static inline HGLOBALStreamImpl *impl_from_IStream(IStream *iface) 00073 { 00074 return CONTAINING_RECORD(iface, HGLOBALStreamImpl, IStream_iface); 00075 } 00076 00077 static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface( 00078 IStream* iface, 00079 REFIID riid, /* [in] */ 00080 void** ppvObject) /* [iid_is][out] */ 00081 { 00082 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00083 00084 if (ppvObject==0) 00085 return E_INVALIDARG; 00086 00087 *ppvObject = 0; 00088 00089 if (IsEqualIID(&IID_IUnknown, riid) || 00090 IsEqualIID(&IID_ISequentialStream, riid) || 00091 IsEqualIID(&IID_IStream, riid)) 00092 { 00093 *ppvObject = This; 00094 } 00095 00096 if ((*ppvObject)==0) 00097 return E_NOINTERFACE; 00098 00099 IStream_AddRef(iface); 00100 00101 return S_OK; 00102 } 00103 00104 static ULONG WINAPI HGLOBALStreamImpl_AddRef(IStream* iface) 00105 { 00106 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00107 return InterlockedIncrement(&This->ref); 00108 } 00109 00110 static ULONG WINAPI HGLOBALStreamImpl_Release( 00111 IStream* iface) 00112 { 00113 HGLOBALStreamImpl* This= impl_from_IStream(iface); 00114 ULONG ref = InterlockedDecrement(&This->ref); 00115 00116 if (!ref) 00117 { 00118 if (This->deleteOnRelease) 00119 { 00120 GlobalFree(This->supportHandle); 00121 This->supportHandle = NULL; 00122 } 00123 00124 HeapFree(GetProcessHeap(), 0, This); 00125 } 00126 00127 return ref; 00128 } 00129 00130 /*** 00131 * This method is part of the ISequentialStream interface. 00132 * 00133 * If reads a block of information from the stream at the current 00134 * position. It then moves the current position at the end of the 00135 * read block 00136 * 00137 * See the documentation of ISequentialStream for more info. 00138 */ 00139 static HRESULT WINAPI HGLOBALStreamImpl_Read( 00140 IStream* iface, 00141 void* pv, /* [length_is][size_is][out] */ 00142 ULONG cb, /* [in] */ 00143 ULONG* pcbRead) /* [out] */ 00144 { 00145 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00146 00147 void* supportBuffer; 00148 ULONG bytesReadBuffer; 00149 ULONG bytesToReadFromBuffer; 00150 00151 TRACE("(%p, %p, %d, %p)\n", iface, 00152 pv, cb, pcbRead); 00153 00154 /* 00155 * If the caller is not interested in the number of bytes read, 00156 * we use another buffer to avoid "if" statements in the code. 00157 */ 00158 if (pcbRead==0) 00159 pcbRead = &bytesReadBuffer; 00160 00161 /* 00162 * Using the known size of the stream, calculate the number of bytes 00163 * to read from the block chain 00164 */ 00165 bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); 00166 00167 /* 00168 * Lock the buffer in position and copy the data. 00169 */ 00170 supportBuffer = GlobalLock(This->supportHandle); 00171 if (!supportBuffer) 00172 { 00173 WARN("read from invalid hglobal %p\n", This->supportHandle); 00174 *pcbRead = 0; 00175 return S_OK; 00176 } 00177 00178 memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer); 00179 00180 /* 00181 * Move the current position to the new position 00182 */ 00183 This->currentPosition.u.LowPart+=bytesToReadFromBuffer; 00184 00185 /* 00186 * Return the number of bytes read. 00187 */ 00188 *pcbRead = bytesToReadFromBuffer; 00189 00190 /* 00191 * Cleanup 00192 */ 00193 GlobalUnlock(This->supportHandle); 00194 00195 /* 00196 * Always returns S_OK even if the end of the stream is reached before the 00197 * buffer is filled 00198 */ 00199 00200 return S_OK; 00201 } 00202 00203 /*** 00204 * This method is part of the ISequentialStream interface. 00205 * 00206 * It writes a block of information to the stream at the current 00207 * position. It then moves the current position at the end of the 00208 * written block. If the stream is too small to fit the block, 00209 * the stream is grown to fit. 00210 * 00211 * See the documentation of ISequentialStream for more info. 00212 */ 00213 static HRESULT WINAPI HGLOBALStreamImpl_Write( 00214 IStream* iface, 00215 const void* pv, /* [size_is][in] */ 00216 ULONG cb, /* [in] */ 00217 ULONG* pcbWritten) /* [out] */ 00218 { 00219 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00220 00221 void* supportBuffer; 00222 ULARGE_INTEGER newSize; 00223 ULONG bytesWritten = 0; 00224 00225 TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten); 00226 00227 /* 00228 * If the caller is not interested in the number of bytes written, 00229 * we use another buffer to avoid "if" statements in the code. 00230 */ 00231 if (pcbWritten == 0) 00232 pcbWritten = &bytesWritten; 00233 00234 if (cb == 0) 00235 goto out; 00236 00237 *pcbWritten = 0; 00238 00239 newSize.u.HighPart = 0; 00240 newSize.u.LowPart = This->currentPosition.u.LowPart + cb; 00241 00242 /* 00243 * Verify if we need to grow the stream 00244 */ 00245 if (newSize.u.LowPart > This->streamSize.u.LowPart) 00246 { 00247 /* grow stream */ 00248 HRESULT hr = IStream_SetSize(iface, newSize); 00249 if (FAILED(hr)) 00250 { 00251 ERR("IStream_SetSize failed with error 0x%08x\n", hr); 00252 return hr; 00253 } 00254 } 00255 00256 /* 00257 * Lock the buffer in position and copy the data. 00258 */ 00259 supportBuffer = GlobalLock(This->supportHandle); 00260 if (!supportBuffer) 00261 { 00262 WARN("write to invalid hglobal %p\n", This->supportHandle); 00263 return S_OK; 00264 } 00265 00266 memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb); 00267 00268 /* 00269 * Move the current position to the new position 00270 */ 00271 This->currentPosition.u.LowPart+=cb; 00272 00273 /* 00274 * Cleanup 00275 */ 00276 GlobalUnlock(This->supportHandle); 00277 00278 out: 00279 /* 00280 * Return the number of bytes read. 00281 */ 00282 *pcbWritten = cb; 00283 00284 return S_OK; 00285 } 00286 00287 /*** 00288 * This method is part of the IStream interface. 00289 * 00290 * It will move the current stream pointer according to the parameters 00291 * given. 00292 * 00293 * See the documentation of IStream for more info. 00294 */ 00295 static HRESULT WINAPI HGLOBALStreamImpl_Seek( 00296 IStream* iface, 00297 LARGE_INTEGER dlibMove, /* [in] */ 00298 DWORD dwOrigin, /* [in] */ 00299 ULARGE_INTEGER* plibNewPosition) /* [out] */ 00300 { 00301 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00302 00303 ULARGE_INTEGER newPosition = This->currentPosition; 00304 HRESULT hr = S_OK; 00305 00306 TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart, 00307 dlibMove.u.LowPart, dwOrigin, plibNewPosition); 00308 00309 /* 00310 * The file pointer is moved depending on the given "function" 00311 * parameter. 00312 */ 00313 switch (dwOrigin) 00314 { 00315 case STREAM_SEEK_SET: 00316 newPosition.u.HighPart = 0; 00317 newPosition.u.LowPart = 0; 00318 break; 00319 case STREAM_SEEK_CUR: 00320 break; 00321 case STREAM_SEEK_END: 00322 newPosition = This->streamSize; 00323 break; 00324 default: 00325 hr = STG_E_SEEKERROR; 00326 goto end; 00327 } 00328 00329 /* 00330 * Move the actual file pointer 00331 * If the file pointer ends-up after the end of the stream, the next Write operation will 00332 * make the file larger. This is how it is documented. 00333 */ 00334 newPosition.u.HighPart = 0; 00335 newPosition.u.LowPart += dlibMove.QuadPart; 00336 00337 if (dlibMove.u.LowPart >= 0x80000000 && 00338 newPosition.u.LowPart >= dlibMove.u.LowPart) 00339 { 00340 /* We tried to seek backwards and went past the start. */ 00341 hr = STG_E_SEEKERROR; 00342 goto end; 00343 } 00344 00345 This->currentPosition = newPosition; 00346 00347 end: 00348 if (plibNewPosition) *plibNewPosition = This->currentPosition; 00349 00350 return hr; 00351 } 00352 00353 /*** 00354 * This method is part of the IStream interface. 00355 * 00356 * It will change the size of a stream. 00357 * 00358 * TODO: Switch from small blocks to big blocks and vice versa. 00359 * 00360 * See the documentation of IStream for more info. 00361 */ 00362 static HRESULT WINAPI HGLOBALStreamImpl_SetSize( 00363 IStream* iface, 00364 ULARGE_INTEGER libNewSize) /* [in] */ 00365 { 00366 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00367 HGLOBAL supportHandle; 00368 00369 TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); 00370 00371 /* 00372 * HighPart is ignored as shown in tests 00373 */ 00374 00375 if (This->streamSize.u.LowPart == libNewSize.u.LowPart) 00376 return S_OK; 00377 00378 /* 00379 * Re allocate the HGlobal to fit the new size of the stream. 00380 */ 00381 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); 00382 00383 if (supportHandle == 0) 00384 return E_OUTOFMEMORY; 00385 00386 This->supportHandle = supportHandle; 00387 This->streamSize.u.LowPart = libNewSize.u.LowPart; 00388 00389 return S_OK; 00390 } 00391 00392 /*** 00393 * This method is part of the IStream interface. 00394 * 00395 * It will copy the 'cb' Bytes to 'pstm' IStream. 00396 * 00397 * See the documentation of IStream for more info. 00398 */ 00399 static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( 00400 IStream* iface, 00401 IStream* pstm, /* [unique][in] */ 00402 ULARGE_INTEGER cb, /* [in] */ 00403 ULARGE_INTEGER* pcbRead, /* [out] */ 00404 ULARGE_INTEGER* pcbWritten) /* [out] */ 00405 { 00406 HRESULT hr = S_OK; 00407 BYTE tmpBuffer[128]; 00408 ULONG bytesRead, bytesWritten, copySize; 00409 ULARGE_INTEGER totalBytesRead; 00410 ULARGE_INTEGER totalBytesWritten; 00411 00412 TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm, 00413 cb.u.LowPart, pcbRead, pcbWritten); 00414 00415 if ( pstm == 0 ) 00416 return STG_E_INVALIDPOINTER; 00417 00418 totalBytesRead.QuadPart = 0; 00419 totalBytesWritten.QuadPart = 0; 00420 00421 while ( cb.QuadPart > 0 ) 00422 { 00423 if ( cb.QuadPart >= sizeof(tmpBuffer) ) 00424 copySize = sizeof(tmpBuffer); 00425 else 00426 copySize = cb.u.LowPart; 00427 00428 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead); 00429 if (FAILED(hr)) 00430 break; 00431 00432 totalBytesRead.QuadPart += bytesRead; 00433 00434 if (bytesRead) 00435 { 00436 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); 00437 if (FAILED(hr)) 00438 break; 00439 00440 totalBytesWritten.QuadPart += bytesWritten; 00441 } 00442 00443 if (bytesRead!=copySize) 00444 cb.QuadPart = 0; 00445 else 00446 cb.QuadPart -= bytesRead; 00447 } 00448 00449 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart; 00450 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart; 00451 00452 return hr; 00453 } 00454 00455 /*** 00456 * This method is part of the IStream interface. 00457 * 00458 * For streams supported by HGLOBALS, this function does nothing. 00459 * This is what the documentation tells us. 00460 * 00461 * See the documentation of IStream for more info. 00462 */ 00463 static HRESULT WINAPI HGLOBALStreamImpl_Commit( 00464 IStream* iface, 00465 DWORD grfCommitFlags) /* [in] */ 00466 { 00467 return S_OK; 00468 } 00469 00470 /*** 00471 * This method is part of the IStream interface. 00472 * 00473 * For streams supported by HGLOBALS, this function does nothing. 00474 * This is what the documentation tells us. 00475 * 00476 * See the documentation of IStream for more info. 00477 */ 00478 static HRESULT WINAPI HGLOBALStreamImpl_Revert( 00479 IStream* iface) 00480 { 00481 return S_OK; 00482 } 00483 00484 /*** 00485 * This method is part of the IStream interface. 00486 * 00487 * For streams supported by HGLOBALS, this function does nothing. 00488 * This is what the documentation tells us. 00489 * 00490 * See the documentation of IStream for more info. 00491 */ 00492 static HRESULT WINAPI HGLOBALStreamImpl_LockRegion( 00493 IStream* iface, 00494 ULARGE_INTEGER libOffset, /* [in] */ 00495 ULARGE_INTEGER cb, /* [in] */ 00496 DWORD dwLockType) /* [in] */ 00497 { 00498 return STG_E_INVALIDFUNCTION; 00499 } 00500 00501 /* 00502 * This method is part of the IStream interface. 00503 * 00504 * For streams supported by HGLOBALS, this function does nothing. 00505 * This is what the documentation tells us. 00506 * 00507 * See the documentation of IStream for more info. 00508 */ 00509 static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( 00510 IStream* iface, 00511 ULARGE_INTEGER libOffset, /* [in] */ 00512 ULARGE_INTEGER cb, /* [in] */ 00513 DWORD dwLockType) /* [in] */ 00514 { 00515 return S_OK; 00516 } 00517 00518 /*** 00519 * This method is part of the IStream interface. 00520 * 00521 * This method returns information about the current 00522 * stream. 00523 * 00524 * See the documentation of IStream for more info. 00525 */ 00526 static HRESULT WINAPI HGLOBALStreamImpl_Stat( 00527 IStream* iface, 00528 STATSTG* pstatstg, /* [out] */ 00529 DWORD grfStatFlag) /* [in] */ 00530 { 00531 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00532 00533 memset(pstatstg, 0, sizeof(STATSTG)); 00534 00535 pstatstg->pwcsName = NULL; 00536 pstatstg->type = STGTY_STREAM; 00537 pstatstg->cbSize = This->streamSize; 00538 00539 return S_OK; 00540 } 00541 00542 static HRESULT WINAPI HGLOBALStreamImpl_Clone( 00543 IStream* iface, 00544 IStream** ppstm) /* [out] */ 00545 { 00546 HGLOBALStreamImpl* This = impl_from_IStream(iface); 00547 ULARGE_INTEGER dummy; 00548 LARGE_INTEGER offset; 00549 HRESULT hr; 00550 00551 TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart); 00552 hr = CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm); 00553 if(FAILED(hr)) 00554 return hr; 00555 offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart; 00556 IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy); 00557 return S_OK; 00558 } 00559 00560 static const IStreamVtbl HGLOBALStreamImplVtbl = 00561 { 00562 HGLOBALStreamImpl_QueryInterface, 00563 HGLOBALStreamImpl_AddRef, 00564 HGLOBALStreamImpl_Release, 00565 HGLOBALStreamImpl_Read, 00566 HGLOBALStreamImpl_Write, 00567 HGLOBALStreamImpl_Seek, 00568 HGLOBALStreamImpl_SetSize, 00569 HGLOBALStreamImpl_CopyTo, 00570 HGLOBALStreamImpl_Commit, 00571 HGLOBALStreamImpl_Revert, 00572 HGLOBALStreamImpl_LockRegion, 00573 HGLOBALStreamImpl_UnlockRegion, 00574 HGLOBALStreamImpl_Stat, 00575 HGLOBALStreamImpl_Clone 00576 }; 00577 00578 /*********************************************************************** 00579 * CreateStreamOnHGlobal [OLE32.@] 00580 */ 00581 HRESULT WINAPI CreateStreamOnHGlobal( 00582 HGLOBAL hGlobal, 00583 BOOL fDeleteOnRelease, 00584 LPSTREAM* ppstm) 00585 { 00586 HGLOBALStreamImpl* This; 00587 00588 if (!ppstm) 00589 return E_INVALIDARG; 00590 00591 This = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl)); 00592 if (!This) return E_OUTOFMEMORY; 00593 00594 This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl; 00595 This->ref = 1; 00596 00597 /* initialize the support */ 00598 This->supportHandle = hGlobal; 00599 This->deleteOnRelease = fDeleteOnRelease; 00600 00601 /* allocate a handle if one is not supplied */ 00602 if (!This->supportHandle) 00603 This->supportHandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0); 00604 00605 /* start at the beginning */ 00606 This->currentPosition.u.HighPart = 0; 00607 This->currentPosition.u.LowPart = 0; 00608 00609 /* initialize the size of the stream to the size of the handle */ 00610 This->streamSize.u.HighPart = 0; 00611 This->streamSize.u.LowPart = GlobalSize(This->supportHandle); 00612 00613 *ppstm = &This->IStream_iface; 00614 00615 return S_OK; 00616 } 00617 00618 /*********************************************************************** 00619 * GetHGlobalFromStream [OLE32.@] 00620 */ 00621 HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal) 00622 { 00623 HGLOBALStreamImpl* pStream; 00624 00625 if (pstm == NULL) 00626 return E_INVALIDARG; 00627 00628 pStream = (HGLOBALStreamImpl*) pstm; 00629 00630 /* 00631 * Verify that the stream object was created with CreateStreamOnHGlobal. 00632 */ 00633 if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl) 00634 *phglobal = pStream->supportHandle; 00635 else 00636 { 00637 *phglobal = 0; 00638 return E_INVALIDARG; 00639 } 00640 00641 return S_OK; 00642 } Generated on Sat May 26 2012 04:24:09 for ReactOS by
1.7.6.1
|