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
;
52 ULARGE_INTEGER filesize
;
58 static const ILockBytesVtbl FileLockBytesImpl_Vtbl
;
60 static inline FileLockBytesImpl
*impl_from_ILockBytes(ILockBytes
*iface
)
62 return CONTAINING_RECORD(iface
, FileLockBytesImpl
, ILockBytes_iface
);
65 /***********************************************************
66 * Prototypes for private methods
69 /* Note that this evaluates a and b multiple times, so don't
70 * pass expressions with side effects. */
71 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
73 /****************************************************************************
76 * This function will return a protection mode flag for a file-mapping object
77 * from the open flags of a file.
79 static DWORD
GetProtectMode(DWORD openFlags
)
81 switch(STGM_ACCESS_MODE(openFlags
))
85 return PAGE_READWRITE
;
90 /******************************************************************************
91 * FileLockBytesImpl_Construct
93 * Initialize a big block object supported by a file.
95 HRESULT
FileLockBytesImpl_Construct(HANDLE hFile
, DWORD openFlags
, LPCWSTR pwcsName
, ILockBytes
**pLockBytes
)
97 FileLockBytesImpl
*This
;
98 WCHAR fullpath
[MAX_PATH
];
100 if (hFile
== INVALID_HANDLE_VALUE
)
103 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl
));
106 return E_OUTOFMEMORY
;
108 This
->ILockBytes_iface
.lpVtbl
= &FileLockBytesImpl_Vtbl
;
111 This
->filesize
.u
.LowPart
= GetFileSize(This
->hfile
,
112 &This
->filesize
.u
.HighPart
);
113 This
->flProtect
= GetProtectMode(openFlags
);
116 if (!GetFullPathNameW(pwcsName
, MAX_PATH
, fullpath
, NULL
))
118 lstrcpynW(fullpath
, pwcsName
, MAX_PATH
);
120 This
->pwcsName
= HeapAlloc(GetProcessHeap(), 0,
121 (lstrlenW(fullpath
)+1)*sizeof(WCHAR
));
124 HeapFree(GetProcessHeap(), 0, This
);
125 return E_OUTOFMEMORY
;
127 strcpyW(This
->pwcsName
, fullpath
);
130 This
->pwcsName
= NULL
;
132 TRACE("file len %u\n", This
->filesize
.u
.LowPart
);
134 *pLockBytes
= &This
->ILockBytes_iface
;
139 /* ILockByte Interfaces */
141 static HRESULT WINAPI
FileLockBytesImpl_QueryInterface(ILockBytes
*iface
, REFIID riid
,
144 if (IsEqualIID(riid
, &IID_ILockBytes
) || IsEqualIID(riid
, &IID_ILockBytes
))
149 return E_NOINTERFACE
;
152 IUnknown_AddRef((IUnknown
*)*ppvObject
);
157 static ULONG WINAPI
FileLockBytesImpl_AddRef(ILockBytes
*iface
)
159 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
160 return InterlockedIncrement(&This
->ref
);
163 static ULONG WINAPI
FileLockBytesImpl_Release(ILockBytes
*iface
)
165 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
168 ref
= InterlockedDecrement(&This
->ref
);
172 CloseHandle(This
->hfile
);
173 HeapFree(GetProcessHeap(), 0, This
->pwcsName
);
174 HeapFree(GetProcessHeap(), 0, This
);
180 /******************************************************************************
181 * This method is part of the ILockBytes interface.
183 * It reads a block of information from the byte array at the specified
186 * See the documentation of ILockBytes for more info.
188 static HRESULT WINAPI
FileLockBytesImpl_ReadAt(
190 ULARGE_INTEGER ulOffset
, /* [in] */
191 void* pv
, /* [length_is][size_is][out] */
193 ULONG
* pcbRead
) /* [out] */
195 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
196 ULONG bytes_left
= cb
;
199 LARGE_INTEGER offset
;
202 TRACE("(%p)-> %i %p %i %p\n",This
, ulOffset
.u
.LowPart
, pv
, cb
, pcbRead
);
204 /* verify a sane environment */
205 if (!This
) return E_FAIL
;
210 offset
.QuadPart
= ulOffset
.QuadPart
;
212 ret
= SetFilePointerEx(This
->hfile
, offset
, NULL
, FILE_BEGIN
);
215 return STG_E_READFAULT
;
219 ret
= ReadFile(This
->hfile
, readPtr
, bytes_left
, &cbRead
, NULL
);
221 if (!ret
|| cbRead
== 0)
222 return STG_E_READFAULT
;
227 bytes_left
-= cbRead
;
235 /******************************************************************************
236 * This method is part of the ILockBytes interface.
238 * It writes the specified bytes at the specified offset.
239 * position. If the file is too small, it will be resized.
241 * See the documentation of ILockBytes for more info.
243 static HRESULT WINAPI
FileLockBytesImpl_WriteAt(
245 ULARGE_INTEGER ulOffset
, /* [in] */
246 const void* pv
, /* [size_is][in] */
248 ULONG
* pcbWritten
) /* [out] */
250 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
251 ULONG size_needed
= ulOffset
.u
.LowPart
+ cb
;
252 ULONG bytes_left
= cb
;
253 const BYTE
*writePtr
= pv
;
255 LARGE_INTEGER offset
;
258 TRACE("(%p)-> %i %p %i %p\n",This
, ulOffset
.u
.LowPart
, pv
, cb
, pcbWritten
);
260 /* verify a sane environment */
261 if (!This
) return E_FAIL
;
263 if (This
->flProtect
!= PAGE_READWRITE
)
264 return STG_E_ACCESSDENIED
;
269 if (size_needed
> This
->filesize
.u
.LowPart
)
271 ULARGE_INTEGER newSize
;
272 newSize
.u
.HighPart
= 0;
273 newSize
.u
.LowPart
= size_needed
;
274 ILockBytes_SetSize(iface
, newSize
);
277 offset
.QuadPart
= ulOffset
.QuadPart
;
279 ret
= SetFilePointerEx(This
->hfile
, offset
, NULL
, FILE_BEGIN
);
282 return STG_E_READFAULT
;
286 ret
= WriteFile(This
->hfile
, writePtr
, bytes_left
, &cbWritten
, NULL
);
289 return STG_E_READFAULT
;
292 *pcbWritten
+= cbWritten
;
294 bytes_left
-= cbWritten
;
295 writePtr
+= cbWritten
;
302 static HRESULT WINAPI
FileLockBytesImpl_Flush(ILockBytes
* iface
)
307 /******************************************************************************
310 * Sets the size of the file.
313 static HRESULT WINAPI
FileLockBytesImpl_SetSize(ILockBytes
* iface
, ULARGE_INTEGER newSize
)
315 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
317 LARGE_INTEGER newpos
;
319 if (This
->filesize
.u
.LowPart
== newSize
.u
.LowPart
)
322 TRACE("from %u to %u\n", This
->filesize
.u
.LowPart
, newSize
.u
.LowPart
);
324 newpos
.QuadPart
= newSize
.QuadPart
;
325 if (SetFilePointerEx(This
->hfile
, newpos
, NULL
, FILE_BEGIN
))
327 SetEndOfFile(This
->hfile
);
330 This
->filesize
= newSize
;
334 static HRESULT WINAPI
FileLockBytesImpl_LockRegion(ILockBytes
* iface
,
335 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
341 static HRESULT WINAPI
FileLockBytesImpl_UnlockRegion(ILockBytes
* iface
,
342 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
348 static HRESULT WINAPI
FileLockBytesImpl_Stat(ILockBytes
* iface
,
349 STATSTG
*pstatstg
, DWORD grfStatFlag
)
351 FileLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
353 if (!(STATFLAG_NONAME
& grfStatFlag
) && This
->pwcsName
)
356 CoTaskMemAlloc((lstrlenW(This
->pwcsName
)+1)*sizeof(WCHAR
));
358 strcpyW(pstatstg
->pwcsName
, This
->pwcsName
);
361 pstatstg
->pwcsName
= NULL
;
363 pstatstg
->type
= STGTY_LOCKBYTES
;
364 pstatstg
->cbSize
= This
->filesize
;
365 /* FIXME: If the implementation is exported, we'll need to set other fields. */
370 static const ILockBytesVtbl FileLockBytesImpl_Vtbl
= {
371 FileLockBytesImpl_QueryInterface
,
372 FileLockBytesImpl_AddRef
,
373 FileLockBytesImpl_Release
,
374 FileLockBytesImpl_ReadAt
,
375 FileLockBytesImpl_WriteAt
,
376 FileLockBytesImpl_Flush
,
377 FileLockBytesImpl_SetSize
,
378 FileLockBytesImpl_LockRegion
,
379 FileLockBytesImpl_UnlockRegion
,
380 FileLockBytesImpl_Stat