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
27 #define NONAMELESSUNION
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
40 /******************************************************************************
41 * HGLOBALLockBytesImpl definition.
43 * This class implements the ILockBytes interface and represents a byte array
44 * object supported by an HGLOBAL pointer.
46 struct HGLOBALLockBytesImpl
48 ILockBytes ILockBytes_iface
;
52 * Support for the LockBytes object
54 HGLOBAL supportHandle
;
57 * This flag is TRUE if the HGLOBAL is destroyed when the object
58 * is finally released.
63 * Helper variable that contains the size of the byte array
65 ULARGE_INTEGER byteArraySize
;
68 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl
;
70 static inline HGLOBALLockBytesImpl
*impl_from_ILockBytes( ILockBytes
*iface
)
72 return CONTAINING_RECORD(iface
, HGLOBALLockBytesImpl
, ILockBytes_iface
);
75 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl
;
77 /******************************************************************************
78 * CreateILockBytesOnHGlobal [OLE32.@]
80 * Create a byte array object which is intended to be the compound file foundation.
81 * This object supports a COM implementation of the ILockBytes interface.
84 * global [ I] Global memory handle
85 * delete_on_release [ I] Whether the handle should be freed when the object is released.
86 * ret [ O] Address of ILockBytes pointer that receives
87 * the interface pointer to the new byte array object.
93 * The supplied ILockBytes pointer can be used by the StgCreateDocfileOnILockBytes
94 * function to build a compound file on top of this byte array object.
95 * The ILockBytes interface instance calls the GlobalReAlloc function to grow
96 * the memory block as required.
98 HRESULT WINAPI
CreateILockBytesOnHGlobal(HGLOBAL global
, BOOL delete_on_release
, ILockBytes
**ret
)
100 HGLOBALLockBytesImpl
* lockbytes
;
102 lockbytes
= HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl
));
103 if (!lockbytes
) return E_OUTOFMEMORY
;
105 lockbytes
->ILockBytes_iface
.lpVtbl
= &HGLOBALLockBytesImpl_Vtbl
;
109 * Initialize the support.
111 lockbytes
->supportHandle
= global
;
112 lockbytes
->deleteOnRelease
= delete_on_release
;
115 * This method will allocate a handle if one is not supplied.
117 if (lockbytes
->supportHandle
== 0)
118 lockbytes
->supportHandle
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_NODISCARD
, 0);
121 * Initialize the size of the array to the size of the handle.
123 lockbytes
->byteArraySize
.u
.HighPart
= 0;
124 lockbytes
->byteArraySize
.u
.LowPart
= GlobalSize(lockbytes
->supportHandle
);
126 *ret
= &lockbytes
->ILockBytes_iface
;
131 /******************************************************************************
132 * GetHGlobalFromILockBytes [OLE32.@]
134 * Retrieve a global memory handle to a byte array object created
135 * using the CreateILockBytesOnHGlobal function.
138 * plkbyt [ I] Pointer to the ILockBytes interface on byte array object
139 * phglobal [ O] Address to store a global memory handle
141 * S_OK if *phglobal has a correct value
142 * E_INVALIDARG if any parameters are invalid
145 HRESULT WINAPI
GetHGlobalFromILockBytes(ILockBytes
* iface
, HGLOBAL
* phglobal
)
147 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
150 ULARGE_INTEGER start
;
154 if (This
->ILockBytes_iface
.lpVtbl
== &HGLOBALLockBytesImpl_Vtbl
) {
155 *phglobal
= This
->supportHandle
;
160 /* It is not our lockbytes implementation, so use a more generic way */
161 hres
= ILockBytes_Stat(iface
,&stbuf
,STATFLAG_NONAME
);
163 ERR("Cannot ILockBytes_Stat, %x\n",hres
);
166 TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf
.cbSize
.QuadPart
));
167 *phglobal
= GlobalAlloc( GMEM_MOVEABLE
|GMEM_SHARE
, stbuf
.cbSize
.u
.LowPart
);
170 memset(&start
,0,sizeof(start
));
171 hres
= ILockBytes_ReadAt(iface
, start
, GlobalLock(*phglobal
), stbuf
.cbSize
.u
.LowPart
, &xread
);
172 GlobalUnlock(*phglobal
);
174 FIXME("%p->ReadAt failed with %x\n",iface
,hres
);
177 if (stbuf
.cbSize
.u
.LowPart
!= xread
) {
178 FIXME("Read size is not requested size %d vs %d?\n",stbuf
.cbSize
.u
.LowPart
, xread
);
183 /******************************************************************************
185 * HGLOBALLockBytesImpl implementation
189 /******************************************************************************
190 * This implements the IUnknown method QueryInterface for this
193 static HRESULT WINAPI
HGLOBALLockBytesImpl_QueryInterface(
195 REFIID riid
, /* [in] */
196 void** ppvObject
) /* [iid_is][out] */
198 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
205 if (IsEqualIID(riid
, &IID_IUnknown
) ||
206 IsEqualIID(riid
, &IID_ILockBytes
))
208 *ppvObject
= &This
->ILockBytes_iface
;
211 return E_NOINTERFACE
;
213 ILockBytes_AddRef(iface
);
218 /******************************************************************************
219 * This implements the IUnknown method AddRef for this
222 static ULONG WINAPI
HGLOBALLockBytesImpl_AddRef(ILockBytes
* iface
)
224 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
225 return InterlockedIncrement(&This
->ref
);
228 /******************************************************************************
229 * This implements the IUnknown method Release for this
232 static ULONG WINAPI
HGLOBALLockBytesImpl_Release(ILockBytes
* iface
)
234 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
237 ref
= InterlockedDecrement(&This
->ref
);
240 if (This
->deleteOnRelease
)
242 GlobalFree(This
->supportHandle
);
243 This
->supportHandle
= 0;
245 HeapFree(GetProcessHeap(), 0, This
);
251 /******************************************************************************
252 * This method is part of the ILockBytes interface.
254 * It reads a block of information from the byte array at the specified
257 * See the documentation of ILockBytes for more info.
259 static HRESULT WINAPI
HGLOBALLockBytesImpl_ReadAt(
261 ULARGE_INTEGER ulOffset
, /* [in] */
262 void* pv
, /* [length_is][size_is][out] */
264 ULONG
* pcbRead
) /* [out] */
266 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
269 ULONG bytesReadBuffer
= 0;
270 ULONG bytesToReadFromBuffer
;
273 * If the caller is not interested in the number of bytes read,
274 * we use another buffer to avoid "if" statements in the code.
277 pcbRead
= &bytesReadBuffer
;
280 * Make sure the offset is valid.
282 if (ulOffset
.u
.LowPart
> This
->byteArraySize
.u
.LowPart
)
286 * Using the known size of the array, calculate the number of bytes
289 bytesToReadFromBuffer
= min(This
->byteArraySize
.u
.LowPart
-
290 ulOffset
.u
.LowPart
, cb
);
293 * Lock the buffer in position and copy the data.
295 supportBuffer
= GlobalLock(This
->supportHandle
);
298 (char *) supportBuffer
+ ulOffset
.u
.LowPart
,
299 bytesToReadFromBuffer
);
302 * Return the number of bytes read.
304 *pcbRead
= bytesToReadFromBuffer
;
309 GlobalUnlock(This
->supportHandle
);
312 * The function returns S_OK if the specified number of bytes were read
313 * or the end of the array was reached.
314 * It returns STG_E_READFAULT if the number of bytes to read does not equal
315 * the number of bytes actually read.
320 return STG_E_READFAULT
;
323 /******************************************************************************
324 * This method is part of the ILockBytes interface.
326 * It writes the specified bytes at the specified offset.
327 * position. If the array is too small, it will be resized.
329 * See the documentation of ILockBytes for more info.
331 static HRESULT WINAPI
HGLOBALLockBytesImpl_WriteAt(
333 ULARGE_INTEGER ulOffset
, /* [in] */
334 const void* pv
, /* [size_is][in] */
336 ULONG
* pcbWritten
) /* [out] */
338 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
341 ULARGE_INTEGER newSize
;
342 ULONG bytesWritten
= 0;
345 * If the caller is not interested in the number of bytes written,
346 * we use another buffer to avoid "if" statements in the code.
349 pcbWritten
= &bytesWritten
;
357 newSize
.u
.HighPart
= 0;
358 newSize
.u
.LowPart
= ulOffset
.u
.LowPart
+ cb
;
362 * Verify if we need to grow the stream
364 if (newSize
.u
.LowPart
> This
->byteArraySize
.u
.LowPart
)
367 if (ILockBytes_SetSize(iface
, newSize
) == STG_E_MEDIUMFULL
)
368 return STG_E_MEDIUMFULL
;
372 * Lock the buffer in position and copy the data.
374 supportBuffer
= GlobalLock(This
->supportHandle
);
376 memcpy((char *) supportBuffer
+ ulOffset
.u
.LowPart
, pv
, cb
);
379 * Return the number of bytes written.
386 GlobalUnlock(This
->supportHandle
);
391 /******************************************************************************
392 * This method is part of the ILockBytes interface.
394 * See the documentation of ILockBytes for more info.
396 static HRESULT WINAPI
HGLOBALLockBytesImpl_Flush(ILockBytes
* iface
)
401 /******************************************************************************
402 * This method is part of the ILockBytes interface.
404 * It will change the size of the byte array.
406 * See the documentation of ILockBytes for more info.
408 static HRESULT WINAPI
HGLOBALLockBytesImpl_SetSize(
410 ULARGE_INTEGER libNewSize
) /* [in] */
412 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
413 HGLOBAL supportHandle
;
418 if (libNewSize
.u
.HighPart
!= 0)
419 return STG_E_INVALIDFUNCTION
;
421 if (This
->byteArraySize
.u
.LowPart
== libNewSize
.u
.LowPart
)
425 * Re allocate the HGlobal to fit the new size of the stream.
427 supportHandle
= GlobalReAlloc(This
->supportHandle
, libNewSize
.u
.LowPart
, 0);
429 if (supportHandle
== 0)
430 return STG_E_MEDIUMFULL
;
432 This
->supportHandle
= supportHandle
;
433 This
->byteArraySize
.u
.LowPart
= libNewSize
.u
.LowPart
;
438 /******************************************************************************
439 * This method is part of the ILockBytes interface.
441 * The global memory implementation of ILockBytes does not support locking.
443 * See the documentation of ILockBytes for more info.
445 static HRESULT WINAPI
HGLOBALLockBytesImpl_LockRegion(
447 ULARGE_INTEGER libOffset
, /* [in] */
448 ULARGE_INTEGER cb
, /* [in] */
449 DWORD dwLockType
) /* [in] */
451 return STG_E_INVALIDFUNCTION
;
454 /******************************************************************************
455 * This method is part of the ILockBytes interface.
457 * The global memory implementation of ILockBytes does not support locking.
459 * See the documentation of ILockBytes for more info.
461 static HRESULT WINAPI
HGLOBALLockBytesImpl_UnlockRegion(
463 ULARGE_INTEGER libOffset
, /* [in] */
464 ULARGE_INTEGER cb
, /* [in] */
465 DWORD dwLockType
) /* [in] */
467 return STG_E_INVALIDFUNCTION
;
470 /******************************************************************************
471 * This method is part of the ILockBytes interface.
473 * This method returns information about the current
476 * See the documentation of ILockBytes for more info.
478 static HRESULT WINAPI
HGLOBALLockBytesImpl_Stat(
480 STATSTG
* pstatstg
, /* [out] */
481 DWORD grfStatFlag
) /* [in] */
483 HGLOBALLockBytesImpl
* This
= impl_from_ILockBytes(iface
);
485 memset(pstatstg
, 0, sizeof(STATSTG
));
487 pstatstg
->pwcsName
= NULL
;
488 pstatstg
->type
= STGTY_LOCKBYTES
;
489 pstatstg
->cbSize
= This
->byteArraySize
;
495 * Virtual function table for the HGLOBALLockBytesImpl class.
497 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl
=
499 HGLOBALLockBytesImpl_QueryInterface
,
500 HGLOBALLockBytesImpl_AddRef
,
501 HGLOBALLockBytesImpl_Release
,
502 HGLOBALLockBytesImpl_ReadAt
,
503 HGLOBALLockBytesImpl_WriteAt
,
504 HGLOBALLockBytesImpl_Flush
,
505 HGLOBALLockBytesImpl_SetSize
,
506 HGLOBALLockBytesImpl_LockRegion
,
507 HGLOBALLockBytesImpl_UnlockRegion
,
508 HGLOBALLockBytesImpl_Stat
,