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