winaspi.dll16: Simplify the "pointer to start of array" idiom.
[wine/multimedia.git] / dlls / ole32 / memlockbytes.c
blob81d3b32ab2b4648e5bba7aa1296e406a2b32c1e6
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 "config.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
28 #define COBJMACROS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "objbase.h"
36 #include "ole2.h"
37 #include "winerror.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43 /******************************************************************************
44 * HGLOBALLockBytesImpl definition.
46 * This class implements the ILockBytes interface and represents a byte array
47 * object supported by an HGLOBAL pointer.
49 struct HGLOBALLockBytesImpl
51 ILockBytes ILockBytes_iface;
52 LONG ref;
55 * Support for the LockBytes object
57 HGLOBAL supportHandle;
60 * This flag is TRUE if the HGLOBAL is destroyed when the object
61 * is finally released.
63 BOOL deleteOnRelease;
66 * Helper variable that contains the size of the byte array
68 ULARGE_INTEGER byteArraySize;
71 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
73 static inline HGLOBALLockBytesImpl *impl_from_ILockBytes( ILockBytes *iface )
75 return CONTAINING_RECORD(iface, HGLOBALLockBytesImpl, ILockBytes_iface);
78 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl;
80 /******************************************************************************
81 * CreateILockBytesOnHGlobal [OLE32.@]
83 * Create a byte array object which is intended to be the compound file foundation.
84 * This object supports a COM implementation of the ILockBytes interface.
86 * PARAMS
87 * global [ I] Global memory handle
88 * delete_on_release [ I] Whether the handle should be freed when the object is released.
89 * ret [ O] Address of ILockBytes pointer that receives
90 * the interface pointer to the new byte array object.
92 * RETURNS
93 * Success: S_OK
95 * NOTES
96 * The supplied ILockBytes pointer can be used by the StgCreateDocfileOnILockBytes
97 * function to build a compound file on top of this byte array object.
98 * The ILockBytes interface instance calls the GlobalReAlloc function to grow
99 * the memory block as required.
101 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL global, BOOL delete_on_release, ILockBytes **ret)
103 HGLOBALLockBytesImpl* lockbytes;
105 lockbytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
106 if (!lockbytes) return E_OUTOFMEMORY;
108 lockbytes->ILockBytes_iface.lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
109 lockbytes->ref = 1;
112 * Initialize the support.
114 lockbytes->supportHandle = global;
115 lockbytes->deleteOnRelease = delete_on_release;
118 * This method will allocate a handle if one is not supplied.
120 if (lockbytes->supportHandle == 0)
121 lockbytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
124 * Initialize the size of the array to the size of the handle.
126 lockbytes->byteArraySize.u.HighPart = 0;
127 lockbytes->byteArraySize.u.LowPart = GlobalSize(lockbytes->supportHandle);
129 *ret = &lockbytes->ILockBytes_iface;
131 return S_OK;
134 /******************************************************************************
135 * GetHGlobalFromILockBytes [OLE32.@]
137 * Retrieve a global memory handle to a byte array object created
138 * using the CreateILockBytesOnHGlobal function.
140 * PARAMS
141 * plkbyt [ I] Pointer to the ILockBytes interface on byte array object
142 * phglobal [ O] Address to store a global memory handle
143 * RETURNS
144 * S_OK if *phglobal has a correct value
145 * E_INVALIDARG if any parameters are invalid
148 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* iface, HGLOBAL* phglobal)
150 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
151 STATSTG stbuf;
152 HRESULT hres;
153 ULARGE_INTEGER start;
154 ULONG xread;
156 *phglobal = 0;
157 if (This->ILockBytes_iface.lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
158 *phglobal = This->supportHandle;
159 if (*phglobal == 0)
160 return E_INVALIDARG;
161 return S_OK;
163 /* It is not our lockbytes implementation, so use a more generic way */
164 hres = ILockBytes_Stat(iface,&stbuf,STATFLAG_NONAME);
165 if (hres != S_OK) {
166 ERR("Cannot ILockBytes_Stat, %x\n",hres);
167 return hres;
169 TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf.cbSize.QuadPart));
170 *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart);
171 if (!*phglobal)
172 return E_INVALIDARG;
173 memset(&start,0,sizeof(start));
174 hres = ILockBytes_ReadAt(iface, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread);
175 GlobalUnlock(*phglobal);
176 if (hres != S_OK) {
177 FIXME("%p->ReadAt failed with %x\n",iface,hres);
178 return hres;
180 if (stbuf.cbSize.u.LowPart != xread) {
181 FIXME("Read size is not requested size %d vs %d?\n",stbuf.cbSize.u.LowPart, xread);
183 return S_OK;
186 /******************************************************************************
188 * HGLOBALLockBytesImpl implementation
192 /******************************************************************************
193 * This implements the IUnknown method QueryInterface for this
194 * class
196 static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
197 ILockBytes* iface,
198 REFIID riid, /* [in] */
199 void** ppvObject) /* [iid_is][out] */
201 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
203 if (ppvObject==0)
204 return E_INVALIDARG;
206 *ppvObject = 0;
208 if (IsEqualIID(riid, &IID_IUnknown) ||
209 IsEqualIID(riid, &IID_ILockBytes))
211 *ppvObject = &This->ILockBytes_iface;
213 else
214 return E_NOINTERFACE;
216 ILockBytes_AddRef(iface);
218 return S_OK;
221 /******************************************************************************
222 * This implements the IUnknown method AddRef for this
223 * class
225 static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
227 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
228 return InterlockedIncrement(&This->ref);
231 /******************************************************************************
232 * This implements the IUnknown method Release for this
233 * class
235 static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
237 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
238 ULONG ref;
240 ref = InterlockedDecrement(&This->ref);
241 if (!ref)
243 if (This->deleteOnRelease)
245 GlobalFree(This->supportHandle);
246 This->supportHandle = 0;
248 HeapFree(GetProcessHeap(), 0, This);
251 return ref;
254 /******************************************************************************
255 * This method is part of the ILockBytes interface.
257 * It reads a block of information from the byte array at the specified
258 * offset.
260 * See the documentation of ILockBytes for more info.
262 static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
263 ILockBytes* iface,
264 ULARGE_INTEGER ulOffset, /* [in] */
265 void* pv, /* [length_is][size_is][out] */
266 ULONG cb, /* [in] */
267 ULONG* pcbRead) /* [out] */
269 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
271 void* supportBuffer;
272 ULONG bytesReadBuffer = 0;
273 ULONG bytesToReadFromBuffer;
276 * If the caller is not interested in the number of bytes read,
277 * we use another buffer to avoid "if" statements in the code.
279 if (pcbRead == 0)
280 pcbRead = &bytesReadBuffer;
283 * Make sure the offset is valid.
285 if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
286 return E_FAIL;
289 * Using the known size of the array, calculate the number of bytes
290 * to read.
292 bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart -
293 ulOffset.u.LowPart, cb);
296 * Lock the buffer in position and copy the data.
298 supportBuffer = GlobalLock(This->supportHandle);
300 memcpy(pv,
301 (char *) supportBuffer + ulOffset.u.LowPart,
302 bytesToReadFromBuffer);
305 * Return the number of bytes read.
307 *pcbRead = bytesToReadFromBuffer;
310 * Cleanup
312 GlobalUnlock(This->supportHandle);
315 * The function returns S_OK if the specified number of bytes were read
316 * or the end of the array was reached.
317 * It returns STG_E_READFAULT if the number of bytes to read does not equal
318 * the number of bytes actually read.
320 if(*pcbRead == cb)
321 return S_OK;
323 return STG_E_READFAULT;
326 /******************************************************************************
327 * This method is part of the ILockBytes interface.
329 * It writes the specified bytes at the specified offset.
330 * position. If the array is too small, it will be resized.
332 * See the documentation of ILockBytes for more info.
334 static HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
335 ILockBytes* iface,
336 ULARGE_INTEGER ulOffset, /* [in] */
337 const void* pv, /* [size_is][in] */
338 ULONG cb, /* [in] */
339 ULONG* pcbWritten) /* [out] */
341 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
343 void* supportBuffer;
344 ULARGE_INTEGER newSize;
345 ULONG bytesWritten = 0;
348 * If the caller is not interested in the number of bytes written,
349 * we use another buffer to avoid "if" statements in the code.
351 if (pcbWritten == 0)
352 pcbWritten = &bytesWritten;
354 if (cb == 0)
356 return S_OK;
358 else
360 newSize.u.HighPart = 0;
361 newSize.u.LowPart = ulOffset.u.LowPart + cb;
365 * Verify if we need to grow the stream
367 if (newSize.u.LowPart > This->byteArraySize.u.LowPart)
369 /* grow stream */
370 if (ILockBytes_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
371 return STG_E_MEDIUMFULL;
375 * Lock the buffer in position and copy the data.
377 supportBuffer = GlobalLock(This->supportHandle);
379 memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb);
382 * Return the number of bytes written.
384 *pcbWritten = cb;
387 * Cleanup
389 GlobalUnlock(This->supportHandle);
391 return S_OK;
394 /******************************************************************************
395 * This method is part of the ILockBytes interface.
397 * See the documentation of ILockBytes for more info.
399 static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
401 return S_OK;
404 /******************************************************************************
405 * This method is part of the ILockBytes interface.
407 * It will change the size of the byte array.
409 * See the documentation of ILockBytes for more info.
411 static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
412 ILockBytes* iface,
413 ULARGE_INTEGER libNewSize) /* [in] */
415 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
416 HGLOBAL supportHandle;
419 * As documented.
421 if (libNewSize.u.HighPart != 0)
422 return STG_E_INVALIDFUNCTION;
424 if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
425 return S_OK;
428 * Re allocate the HGlobal to fit the new size of the stream.
430 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
432 if (supportHandle == 0)
433 return STG_E_MEDIUMFULL;
435 This->supportHandle = supportHandle;
436 This->byteArraySize.u.LowPart = libNewSize.u.LowPart;
438 return S_OK;
441 /******************************************************************************
442 * This method is part of the ILockBytes interface.
444 * The global memory implementation of ILockBytes does not support locking.
446 * See the documentation of ILockBytes for more info.
448 static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
449 ILockBytes* iface,
450 ULARGE_INTEGER libOffset, /* [in] */
451 ULARGE_INTEGER cb, /* [in] */
452 DWORD dwLockType) /* [in] */
454 return STG_E_INVALIDFUNCTION;
457 /******************************************************************************
458 * This method is part of the ILockBytes interface.
460 * The global memory implementation of ILockBytes does not support locking.
462 * See the documentation of ILockBytes for more info.
464 static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
465 ILockBytes* iface,
466 ULARGE_INTEGER libOffset, /* [in] */
467 ULARGE_INTEGER cb, /* [in] */
468 DWORD dwLockType) /* [in] */
470 return STG_E_INVALIDFUNCTION;
473 /******************************************************************************
474 * This method is part of the ILockBytes interface.
476 * This method returns information about the current
477 * byte array object.
479 * See the documentation of ILockBytes for more info.
481 static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
482 ILockBytes* iface,
483 STATSTG* pstatstg, /* [out] */
484 DWORD grfStatFlag) /* [in] */
486 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
488 memset(pstatstg, 0, sizeof(STATSTG));
490 pstatstg->pwcsName = NULL;
491 pstatstg->type = STGTY_LOCKBYTES;
492 pstatstg->cbSize = This->byteArraySize;
494 return S_OK;
498 * Virtual function table for the HGLOBALLockBytesImpl class.
500 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
502 HGLOBALLockBytesImpl_QueryInterface,
503 HGLOBALLockBytesImpl_AddRef,
504 HGLOBALLockBytesImpl_Release,
505 HGLOBALLockBytesImpl_ReadAt,
506 HGLOBALLockBytesImpl_WriteAt,
507 HGLOBALLockBytesImpl_Flush,
508 HGLOBALLockBytesImpl_SetSize,
509 HGLOBALLockBytesImpl_LockRegion,
510 HGLOBALLockBytesImpl_UnlockRegion,
511 HGLOBALLockBytesImpl_Stat,