1 /******************************************************************************
3 * File-based ILockBytes implementation
5 * Copyright 1999 Thuy Nguyen
6 * Copyright 2010 Vincent Povirk for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
41 #include "storage32.h"
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(storage);
48 typedef struct FileLockBytesImpl
50 const ILockBytesVtbl *lpVtbl;
52 ULARGE_INTEGER filesize;
58 static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
60 /***********************************************************
61 * Prototypes for private methods
64 /* Note that this evaluates a and b multiple times, so don't
65 * pass expressions with side effects. */
66 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
68 /****************************************************************************
71 * This function will return a protection mode flag for a file-mapping object
72 * from the open flags of a file.
74 static DWORD GetProtectMode(DWORD openFlags)
76 switch(STGM_ACCESS_MODE(openFlags))
80 return PAGE_READWRITE;
85 /******************************************************************************
86 * FileLockBytesImpl_Construct
88 * Initialize a big block object supported by a file.
90 HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes)
92 FileLockBytesImpl *This;
93 WCHAR fullpath[MAX_PATH];
95 if (hFile == INVALID_HANDLE_VALUE)
98 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
101 return E_OUTOFMEMORY;
103 This->lpVtbl = &FileLockBytesImpl_Vtbl;
106 This->filesize.u.LowPart = GetFileSize(This->hfile,
107 &This->filesize.u.HighPart);
108 This->flProtect = GetProtectMode(openFlags);
111 if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL))
113 lstrcpynW(fullpath, pwcsName, MAX_PATH);
115 This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
116 (lstrlenW(fullpath)+1)*sizeof(WCHAR));
119 HeapFree(GetProcessHeap(), 0, This);
120 return E_OUTOFMEMORY;
122 strcpyW(This->pwcsName, fullpath);
125 This->pwcsName = NULL;
127 TRACE("file len %u\n", This->filesize.u.LowPart);
129 *pLockBytes = (ILockBytes*)This;
134 /* ILockByte Interfaces */
136 static HRESULT WINAPI FileLockBytesImpl_QueryInterface(ILockBytes *iface, REFIID riid,
139 if (IsEqualIID(riid, &IID_ILockBytes) || IsEqualIID(riid, &IID_ILockBytes))
144 return E_NOINTERFACE;
147 IUnknown_AddRef((IUnknown*)*ppvObject);
152 static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes *iface)
154 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
155 return InterlockedIncrement(&This->ref);
158 static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes *iface)
160 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
163 ref = InterlockedDecrement(&This->ref);
167 CloseHandle(This->hfile);
168 HeapFree(GetProcessHeap(), 0, This->pwcsName);
169 HeapFree(GetProcessHeap(), 0, This);
175 /******************************************************************************
176 * This method is part of the ILockBytes interface.
178 * It reads a block of information from the byte array at the specified
181 * See the documentation of ILockBytes for more info.
183 static HRESULT WINAPI FileLockBytesImpl_ReadAt(
185 ULARGE_INTEGER ulOffset, /* [in] */
186 void* pv, /* [length_is][size_is][out] */
188 ULONG* pcbRead) /* [out] */
190 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
191 ULONG bytes_left = cb;
194 LARGE_INTEGER offset;
197 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
199 /* verify a sane environment */
200 if (!This) return E_FAIL;
205 offset.QuadPart = ulOffset.QuadPart;
207 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
210 return STG_E_READFAULT;
214 ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL);
216 if (!ret || cbRead == 0)
217 return STG_E_READFAULT;
222 bytes_left -= cbRead;
230 /******************************************************************************
231 * This method is part of the ILockBytes interface.
233 * It writes the specified bytes at the specified offset.
234 * position. If the file is too small, it will be resized.
236 * See the documentation of ILockBytes for more info.
238 static HRESULT WINAPI FileLockBytesImpl_WriteAt(
240 ULARGE_INTEGER ulOffset, /* [in] */
241 const void* pv, /* [size_is][in] */
243 ULONG* pcbWritten) /* [out] */
245 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
246 ULONG size_needed = ulOffset.u.LowPart + cb;
247 ULONG bytes_left = cb;
248 const BYTE *writePtr = pv;
250 LARGE_INTEGER offset;
253 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
255 /* verify a sane environment */
256 if (!This) return E_FAIL;
258 if (This->flProtect != PAGE_READWRITE)
259 return STG_E_ACCESSDENIED;
264 if (size_needed > This->filesize.u.LowPart)
266 ULARGE_INTEGER newSize;
267 newSize.u.HighPart = 0;
268 newSize.u.LowPart = size_needed;
269 ILockBytes_SetSize(iface, newSize);
272 offset.QuadPart = ulOffset.QuadPart;
274 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
277 return STG_E_READFAULT;
281 ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
284 return STG_E_READFAULT;
287 *pcbWritten += cbWritten;
289 bytes_left -= cbWritten;
290 writePtr += cbWritten;
297 static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
302 /******************************************************************************
305 * Sets the size of the file.
308 static HRESULT WINAPI FileLockBytesImpl_SetSize(ILockBytes* iface, ULARGE_INTEGER newSize)
310 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
312 LARGE_INTEGER newpos;
314 if (This->filesize.u.LowPart == newSize.u.LowPart)
317 TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart);
319 newpos.QuadPart = newSize.QuadPart;
320 if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
322 SetEndOfFile(This->hfile);
325 This->filesize = newSize;
329 static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
330 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
336 static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
337 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
343 static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
344 STATSTG *pstatstg, DWORD grfStatFlag)
346 FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
348 if (!(STATFLAG_NONAME & grfStatFlag) && This->pwcsName)
351 CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
353 strcpyW(pstatstg->pwcsName, This->pwcsName);
356 pstatstg->pwcsName = NULL;
358 pstatstg->type = STGTY_LOCKBYTES;
359 pstatstg->cbSize = This->filesize;
360 /* FIXME: If the implementation is exported, we'll need to set other fields. */
365 static const ILockBytesVtbl FileLockBytesImpl_Vtbl = {
366 FileLockBytesImpl_QueryInterface,
367 FileLockBytesImpl_AddRef,
368 FileLockBytesImpl_Release,
369 FileLockBytesImpl_ReadAt,
370 FileLockBytesImpl_WriteAt,
371 FileLockBytesImpl_Flush,
372 FileLockBytesImpl_SetSize,
373 FileLockBytesImpl_LockRegion,
374 FileLockBytesImpl_UnlockRegion,
375 FileLockBytesImpl_Stat