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 ILockBytes ILockBytes_iface
;
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 /* Note that this evaluates a and b multiple times, so don't
69 * pass expressions with side effects. */
70 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
72 /****************************************************************************
75 * This function will return a protection mode flag for a file-mapping object
76 * from the open flags of a file.
78 static DWORD
GetProtectMode(DWORD openFlags
)
80 switch(STGM_ACCESS_MODE(openFlags
))
84 return PAGE_READWRITE
;
89 /******************************************************************************
90 * FileLockBytesImpl_Construct
92 * Initialize a big block object supported by a file.
94 HRESULT
FileLockBytesImpl_Construct(HANDLE hFile
, DWORD openFlags
, LPCWSTR pwcsName
, ILockBytes
**pLockBytes
)
96 FileLockBytesImpl
*This
;
97 WCHAR fullpath
[MAX_PATH
];
99 if (hFile
== INVALID_HANDLE_VALUE
)
102 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl
));
105 return E_OUTOFMEMORY
;
107 This
->ILockBytes_iface
.lpVtbl
= &FileLockBytesImpl_Vtbl
;
110 This
->flProtect
= GetProtectMode(openFlags
);
113 if (!GetFullPathNameW(pwcsName
, MAX_PATH
, fullpath
, NULL
))
115 lstrcpynW(fullpath
, pwcsName
, MAX_PATH
);
117 This
->pwcsName
= HeapAlloc(GetProcessHeap(), 0,
118 (lstrlenW(fullpath
)+1)*sizeof(WCHAR
));
121 HeapFree(GetProcessHeap(), 0, This
);
122 return E_OUTOFMEMORY
;
124 strcpyW(This
->pwcsName
, fullpath
);
127 This
->pwcsName
= NULL
;
129 *pLockBytes
= &This
->ILockBytes_iface
;
134 /* ILockByte Interfaces */
136 static HRESULT WINAPI
FileLockBytesImpl_QueryInterface(ILockBytes
*iface
, REFIID riid
,
139 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_ILockBytes
))
144 return E_NOINTERFACE
;
147 IUnknown_AddRef((IUnknown
*)*ppvObject
);
152 static ULONG WINAPI
FileLockBytesImpl_AddRef(ILockBytes
*iface
)
154 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
155 return InterlockedIncrement(&This
->ref
);
158 static ULONG WINAPI
FileLockBytesImpl_Release(ILockBytes
*iface
)
160 FileLockBytesImpl
* This
= impl_from_ILockBytes(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
= impl_from_ILockBytes(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
= impl_from_ILockBytes(iface
);
246 ULONG bytes_left
= cb
;
247 const BYTE
*writePtr
= pv
;
249 LARGE_INTEGER offset
;
252 TRACE("(%p)-> %i %p %i %p\n",This
, ulOffset
.u
.LowPart
, pv
, cb
, pcbWritten
);
254 /* verify a sane environment */
255 if (!This
) return E_FAIL
;
257 if (This
->flProtect
!= PAGE_READWRITE
)
258 return STG_E_ACCESSDENIED
;
263 offset
.QuadPart
= ulOffset
.QuadPart
;
265 ret
= SetFilePointerEx(This
->hfile
, offset
, NULL
, FILE_BEGIN
);
268 return STG_E_WRITEFAULT
;
272 ret
= WriteFile(This
->hfile
, writePtr
, bytes_left
, &cbWritten
, NULL
);
275 return STG_E_WRITEFAULT
;
278 *pcbWritten
+= cbWritten
;
280 bytes_left
-= cbWritten
;
281 writePtr
+= cbWritten
;
288 static HRESULT WINAPI
FileLockBytesImpl_Flush(ILockBytes
* iface
)
293 /******************************************************************************
296 * Sets the size of the file.
299 static HRESULT WINAPI
FileLockBytesImpl_SetSize(ILockBytes
* iface
, ULARGE_INTEGER newSize
)
301 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
303 LARGE_INTEGER newpos
;
305 TRACE("new size %u\n", newSize
.u
.LowPart
);
307 newpos
.QuadPart
= newSize
.QuadPart
;
308 if (SetFilePointerEx(This
->hfile
, newpos
, NULL
, FILE_BEGIN
))
310 SetEndOfFile(This
->hfile
);
316 static HRESULT
get_lock_error(void)
318 switch (GetLastError())
320 case ERROR_LOCK_VIOLATION
: return STG_E_LOCKVIOLATION
; break;
321 case ERROR_ACCESS_DENIED
: return STG_E_ACCESSDENIED
; break;
322 case ERROR_NOT_SUPPORTED
: return STG_E_INVALIDFUNCTION
; break;
324 FIXME("no mapping for error %d\n", GetLastError());
325 return STG_E_INVALIDFUNCTION
;
329 static HRESULT WINAPI
FileLockBytesImpl_LockRegion(ILockBytes
* iface
,
330 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
332 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
334 DWORD lock_flags
= LOCKFILE_FAIL_IMMEDIATELY
;
336 TRACE("ofs %u count %u flags %x\n", libOffset
.u
.LowPart
, cb
.u
.LowPart
, dwLockType
);
338 if (dwLockType
& LOCK_WRITE
)
339 return STG_E_INVALIDFUNCTION
;
341 if (dwLockType
& (LOCK_EXCLUSIVE
|LOCK_ONLYONCE
))
342 lock_flags
|= LOCKFILE_EXCLUSIVE_LOCK
;
345 ol
.u
.s
.Offset
= libOffset
.u
.LowPart
;
346 ol
.u
.s
.OffsetHigh
= libOffset
.u
.HighPart
;
348 if (LockFileEx(This
->hfile
, lock_flags
, 0, cb
.u
.LowPart
, cb
.u
.HighPart
, &ol
))
350 return get_lock_error();
353 HRESULT
FileLockBytesImpl_LockRegionSync(ILockBytes
* iface
,
354 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
)
356 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
359 if (iface
->lpVtbl
!= &FileLockBytesImpl_Vtbl
)
363 ol
.u
.s
.Offset
= libOffset
.u
.LowPart
;
364 ol
.u
.s
.OffsetHigh
= libOffset
.u
.HighPart
;
366 if (LockFileEx(This
->hfile
, LOCKFILE_EXCLUSIVE_LOCK
, 0, cb
.u
.LowPart
, cb
.u
.HighPart
, &ol
))
368 return get_lock_error();
371 static HRESULT WINAPI
FileLockBytesImpl_UnlockRegion(ILockBytes
* iface
,
372 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
374 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
377 TRACE("ofs %u count %u flags %x\n", libOffset
.u
.LowPart
, cb
.u
.LowPart
, dwLockType
);
379 if (dwLockType
& LOCK_WRITE
)
380 return STG_E_INVALIDFUNCTION
;
383 ol
.u
.s
.Offset
= libOffset
.u
.LowPart
;
384 ol
.u
.s
.OffsetHigh
= libOffset
.u
.HighPart
;
386 if (UnlockFileEx(This
->hfile
, 0, cb
.u
.LowPart
, cb
.u
.HighPart
, &ol
))
388 return get_lock_error();
391 static HRESULT WINAPI
FileLockBytesImpl_Stat(ILockBytes
* iface
,
392 STATSTG
*pstatstg
, DWORD grfStatFlag
)
394 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
396 if (!(STATFLAG_NONAME
& grfStatFlag
) && This
->pwcsName
)
399 CoTaskMemAlloc((lstrlenW(This
->pwcsName
)+1)*sizeof(WCHAR
));
401 strcpyW(pstatstg
->pwcsName
, This
->pwcsName
);
404 pstatstg
->pwcsName
= NULL
;
406 pstatstg
->type
= STGTY_LOCKBYTES
;
408 pstatstg
->cbSize
.u
.LowPart
= GetFileSize(This
->hfile
, &pstatstg
->cbSize
.u
.HighPart
);
409 /* FIXME: If the implementation is exported, we'll need to set other fields. */
414 static const ILockBytesVtbl FileLockBytesImpl_Vtbl
= {
415 FileLockBytesImpl_QueryInterface
,
416 FileLockBytesImpl_AddRef
,
417 FileLockBytesImpl_Release
,
418 FileLockBytesImpl_ReadAt
,
419 FileLockBytesImpl_WriteAt
,
420 FileLockBytesImpl_Flush
,
421 FileLockBytesImpl_SetSize
,
422 FileLockBytesImpl_LockRegion
,
423 FileLockBytesImpl_UnlockRegion
,
424 FileLockBytesImpl_Stat