Added support for WODM_BREAKLOOP message.
[wine.git] / dlls / ole32 / memlockbytes.c
blob410dc2f020dadf4f859bd9cf05469cb3623fa767
1 /******************************************************************************
3 * Global memory implementation of ILockBytes.
5 * Copyright 1999 Thuy Nguyen
7 */
9 #include <string.h>
10 #include "winbase.h"
11 #include "winerror.h"
12 #include "objbase.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(ole)
18 /******************************************************************************
19 * HGLOBALLockBytesImpl definition.
21 * This class imlements the ILockBytes inteface and represents a byte array
22 * object supported by an HGLOBAL pointer.
24 struct HGLOBALLockBytesImpl
27 * Needs to be the first item in the stuct
28 * since we want to cast this in an ILockBytes pointer
30 ICOM_VFIELD(ILockBytes);
33 * Reference count
35 ULONG ref;
38 * Support for the LockBytes object
40 HGLOBAL supportHandle;
43 * This flag is TRUE if the HGLOBAL is destroyed when the object
44 * is finally released.
46 BOOL deleteOnRelease;
49 * Helper variable that contains the size of the byte array
51 ULARGE_INTEGER byteArraySize;
54 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
57 * Method definition for the HGLOBALLockBytesImpl class.
59 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(
60 HGLOBAL hGlobal,
61 BOOL fDeleteOnRelease);
63 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This);
65 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
66 ILockBytes* iface,
67 REFIID riid, /* [in] */
68 void** ppvObject); /* [iid_is][out] */
70 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(
71 ILockBytes* iface);
73 ULONG WINAPI HGLOBALLockBytesImpl_Release(
74 ILockBytes* iface);
76 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
77 ILockBytes* iface,
78 ULARGE_INTEGER ulOffset, /* [in] */
79 void* pv, /* [length_is][size_is][out] */
80 ULONG cb, /* [in] */
81 ULONG* pcbRead); /* [out] */
83 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
84 ILockBytes* iface,
85 ULARGE_INTEGER ulOffset, /* [in] */
86 const void* pv, /* [size_is][in] */
87 ULONG cb, /* [in] */
88 ULONG* pcbWritten); /* [out] */
90 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(
91 ILockBytes* iface);
93 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
94 ILockBytes* iface,
95 ULARGE_INTEGER libNewSize); /* [in] */
97 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
98 ILockBytes* iface,
99 ULARGE_INTEGER libOffset, /* [in] */
100 ULARGE_INTEGER cb, /* [in] */
101 DWORD dwLockType); /* [in] */
103 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
104 ILockBytes* iface,
105 ULARGE_INTEGER libOffset, /* [in] */
106 ULARGE_INTEGER cb, /* [in] */
107 DWORD dwLockType); /* [in] */
109 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
110 ILockBytes* iface,
111 STATSTG* pstatstg, /* [out] */
112 DWORD grfStatFlag); /* [in] */
115 * Virtual function table for the HGLOBALLockBytesImpl class.
117 static ICOM_VTABLE(ILockBytes) HGLOBALLockBytesImpl_Vtbl =
119 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
120 HGLOBALLockBytesImpl_QueryInterface,
121 HGLOBALLockBytesImpl_AddRef,
122 HGLOBALLockBytesImpl_Release,
123 HGLOBALLockBytesImpl_ReadAt,
124 HGLOBALLockBytesImpl_WriteAt,
125 HGLOBALLockBytesImpl_Flush,
126 HGLOBALLockBytesImpl_SetSize,
127 HGLOBALLockBytesImpl_LockRegion,
128 HGLOBALLockBytesImpl_UnlockRegion,
129 HGLOBALLockBytesImpl_Stat,
132 /******************************************************************************
133 * CreateILockBytesOnHGlobal [OLE32.57]
135 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL hGlobal,
136 BOOL fDeleteOnRelease,
137 LPLOCKBYTES* ppLkbyt)
139 HGLOBALLockBytesImpl* newLockBytes;
141 newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease);
143 if (newLockBytes != NULL)
145 return IUnknown_QueryInterface((IUnknown*)newLockBytes,
146 &IID_ILockBytes,
147 (void**)ppLkbyt);
150 return E_OUTOFMEMORY;
153 /******************************************************************************
154 * GetHGlobalFromILockBytes [OLE32.70]
156 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal)
158 HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt;
160 if (ICOM_VTBL(pMemLockBytes) == &HGLOBALLockBytesImpl_Vtbl)
161 *phglobal = pMemLockBytes->supportHandle;
162 else
163 *phglobal = 0;
165 if (*phglobal == 0)
166 return E_INVALIDARG;
168 return S_OK;
171 /******************************************************************************
173 * HGLOBALLockBytesImpl implementation
177 /******************************************************************************
178 * This is the constructor for the HGLOBALLockBytesImpl class.
180 * Params:
181 * hGlobal - Handle that will support the stream. can be NULL.
182 * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
183 * when the IStream object is destroyed.
185 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal,
186 BOOL fDeleteOnRelease)
188 HGLOBALLockBytesImpl* newLockBytes;
189 newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
191 if (newLockBytes!=0)
194 * Set up the virtual function table and reference count.
196 ICOM_VTBL(newLockBytes) = &HGLOBALLockBytesImpl_Vtbl;
197 newLockBytes->ref = 0;
200 * Initialize the support.
202 newLockBytes->supportHandle = hGlobal;
203 newLockBytes->deleteOnRelease = fDeleteOnRelease;
206 * This method will allocate a handle if one is not supplied.
208 if (newLockBytes->supportHandle == 0)
210 newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE |
211 GMEM_NODISCARD,
216 * Initialize the size of the array to the size of the handle.
218 newLockBytes->byteArraySize.s.HighPart = 0;
219 newLockBytes->byteArraySize.s.LowPart = GlobalSize(
220 newLockBytes->supportHandle);
223 return newLockBytes;
226 /******************************************************************************
227 * This is the destructor of the HGLOBALStreamImpl class.
229 * This method will clean-up all the resources used-up by the given
230 * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be
231 * freed and will not be valid anymore.
233 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This)
236 * Release the HGlobal if the constructor asked for that.
238 if (This->deleteOnRelease)
240 GlobalFree(This->supportHandle);
241 This->supportHandle = 0;
245 * Finally, free the memory used-up by the class.
247 HeapFree(GetProcessHeap(), 0, This);
250 /******************************************************************************
251 * This implements the IUnknown method QueryInterface for this
252 * class
254 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
255 ILockBytes* iface,
256 REFIID riid, /* [in] */
257 void** ppvObject) /* [iid_is][out] */
259 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
262 * Perform a sanity check on the parameters.
264 if (ppvObject==0)
265 return E_INVALIDARG;
268 * Initialize the return parameter.
270 *ppvObject = 0;
273 * Compare the riid with the interface IDs implemented by this object.
275 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
277 *ppvObject = (ILockBytes*)This;
279 else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
281 *ppvObject = (ILockBytes*)This;
285 * Check that we obtained an interface.
287 if ((*ppvObject)==0)
288 return E_NOINTERFACE;
291 * Query Interface always increases the reference count by one when it is
292 * successful
294 HGLOBALLockBytesImpl_AddRef(iface);
296 return S_OK;;
299 /******************************************************************************
300 * This implements the IUnknown method AddRef for this
301 * class
303 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
305 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
307 This->ref++;
309 return This->ref;
312 /******************************************************************************
313 * This implements the IUnknown method Release for this
314 * class
316 ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
318 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
320 ULONG newRef;
322 This->ref--;
324 newRef = This->ref;
327 * If the reference count goes down to 0, perform suicide.
329 if (newRef==0)
331 HGLOBALLockBytesImpl_Destroy(This);
334 return newRef;
337 /******************************************************************************
338 * This method is part of the ILockBytes interface.
340 * It reads a block of information from the byte array at the specified
341 * offset.
343 * See the documentation of ILockBytes for more info.
345 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
346 ILockBytes* iface,
347 ULARGE_INTEGER ulOffset, /* [in] */
348 void* pv, /* [length_is][size_is][out] */
349 ULONG cb, /* [in] */
350 ULONG* pcbRead) /* [out] */
352 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
354 void* supportBuffer;
355 ULONG bytesReadBuffer = 0;
356 ULONG bytesToReadFromBuffer;
359 * If the caller is not interested in the number of bytes read,
360 * we use another buffer to avoid "if" statements in the code.
362 if (pcbRead == 0)
363 pcbRead = &bytesReadBuffer;
366 * Make sure the offset is valid.
368 if (ulOffset.s.LowPart > This->byteArraySize.s.LowPart)
369 return E_FAIL;
372 * Using the known size of the array, calculate the number of bytes
373 * to read.
375 bytesToReadFromBuffer = MIN(This->byteArraySize.s.LowPart -
376 ulOffset.s.LowPart, cb);
379 * Lock the buffer in position and copy the data.
381 supportBuffer = GlobalLock(This->supportHandle);
383 memcpy(pv,
384 (char *) supportBuffer + ulOffset.s.LowPart,
385 bytesToReadFromBuffer);
388 * Return the number of bytes read.
390 *pcbRead = bytesToReadFromBuffer;
393 * Cleanup
395 GlobalUnlock(This->supportHandle);
398 * The function returns S_OK if the specified number of bytes were read
399 * or the end of the array was reached.
400 * It returns STG_E_READFAULT if the number of bytes to read does not equal
401 * the number of bytes actually read.
403 if(*pcbRead == cb)
404 return S_OK;
406 return STG_E_READFAULT;
409 /******************************************************************************
410 * This method is part of the ILockBytes interface.
412 * It writes the specified bytes at the specified offset.
413 * position. If the array is too small, it will be resized.
415 * See the documentation of ILockBytes for more info.
417 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
418 ILockBytes* iface,
419 ULARGE_INTEGER ulOffset, /* [in] */
420 const void* pv, /* [size_is][in] */
421 ULONG cb, /* [in] */
422 ULONG* pcbWritten) /* [out] */
424 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
426 void* supportBuffer;
427 ULARGE_INTEGER newSize;
428 ULONG bytesWritten = 0;
431 * If the caller is not interested in the number of bytes written,
432 * we use another buffer to avoid "if" statements in the code.
434 if (pcbWritten == 0)
435 pcbWritten = &bytesWritten;
437 if (cb == 0)
439 return S_OK;
441 else
443 newSize.s.HighPart = 0;
444 newSize.s.LowPart = ulOffset.s.LowPart + cb;
448 * Verify if we need to grow the stream
450 if (newSize.s.LowPart > This->byteArraySize.s.LowPart)
452 /* grow stream */
453 if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
454 return STG_E_MEDIUMFULL;
458 * Lock the buffer in position and copy the data.
460 supportBuffer = GlobalLock(This->supportHandle);
462 memcpy((char *) supportBuffer + ulOffset.s.LowPart, pv, cb);
465 * Return the number of bytes written.
467 *pcbWritten = cb;
470 * Cleanup
472 GlobalUnlock(This->supportHandle);
474 return S_OK;
477 /******************************************************************************
478 * This method is part of the ILockBytes interface.
480 * See the documentation of ILockBytes for more info.
482 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
484 return S_OK;
487 /******************************************************************************
488 * This method is part of the ILockBytes interface.
490 * It will change the size of the byte array.
492 * See the documentation of ILockBytes for more info.
494 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
495 ILockBytes* iface,
496 ULARGE_INTEGER libNewSize) /* [in] */
498 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
501 * As documented.
503 if (libNewSize.s.HighPart != 0)
504 return STG_E_INVALIDFUNCTION;
506 if (This->byteArraySize.s.LowPart == libNewSize.s.LowPart)
507 return S_OK;
510 * Re allocate the HGlobal to fit the new size of the stream.
512 This->supportHandle = GlobalReAlloc(This->supportHandle,
513 libNewSize.s.LowPart,
516 if (This->supportHandle == 0)
517 return STG_E_MEDIUMFULL;
519 This->byteArraySize.s.LowPart = libNewSize.s.LowPart;
521 return S_OK;
524 /******************************************************************************
525 * This method is part of the ILockBytes interface.
527 * The global memory implementation of ILockBytes does not support locking.
529 * See the documentation of ILockBytes for more info.
531 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
532 ILockBytes* iface,
533 ULARGE_INTEGER libOffset, /* [in] */
534 ULARGE_INTEGER cb, /* [in] */
535 DWORD dwLockType) /* [in] */
537 return STG_E_INVALIDFUNCTION;
540 /******************************************************************************
541 * This method is part of the ILockBytes interface.
543 * The global memory implementation of ILockBytes does not support locking.
545 * See the documentation of ILockBytes for more info.
547 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
548 ILockBytes* iface,
549 ULARGE_INTEGER libOffset, /* [in] */
550 ULARGE_INTEGER cb, /* [in] */
551 DWORD dwLockType) /* [in] */
553 return STG_E_INVALIDFUNCTION;
556 /******************************************************************************
557 * This method is part of the ILockBytes interface.
559 * This method returns information about the current
560 * byte array object.
562 * See the documentation of ILockBytes for more info.
564 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
565 ILockBytes* iface,
566 STATSTG* pstatstg, /* [out] */
567 DWORD grfStatFlag) /* [in] */
569 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
571 memset(pstatstg, 0, sizeof(STATSTG));
573 pstatstg->pwcsName = NULL;
574 pstatstg->type = STGTY_LOCKBYTES;
575 pstatstg->cbSize = This->byteArraySize;
577 return S_OK;