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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

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