[NTOSKRNL] Drop the useless Timestamp field
[reactos.git] / dll / win32 / ole32 / memlockbytes.c
1 /******************************************************************************
2 *
3 * Global memory implementation of ILockBytes.
4 *
5 * Copyright 1999 Thuy Nguyen
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27
28 #define COBJMACROS
29 #define NONAMELESSUNION
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "objbase.h"
35 #include "ole2.h"
36 #include "winerror.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41
42 /******************************************************************************
43 * HGLOBALLockBytesImpl definition.
44 *
45 * This class implements the ILockBytes interface and represents a byte array
46 * object supported by an HGLOBAL pointer.
47 */
48 struct HGLOBALLockBytesImpl
49 {
50 ILockBytes ILockBytes_iface;
51 LONG ref;
52
53 /*
54 * Support for the LockBytes object
55 */
56 HGLOBAL supportHandle;
57
58 /*
59 * This flag is TRUE if the HGLOBAL is destroyed when the object
60 * is finally released.
61 */
62 BOOL deleteOnRelease;
63
64 /*
65 * Helper variable that contains the size of the byte array
66 */
67 ULARGE_INTEGER byteArraySize;
68 };
69
70 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
71
72 static inline HGLOBALLockBytesImpl *impl_from_ILockBytes( ILockBytes *iface )
73 {
74 return CONTAINING_RECORD(iface, HGLOBALLockBytesImpl, ILockBytes_iface);
75 }
76
77 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl;
78
79 /******************************************************************************
80 * CreateILockBytesOnHGlobal [OLE32.@]
81 *
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.
84 *
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.
90 *
91 * RETURNS
92 * Success: S_OK
93 *
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.
99 */
100 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL global, BOOL delete_on_release, ILockBytes **ret)
101 {
102 HGLOBALLockBytesImpl* lockbytes;
103
104 lockbytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
105 if (!lockbytes) return E_OUTOFMEMORY;
106
107 lockbytes->ILockBytes_iface.lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
108 lockbytes->ref = 1;
109
110 /*
111 * Initialize the support.
112 */
113 lockbytes->supportHandle = global;
114 lockbytes->deleteOnRelease = delete_on_release;
115
116 /*
117 * This method will allocate a handle if one is not supplied.
118 */
119 if (lockbytes->supportHandle == 0)
120 lockbytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
121
122 /*
123 * Initialize the size of the array to the size of the handle.
124 */
125 lockbytes->byteArraySize.u.HighPart = 0;
126 lockbytes->byteArraySize.u.LowPart = GlobalSize(lockbytes->supportHandle);
127
128 *ret = &lockbytes->ILockBytes_iface;
129
130 return S_OK;
131 }
132
133 /******************************************************************************
134 * GetHGlobalFromILockBytes [OLE32.@]
135 *
136 * Retrieve a global memory handle to a byte array object created
137 * using the CreateILockBytesOnHGlobal function.
138 *
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
145 *
146 */
147 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* iface, HGLOBAL* phglobal)
148 {
149 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
150 STATSTG stbuf;
151 HRESULT hres;
152 ULARGE_INTEGER start;
153 ULONG xread;
154
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;
161 }
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;
167 }
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;
178 }
179 if (stbuf.cbSize.u.LowPart != xread) {
180 FIXME("Read size is not requested size %d vs %d?\n",stbuf.cbSize.u.LowPart, xread);
181 }
182 return S_OK;
183 }
184
185 /******************************************************************************
186 *
187 * HGLOBALLockBytesImpl implementation
188 *
189 */
190
191 /******************************************************************************
192 * This implements the IUnknown method QueryInterface for this
193 * class
194 */
195 static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
196 ILockBytes* iface,
197 REFIID riid, /* [in] */
198 void** ppvObject) /* [iid_is][out] */
199 {
200 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
201
202 if (ppvObject==0)
203 return E_INVALIDARG;
204
205 *ppvObject = 0;
206
207 if (IsEqualIID(riid, &IID_IUnknown) ||
208 IsEqualIID(riid, &IID_ILockBytes))
209 {
210 *ppvObject = &This->ILockBytes_iface;
211 }
212 else
213 return E_NOINTERFACE;
214
215 ILockBytes_AddRef(iface);
216
217 return S_OK;
218 }
219
220 /******************************************************************************
221 * This implements the IUnknown method AddRef for this
222 * class
223 */
224 static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
225 {
226 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
227 return InterlockedIncrement(&This->ref);
228 }
229
230 /******************************************************************************
231 * This implements the IUnknown method Release for this
232 * class
233 */
234 static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
235 {
236 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
237 ULONG ref;
238
239 ref = InterlockedDecrement(&This->ref);
240 if (!ref)
241 {
242 if (This->deleteOnRelease)
243 {
244 GlobalFree(This->supportHandle);
245 This->supportHandle = 0;
246 }
247 HeapFree(GetProcessHeap(), 0, This);
248 }
249
250 return ref;
251 }
252
253 /******************************************************************************
254 * This method is part of the ILockBytes interface.
255 *
256 * It reads a block of information from the byte array at the specified
257 * offset.
258 *
259 * See the documentation of ILockBytes for more info.
260 */
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] */
267 {
268 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
269
270 void* supportBuffer;
271 ULONG bytesReadBuffer = 0;
272 ULONG bytesToReadFromBuffer;
273
274 /*
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.
277 */
278 if (pcbRead == 0)
279 pcbRead = &bytesReadBuffer;
280
281 /*
282 * Make sure the offset is valid.
283 */
284 if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
285 return E_FAIL;
286
287 /*
288 * Using the known size of the array, calculate the number of bytes
289 * to read.
290 */
291 bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart -
292 ulOffset.u.LowPart, cb);
293
294 /*
295 * Lock the buffer in position and copy the data.
296 */
297 supportBuffer = GlobalLock(This->supportHandle);
298
299 memcpy(pv,
300 (char *) supportBuffer + ulOffset.u.LowPart,
301 bytesToReadFromBuffer);
302
303 /*
304 * Return the number of bytes read.
305 */
306 *pcbRead = bytesToReadFromBuffer;
307
308 /*
309 * Cleanup
310 */
311 GlobalUnlock(This->supportHandle);
312
313 /*
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.
318 */
319 if(*pcbRead == cb)
320 return S_OK;
321
322 return STG_E_READFAULT;
323 }
324
325 /******************************************************************************
326 * This method is part of the ILockBytes interface.
327 *
328 * It writes the specified bytes at the specified offset.
329 * position. If the array is too small, it will be resized.
330 *
331 * See the documentation of ILockBytes for more info.
332 */
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] */
339 {
340 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
341
342 void* supportBuffer;
343 ULARGE_INTEGER newSize;
344 ULONG bytesWritten = 0;
345
346 /*
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.
349 */
350 if (pcbWritten == 0)
351 pcbWritten = &bytesWritten;
352
353 if (cb == 0)
354 {
355 return S_OK;
356 }
357 else
358 {
359 newSize.u.HighPart = 0;
360 newSize.u.LowPart = ulOffset.u.LowPart + cb;
361 }
362
363 /*
364 * Verify if we need to grow the stream
365 */
366 if (newSize.u.LowPart > This->byteArraySize.u.LowPart)
367 {
368 /* grow stream */
369 if (ILockBytes_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
370 return STG_E_MEDIUMFULL;
371 }
372
373 /*
374 * Lock the buffer in position and copy the data.
375 */
376 supportBuffer = GlobalLock(This->supportHandle);
377
378 memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb);
379
380 /*
381 * Return the number of bytes written.
382 */
383 *pcbWritten = cb;
384
385 /*
386 * Cleanup
387 */
388 GlobalUnlock(This->supportHandle);
389
390 return S_OK;
391 }
392
393 /******************************************************************************
394 * This method is part of the ILockBytes interface.
395 *
396 * See the documentation of ILockBytes for more info.
397 */
398 static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
399 {
400 return S_OK;
401 }
402
403 /******************************************************************************
404 * This method is part of the ILockBytes interface.
405 *
406 * It will change the size of the byte array.
407 *
408 * See the documentation of ILockBytes for more info.
409 */
410 static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
411 ILockBytes* iface,
412 ULARGE_INTEGER libNewSize) /* [in] */
413 {
414 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
415 HGLOBAL supportHandle;
416
417 /*
418 * As documented.
419 */
420 if (libNewSize.u.HighPart != 0)
421 return STG_E_INVALIDFUNCTION;
422
423 if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
424 return S_OK;
425
426 /*
427 * Re allocate the HGlobal to fit the new size of the stream.
428 */
429 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
430
431 if (supportHandle == 0)
432 return STG_E_MEDIUMFULL;
433
434 This->supportHandle = supportHandle;
435 This->byteArraySize.u.LowPart = libNewSize.u.LowPart;
436
437 return S_OK;
438 }
439
440 /******************************************************************************
441 * This method is part of the ILockBytes interface.
442 *
443 * The global memory implementation of ILockBytes does not support locking.
444 *
445 * See the documentation of ILockBytes for more info.
446 */
447 static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
448 ILockBytes* iface,
449 ULARGE_INTEGER libOffset, /* [in] */
450 ULARGE_INTEGER cb, /* [in] */
451 DWORD dwLockType) /* [in] */
452 {
453 return STG_E_INVALIDFUNCTION;
454 }
455
456 /******************************************************************************
457 * This method is part of the ILockBytes interface.
458 *
459 * The global memory implementation of ILockBytes does not support locking.
460 *
461 * See the documentation of ILockBytes for more info.
462 */
463 static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
464 ILockBytes* iface,
465 ULARGE_INTEGER libOffset, /* [in] */
466 ULARGE_INTEGER cb, /* [in] */
467 DWORD dwLockType) /* [in] */
468 {
469 return STG_E_INVALIDFUNCTION;
470 }
471
472 /******************************************************************************
473 * This method is part of the ILockBytes interface.
474 *
475 * This method returns information about the current
476 * byte array object.
477 *
478 * See the documentation of ILockBytes for more info.
479 */
480 static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
481 ILockBytes* iface,
482 STATSTG* pstatstg, /* [out] */
483 DWORD grfStatFlag) /* [in] */
484 {
485 HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
486
487 memset(pstatstg, 0, sizeof(STATSTG));
488
489 pstatstg->pwcsName = NULL;
490 pstatstg->type = STGTY_LOCKBYTES;
491 pstatstg->cbSize = This->byteArraySize;
492
493 return S_OK;
494 }
495
496 /*
497 * Virtual function table for the HGLOBALLockBytesImpl class.
498 */
499 static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
500 {
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,
511 };