mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / ole32 / filelockbytes.c
blobe9699c01650bd753951ce8b654208a4d9f89bf5a
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
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <limits.h>
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "ole2.h"
41 #include "storage32.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(storage);
47 typedef struct FileLockBytesImpl
49 ILockBytes ILockBytes_iface;
50 LONG ref;
51 HANDLE hfile;
52 DWORD flProtect;
53 LPWSTR pwcsName;
54 } FileLockBytesImpl;
56 static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
58 static inline FileLockBytesImpl *impl_from_ILockBytes(ILockBytes *iface)
60 return CONTAINING_RECORD(iface, FileLockBytesImpl, ILockBytes_iface);
63 /***********************************************************
64 * Prototypes for private methods
67 /****************************************************************************
68 * GetProtectMode
70 * This function will return a protection mode flag for a file-mapping object
71 * from the open flags of a file.
73 static DWORD GetProtectMode(DWORD openFlags)
75 switch(STGM_ACCESS_MODE(openFlags))
77 case STGM_WRITE:
78 case STGM_READWRITE:
79 return PAGE_READWRITE;
81 return PAGE_READONLY;
84 /******************************************************************************
85 * FileLockBytesImpl_Construct
87 * Initialize a big block object supported by a file.
89 HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes)
91 FileLockBytesImpl *This;
92 WCHAR fullpath[MAX_PATH];
94 if (hFile == INVALID_HANDLE_VALUE)
95 return E_FAIL;
97 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
99 if (!This)
100 return E_OUTOFMEMORY;
102 This->ILockBytes_iface.lpVtbl = &FileLockBytesImpl_Vtbl;
103 This->ref = 1;
104 This->hfile = hFile;
105 This->flProtect = GetProtectMode(openFlags);
107 if(pwcsName) {
108 if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL))
110 lstrcpynW(fullpath, pwcsName, MAX_PATH);
112 This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
113 (lstrlenW(fullpath)+1)*sizeof(WCHAR));
114 if (!This->pwcsName)
116 HeapFree(GetProcessHeap(), 0, This);
117 return E_OUTOFMEMORY;
119 lstrcpyW(This->pwcsName, fullpath);
121 else
122 This->pwcsName = NULL;
124 *pLockBytes = &This->ILockBytes_iface;
126 return S_OK;
129 /* ILockByte Interfaces */
131 static HRESULT WINAPI FileLockBytesImpl_QueryInterface(ILockBytes *iface, REFIID riid,
132 void **ppvObject)
134 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ILockBytes))
135 *ppvObject = iface;
136 else
138 *ppvObject = NULL;
139 return E_NOINTERFACE;
142 IUnknown_AddRef((IUnknown*)*ppvObject);
144 return S_OK;
147 static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes *iface)
149 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
150 return InterlockedIncrement(&This->ref);
153 static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes *iface)
155 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
156 ULONG ref;
158 ref = InterlockedDecrement(&This->ref);
160 if (ref == 0)
162 CloseHandle(This->hfile);
163 HeapFree(GetProcessHeap(), 0, This->pwcsName);
164 HeapFree(GetProcessHeap(), 0, This);
167 return ref;
170 /******************************************************************************
171 * This method is part of the ILockBytes interface.
173 * It reads a block of information from the byte array at the specified
174 * offset.
176 * See the documentation of ILockBytes for more info.
178 static HRESULT WINAPI FileLockBytesImpl_ReadAt(
179 ILockBytes* iface,
180 ULARGE_INTEGER ulOffset, /* [in] */
181 void* pv, /* [length_is][size_is][out] */
182 ULONG cb, /* [in] */
183 ULONG* pcbRead) /* [out] */
185 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
186 ULONG bytes_left = cb;
187 LPBYTE readPtr = pv;
188 BOOL ret;
189 LARGE_INTEGER offset;
190 ULONG cbRead;
192 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
194 /* verify a sane environment */
195 if (!This) return E_FAIL;
197 if (pcbRead)
198 *pcbRead = 0;
200 offset.QuadPart = ulOffset.QuadPart;
202 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
204 if (!ret)
205 return STG_E_READFAULT;
207 while (bytes_left)
209 ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL);
211 if (!ret || cbRead == 0)
212 return STG_E_READFAULT;
214 if (pcbRead)
215 *pcbRead += cbRead;
217 bytes_left -= cbRead;
218 readPtr += cbRead;
221 TRACE("finished\n");
222 return S_OK;
225 /******************************************************************************
226 * This method is part of the ILockBytes interface.
228 * It writes the specified bytes at the specified offset.
229 * position. If the file is too small, it will be resized.
231 * See the documentation of ILockBytes for more info.
233 static HRESULT WINAPI FileLockBytesImpl_WriteAt(
234 ILockBytes* iface,
235 ULARGE_INTEGER ulOffset, /* [in] */
236 const void* pv, /* [size_is][in] */
237 ULONG cb, /* [in] */
238 ULONG* pcbWritten) /* [out] */
240 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
241 ULONG bytes_left = cb;
242 const BYTE *writePtr = pv;
243 BOOL ret;
244 LARGE_INTEGER offset;
245 ULONG cbWritten;
247 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
249 /* verify a sane environment */
250 if (!This) return E_FAIL;
252 if (This->flProtect != PAGE_READWRITE)
253 return STG_E_ACCESSDENIED;
255 if (pcbWritten)
256 *pcbWritten = 0;
258 offset.QuadPart = ulOffset.QuadPart;
260 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
262 if (!ret)
263 return STG_E_WRITEFAULT;
265 while (bytes_left)
267 ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
269 if (!ret)
270 return STG_E_WRITEFAULT;
272 if (pcbWritten)
273 *pcbWritten += cbWritten;
275 bytes_left -= cbWritten;
276 writePtr += cbWritten;
279 TRACE("finished\n");
280 return S_OK;
283 static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
285 return S_OK;
288 /******************************************************************************
289 * ILockBytes_SetSize
291 * Sets the size of the file.
294 static HRESULT WINAPI FileLockBytesImpl_SetSize(ILockBytes* iface, ULARGE_INTEGER newSize)
296 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
297 HRESULT hr = S_OK;
298 LARGE_INTEGER newpos;
300 TRACE("new size %u\n", newSize.u.LowPart);
302 newpos.QuadPart = newSize.QuadPart;
303 if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
305 SetEndOfFile(This->hfile);
308 return hr;
311 static HRESULT get_lock_error(void)
313 switch (GetLastError())
315 case ERROR_LOCK_VIOLATION: return STG_E_LOCKVIOLATION; break;
316 case ERROR_ACCESS_DENIED: return STG_E_ACCESSDENIED; break;
317 case ERROR_NOT_SUPPORTED: return STG_E_INVALIDFUNCTION; break;
318 default:
319 FIXME("no mapping for error %d\n", GetLastError());
320 return STG_E_INVALIDFUNCTION;
324 static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
325 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
327 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
328 OVERLAPPED ol;
329 DWORD lock_flags = LOCKFILE_FAIL_IMMEDIATELY;
331 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
333 if (dwLockType & LOCK_WRITE)
334 return STG_E_INVALIDFUNCTION;
336 if (dwLockType & (LOCK_EXCLUSIVE|LOCK_ONLYONCE))
337 lock_flags |= LOCKFILE_EXCLUSIVE_LOCK;
339 ol.hEvent = 0;
340 ol.u.s.Offset = libOffset.u.LowPart;
341 ol.u.s.OffsetHigh = libOffset.u.HighPart;
343 if (LockFileEx(This->hfile, lock_flags, 0, cb.u.LowPart, cb.u.HighPart, &ol))
344 return S_OK;
345 return get_lock_error();
348 static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
349 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
351 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
352 OVERLAPPED ol;
354 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
356 if (dwLockType & LOCK_WRITE)
357 return STG_E_INVALIDFUNCTION;
359 ol.hEvent = 0;
360 ol.u.s.Offset = libOffset.u.LowPart;
361 ol.u.s.OffsetHigh = libOffset.u.HighPart;
363 if (UnlockFileEx(This->hfile, 0, cb.u.LowPart, cb.u.HighPart, &ol))
364 return S_OK;
365 return get_lock_error();
368 static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
369 STATSTG *pstatstg, DWORD grfStatFlag)
371 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
373 if (!(STATFLAG_NONAME & grfStatFlag) && This->pwcsName)
375 pstatstg->pwcsName =
376 CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
378 lstrcpyW(pstatstg->pwcsName, This->pwcsName);
380 else
381 pstatstg->pwcsName = NULL;
383 pstatstg->type = STGTY_LOCKBYTES;
385 pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile, &pstatstg->cbSize.u.HighPart);
386 /* FIXME: If the implementation is exported, we'll need to set other fields. */
388 pstatstg->grfLocksSupported = LOCK_EXCLUSIVE|LOCK_ONLYONCE|WINE_LOCK_READ;
390 return S_OK;
393 static const ILockBytesVtbl FileLockBytesImpl_Vtbl = {
394 FileLockBytesImpl_QueryInterface,
395 FileLockBytesImpl_AddRef,
396 FileLockBytesImpl_Release,
397 FileLockBytesImpl_ReadAt,
398 FileLockBytesImpl_WriteAt,
399 FileLockBytesImpl_Flush,
400 FileLockBytesImpl_SetSize,
401 FileLockBytesImpl_LockRegion,
402 FileLockBytesImpl_UnlockRegion,
403 FileLockBytesImpl_Stat