ole32: Fix a typo in a TRACE() message.
[wine.git] / dlls / ole32 / filelockbytes.c
blobc5cb45f77fcb7859ba7c0a497dcff6089911f2d5
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"
44 #include "wine/unicode.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(storage);
48 typedef struct FileLockBytesImpl
50 ILockBytes ILockBytes_iface;
51 LONG ref;
52 HANDLE hfile;
53 DWORD flProtect;
54 LPWSTR pwcsName;
55 } FileLockBytesImpl;
57 static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
59 static inline FileLockBytesImpl *impl_from_ILockBytes(ILockBytes *iface)
61 return CONTAINING_RECORD(iface, FileLockBytesImpl, ILockBytes_iface);
64 /***********************************************************
65 * Prototypes for private methods
68 /****************************************************************************
69 * GetProtectMode
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))
78 case STGM_WRITE:
79 case STGM_READWRITE:
80 return PAGE_READWRITE;
82 return PAGE_READONLY;
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)
96 return E_FAIL;
98 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
100 if (!This)
101 return E_OUTOFMEMORY;
103 This->ILockBytes_iface.lpVtbl = &FileLockBytesImpl_Vtbl;
104 This->ref = 1;
105 This->hfile = hFile;
106 This->flProtect = GetProtectMode(openFlags);
108 if(pwcsName) {
109 if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL))
111 lstrcpynW(fullpath, pwcsName, MAX_PATH);
113 This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
114 (lstrlenW(fullpath)+1)*sizeof(WCHAR));
115 if (!This->pwcsName)
117 HeapFree(GetProcessHeap(), 0, This);
118 return E_OUTOFMEMORY;
120 strcpyW(This->pwcsName, fullpath);
122 else
123 This->pwcsName = NULL;
125 *pLockBytes = &This->ILockBytes_iface;
127 return S_OK;
130 /* ILockByte Interfaces */
132 static HRESULT WINAPI FileLockBytesImpl_QueryInterface(ILockBytes *iface, REFIID riid,
133 void **ppvObject)
135 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ILockBytes))
136 *ppvObject = iface;
137 else
139 *ppvObject = NULL;
140 return E_NOINTERFACE;
143 IUnknown_AddRef((IUnknown*)*ppvObject);
145 return S_OK;
148 static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes *iface)
150 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
151 return InterlockedIncrement(&This->ref);
154 static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes *iface)
156 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
157 ULONG ref;
159 ref = InterlockedDecrement(&This->ref);
161 if (ref == 0)
163 CloseHandle(This->hfile);
164 HeapFree(GetProcessHeap(), 0, This->pwcsName);
165 HeapFree(GetProcessHeap(), 0, This);
168 return ref;
171 /******************************************************************************
172 * This method is part of the ILockBytes interface.
174 * It reads a block of information from the byte array at the specified
175 * offset.
177 * See the documentation of ILockBytes for more info.
179 static HRESULT WINAPI FileLockBytesImpl_ReadAt(
180 ILockBytes* iface,
181 ULARGE_INTEGER ulOffset, /* [in] */
182 void* pv, /* [length_is][size_is][out] */
183 ULONG cb, /* [in] */
184 ULONG* pcbRead) /* [out] */
186 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
187 ULONG bytes_left = cb;
188 LPBYTE readPtr = pv;
189 BOOL ret;
190 LARGE_INTEGER offset;
191 ULONG cbRead;
193 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
195 /* verify a sane environment */
196 if (!This) return E_FAIL;
198 if (pcbRead)
199 *pcbRead = 0;
201 offset.QuadPart = ulOffset.QuadPart;
203 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
205 if (!ret)
206 return STG_E_READFAULT;
208 while (bytes_left)
210 ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL);
212 if (!ret || cbRead == 0)
213 return STG_E_READFAULT;
215 if (pcbRead)
216 *pcbRead += cbRead;
218 bytes_left -= cbRead;
219 readPtr += cbRead;
222 TRACE("finished\n");
223 return S_OK;
226 /******************************************************************************
227 * This method is part of the ILockBytes interface.
229 * It writes the specified bytes at the specified offset.
230 * position. If the file is too small, it will be resized.
232 * See the documentation of ILockBytes for more info.
234 static HRESULT WINAPI FileLockBytesImpl_WriteAt(
235 ILockBytes* iface,
236 ULARGE_INTEGER ulOffset, /* [in] */
237 const void* pv, /* [size_is][in] */
238 ULONG cb, /* [in] */
239 ULONG* pcbWritten) /* [out] */
241 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
242 ULONG bytes_left = cb;
243 const BYTE *writePtr = pv;
244 BOOL ret;
245 LARGE_INTEGER offset;
246 ULONG cbWritten;
248 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
250 /* verify a sane environment */
251 if (!This) return E_FAIL;
253 if (This->flProtect != PAGE_READWRITE)
254 return STG_E_ACCESSDENIED;
256 if (pcbWritten)
257 *pcbWritten = 0;
259 offset.QuadPart = ulOffset.QuadPart;
261 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
263 if (!ret)
264 return STG_E_WRITEFAULT;
266 while (bytes_left)
268 ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
270 if (!ret)
271 return STG_E_WRITEFAULT;
273 if (pcbWritten)
274 *pcbWritten += cbWritten;
276 bytes_left -= cbWritten;
277 writePtr += cbWritten;
280 TRACE("finished\n");
281 return S_OK;
284 static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
286 return S_OK;
289 /******************************************************************************
290 * ILockBytes_SetSize
292 * Sets the size of the file.
295 static HRESULT WINAPI FileLockBytesImpl_SetSize(ILockBytes* iface, ULARGE_INTEGER newSize)
297 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
298 HRESULT hr = S_OK;
299 LARGE_INTEGER newpos;
301 TRACE("new size %u\n", newSize.u.LowPart);
303 newpos.QuadPart = newSize.QuadPart;
304 if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
306 SetEndOfFile(This->hfile);
309 return hr;
312 static HRESULT get_lock_error(void)
314 switch (GetLastError())
316 case ERROR_LOCK_VIOLATION: return STG_E_LOCKVIOLATION; break;
317 case ERROR_ACCESS_DENIED: return STG_E_ACCESSDENIED; break;
318 case ERROR_NOT_SUPPORTED: return STG_E_INVALIDFUNCTION; break;
319 default:
320 FIXME("no mapping for error %d\n", GetLastError());
321 return STG_E_INVALIDFUNCTION;
325 static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
326 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
328 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
329 OVERLAPPED ol;
330 DWORD lock_flags = LOCKFILE_FAIL_IMMEDIATELY;
332 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
334 if (dwLockType & LOCK_WRITE)
335 return STG_E_INVALIDFUNCTION;
337 if (dwLockType & (LOCK_EXCLUSIVE|LOCK_ONLYONCE))
338 lock_flags |= LOCKFILE_EXCLUSIVE_LOCK;
340 ol.hEvent = 0;
341 ol.u.s.Offset = libOffset.u.LowPart;
342 ol.u.s.OffsetHigh = libOffset.u.HighPart;
344 if (LockFileEx(This->hfile, lock_flags, 0, cb.u.LowPart, cb.u.HighPart, &ol))
345 return S_OK;
346 return get_lock_error();
349 static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
350 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
352 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
353 OVERLAPPED ol;
355 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
357 if (dwLockType & LOCK_WRITE)
358 return STG_E_INVALIDFUNCTION;
360 ol.hEvent = 0;
361 ol.u.s.Offset = libOffset.u.LowPart;
362 ol.u.s.OffsetHigh = libOffset.u.HighPart;
364 if (UnlockFileEx(This->hfile, 0, cb.u.LowPart, cb.u.HighPart, &ol))
365 return S_OK;
366 return get_lock_error();
369 static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
370 STATSTG *pstatstg, DWORD grfStatFlag)
372 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
374 if (!(STATFLAG_NONAME & grfStatFlag) && This->pwcsName)
376 pstatstg->pwcsName =
377 CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
379 strcpyW(pstatstg->pwcsName, This->pwcsName);
381 else
382 pstatstg->pwcsName = NULL;
384 pstatstg->type = STGTY_LOCKBYTES;
386 pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile, &pstatstg->cbSize.u.HighPart);
387 /* FIXME: If the implementation is exported, we'll need to set other fields. */
389 pstatstg->grfLocksSupported = LOCK_EXCLUSIVE|LOCK_ONLYONCE|WINE_LOCK_READ;
391 return S_OK;
394 static const ILockBytesVtbl FileLockBytesImpl_Vtbl = {
395 FileLockBytesImpl_QueryInterface,
396 FileLockBytesImpl_AddRef,
397 FileLockBytesImpl_Release,
398 FileLockBytesImpl_ReadAt,
399 FileLockBytesImpl_WriteAt,
400 FileLockBytesImpl_Flush,
401 FileLockBytesImpl_SetSize,
402 FileLockBytesImpl_LockRegion,
403 FileLockBytesImpl_UnlockRegion,
404 FileLockBytesImpl_Stat