ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / dlls / ole32 / memlockbytes.c
blob2d7d4572584d0af4174da24abe0216c91a895452
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 #define NONAMELESSUNION
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "winerror.h"
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;
49 LONG ref;
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.
60 BOOL deleteOnRelease;
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.
83 * PARAMS
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.
89 * RETURNS
90 * Success: S_OK
92 * NOTES
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;
106 lockbytes->ref = 1;
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;
128 return S_OK;
131 /******************************************************************************
132 * GetHGlobalFromILockBytes [OLE32.@]
134 * Retrieve a global memory handle to a byte array object created
135 * using the CreateILockBytesOnHGlobal function.
137 * PARAMS
138 * plkbyt [ I] Pointer to the ILockBytes interface on byte array object
139 * phglobal [ O] Address to store a global memory handle
140 * RETURNS
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);
148 STATSTG stbuf;
149 HRESULT hres;
150 ULARGE_INTEGER start;
151 ULONG xread;
153 *phglobal = 0;
154 if (This->ILockBytes_iface.lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
155 *phglobal = This->supportHandle;
156 if (*phglobal == 0)
157 return E_INVALIDARG;
158 return S_OK;
160 /* It is not our lockbytes implementation, so use a more generic way */
161 hres = ILockBytes_Stat(iface,&stbuf,STATFLAG_NONAME);
162 if (hres != S_OK) {
163 ERR("Cannot ILockBytes_Stat, %x\n",hres);
164 return hres;
166 TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf.cbSize.QuadPart));
167 *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart);
168 if (!*phglobal)
169 return E_INVALIDARG;
170 memset(&start,0,sizeof(start));
171 hres = ILockBytes_ReadAt(iface, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread);
172 GlobalUnlock(*phglobal);
173 if (hres != S_OK) {
174 FIXME("%p->ReadAt failed with %x\n",iface,hres);
175 return 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);
180 return S_OK;
183 /******************************************************************************
185 * HGLOBALLockBytesImpl implementation
189 /******************************************************************************
190 * This implements the IUnknown method QueryInterface for this
191 * class
193 static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
194 ILockBytes* iface,
195 REFIID riid, /* [in] */
196 void** ppvObject) /* [iid_is][out] */
198 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
200 if (ppvObject==0)
201 return E_INVALIDARG;
203 *ppvObject = 0;
205 if (IsEqualIID(riid, &IID_IUnknown) ||
206 IsEqualIID(riid, &IID_ILockBytes))
208 *ppvObject = &This->ILockBytes_iface;
210 else
211 return E_NOINTERFACE;
213 ILockBytes_AddRef(iface);
215 return S_OK;
218 /******************************************************************************
219 * This implements the IUnknown method AddRef for this
220 * class
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
230 * class
232 static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
234 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
235 ULONG ref;
237 ref = InterlockedDecrement(&This->ref);
238 if (!ref)
240 if (This->deleteOnRelease)
242 GlobalFree(This->supportHandle);
243 This->supportHandle = 0;
245 HeapFree(GetProcessHeap(), 0, This);
248 return ref;
251 /******************************************************************************
252 * This method is part of the ILockBytes interface.
254 * It reads a block of information from the byte array at the specified
255 * offset.
257 * See the documentation of ILockBytes for more info.
259 static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
260 ILockBytes* iface,
261 ULARGE_INTEGER ulOffset, /* [in] */
262 void* pv, /* [length_is][size_is][out] */
263 ULONG cb, /* [in] */
264 ULONG* pcbRead) /* [out] */
266 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
268 void* supportBuffer;
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.
276 if (pcbRead == 0)
277 pcbRead = &bytesReadBuffer;
280 * Make sure the offset is valid.
282 if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
283 return E_FAIL;
286 * Using the known size of the array, calculate the number of bytes
287 * to read.
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);
297 memcpy(pv,
298 (char *) supportBuffer + ulOffset.u.LowPart,
299 bytesToReadFromBuffer);
302 * Return the number of bytes read.
304 *pcbRead = bytesToReadFromBuffer;
307 * Cleanup
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.
317 if(*pcbRead == cb)
318 return S_OK;
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(
332 ILockBytes* iface,
333 ULARGE_INTEGER ulOffset, /* [in] */
334 const void* pv, /* [size_is][in] */
335 ULONG cb, /* [in] */
336 ULONG* pcbWritten) /* [out] */
338 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
340 void* supportBuffer;
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.
348 if (pcbWritten == 0)
349 pcbWritten = &bytesWritten;
351 if (cb == 0)
353 return S_OK;
355 else
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)
366 /* grow stream */
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.
381 *pcbWritten = cb;
384 * Cleanup
386 GlobalUnlock(This->supportHandle);
388 return S_OK;
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)
398 return S_OK;
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(
409 ILockBytes* iface,
410 ULARGE_INTEGER libNewSize) /* [in] */
412 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
413 HGLOBAL supportHandle;
416 * As documented.
418 if (libNewSize.u.HighPart != 0)
419 return STG_E_INVALIDFUNCTION;
421 if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
422 return S_OK;
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;
435 return S_OK;
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(
446 ILockBytes* iface,
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(
462 ILockBytes* iface,
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
474 * byte array object.
476 * See the documentation of ILockBytes for more info.
478 static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
479 ILockBytes* iface,
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;
491 return S_OK;
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,