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