/************************************************************************** * IStream_fnWrite */ static HRESULT WINAPI IStream_fnWrite(IStream *iface, const void* pv, ULONG cb, ULONG* pcbWritten) { ISHFileStream *This = (ISHFileStream *)iface; DWORD dwWritten = 0; TRACE("(%p,%p,0x%08lx,%p)\n", This, pv, cb, pcbWritten); if (!pv) return STG_E_INVALIDPOINTER; switch (STGM_ACCESS_MODE(This->dwMode)) { case STGM_WRITE: case STGM_READWRITE: break; default: return E_FAIL; } if (!WriteFile(This->hFile, pv, cb, &dwWritten, NULL)) return HRESULT_FROM_WIN32(GetLastError()); if (pcbWritten) *pcbWritten = dwWritten; return S_OK; }
/**************************************************************************** * GetProtectMode * * This function will return a protection mode flag for a file-mapping object * from the open flags of a file. */ static DWORD GetProtectMode(DWORD openFlags) { switch(STGM_ACCESS_MODE(openFlags)) { case STGM_WRITE: case STGM_READWRITE: return PAGE_READWRITE; } return PAGE_READONLY; }
/************************************************************************* * SHCreateStreamOnFileEx [SHLWAPI.@] * * Create a stream on a file. * * PARAMS * lpszPath [I] Path of file to create stream on * dwMode [I] Mode to create stream in * dwAttributes [I] Attributes of the file * bCreate [I] Whether to create the file if it doesn't exist * lpTemplate [I] Reserved, must be NULL * lppStream [O] Destination for created stream * * RETURNS * Success: S_OK. lppStream contains the new stream object * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code * * NOTES * This function is available in Unicode only. */ HRESULT WINAPI SHCreateStreamOnFileEx(LPCWSTR lpszPath, DWORD dwMode, DWORD dwAttributes, BOOL bCreate, IStream *lpTemplate, IStream **lppStream) { DWORD dwAccess, dwShare, dwCreate; HANDLE hFile; TRACE("(%s,%d,0x%08X,%d,%p,%p)\n", debugstr_w(lpszPath), dwMode, dwAttributes, bCreate, lpTemplate, lppStream); if (!lpszPath || !lppStream || lpTemplate) return E_INVALIDARG; *lppStream = NULL; /* Access */ switch (STGM_ACCESS_MODE(dwMode)) { case STGM_WRITE: case STGM_READWRITE: dwAccess = GENERIC_READ|GENERIC_WRITE; break; case STGM_READ: dwAccess = GENERIC_READ; break; default: return E_INVALIDARG; } /* Sharing */ switch (STGM_SHARE_MODE(dwMode)) { case 0: case STGM_SHARE_DENY_NONE: dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE; break; case STGM_SHARE_DENY_READ: dwShare = FILE_SHARE_WRITE; break; case STGM_SHARE_DENY_WRITE: dwShare = FILE_SHARE_READ; break; case STGM_SHARE_EXCLUSIVE: dwShare = 0; break; default: return E_INVALIDARG; } switch(STGM_CREATE_MODE(dwMode)) { case STGM_FAILIFTHERE: dwCreate = bCreate ? CREATE_NEW : OPEN_EXISTING; break; case STGM_CREATE: dwCreate = CREATE_ALWAYS; break; default: return E_INVALIDARG; } /* Open HANDLE to file */ hFile = CreateFileW(lpszPath, dwAccess, dwShare, NULL, dwCreate, dwAttributes, 0); if(hFile == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError()); *lppStream = IStream_Create(lpszPath, hFile, dwMode); if(!*lppStream) { CloseHandle(hFile); return E_OUTOFMEMORY; } return S_OK; }
/*** * This method is part of the ISequentialStream interface. * * It writes a block of information to the stream at the current * position. It then moves the current position at the end of the * written block. If the stream is too small to fit the block, * the stream is grown to fit. * * See the documentation of ISequentialStream for more info. */ static HRESULT WINAPI StgStreamImpl_Write( IStream* iface, const void* pv, /* [size_is][in] */ ULONG cb, /* [in] */ ULONG* pcbWritten) /* [out] */ { StgStreamImpl* This = impl_from_IStream(iface); ULONG bytesWritten = 0; HRESULT res; TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten); /* * Do we have permission to write to this stream? */ switch(STGM_ACCESS_MODE(This->grfMode)) { case STGM_WRITE: case STGM_READWRITE: break; default: WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode)); return STG_E_ACCESSDENIED; } if (!pv) return STG_E_INVALIDPOINTER; if (!This->parentStorage) { WARN("storage reverted\n"); return STG_E_REVERTED; } /* * If the caller is not interested in the number of bytes written, * we use another buffer to avoid "if" statements in the code. */ if (pcbWritten == 0) pcbWritten = &bytesWritten; /* * Initialize the out parameter */ *pcbWritten = 0; if (cb == 0) { TRACE("<-- S_OK, written 0\n"); return S_OK; } res = StorageBaseImpl_StreamWriteAt(This->parentStorage, This->dirEntry, This->currentPosition, cb, pv, pcbWritten); /* * Advance the position pointer for the number of positions written. */ This->currentPosition.QuadPart += *pcbWritten; if (SUCCEEDED(res)) res = StorageBaseImpl_Flush(This->parentStorage); TRACE("<-- %08x, written %u\n", res, *pcbWritten); return res; }
/*** * This method is part of the ISequentialStream interface. * * It writes a block of information to the stream at the current * position. It then moves the current position at the end of the * written block. If the stream is too small to fit the block, * the stream is grown to fit. * * See the documentation of ISequentialStream for more info. */ static HRESULT WINAPI StgStreamImpl_Write( IStream* iface, const void* pv, /* [size_is][in] */ ULONG cb, /* [in] */ ULONG* pcbWritten) /* [out] */ { StgStreamImpl* const This=(StgStreamImpl*)iface; ULARGE_INTEGER newSize; ULONG bytesWritten = 0; TRACE("(%p, %p, %ld, %p)\n", iface, pv, cb, pcbWritten); /* * Do we have permission to write to this stream? */ switch(STGM_ACCESS_MODE(This->grfMode)) { case STGM_WRITE: case STGM_READWRITE: break; default: WARN("access denied by flags: 0x%lx\n", STGM_ACCESS_MODE(This->grfMode)); return STG_E_ACCESSDENIED; } if (!pv) return STG_E_INVALIDPOINTER; if (!This->parentStorage) { WARN("storage reverted\n"); return STG_E_REVERTED; } /* * If the caller is not interested in the number of bytes written, * we use another buffer to avoid "if" statements in the code. */ if (pcbWritten == 0) pcbWritten = &bytesWritten; /* * Initialize the out parameter */ *pcbWritten = 0; if (cb == 0) { TRACE("<-- S_OK, written 0\n"); return S_OK; } else { newSize.u.HighPart = 0; newSize.u.LowPart = This->currentPosition.u.LowPart + cb; } /* * Verify if we need to grow the stream */ if (newSize.u.LowPart > This->streamSize.u.LowPart) { /* grow stream */ IStream_SetSize(iface, newSize); } /* * Depending on the type of chain that was opened when the stream was constructed, * we delegate the work to the method that readwrites to the block chains. */ if (This->smallBlockChain!=0) { SmallBlockChainStream_WriteAt(This->smallBlockChain, This->currentPosition, cb, pv, pcbWritten); } else if (This->bigBlockChain!=0) { BlockChainStream_WriteAt(This->bigBlockChain, This->currentPosition, cb, pv, pcbWritten); } else assert(FALSE); /* * Advance the position pointer for the number of positions written. */ This->currentPosition.u.LowPart += *pcbWritten; TRACE("<-- S_OK, written %lu\n", *pcbWritten); return S_OK; }