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