source: trunk/src/ole32/memlockbytes.c@ 21916

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 16.3 KB
Line 
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "config.h"
23
24#include <string.h>
25
26#include "windef.h"
27#include "objbase.h"
28#include "ole2.h"
29#include "winbase.h"
30#include "winerror.h"
31
32#include "wine/debug.h"
33
34WINE_DEFAULT_DEBUG_CHANNEL(ole);
35
36/******************************************************************************
37 * HGLOBALLockBytesImpl definition.
38 *
39 * This class imlements the ILockBytes inteface and represents a byte array
40 * object supported by an HGLOBAL pointer.
41 */
42struct HGLOBALLockBytesImpl
43{
44 /*
45 * Needs to be the first item in the stuct
46 * since we want to cast this in an ILockBytes pointer
47 */
48 ICOM_VFIELD(ILockBytes);
49
50 /*
51 * Reference count
52 */
53 ULONG ref;
54
55 /*
56 * Support for the LockBytes object
57 */
58 HGLOBAL supportHandle;
59
60 /*
61 * This flag is TRUE if the HGLOBAL is destroyed when the object
62 * is finally released.
63 */
64 BOOL deleteOnRelease;
65
66 /*
67 * Helper variable that contains the size of the byte array
68 */
69 ULARGE_INTEGER byteArraySize;
70};
71
72typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
73
74/*
75 * Method definition for the HGLOBALLockBytesImpl class.
76 */
77HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(
78 HGLOBAL hGlobal,
79 BOOL fDeleteOnRelease);
80
81void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This);
82
83HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
84 ILockBytes* iface,
85 REFIID riid, /* [in] */
86 void** ppvObject); /* [iid_is][out] */
87
88ULONG WINAPI HGLOBALLockBytesImpl_AddRef(
89 ILockBytes* iface);
90
91ULONG WINAPI HGLOBALLockBytesImpl_Release(
92 ILockBytes* iface);
93
94HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
95 ILockBytes* iface,
96 ULARGE_INTEGER ulOffset, /* [in] */
97 void* pv, /* [length_is][size_is][out] */
98 ULONG cb, /* [in] */
99 ULONG* pcbRead); /* [out] */
100
101HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
102 ILockBytes* iface,
103 ULARGE_INTEGER ulOffset, /* [in] */
104 const void* pv, /* [size_is][in] */
105 ULONG cb, /* [in] */
106 ULONG* pcbWritten); /* [out] */
107
108HRESULT WINAPI HGLOBALLockBytesImpl_Flush(
109 ILockBytes* iface);
110
111HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
112 ILockBytes* iface,
113 ULARGE_INTEGER libNewSize); /* [in] */
114
115HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
116 ILockBytes* iface,
117 ULARGE_INTEGER libOffset, /* [in] */
118 ULARGE_INTEGER cb, /* [in] */
119 DWORD dwLockType); /* [in] */
120
121HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
122 ILockBytes* iface,
123 ULARGE_INTEGER libOffset, /* [in] */
124 ULARGE_INTEGER cb, /* [in] */
125 DWORD dwLockType); /* [in] */
126
127HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
128 ILockBytes* iface,
129 STATSTG* pstatstg, /* [out] */
130 DWORD grfStatFlag); /* [in] */
131
132/*
133 * Virtual function table for the HGLOBALLockBytesImpl class.
134 */
135static ICOM_VTABLE(ILockBytes) HGLOBALLockBytesImpl_Vtbl =
136{
137 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
138 HGLOBALLockBytesImpl_QueryInterface,
139 HGLOBALLockBytesImpl_AddRef,
140 HGLOBALLockBytesImpl_Release,
141 HGLOBALLockBytesImpl_ReadAt,
142 HGLOBALLockBytesImpl_WriteAt,
143 HGLOBALLockBytesImpl_Flush,
144 HGLOBALLockBytesImpl_SetSize,
145 HGLOBALLockBytesImpl_LockRegion,
146 HGLOBALLockBytesImpl_UnlockRegion,
147 HGLOBALLockBytesImpl_Stat,
148};
149
150/******************************************************************************
151 * CreateILockBytesOnHGlobal [OLE32.57]
152 */
153HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL hGlobal,
154 BOOL fDeleteOnRelease,
155 LPLOCKBYTES* ppLkbyt)
156{
157 HGLOBALLockBytesImpl* newLockBytes;
158
159 newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease);
160
161 if (newLockBytes != NULL)
162 {
163 return IUnknown_QueryInterface((IUnknown*)newLockBytes,
164 &IID_ILockBytes,
165 (void**)ppLkbyt);
166 }
167
168 return E_OUTOFMEMORY;
169}
170
171/******************************************************************************
172 * GetHGlobalFromILockBytes [OLE32.70]
173 */
174HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal)
175{
176 HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt;
177
178 if (ICOM_VTBL(pMemLockBytes) == &HGLOBALLockBytesImpl_Vtbl)
179 *phglobal = pMemLockBytes->supportHandle;
180 else
181 *phglobal = 0;
182
183 if (*phglobal == 0)
184 return E_INVALIDARG;
185
186 return S_OK;
187}
188
189/******************************************************************************
190 *
191 * HGLOBALLockBytesImpl implementation
192 *
193 */
194
195/******************************************************************************
196 * This is the constructor for the HGLOBALLockBytesImpl class.
197 *
198 * Params:
199 * hGlobal - Handle that will support the stream. can be NULL.
200 * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
201 * when the IStream object is destroyed.
202 */
203HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal,
204 BOOL fDeleteOnRelease)
205{
206 HGLOBALLockBytesImpl* newLockBytes;
207 newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
208
209 if (newLockBytes!=0)
210 {
211 /*
212 * Set up the virtual function table and reference count.
213 */
214 ICOM_VTBL(newLockBytes) = &HGLOBALLockBytesImpl_Vtbl;
215 newLockBytes->ref = 0;
216
217 /*
218 * Initialize the support.
219 */
220 newLockBytes->supportHandle = hGlobal;
221 newLockBytes->deleteOnRelease = fDeleteOnRelease;
222
223 /*
224 * This method will allocate a handle if one is not supplied.
225 */
226 if (newLockBytes->supportHandle == 0)
227 {
228 newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE |
229 GMEM_NODISCARD,
230 0);
231 }
232
233 /*
234 * Initialize the size of the array to the size of the handle.
235 */
236 newLockBytes->byteArraySize.DUMMYSTRUCTNAME_DOT HighPart = 0;
237 newLockBytes->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart = GlobalSize(
238 newLockBytes->supportHandle);
239 }
240
241 return newLockBytes;
242}
243
244/******************************************************************************
245 * This is the destructor of the HGLOBALStreamImpl class.
246 *
247 * This method will clean-up all the resources used-up by the given
248 * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be
249 * freed and will not be valid anymore.
250 */
251void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This)
252{
253 /*
254 * Release the HGlobal if the constructor asked for that.
255 */
256 if (This->deleteOnRelease)
257 {
258 GlobalFree(This->supportHandle);
259 This->supportHandle = 0;
260 }
261
262 /*
263 * Finally, free the memory used-up by the class.
264 */
265 HeapFree(GetProcessHeap(), 0, This);
266}
267
268/******************************************************************************
269 * This implements the IUnknown method QueryInterface for this
270 * class
271 */
272HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
273 ILockBytes* iface,
274 REFIID riid, /* [in] */
275 void** ppvObject) /* [iid_is][out] */
276{
277 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
278
279 /*
280 * Perform a sanity check on the parameters.
281 */
282 if (ppvObject==0)
283 return E_INVALIDARG;
284
285 /*
286 * Initialize the return parameter.
287 */
288 *ppvObject = 0;
289
290 /*
291 * Compare the riid with the interface IDs implemented by this object.
292 */
293 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
294 {
295 *ppvObject = (ILockBytes*)This;
296 }
297 else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
298 {
299 *ppvObject = (ILockBytes*)This;
300 }
301
302 /*
303 * Check that we obtained an interface.
304 */
305 if ((*ppvObject)==0)
306 return E_NOINTERFACE;
307
308 /*
309 * Query Interface always increases the reference count by one when it is
310 * successful
311 */
312 HGLOBALLockBytesImpl_AddRef(iface);
313
314 return S_OK;
315}
316
317/******************************************************************************
318 * This implements the IUnknown method AddRef for this
319 * class
320 */
321ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
322{
323 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
324
325 This->ref++;
326
327 return This->ref;
328}
329
330/******************************************************************************
331 * This implements the IUnknown method Release for this
332 * class
333 */
334ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
335{
336 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
337
338 ULONG newRef;
339
340 This->ref--;
341
342 newRef = This->ref;
343
344 /*
345 * If the reference count goes down to 0, perform suicide.
346 */
347 if (newRef==0)
348 {
349 HGLOBALLockBytesImpl_Destroy(This);
350 }
351
352 return newRef;
353}
354
355/******************************************************************************
356 * This method is part of the ILockBytes interface.
357 *
358 * It reads a block of information from the byte array at the specified
359 * offset.
360 *
361 * See the documentation of ILockBytes for more info.
362 */
363HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
364 ILockBytes* iface,
365 ULARGE_INTEGER ulOffset, /* [in] */
366 void* pv, /* [length_is][size_is][out] */
367 ULONG cb, /* [in] */
368 ULONG* pcbRead) /* [out] */
369{
370 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
371
372 void* supportBuffer;
373 ULONG bytesReadBuffer = 0;
374 ULONG bytesToReadFromBuffer;
375
376 /*
377 * If the caller is not interested in the number of bytes read,
378 * we use another buffer to avoid "if" statements in the code.
379 */
380 if (pcbRead == 0)
381 pcbRead = &bytesReadBuffer;
382
383 /*
384 * Make sure the offset is valid.
385 */
386 if (ulOffset.DUMMYSTRUCTNAME_DOT LowPart > This->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart)
387 return E_FAIL;
388
389 /*
390 * Using the known size of the array, calculate the number of bytes
391 * to read.
392 */
393 bytesToReadFromBuffer = min(This->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart -
394 ulOffset.DUMMYSTRUCTNAME_DOT LowPart, cb);
395
396 /*
397 * Lock the buffer in position and copy the data.
398 */
399 supportBuffer = GlobalLock(This->supportHandle);
400
401 memcpy(pv,
402 (char *) supportBuffer + ulOffset.DUMMYSTRUCTNAME_DOT LowPart,
403 bytesToReadFromBuffer);
404
405 /*
406 * Return the number of bytes read.
407 */
408 *pcbRead = bytesToReadFromBuffer;
409
410 /*
411 * Cleanup
412 */
413 GlobalUnlock(This->supportHandle);
414
415 /*
416 * The function returns S_OK if the specified number of bytes were read
417 * or the end of the array was reached.
418 * It returns STG_E_READFAULT if the number of bytes to read does not equal
419 * the number of bytes actually read.
420 */
421 if(*pcbRead == cb)
422 return S_OK;
423
424 return STG_E_READFAULT;
425}
426
427/******************************************************************************
428 * This method is part of the ILockBytes interface.
429 *
430 * It writes the specified bytes at the specified offset.
431 * position. If the array is too small, it will be resized.
432 *
433 * See the documentation of ILockBytes for more info.
434 */
435HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
436 ILockBytes* iface,
437 ULARGE_INTEGER ulOffset, /* [in] */
438 const void* pv, /* [size_is][in] */
439 ULONG cb, /* [in] */
440 ULONG* pcbWritten) /* [out] */
441{
442 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
443
444 void* supportBuffer;
445 ULARGE_INTEGER newSize;
446 ULONG bytesWritten = 0;
447
448 /*
449 * If the caller is not interested in the number of bytes written,
450 * we use another buffer to avoid "if" statements in the code.
451 */
452 if (pcbWritten == 0)
453 pcbWritten = &bytesWritten;
454
455 if (cb == 0)
456 {
457 return S_OK;
458 }
459 else
460 {
461 newSize.DUMMYSTRUCTNAME_DOT HighPart = 0;
462 newSize.DUMMYSTRUCTNAME_DOT LowPart = ulOffset.DUMMYSTRUCTNAME_DOT LowPart + cb;
463 }
464
465 /*
466 * Verify if we need to grow the stream
467 */
468 if (newSize.DUMMYSTRUCTNAME_DOT LowPart > This->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart)
469 {
470 /* grow stream */
471 if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
472 return STG_E_MEDIUMFULL;
473 }
474
475 /*
476 * Lock the buffer in position and copy the data.
477 */
478 supportBuffer = GlobalLock(This->supportHandle);
479
480 memcpy((char *) supportBuffer + ulOffset.DUMMYSTRUCTNAME_DOT LowPart, pv, cb);
481
482 /*
483 * Return the number of bytes written.
484 */
485 *pcbWritten = cb;
486
487 /*
488 * Cleanup
489 */
490 GlobalUnlock(This->supportHandle);
491
492 return S_OK;
493}
494
495/******************************************************************************
496 * This method is part of the ILockBytes interface.
497 *
498 * See the documentation of ILockBytes for more info.
499 */
500HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
501{
502 return S_OK;
503}
504
505/******************************************************************************
506 * This method is part of the ILockBytes interface.
507 *
508 * It will change the size of the byte array.
509 *
510 * See the documentation of ILockBytes for more info.
511 */
512HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
513 ILockBytes* iface,
514 ULARGE_INTEGER libNewSize) /* [in] */
515{
516 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
517
518 /*
519 * As documented.
520 */
521 if (libNewSize.DUMMYSTRUCTNAME_DOT HighPart != 0)
522 return STG_E_INVALIDFUNCTION;
523
524 if (This->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart == libNewSize.DUMMYSTRUCTNAME_DOT LowPart)
525 return S_OK;
526
527 /*
528 * Re allocate the HGlobal to fit the new size of the stream.
529 */
530 This->supportHandle = GlobalReAlloc(This->supportHandle,
531 libNewSize.DUMMYSTRUCTNAME_DOT LowPart,
532 0);
533
534 if (This->supportHandle == 0)
535 return STG_E_MEDIUMFULL;
536
537 This->byteArraySize.DUMMYSTRUCTNAME_DOT LowPart = libNewSize.DUMMYSTRUCTNAME_DOT LowPart;
538
539 return S_OK;
540}
541
542/******************************************************************************
543 * This method is part of the ILockBytes interface.
544 *
545 * The global memory implementation of ILockBytes does not support locking.
546 *
547 * See the documentation of ILockBytes for more info.
548 */
549HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
550 ILockBytes* iface,
551 ULARGE_INTEGER libOffset, /* [in] */
552 ULARGE_INTEGER cb, /* [in] */
553 DWORD dwLockType) /* [in] */
554{
555 return STG_E_INVALIDFUNCTION;
556}
557
558/******************************************************************************
559 * This method is part of the ILockBytes interface.
560 *
561 * The global memory implementation of ILockBytes does not support locking.
562 *
563 * See the documentation of ILockBytes for more info.
564 */
565HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
566 ILockBytes* iface,
567 ULARGE_INTEGER libOffset, /* [in] */
568 ULARGE_INTEGER cb, /* [in] */
569 DWORD dwLockType) /* [in] */
570{
571 return STG_E_INVALIDFUNCTION;
572}
573
574/******************************************************************************
575 * This method is part of the ILockBytes interface.
576 *
577 * This method returns information about the current
578 * byte array object.
579 *
580 * See the documentation of ILockBytes for more info.
581 */
582HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
583 ILockBytes* iface,
584 STATSTG* pstatstg, /* [out] */
585 DWORD grfStatFlag) /* [in] */
586{
587 HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
588
589 memset(pstatstg, 0, sizeof(STATSTG));
590
591 pstatstg->pwcsName = NULL;
592 pstatstg->type = STGTY_LOCKBYTES;
593 pstatstg->cbSize = This->byteArraySize;
594
595 return S_OK;
596}
597
Note: See TracBrowser for help on using the repository browser.