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

Last change on this file since 7926 was 7926, checked in by sandervl, 24 years ago

Wine 20020215 resync

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