2 * Global memory implementation of ILockBytes.
4 * Copyright 1999 Thuy Nguyen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
29 #include "wine/winbase16.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41 /******************************************************************************
42 * HGLOBALLockBytesImpl16 definition.
44 * This class imlements the ILockBytes inteface and represents a byte array
45 * object supported by an HGLOBAL pointer.
47 struct HGLOBALLockBytesImpl16
50 * Needs to be the first item in the stuct
51 * since we want to cast this in an ILockBytes pointer
53 ICOM_VFIELD(ILockBytes16);
57 * Support for the LockBytes object
59 HGLOBAL16 supportHandle;
62 * This flag is TRUE if the HGLOBAL is destroyed when the object
63 * is finally released.
67 * Helper variable that contains the size of the byte array
69 ULARGE_INTEGER byteArraySize;
72 typedef struct HGLOBALLockBytesImpl16 HGLOBALLockBytesImpl16;
74 HGLOBALLockBytesImpl16* HGLOBALLockBytesImpl16_Construct(
76 BOOL16 fDeleteOnRelease);
78 void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This);
80 HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface(
82 REFIID riid, /* [in] */
83 void** ppvObject); /* [iid_is][out] */
85 ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(
88 ULONG WINAPI HGLOBALLockBytesImpl16_Release(
91 HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt(
93 ULARGE_INTEGER ulOffset, /* [in] */
94 void* pv, /* [length_is][size_is][out] */
96 ULONG* pcbRead); /* [out] */
98 HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt(
100 ULARGE_INTEGER ulOffset, /* [in] */
101 const void* pv, /* [size_is][in] */
103 ULONG* pcbWritten); /* [out] */
105 HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(
106 ILockBytes16* iface);
108 HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize(
110 ULARGE_INTEGER libNewSize); /* [in] */
112 HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion(
114 ULARGE_INTEGER libOffset, /* [in] */
115 ULARGE_INTEGER cb, /* [in] */
116 DWORD dwLockType); /* [in] */
118 HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion(
120 ULARGE_INTEGER libOffset, /* [in] */
121 ULARGE_INTEGER cb, /* [in] */
122 DWORD dwLockType); /* [in] */
124 HRESULT WINAPI HGLOBALLockBytesImpl16_Stat(
126 STATSTG16* pstatstg, /* [out] */
127 DWORD grfStatFlag); /* [in] */
129 /******************************************************************************
131 * HGLOBALLockBytesImpl16 implementation
135 /******************************************************************************
136 * This is the constructor for the HGLOBALLockBytesImpl16 class.
139 * hGlobal - Handle that will support the stream. can be NULL.
140 * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL16 will be released
141 * when the IStream object is destroyed.
143 HGLOBALLockBytesImpl16*
144 HGLOBALLockBytesImpl16_Construct(HGLOBAL16 hGlobal,
145 BOOL16 fDeleteOnRelease)
147 HGLOBALLockBytesImpl16* newLockBytes;
149 static ICOM_VTABLE(ILockBytes16) vt16;
150 static SEGPTR msegvt16;
151 HMODULE16 hcomp = GetModuleHandle16("OLE2");
154 TRACE("(%x,%d)\n",hGlobal,fDeleteOnRelease);
155 newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl16));
156 if (newLockBytes == NULL)
160 * Set up the virtual function table and reference count.
164 #define VTENT(x) vt16.x = (void*)GetProcAddress16(hcomp,"HGLOBALLockBytesImpl16_"#x);assert(vt16.x)
165 VTENT(QueryInterface);
175 msegvt16 = MapLS( &vt16 );
177 newLockBytes->lpVtbl = (ICOM_VTABLE(ILockBytes16)*)msegvt16;
178 newLockBytes->ref = 0;
180 * Initialize the support.
182 newLockBytes->supportHandle = hGlobal;
183 newLockBytes->deleteOnRelease = fDeleteOnRelease;
186 * This method will allocate a handle if one is not supplied.
188 if (newLockBytes->supportHandle == 0)
189 newLockBytes->supportHandle = GlobalAlloc16(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
192 * Initialize the size of the array to the size of the handle.
194 newLockBytes->byteArraySize.s.HighPart = 0;
195 newLockBytes->byteArraySize.s.LowPart = GlobalSize16(
196 newLockBytes->supportHandle);
198 return (HGLOBALLockBytesImpl16*)MapLS(newLockBytes);
201 /******************************************************************************
202 * This is the destructor of the HGLOBALStreamImpl class.
204 * This method will clean-up all the resources used-up by the given
205 * HGLOBALLockBytesImpl16 class. The pointer passed-in to this function will be
206 * freed and will not be valid anymore.
208 void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This)
212 * Release the HGlobal if the constructor asked for that.
214 if (This->deleteOnRelease)
216 GlobalFree16(This->supportHandle);
217 This->supportHandle = 0;
221 * Finally, free the memory used-up by the class.
223 HeapFree(GetProcessHeap(), 0, This);
226 /******************************************************************************
227 * This implements the IUnknown method QueryInterface for this
230 HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface(
231 ILockBytes16* iface, /* [in] SEGPTR */
232 REFIID riid, /* [in] */
233 void** ppvObject) /* [iid_is][out] (ptr to SEGPTR!) */
235 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)MapSL((SEGPTR)iface);
237 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
239 * Perform a sanity check on the parameters.
245 * Initialize the return parameter.
249 * Compare the riid with the interface IDs implemented by this object.
251 if ( !memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) ||
252 !memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes))
254 *ppvObject = (void*)iface;
257 * Check that we obtained an interface.
260 return E_NOINTERFACE;
263 * Query Interface always increases the reference count by one when it is
266 HGLOBALLockBytesImpl16_AddRef((ILockBytes16*)This);
271 /******************************************************************************
272 * This implements the IUnknown method AddRef for this
275 ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface)
277 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
279 TRACE("(%p)\n",This);
286 /******************************************************************************
287 * This implements the IUnknown method Release for this
290 ULONG WINAPI HGLOBALLockBytesImpl16_Release(ILockBytes16* iface)
292 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
295 TRACE("(%p)\n",This);
302 * If the reference count goes down to 0, perform suicide.
305 HGLOBALLockBytesImpl16_Destroy(This);
309 /******************************************************************************
310 * This method is part of the ILockBytes interface.
312 * It reads a block of information from the byte array at the specified
315 * See the documentation of ILockBytes for more info.
317 HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt(
319 ULARGE_INTEGER ulOffset, /* [in] */
320 void* pv, /* [length_is][size_is][out] */
322 ULONG* pcbRead) /* [out] */
324 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
327 ULONG bytesReadBuffer = 0;
328 ULONG bytesToReadFromBuffer;
330 TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.s.LowPart,pv,cb,pcbRead);
332 * If the caller is not interested in the number of bytes read,
333 * we use another buffer to avoid "if" statements in the code.
336 pcbRead = &bytesReadBuffer;
339 * Make sure the offset is valid.
341 if (ulOffset.s.LowPart > This->byteArraySize.s.LowPart)
345 * Using the known size of the array, calculate the number of bytes
348 bytesToReadFromBuffer = min(This->byteArraySize.s.LowPart -
349 ulOffset.s.LowPart, cb);
352 * Lock the buffer in position and copy the data.
354 supportBuffer = GlobalLock16(This->supportHandle);
357 (char *) supportBuffer + ulOffset.s.LowPart,
358 bytesToReadFromBuffer);
361 * Return the number of bytes read.
363 *pcbRead = bytesToReadFromBuffer;
368 GlobalUnlock16(This->supportHandle);
371 * The function returns S_OK if the specified number of bytes were read
372 * or the end of the array was reached.
373 * It returns STG_E_READFAULT if the number of bytes to read does not equal
374 * the number of bytes actually read.
379 return STG_E_READFAULT;
382 /******************************************************************************
383 * This method is part of the ILockBytes interface.
385 * It writes the specified bytes at the specified offset.
386 * position. If the array is too small, it will be resized.
388 * See the documentation of ILockBytes for more info.
390 HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt(
392 ULARGE_INTEGER ulOffset, /* [in] */
393 const void* pv, /* [size_is][in] */
395 ULONG* pcbWritten) /* [out] */
397 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
400 ULARGE_INTEGER newSize;
401 ULONG bytesWritten = 0;
403 TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.s.LowPart,pv,cb,pcbWritten);
405 * If the caller is not interested in the number of bytes written,
406 * we use another buffer to avoid "if" statements in the code.
409 pcbWritten = &bytesWritten;
414 newSize.s.HighPart = 0;
415 newSize.s.LowPart = ulOffset.s.LowPart + cb;
418 * Verify if we need to grow the stream
420 if (newSize.s.LowPart > This->byteArraySize.s.LowPart)
423 if (HGLOBALLockBytesImpl16_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
424 return STG_E_MEDIUMFULL;
428 * Lock the buffer in position and copy the data.
430 supportBuffer = GlobalLock16(This->supportHandle);
432 memcpy((char *) supportBuffer + ulOffset.s.LowPart, pv, cb);
435 * Return the number of bytes written.
442 GlobalUnlock16(This->supportHandle);
447 /******************************************************************************
448 * This method is part of the ILockBytes interface.
450 * See the documentation of ILockBytes for more info.
452 HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface)
454 TRACE("(%p)\n",iface);
458 /******************************************************************************
459 * This method is part of the ILockBytes interface.
461 * It will change the size of the byte array.
463 * See the documentation of ILockBytes for more info.
465 HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize(
467 ULARGE_INTEGER libNewSize) /* [in] */
469 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
471 TRACE("(%p,%ld)\n",This,libNewSize.s.LowPart);
475 if (libNewSize.s.HighPart != 0)
476 return STG_E_INVALIDFUNCTION;
478 if (This->byteArraySize.s.LowPart == libNewSize.s.LowPart)
482 * Re allocate the HGlobal to fit the new size of the stream.
484 This->supportHandle = GlobalReAlloc16(This->supportHandle,
485 libNewSize.s.LowPart,
488 if (This->supportHandle == 0)
489 return STG_E_MEDIUMFULL;
491 This->byteArraySize.s.LowPart = libNewSize.s.LowPart;
496 /******************************************************************************
497 * This method is part of the ILockBytes interface.
499 * The global memory implementation of ILockBytes does not support locking.
501 * See the documentation of ILockBytes for more info.
503 HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion(
505 ULARGE_INTEGER libOffset, /* [in] */
506 ULARGE_INTEGER cb, /* [in] */
507 DWORD dwLockType) /* [in] */
509 return STG_E_INVALIDFUNCTION;
512 /******************************************************************************
513 * This method is part of the ILockBytes interface.
515 * The global memory implementation of ILockBytes does not support locking.
517 * See the documentation of ILockBytes for more info.
519 HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion(
521 ULARGE_INTEGER libOffset, /* [in] */
522 ULARGE_INTEGER cb, /* [in] */
523 DWORD dwLockType) /* [in] */
525 return STG_E_INVALIDFUNCTION;
528 /******************************************************************************
529 * This method is part of the ILockBytes interface.
531 * This method returns information about the current
534 * See the documentation of ILockBytes for more info.
536 HRESULT WINAPI HGLOBALLockBytesImpl16_Stat(
538 STATSTG16* pstatstg, /* [out] */
539 DWORD grfStatFlag) /* [in] */
541 HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
543 memset(pstatstg, 0, sizeof(STATSTG16));
545 pstatstg->pwcsName = NULL;
546 pstatstg->type = STGTY_LOCKBYTES;
547 pstatstg->cbSize = This->byteArraySize;
552 /******************************************************************************
553 * CreateILockBytesOnHGlobal [OLE2.54]
555 * Creates an ILockBytes interface for a HGLOBAL handle.
558 * hGlobal the global handle (16bit)
559 * fDeleteOnRelease delete handle on release.
560 * ppLkbyt pointer to ILockBytes interface.
563 * Staddard OLE error return codes.
566 HRESULT WINAPI CreateILockBytesOnHGlobal16(HGLOBAL16 hGlobal,
567 BOOL16 fDeleteOnRelease,
568 /*SEGPTR**/ LPLOCKBYTES16* ppLkbyt)
570 HGLOBALLockBytesImpl16* newLockBytes; /* SEGPTR */
572 newLockBytes = HGLOBALLockBytesImpl16_Construct(hGlobal, fDeleteOnRelease);
574 if (newLockBytes != NULL)
575 return HGLOBALLockBytesImpl16_QueryInterface((ILockBytes16*)newLockBytes,
578 return E_OUTOFMEMORY;