ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / ole32 / memlockbytes.c
blobb2fc5b4f4db875a083e7d239a96118658e08ef7b
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
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "objbase.h"
35 #include "ole2.h"
36 #include "winerror.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 /******************************************************************************
43 * HGLOBALLockBytesImpl definition.
45 * This class implements the ILockBytes interface and represents a byte array
46 * object supported by an HGLOBAL pointer.
48 struct HGLOBALLockBytesImpl
50 ILockBytes ILockBytes_iface;
51 LONG ref;
54 * Support for the LockBytes object
56 HGLOBAL supportHandle;
59 * This flag is TRUE if the HGLOBAL is destroyed when the object
60 * is finally released.
62 BOOL deleteOnRelease;
65 * Helper variable that contains the size of the byte array
67 ULARGE_INTEGER byteArraySize;
70 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
72 static inline HGLOBALLockBytesImpl *impl_from_ILockBytes( ILockBytes *iface )
74 return CONTAINING_RECORD(iface, HGLOBALLockBytesImpl, ILockBytes_iface);
77 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl;
79 /******************************************************************************
80 * CreateILockBytesOnHGlobal [OLE32.@]
82 * Create a byte array object which is intended to be the compound file foundation.
83 * This object supports a COM implementation of the ILockBytes interface.
85 * PARAMS
86 * global [ I] Global memory handle
87 * delete_on_release [ I] Whether the handle should be freed when the object is released.
88 * ret [ O] Address of ILockBytes pointer that receives
89 * the interface pointer to the new byte array object.
91 * RETURNS
92 * Success: S_OK
94 * NOTES
95 * The supplied ILockBytes pointer can be used by the StgCreateDocfileOnILockBytes
96 * function to build a compound file on top of this byte array object.
97 * The ILockBytes interface instance calls the GlobalReAlloc function to grow
98 * the memory block as required.
100 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL global, BOOL delete_on_release, ILockBytes **ret)
102 HGLOBALLockBytesImpl* lockbytes;
104 lockbytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
105 if (!lockbytes) return E_OUTOFMEMORY;
107 lockbytes->ILockBytes_iface.lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
108 lockbytes->ref = 1;
111 * Initialize the support.
113 lockbytes->supportHandle = global;
114 lockbytes->deleteOnRelease = delete_on_release;
117 * This method will allocate a handle if one is not supplied.
119 if (lockbytes->supportHandle == 0)
120 lockbytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
123 * Initialize the size of the array to the size of the handle.
125 lockbytes->byteArraySize.u.HighPart = 0;
126 lockbytes->byteArraySize.u.LowPart = GlobalSize(lockbytes->supportHandle);
128 *ret = &lockbytes->ILockBytes_iface;
130 return S_OK;
133 /******************************************************************************
134 * GetHGlobalFromILockBytes [OLE32.@]
136 * Retrieve a global memory handle to a byte array object created
137 * using the CreateILockBytesOnHGlobal function.
139 * PARAMS
140 * plkbyt [ I] Pointer to the ILockBytes interface on byte array object
141 * phglobal [ O] Address to store a global memory handle
142 * RETURNS
143 * S_OK if *phglobal has a correct value
144 * E_INVALIDARG if any parameters are invalid
147 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* iface, HGLOBAL* phglobal)
149 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
150 STATSTG stbuf;
151 HRESULT hres;
152 ULARGE_INTEGER start;
153 ULONG xread;
155 *phglobal = 0;
156 if (This->ILockBytes_iface.lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
157 *phglobal = This->supportHandle;
158 if (*phglobal == 0)
159 return E_INVALIDARG;
160 return S_OK;
162 /* It is not our lockbytes implementation, so use a more generic way */
163 hres = ILockBytes_Stat(iface,&stbuf,STATFLAG_NONAME);
164 if (hres != S_OK) {
165 ERR("Cannot ILockBytes_Stat, %x\n",hres);
166 return hres;
168 TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf.cbSize.QuadPart));
169 *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart);
170 if (!*phglobal)
171 return E_INVALIDARG;
172 memset(&start,0,sizeof(start));
173 hres = ILockBytes_ReadAt(iface, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread);
174 GlobalUnlock(*phglobal);
175 if (hres != S_OK) {
176 FIXME("%p->ReadAt failed with %x\n",iface,hres);
177 return hres;
179 if (stbuf.cbSize.u.LowPart != xread) {
180 FIXME("Read size is not requested size %d vs %d?\n",stbuf.cbSize.u.LowPart, xread);
182 return S_OK;
185 /******************************************************************************
187 * HGLOBALLockBytesImpl implementation
191 /******************************************************************************
192 * This implements the IUnknown method QueryInterface for this
193 * class
195 static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
196 ILockBytes* iface,
197 REFIID riid, /* [in] */
198 void** ppvObject) /* [iid_is][out] */
200 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
202 if (ppvObject==0)
203 return E_INVALIDARG;
205 *ppvObject = 0;
207 if (IsEqualIID(riid, &IID_IUnknown) ||
208 IsEqualIID(riid, &IID_ILockBytes))
210 *ppvObject = &This->ILockBytes_iface;
212 else
213 return E_NOINTERFACE;
215 ILockBytes_AddRef(iface);
217 return S_OK;
220 /******************************************************************************
221 * This implements the IUnknown method AddRef for this
222 * class
224 static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
226 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
227 return InterlockedIncrement(&This->ref);
230 /******************************************************************************
231 * This implements the IUnknown method Release for this
232 * class
234 static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
236 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
237 ULONG ref;
239 ref = InterlockedDecrement(&This->ref);
240 if (!ref)
242 if (This->deleteOnRelease)
244 GlobalFree(This->supportHandle);
245 This->supportHandle = 0;
247 HeapFree(GetProcessHeap(), 0, This);
250 return ref;
253 /******************************************************************************
254 * This method is part of the ILockBytes interface.
256 * It reads a block of information from the byte array at the specified
257 * offset.
259 * See the documentation of ILockBytes for more info.
261 static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
262 ILockBytes* iface,
263 ULARGE_INTEGER ulOffset, /* [in] */
264 void* pv, /* [length_is][size_is][out] */
265 ULONG cb, /* [in] */
266 ULONG* pcbRead) /* [out] */
268 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
270 void* supportBuffer;
271 ULONG bytesReadBuffer = 0;
272 ULONG bytesToReadFromBuffer;
275 * If the caller is not interested in the number of bytes read,
276 * we use another buffer to avoid "if" statements in the code.
278 if (pcbRead == 0)
279 pcbRead = &bytesReadBuffer;
282 * Make sure the offset is valid.
284 if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
285 return E_FAIL;
288 * Using the known size of the array, calculate the number of bytes
289 * to read.
291 bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart -
292 ulOffset.u.LowPart, cb);
295 * Lock the buffer in position and copy the data.
297 supportBuffer = GlobalLock(This->supportHandle);
299 memcpy(pv,
300 (char *) supportBuffer + ulOffset.u.LowPart,
301 bytesToReadFromBuffer);
304 * Return the number of bytes read.
306 *pcbRead = bytesToReadFromBuffer;
309 * Cleanup
311 GlobalUnlock(This->supportHandle);
314 * The function returns S_OK if the specified number of bytes were read
315 * or the end of the array was reached.
316 * It returns STG_E_READFAULT if the number of bytes to read does not equal
317 * the number of bytes actually read.
319 if(*pcbRead == cb)
320 return S_OK;
322 return STG_E_READFAULT;
325 /******************************************************************************
326 * This method is part of the ILockBytes interface.
328 * It writes the specified bytes at the specified offset.
329 * position. If the array is too small, it will be resized.
331 * See the documentation of ILockBytes for more info.
333 static HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
334 ILockBytes* iface,
335 ULARGE_INTEGER ulOffset, /* [in] */
336 const void* pv, /* [size_is][in] */
337 ULONG cb, /* [in] */
338 ULONG* pcbWritten) /* [out] */
340 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
342 void* supportBuffer;
343 ULARGE_INTEGER newSize;
344 ULONG bytesWritten = 0;
347 * If the caller is not interested in the number of bytes written,
348 * we use another buffer to avoid "if" statements in the code.
350 if (pcbWritten == 0)
351 pcbWritten = &bytesWritten;
353 if (cb == 0)
355 return S_OK;
357 else
359 newSize.u.HighPart = 0;
360 newSize.u.LowPart = ulOffset.u.LowPart + cb;
364 * Verify if we need to grow the stream
366 if (newSize.u.LowPart > This->byteArraySize.u.LowPart)
368 /* grow stream */
369 if (ILockBytes_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
370 return STG_E_MEDIUMFULL;
374 * Lock the buffer in position and copy the data.
376 supportBuffer = GlobalLock(This->supportHandle);
378 memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb);
381 * Return the number of bytes written.
383 *pcbWritten = cb;
386 * Cleanup
388 GlobalUnlock(This->supportHandle);
390 return S_OK;
393 /******************************************************************************
394 * This method is part of the ILockBytes interface.
396 * See the documentation of ILockBytes for more info.
398 static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
400 return S_OK;
403 /******************************************************************************
404 * This method is part of the ILockBytes interface.
406 * It will change the size of the byte array.
408 * See the documentation of ILockBytes for more info.
410 static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
411 ILockBytes* iface,
412 ULARGE_INTEGER libNewSize) /* [in] */
414 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
415 HGLOBAL supportHandle;
418 * As documented.
420 if (libNewSize.u.HighPart != 0)
421 return STG_E_INVALIDFUNCTION;
423 if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
424 return S_OK;
427 * Re allocate the HGlobal to fit the new size of the stream.
429 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
431 if (supportHandle == 0)
432 return STG_E_MEDIUMFULL;
434 This->supportHandle = supportHandle;
435 This->byteArraySize.u.LowPart = libNewSize.u.LowPart;
437 return S_OK;
440 /******************************************************************************
441 * This method is part of the ILockBytes interface.
443 * The global memory implementation of ILockBytes does not support locking.
445 * See the documentation of ILockBytes for more info.
447 static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
448 ILockBytes* iface,
449 ULARGE_INTEGER libOffset, /* [in] */
450 ULARGE_INTEGER cb, /* [in] */
451 DWORD dwLockType) /* [in] */
453 return STG_E_INVALIDFUNCTION;
456 /******************************************************************************
457 * This method is part of the ILockBytes interface.
459 * The global memory implementation of ILockBytes does not support locking.
461 * See the documentation of ILockBytes for more info.
463 static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
464 ILockBytes* iface,
465 ULARGE_INTEGER libOffset, /* [in] */
466 ULARGE_INTEGER cb, /* [in] */
467 DWORD dwLockType) /* [in] */
469 return STG_E_INVALIDFUNCTION;
472 /******************************************************************************
473 * This method is part of the ILockBytes interface.
475 * This method returns information about the current
476 * byte array object.
478 * See the documentation of ILockBytes for more info.
480 static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
481 ILockBytes* iface,
482 STATSTG* pstatstg, /* [out] */
483 DWORD grfStatFlag) /* [in] */
485 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
487 memset(pstatstg, 0, sizeof(STATSTG));
489 pstatstg->pwcsName = NULL;
490 pstatstg->type = STGTY_LOCKBYTES;
491 pstatstg->cbSize = This->byteArraySize;
493 return S_OK;
497 * Virtual function table for the HGLOBALLockBytesImpl class.
499 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
501 HGLOBALLockBytesImpl_QueryInterface,
502 HGLOBALLockBytesImpl_AddRef,
503 HGLOBALLockBytesImpl_Release,
504 HGLOBALLockBytesImpl_ReadAt,
505 HGLOBALLockBytesImpl_WriteAt,
506 HGLOBALLockBytesImpl_Flush,
507 HGLOBALLockBytesImpl_SetSize,
508 HGLOBALLockBytesImpl_LockRegion,
509 HGLOBALLockBytesImpl_UnlockRegion,
510 HGLOBALLockBytesImpl_Stat,