wined3d: Use return type to return result from read_dword.
[wine.git] / dlls / ole32 / memlockbytes.c
blob12f014793593b8d9babd328dd6018d52a6f8c22d
1 /******************************************************************************
3 * Global memory implementation of ILockBytes.
5 * Copyright 1999 Thuy Nguyen
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
26 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "objbase.h"
31 #include "ole2.h"
32 #include "winerror.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 /******************************************************************************
39 * HGLOBALLockBytesImpl definition.
41 * This class implements the ILockBytes interface and represents a byte array
42 * object supported by an HGLOBAL pointer.
44 struct HGLOBALLockBytesImpl
46 ILockBytes ILockBytes_iface;
47 LONG ref;
50 * Support for the LockBytes object
52 HGLOBAL supportHandle;
55 * This flag is TRUE if the HGLOBAL is destroyed when the object
56 * is finally released.
58 BOOL deleteOnRelease;
61 * Helper variable that contains the size of the byte array
63 ULARGE_INTEGER byteArraySize;
66 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
68 static inline HGLOBALLockBytesImpl *impl_from_ILockBytes( ILockBytes *iface )
70 return CONTAINING_RECORD(iface, HGLOBALLockBytesImpl, ILockBytes_iface);
73 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl;
75 /******************************************************************************
76 * CreateILockBytesOnHGlobal [OLE32.@]
78 * Create a byte array object which is intended to be the compound file foundation.
79 * This object supports a COM implementation of the ILockBytes interface.
81 * PARAMS
82 * global [ I] Global memory handle
83 * delete_on_release [ I] Whether the handle should be freed when the object is released.
84 * ret [ O] Address of ILockBytes pointer that receives
85 * the interface pointer to the new byte array object.
87 * RETURNS
88 * Success: S_OK
90 * NOTES
91 * The supplied ILockBytes pointer can be used by the StgCreateDocfileOnILockBytes
92 * function to build a compound file on top of this byte array object.
93 * The ILockBytes interface instance calls the GlobalReAlloc function to grow
94 * the memory block as required.
96 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL global, BOOL delete_on_release, ILockBytes **ret)
98 HGLOBALLockBytesImpl* lockbytes;
100 lockbytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
101 if (!lockbytes) return E_OUTOFMEMORY;
103 lockbytes->ILockBytes_iface.lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
104 lockbytes->ref = 1;
107 * Initialize the support.
109 lockbytes->supportHandle = global;
110 lockbytes->deleteOnRelease = delete_on_release;
113 * This method will allocate a handle if one is not supplied.
115 if (lockbytes->supportHandle == 0)
116 lockbytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
119 * Initialize the size of the array to the size of the handle.
121 lockbytes->byteArraySize.HighPart = 0;
122 lockbytes->byteArraySize.LowPart = GlobalSize(lockbytes->supportHandle);
124 *ret = &lockbytes->ILockBytes_iface;
126 return S_OK;
129 /******************************************************************************
130 * GetHGlobalFromILockBytes [OLE32.@]
132 * Retrieve a global memory handle to a byte array object created
133 * using the CreateILockBytesOnHGlobal function.
135 * PARAMS
136 * plkbyt [ I] Pointer to the ILockBytes interface on byte array object
137 * phglobal [ O] Address to store a global memory handle
138 * RETURNS
139 * S_OK if *phglobal has a correct value
140 * E_INVALIDARG if any parameters are invalid
143 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* iface, HGLOBAL* phglobal)
145 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
146 STATSTG stbuf;
147 HRESULT hres;
148 ULARGE_INTEGER start;
149 ULONG xread;
151 *phglobal = 0;
152 if (This->ILockBytes_iface.lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
153 *phglobal = This->supportHandle;
154 if (*phglobal == 0)
155 return E_INVALIDARG;
156 return S_OK;
158 /* It is not our lockbytes implementation, so use a more generic way */
159 hres = ILockBytes_Stat(iface,&stbuf,STATFLAG_NONAME);
160 if (hres != S_OK) {
161 ERR("Cannot ILockBytes_Stat, %lx\n",hres);
162 return hres;
164 TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf.cbSize.QuadPart));
165 *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.LowPart);
166 if (!*phglobal)
167 return E_INVALIDARG;
168 memset(&start,0,sizeof(start));
169 hres = ILockBytes_ReadAt(iface, start, GlobalLock(*phglobal), stbuf.cbSize.LowPart, &xread);
170 GlobalUnlock(*phglobal);
171 if (hres != S_OK) {
172 FIXME("%p->ReadAt failed with %lx\n",iface,hres);
173 return hres;
175 if (stbuf.cbSize.LowPart != xread) {
176 FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.LowPart, xread);
178 return S_OK;
181 /******************************************************************************
183 * HGLOBALLockBytesImpl implementation
187 /******************************************************************************
188 * This implements the IUnknown method QueryInterface for this
189 * class
191 static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
192 ILockBytes* iface,
193 REFIID riid, /* [in] */
194 void** ppvObject) /* [iid_is][out] */
196 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
198 if (ppvObject==0)
199 return E_INVALIDARG;
201 *ppvObject = 0;
203 if (IsEqualIID(riid, &IID_IUnknown) ||
204 IsEqualIID(riid, &IID_ILockBytes))
206 *ppvObject = &This->ILockBytes_iface;
208 else
209 return E_NOINTERFACE;
211 ILockBytes_AddRef(iface);
213 return S_OK;
216 /******************************************************************************
217 * This implements the IUnknown method AddRef for this
218 * class
220 static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
222 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
223 return InterlockedIncrement(&This->ref);
226 /******************************************************************************
227 * This implements the IUnknown method Release for this
228 * class
230 static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
232 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
233 ULONG ref;
235 ref = InterlockedDecrement(&This->ref);
236 if (!ref)
238 if (This->deleteOnRelease)
240 GlobalFree(This->supportHandle);
241 This->supportHandle = 0;
243 HeapFree(GetProcessHeap(), 0, This);
246 return ref;
249 /******************************************************************************
250 * This method is part of the ILockBytes interface.
252 * It reads a block of information from the byte array at the specified
253 * offset.
255 * See the documentation of ILockBytes for more info.
257 static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
258 ILockBytes* iface,
259 ULARGE_INTEGER ulOffset, /* [in] */
260 void* pv, /* [length_is][size_is][out] */
261 ULONG cb, /* [in] */
262 ULONG* pcbRead) /* [out] */
264 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
266 void* supportBuffer;
267 ULONG bytesReadBuffer = 0;
268 ULONG bytesToReadFromBuffer;
271 * If the caller is not interested in the number of bytes read,
272 * we use another buffer to avoid "if" statements in the code.
274 if (pcbRead == 0)
275 pcbRead = &bytesReadBuffer;
278 * Make sure the offset is valid.
280 if (ulOffset.LowPart > This->byteArraySize.LowPart)
281 return E_FAIL;
284 * Using the known size of the array, calculate the number of bytes
285 * to read.
287 bytesToReadFromBuffer = min(This->byteArraySize.LowPart - ulOffset.LowPart, cb);
290 * Lock the buffer in position and copy the data.
292 supportBuffer = GlobalLock(This->supportHandle);
294 memcpy(pv,
295 (char *) supportBuffer + ulOffset.LowPart,
296 bytesToReadFromBuffer);
299 * Return the number of bytes read.
301 *pcbRead = bytesToReadFromBuffer;
304 * Cleanup
306 GlobalUnlock(This->supportHandle);
309 * The function returns S_OK if the specified number of bytes were read
310 * or the end of the array was reached.
311 * It returns STG_E_READFAULT if the number of bytes to read does not equal
312 * the number of bytes actually read.
314 if(*pcbRead == cb)
315 return S_OK;
317 return STG_E_READFAULT;
320 /******************************************************************************
321 * This method is part of the ILockBytes interface.
323 * It writes the specified bytes at the specified offset.
324 * position. If the array is too small, it will be resized.
326 * See the documentation of ILockBytes for more info.
328 static HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
329 ILockBytes* iface,
330 ULARGE_INTEGER ulOffset, /* [in] */
331 const void* pv, /* [size_is][in] */
332 ULONG cb, /* [in] */
333 ULONG* pcbWritten) /* [out] */
335 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
337 void* supportBuffer;
338 ULARGE_INTEGER newSize;
339 ULONG bytesWritten = 0;
342 * If the caller is not interested in the number of bytes written,
343 * we use another buffer to avoid "if" statements in the code.
345 if (pcbWritten == 0)
346 pcbWritten = &bytesWritten;
348 if (cb == 0)
350 return S_OK;
352 else
354 newSize.HighPart = 0;
355 newSize.LowPart = ulOffset.LowPart + cb;
359 * Verify if we need to grow the stream
361 if (newSize.LowPart > This->byteArraySize.LowPart)
363 /* grow stream */
364 if (ILockBytes_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
365 return STG_E_MEDIUMFULL;
369 * Lock the buffer in position and copy the data.
371 supportBuffer = GlobalLock(This->supportHandle);
373 memcpy((char *) supportBuffer + ulOffset.LowPart, pv, cb);
376 * Return the number of bytes written.
378 *pcbWritten = cb;
381 * Cleanup
383 GlobalUnlock(This->supportHandle);
385 return S_OK;
388 /******************************************************************************
389 * This method is part of the ILockBytes interface.
391 * See the documentation of ILockBytes for more info.
393 static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
395 return S_OK;
398 /******************************************************************************
399 * This method is part of the ILockBytes interface.
401 * It will change the size of the byte array.
403 * See the documentation of ILockBytes for more info.
405 static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
406 ILockBytes* iface,
407 ULARGE_INTEGER libNewSize) /* [in] */
409 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
410 HGLOBAL supportHandle;
413 * As documented.
415 if (libNewSize.HighPart != 0)
416 return STG_E_INVALIDFUNCTION;
418 if (This->byteArraySize.LowPart == libNewSize.LowPart)
419 return S_OK;
422 * Re allocate the HGlobal to fit the new size of the stream.
424 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.LowPart, GMEM_MOVEABLE);
426 if (supportHandle == 0)
427 return STG_E_MEDIUMFULL;
429 This->supportHandle = supportHandle;
430 This->byteArraySize.LowPart = libNewSize.LowPart;
432 return S_OK;
435 /******************************************************************************
436 * This method is part of the ILockBytes interface.
438 * The global memory implementation of ILockBytes does not support locking.
440 * See the documentation of ILockBytes for more info.
442 static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
443 ILockBytes* iface,
444 ULARGE_INTEGER libOffset, /* [in] */
445 ULARGE_INTEGER cb, /* [in] */
446 DWORD dwLockType) /* [in] */
448 return STG_E_INVALIDFUNCTION;
451 /******************************************************************************
452 * This method is part of the ILockBytes interface.
454 * The global memory implementation of ILockBytes does not support locking.
456 * See the documentation of ILockBytes for more info.
458 static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
459 ILockBytes* iface,
460 ULARGE_INTEGER libOffset, /* [in] */
461 ULARGE_INTEGER cb, /* [in] */
462 DWORD dwLockType) /* [in] */
464 return STG_E_INVALIDFUNCTION;
467 /******************************************************************************
468 * This method is part of the ILockBytes interface.
470 * This method returns information about the current
471 * byte array object.
473 * See the documentation of ILockBytes for more info.
475 static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
476 ILockBytes* iface,
477 STATSTG* pstatstg, /* [out] */
478 DWORD grfStatFlag) /* [in] */
480 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
482 memset(pstatstg, 0, sizeof(STATSTG));
484 pstatstg->pwcsName = NULL;
485 pstatstg->type = STGTY_LOCKBYTES;
486 pstatstg->cbSize = This->byteArraySize;
488 return S_OK;
492 * Virtual function table for the HGLOBALLockBytesImpl class.
494 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
496 HGLOBALLockBytesImpl_QueryInterface,
497 HGLOBALLockBytesImpl_AddRef,
498 HGLOBALLockBytesImpl_Release,
499 HGLOBALLockBytesImpl_ReadAt,
500 HGLOBALLockBytesImpl_WriteAt,
501 HGLOBALLockBytesImpl_Flush,
502 HGLOBALLockBytesImpl_SetSize,
503 HGLOBALLockBytesImpl_LockRegion,
504 HGLOBALLockBytesImpl_UnlockRegion,
505 HGLOBALLockBytesImpl_Stat,