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
38 #include "storage32.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(storage
);
44 typedef struct FileLockBytesImpl
46 ILockBytes ILockBytes_iface
;
53 static const ILockBytesVtbl FileLockBytesImpl_Vtbl
;
55 static inline FileLockBytesImpl
*impl_from_ILockBytes(ILockBytes
*iface
)
57 return CONTAINING_RECORD(iface
, FileLockBytesImpl
, ILockBytes_iface
);
60 /***********************************************************
61 * Prototypes for private methods
64 /****************************************************************************
67 * This function will return a protection mode flag for a file-mapping object
68 * from the open flags of a file.
70 static DWORD
GetProtectMode(DWORD openFlags
)
72 switch(STGM_ACCESS_MODE(openFlags
))
76 return PAGE_READWRITE
;
81 /******************************************************************************
82 * FileLockBytesImpl_Construct
84 * Initialize a big block object supported by a file.
86 HRESULT
FileLockBytesImpl_Construct(HANDLE hFile
, DWORD openFlags
, LPCWSTR pwcsName
, ILockBytes
**pLockBytes
)
88 FileLockBytesImpl
*This
;
89 WCHAR fullpath
[MAX_PATH
];
91 if (hFile
== INVALID_HANDLE_VALUE
)
94 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl
));
99 This
->ILockBytes_iface
.lpVtbl
= &FileLockBytesImpl_Vtbl
;
102 This
->flProtect
= GetProtectMode(openFlags
);
105 if (!GetFullPathNameW(pwcsName
, MAX_PATH
, fullpath
, NULL
))
107 lstrcpynW(fullpath
, pwcsName
, MAX_PATH
);
109 This
->pwcsName
= HeapAlloc(GetProcessHeap(), 0,
110 (lstrlenW(fullpath
)+1)*sizeof(WCHAR
));
113 HeapFree(GetProcessHeap(), 0, This
);
114 return E_OUTOFMEMORY
;
116 lstrcpyW(This
->pwcsName
, fullpath
);
119 This
->pwcsName
= NULL
;
121 *pLockBytes
= &This
->ILockBytes_iface
;
126 /* ILockByte Interfaces */
128 static HRESULT WINAPI
FileLockBytesImpl_QueryInterface(ILockBytes
*iface
, REFIID riid
,
131 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_ILockBytes
))
136 return E_NOINTERFACE
;
139 IUnknown_AddRef((IUnknown
*)*ppvObject
);
144 static ULONG WINAPI
FileLockBytesImpl_AddRef(ILockBytes
*iface
)
146 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
147 return InterlockedIncrement(&This
->ref
);
150 static ULONG WINAPI
FileLockBytesImpl_Release(ILockBytes
*iface
)
152 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
155 ref
= InterlockedDecrement(&This
->ref
);
159 CloseHandle(This
->hfile
);
160 HeapFree(GetProcessHeap(), 0, This
->pwcsName
);
161 HeapFree(GetProcessHeap(), 0, This
);
167 /******************************************************************************
168 * This method is part of the ILockBytes interface.
170 * It reads a block of information from the byte array at the specified
173 * See the documentation of ILockBytes for more info.
175 static HRESULT WINAPI
FileLockBytesImpl_ReadAt(
177 ULARGE_INTEGER ulOffset
, /* [in] */
178 void* pv
, /* [length_is][size_is][out] */
180 ULONG
* pcbRead
) /* [out] */
182 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
183 ULONG bytes_left
= cb
;
186 LARGE_INTEGER offset
;
189 TRACE("%p, %ld, %p, %lu, %p.\n", iface
, ulOffset
.LowPart
, pv
, cb
, pcbRead
);
191 /* verify a sane environment */
192 if (!This
) return E_FAIL
;
197 offset
.QuadPart
= ulOffset
.QuadPart
;
199 ret
= SetFilePointerEx(This
->hfile
, offset
, NULL
, FILE_BEGIN
);
202 return STG_E_READFAULT
;
206 ret
= ReadFile(This
->hfile
, readPtr
, bytes_left
, &cbRead
, NULL
);
208 if (!ret
|| cbRead
== 0)
209 return STG_E_READFAULT
;
214 bytes_left
-= cbRead
;
222 /******************************************************************************
223 * This method is part of the ILockBytes interface.
225 * It writes the specified bytes at the specified offset.
226 * position. If the file is too small, it will be resized.
228 * See the documentation of ILockBytes for more info.
230 static HRESULT WINAPI
FileLockBytesImpl_WriteAt(
232 ULARGE_INTEGER ulOffset
, /* [in] */
233 const void* pv
, /* [size_is][in] */
235 ULONG
* pcbWritten
) /* [out] */
237 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
238 ULONG bytes_left
= cb
;
239 const BYTE
*writePtr
= pv
;
241 LARGE_INTEGER offset
;
244 TRACE("%p, %ld, %p, %lu, %p.\n", iface
, ulOffset
.LowPart
, pv
, cb
, pcbWritten
);
246 /* verify a sane environment */
247 if (!This
) return E_FAIL
;
249 if (This
->flProtect
!= PAGE_READWRITE
)
250 return STG_E_ACCESSDENIED
;
255 offset
.QuadPart
= ulOffset
.QuadPart
;
257 ret
= SetFilePointerEx(This
->hfile
, offset
, NULL
, FILE_BEGIN
);
260 return STG_E_WRITEFAULT
;
264 ret
= WriteFile(This
->hfile
, writePtr
, bytes_left
, &cbWritten
, NULL
);
267 return STG_E_WRITEFAULT
;
270 *pcbWritten
+= cbWritten
;
272 bytes_left
-= cbWritten
;
273 writePtr
+= cbWritten
;
280 static HRESULT WINAPI
FileLockBytesImpl_Flush(ILockBytes
* iface
)
285 /******************************************************************************
288 * Sets the size of the file.
291 static HRESULT WINAPI
FileLockBytesImpl_SetSize(ILockBytes
* iface
, ULARGE_INTEGER newSize
)
293 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
295 LARGE_INTEGER newpos
;
297 TRACE("new size %lu\n", newSize
.LowPart
);
299 newpos
.QuadPart
= newSize
.QuadPart
;
300 if (SetFilePointerEx(This
->hfile
, newpos
, NULL
, FILE_BEGIN
))
302 SetEndOfFile(This
->hfile
);
308 static HRESULT
get_lock_error(void)
310 switch (GetLastError())
312 case ERROR_LOCK_VIOLATION
: return STG_E_LOCKVIOLATION
; break;
313 case ERROR_ACCESS_DENIED
: return STG_E_ACCESSDENIED
; break;
314 case ERROR_NOT_SUPPORTED
: return STG_E_INVALIDFUNCTION
; break;
316 FIXME("no mapping for error %ld\n", GetLastError());
317 return STG_E_INVALIDFUNCTION
;
321 static HRESULT WINAPI
FileLockBytesImpl_LockRegion(ILockBytes
* iface
,
322 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
324 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
326 DWORD lock_flags
= LOCKFILE_FAIL_IMMEDIATELY
;
328 TRACE("ofs %lu count %lu flags %lx\n", libOffset
.LowPart
, cb
.LowPart
, dwLockType
);
330 if (dwLockType
& LOCK_WRITE
)
331 return STG_E_INVALIDFUNCTION
;
333 if (dwLockType
& (LOCK_EXCLUSIVE
|LOCK_ONLYONCE
))
334 lock_flags
|= LOCKFILE_EXCLUSIVE_LOCK
;
337 ol
.Offset
= libOffset
.LowPart
;
338 ol
.OffsetHigh
= libOffset
.HighPart
;
340 if (LockFileEx(This
->hfile
, lock_flags
, 0, cb
.LowPart
, cb
.HighPart
, &ol
))
342 return get_lock_error();
345 static HRESULT WINAPI
FileLockBytesImpl_UnlockRegion(ILockBytes
* iface
,
346 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
348 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
351 TRACE("ofs %lu count %lu flags %lx\n", libOffset
.LowPart
, cb
.LowPart
, dwLockType
);
353 if (dwLockType
& LOCK_WRITE
)
354 return STG_E_INVALIDFUNCTION
;
357 ol
.Offset
= libOffset
.LowPart
;
358 ol
.OffsetHigh
= libOffset
.HighPart
;
360 if (UnlockFileEx(This
->hfile
, 0, cb
.LowPart
, cb
.HighPart
, &ol
))
362 return get_lock_error();
365 static HRESULT WINAPI
FileLockBytesImpl_Stat(ILockBytes
* iface
,
366 STATSTG
*pstatstg
, DWORD grfStatFlag
)
368 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
370 if (!(STATFLAG_NONAME
& grfStatFlag
) && This
->pwcsName
)
373 CoTaskMemAlloc((lstrlenW(This
->pwcsName
)+1)*sizeof(WCHAR
));
375 lstrcpyW(pstatstg
->pwcsName
, This
->pwcsName
);
378 pstatstg
->pwcsName
= NULL
;
380 pstatstg
->type
= STGTY_LOCKBYTES
;
382 pstatstg
->cbSize
.LowPart
= GetFileSize(This
->hfile
, &pstatstg
->cbSize
.HighPart
);
383 /* FIXME: If the implementation is exported, we'll need to set other fields. */
385 pstatstg
->grfLocksSupported
= LOCK_EXCLUSIVE
|LOCK_ONLYONCE
|WINE_LOCK_READ
;
390 static const ILockBytesVtbl FileLockBytesImpl_Vtbl
= {
391 FileLockBytesImpl_QueryInterface
,
392 FileLockBytesImpl_AddRef
,
393 FileLockBytesImpl_Release
,
394 FileLockBytesImpl_ReadAt
,
395 FileLockBytesImpl_WriteAt
,
396 FileLockBytesImpl_Flush
,
397 FileLockBytesImpl_SetSize
,
398 FileLockBytesImpl_LockRegion
,
399 FileLockBytesImpl_UnlockRegion
,
400 FileLockBytesImpl_Stat