Fixed a race condition on RPC worker thread creation, and a typo.
[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 <string.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "wine/winbase16.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "winbase.h"
34 #include "winerror.h"
35
36 #include "ifs.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41
42 /******************************************************************************
43  * HGLOBALLockBytesImpl definition.
44  *
45  * This class imlements the ILockBytes inteface and represents a byte array
46  * object supported by an HGLOBAL pointer.
47  */
48 struct HGLOBALLockBytesImpl
49 {
50   /*
51    * Needs to be the first item in the stuct
52    * since we want to cast this in an ILockBytes pointer
53    */
54   ICOM_VFIELD(ILockBytes);
55
56   /*
57    * Reference count
58    */
59   ULONG        ref;
60
61   /*
62    * Support for the LockBytes object
63    */
64   HGLOBAL supportHandle;
65
66   /*
67    * This flag is TRUE if the HGLOBAL is destroyed when the object
68    * is finally released.
69    */
70   BOOL    deleteOnRelease;
71
72   /*
73    * Helper variable that contains the size of the byte array
74    */
75   ULARGE_INTEGER     byteArraySize;
76 };
77
78 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
79
80 /*
81  * Method definition for the HGLOBALLockBytesImpl class.
82  */
83 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(
84     HGLOBAL  hGlobal,
85     BOOL     fDeleteOnRelease);
86
87 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This);
88
89 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
90     ILockBytes*   iface,
91     REFIID        riid,        /* [in] */
92     void**        ppvObject);  /* [iid_is][out] */
93
94 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(
95     ILockBytes*   iface);
96
97 ULONG WINAPI HGLOBALLockBytesImpl_Release(
98     ILockBytes*   iface);
99
100 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
101     ILockBytes*    iface,
102     ULARGE_INTEGER ulOffset,  /* [in] */
103     void*          pv,        /* [length_is][size_is][out] */
104     ULONG          cb,        /* [in] */
105     ULONG*         pcbRead);  /* [out] */
106
107 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
108     ILockBytes*    iface,
109     ULARGE_INTEGER ulOffset,    /* [in] */
110     const void*    pv,          /* [size_is][in] */
111     ULONG          cb,          /* [in] */
112     ULONG*         pcbWritten); /* [out] */
113
114 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(
115     ILockBytes*     iface);
116
117 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
118     ILockBytes*     iface,
119     ULARGE_INTEGER  libNewSize);  /* [in] */
120
121 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
122     ILockBytes*    iface,
123     ULARGE_INTEGER libOffset,   /* [in] */
124     ULARGE_INTEGER cb,          /* [in] */
125     DWORD          dwLockType); /* [in] */
126
127 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
128     ILockBytes*    iface,
129     ULARGE_INTEGER libOffset,   /* [in] */
130     ULARGE_INTEGER cb,          /* [in] */
131     DWORD          dwLockType); /* [in] */
132
133 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
134     ILockBytes*    iface,
135     STATSTG*       pstatstg,     /* [out] */
136     DWORD          grfStatFlag); /* [in]  */
137
138 /*
139  * Virtual function table for the HGLOBALLockBytesImpl class.
140  */
141 static ICOM_VTABLE(ILockBytes) HGLOBALLockBytesImpl_Vtbl =
142 {
143     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
144     HGLOBALLockBytesImpl_QueryInterface,
145     HGLOBALLockBytesImpl_AddRef,
146     HGLOBALLockBytesImpl_Release,
147     HGLOBALLockBytesImpl_ReadAt,
148     HGLOBALLockBytesImpl_WriteAt,
149     HGLOBALLockBytesImpl_Flush,
150     HGLOBALLockBytesImpl_SetSize,
151     HGLOBALLockBytesImpl_LockRegion,
152     HGLOBALLockBytesImpl_UnlockRegion,
153     HGLOBALLockBytesImpl_Stat,
154 };
155
156 /******************************************************************************
157  *           CreateILockBytesOnHGlobal     [OLE32.57]
158  */
159 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL      hGlobal,
160                                          BOOL         fDeleteOnRelease,
161                                          LPLOCKBYTES* ppLkbyt)
162 {
163   HGLOBALLockBytesImpl* newLockBytes;
164
165   newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease);
166
167   if (newLockBytes != NULL)
168   {
169     return IUnknown_QueryInterface((IUnknown*)newLockBytes,
170                                    &IID_ILockBytes,
171                                    (void**)ppLkbyt);
172   }
173
174   return E_OUTOFMEMORY;
175 }
176
177 /******************************************************************************
178  *           GetHGlobalFromILockBytes     [OLE32.70]
179  */
180 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal)
181 {
182   HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt;
183   STATSTG stbuf;
184   HRESULT hres;
185   ULARGE_INTEGER start;
186   ULONG xread;
187
188   *phglobal = 0;
189   if (pMemLockBytes->lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
190     *phglobal = pMemLockBytes->supportHandle;
191     if (*phglobal == 0)
192       return E_INVALIDARG;
193     return S_OK;
194   }
195   /* It is not our lockbytes implementation, so use a more generic way */
196   hres = ILockBytes_Stat(plkbyt,&stbuf,0);
197   if (hres != S_OK) {
198      ERR("Cannot ILockBytes_Stat, %lx\n",hres);
199      return hres;
200   }
201   FIXME("cbSize is %ld\n",stbuf.cbSize.s.LowPart);
202   *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.s.LowPart);
203   if (!*phglobal)
204     return E_INVALIDARG;
205   memset(&start,0,sizeof(start));
206   hres = ILockBytes_ReadAt(plkbyt, start, GlobalLock(*phglobal), stbuf.cbSize.s.LowPart, &xread);
207   GlobalUnlock(*phglobal);
208   if (hres != S_OK) {
209     FIXME("%p->ReadAt failed with %lx\n",plkbyt,hres);
210     return hres;
211   }
212   if (stbuf.cbSize.s.LowPart != xread) {
213     FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.s.LowPart, xread);
214   }
215   return S_OK;
216 }
217
218 /******************************************************************************
219  *
220  * HGLOBALLockBytesImpl implementation
221  *
222  */
223
224 /******************************************************************************
225  * This is the constructor for the HGLOBALLockBytesImpl class.
226  *
227  * Params:
228  *    hGlobal          - Handle that will support the stream. can be NULL.
229  *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
230  *                       when the IStream object is destroyed.
231  */
232 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal,
233                                                      BOOL    fDeleteOnRelease)
234 {
235   HGLOBALLockBytesImpl* newLockBytes;
236   newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
237
238   if (newLockBytes!=0)
239   {
240     /*
241      * Set up the virtual function table and reference count.
242      */
243     newLockBytes->lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
244     newLockBytes->ref    = 0;
245
246     /*
247      * Initialize the support.
248      */
249     newLockBytes->supportHandle = hGlobal;
250     newLockBytes->deleteOnRelease = fDeleteOnRelease;
251
252     /*
253      * This method will allocate a handle if one is not supplied.
254      */
255     if (newLockBytes->supportHandle == 0)
256     {
257       newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE |
258                                                 GMEM_NODISCARD,
259                                                 0);
260     }
261
262     /*
263      * Initialize the size of the array to the size of the handle.
264      */
265     newLockBytes->byteArraySize.s.HighPart = 0;
266     newLockBytes->byteArraySize.s.LowPart  = GlobalSize(
267                                               newLockBytes->supportHandle);
268   }
269
270   return newLockBytes;
271 }
272
273 /******************************************************************************
274  * This is the destructor of the HGLOBALStreamImpl class.
275  *
276  * This method will clean-up all the resources used-up by the given
277  * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be
278  * freed and will not be valid anymore.
279  */
280 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This)
281 {
282   /*
283    * Release the HGlobal if the constructor asked for that.
284    */
285   if (This->deleteOnRelease)
286   {
287     GlobalFree(This->supportHandle);
288     This->supportHandle = 0;
289   }
290
291   /*
292    * Finally, free the memory used-up by the class.
293    */
294   HeapFree(GetProcessHeap(), 0, This);
295 }
296
297 /******************************************************************************
298  * This implements the IUnknown method QueryInterface for this
299  * class
300  */
301 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
302       ILockBytes*  iface,
303       REFIID       riid,        /* [in] */
304       void**       ppvObject)   /* [iid_is][out] */
305 {
306   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
307
308   /*
309    * Perform a sanity check on the parameters.
310    */
311   if (ppvObject==0)
312     return E_INVALIDARG;
313
314   /*
315    * Initialize the return parameter.
316    */
317   *ppvObject = 0;
318
319   /*
320    * Compare the riid with the interface IDs implemented by this object.
321    */
322   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
323   {
324     *ppvObject = (ILockBytes*)This;
325   }
326   else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
327   {
328     *ppvObject = (ILockBytes*)This;
329   }
330
331   /*
332    * Check that we obtained an interface.
333    */
334   if ((*ppvObject)==0)
335     return E_NOINTERFACE;
336
337   /*
338    * Query Interface always increases the reference count by one when it is
339    * successful
340    */
341   HGLOBALLockBytesImpl_AddRef(iface);
342
343   return S_OK;
344 }
345
346 /******************************************************************************
347  * This implements the IUnknown method AddRef for this
348  * class
349  */
350 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
351 {
352   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
353
354   This->ref++;
355
356   return 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
367   ULONG newRef;
368
369   This->ref--;
370
371   newRef = This->ref;
372
373   /*
374    * If the reference count goes down to 0, perform suicide.
375    */
376   if (newRef==0)
377   {
378     HGLOBALLockBytesImpl_Destroy(This);
379   }
380
381   return newRef;
382 }
383
384 /******************************************************************************
385  * This method is part of the ILockBytes interface.
386  *
387  * It reads a block of information from the byte array at the specified
388  * offset.
389  *
390  * See the documentation of ILockBytes for more info.
391  */
392 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
393       ILockBytes*    iface,
394       ULARGE_INTEGER ulOffset,  /* [in] */
395       void*          pv,        /* [length_is][size_is][out] */
396       ULONG          cb,        /* [in] */
397       ULONG*         pcbRead)   /* [out] */
398 {
399   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
400
401   void* supportBuffer;
402   ULONG bytesReadBuffer = 0;
403   ULONG bytesToReadFromBuffer;
404
405   /*
406    * If the caller is not interested in the number of bytes read,
407    * we use another buffer to avoid "if" statements in the code.
408    */
409   if (pcbRead == 0)
410     pcbRead = &bytesReadBuffer;
411
412   /*
413    * Make sure the offset is valid.
414    */
415   if (ulOffset.s.LowPart > This->byteArraySize.s.LowPart)
416     return E_FAIL;
417
418   /*
419    * Using the known size of the array, calculate the number of bytes
420    * to read.
421    */
422   bytesToReadFromBuffer = min(This->byteArraySize.s.LowPart -
423                               ulOffset.s.LowPart, cb);
424
425   /*
426    * Lock the buffer in position and copy the data.
427    */
428   supportBuffer = GlobalLock(This->supportHandle);
429
430   memcpy(pv,
431          (char *) supportBuffer + ulOffset.s.LowPart,
432          bytesToReadFromBuffer);
433
434   /*
435    * Return the number of bytes read.
436    */
437   *pcbRead = bytesToReadFromBuffer;
438
439   /*
440    * Cleanup
441    */
442   GlobalUnlock(This->supportHandle);
443
444   /*
445    * The function returns S_OK if the specified number of bytes were read
446    * or the end of the array was reached.
447    * It returns STG_E_READFAULT if the number of bytes to read does not equal
448    * the number of bytes actually read.
449    */
450   if(*pcbRead == cb)
451     return S_OK;
452
453   return STG_E_READFAULT;
454 }
455
456 /******************************************************************************
457  * This method is part of the ILockBytes interface.
458  *
459  * It writes the specified bytes at the specified offset.
460  * position. If the array is too small, it will be resized.
461  *
462  * See the documentation of ILockBytes for more info.
463  */
464 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
465       ILockBytes*    iface,
466       ULARGE_INTEGER ulOffset,    /* [in] */
467       const void*    pv,          /* [size_is][in] */
468       ULONG          cb,          /* [in] */
469       ULONG*         pcbWritten)  /* [out] */
470 {
471   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
472
473   void*          supportBuffer;
474   ULARGE_INTEGER newSize;
475   ULONG          bytesWritten = 0;
476
477   /*
478    * If the caller is not interested in the number of bytes written,
479    * we use another buffer to avoid "if" statements in the code.
480    */
481   if (pcbWritten == 0)
482     pcbWritten = &bytesWritten;
483
484   if (cb == 0)
485   {
486     return S_OK;
487   }
488   else
489   {
490     newSize.s.HighPart = 0;
491     newSize.s.LowPart = ulOffset.s.LowPart + cb;
492   }
493
494   /*
495    * Verify if we need to grow the stream
496    */
497   if (newSize.s.LowPart > This->byteArraySize.s.LowPart)
498   {
499     /* grow stream */
500     if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
501       return STG_E_MEDIUMFULL;
502   }
503
504   /*
505    * Lock the buffer in position and copy the data.
506    */
507   supportBuffer = GlobalLock(This->supportHandle);
508
509   memcpy((char *) supportBuffer + ulOffset.s.LowPart, pv, cb);
510
511   /*
512    * Return the number of bytes written.
513    */
514   *pcbWritten = cb;
515
516   /*
517    * Cleanup
518    */
519   GlobalUnlock(This->supportHandle);
520
521   return S_OK;
522 }
523
524 /******************************************************************************
525  * This method is part of the ILockBytes interface.
526  *
527  * See the documentation of ILockBytes for more info.
528  */
529 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
530 {
531   return S_OK;
532 }
533
534 /******************************************************************************
535  * This method is part of the ILockBytes interface.
536  *
537  * It will change the size of the byte array.
538  *
539  * See the documentation of ILockBytes for more info.
540  */
541 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
542       ILockBytes*     iface,
543       ULARGE_INTEGER  libNewSize)   /* [in] */
544 {
545   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
546
547   /*
548    * As documented.
549    */
550   if (libNewSize.s.HighPart != 0)
551     return STG_E_INVALIDFUNCTION;
552
553   if (This->byteArraySize.s.LowPart == libNewSize.s.LowPart)
554     return S_OK;
555
556   /*
557    * Re allocate the HGlobal to fit the new size of the stream.
558    */
559   This->supportHandle = GlobalReAlloc(This->supportHandle,
560                                       libNewSize.s.LowPart,
561                                       0);
562
563   if (This->supportHandle == 0)
564     return STG_E_MEDIUMFULL;
565
566   This->byteArraySize.s.LowPart = libNewSize.s.LowPart;
567
568   return S_OK;
569 }
570
571 /******************************************************************************
572  * This method is part of the ILockBytes interface.
573  *
574  * The global memory implementation of ILockBytes does not support locking.
575  *
576  * See the documentation of ILockBytes for more info.
577  */
578 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
579       ILockBytes*    iface,
580       ULARGE_INTEGER libOffset,   /* [in] */
581       ULARGE_INTEGER cb,          /* [in] */
582       DWORD          dwLockType)  /* [in] */
583 {
584   return STG_E_INVALIDFUNCTION;
585 }
586
587 /******************************************************************************
588  * This method is part of the ILockBytes interface.
589  *
590  * The global memory implementation of ILockBytes does not support locking.
591  *
592  * See the documentation of ILockBytes for more info.
593  */
594 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
595       ILockBytes*    iface,
596       ULARGE_INTEGER libOffset,   /* [in] */
597       ULARGE_INTEGER cb,          /* [in] */
598       DWORD          dwLockType)  /* [in] */
599 {
600   return STG_E_INVALIDFUNCTION;
601 }
602
603 /******************************************************************************
604  * This method is part of the ILockBytes interface.
605  *
606  * This method returns information about the current
607  * byte array object.
608  *
609  * See the documentation of ILockBytes for more info.
610  */
611 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
612       ILockBytes*  iface,
613       STATSTG*     pstatstg,     /* [out] */
614       DWORD        grfStatFlag)  /* [in] */
615 {
616   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
617
618   memset(pstatstg, 0, sizeof(STATSTG));
619
620   pstatstg->pwcsName = NULL;
621   pstatstg->type     = STGTY_LOCKBYTES;
622   pstatstg->cbSize   = This->byteArraySize;
623
624   return S_OK;
625 }
626
627 /******************************************************************************
628  * HGLOBALLockBytesImpl16 definition.
629  *
630  * This class imlements the ILockBytes inteface and represents a byte array
631  * object supported by an HGLOBAL pointer.
632  */
633 struct HGLOBALLockBytesImpl16
634 {
635   /*
636    * Needs to be the first item in the stuct
637    * since we want to cast this in an ILockBytes pointer
638    */
639   ICOM_VFIELD(ILockBytes16);
640   ULONG        ref;
641
642   /*
643    * Support for the LockBytes object
644    */
645   HGLOBAL16 supportHandle;
646
647   /*
648    * This flag is TRUE if the HGLOBAL is destroyed when the object
649    * is finally released.
650    */
651   BOOL    deleteOnRelease;
652   /*
653    * Helper variable that contains the size of the byte array
654    */
655   ULARGE_INTEGER     byteArraySize;
656 };
657
658 typedef struct HGLOBALLockBytesImpl16 HGLOBALLockBytesImpl16;
659
660 HGLOBALLockBytesImpl16* HGLOBALLockBytesImpl16_Construct(
661     HGLOBAL16  hGlobal,
662     BOOL16     fDeleteOnRelease);
663
664 void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This);
665
666 HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface(
667     ILockBytes16* iface,
668     REFIID        riid,        /* [in] */
669     void**        ppvObject);  /* [iid_is][out] */
670
671 ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(
672     ILockBytes16* iface);
673
674 ULONG WINAPI HGLOBALLockBytesImpl16_Release(
675     ILockBytes16* iface);
676
677 HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt(
678     ILockBytes16*  iface,
679     ULARGE_INTEGER ulOffset,  /* [in] */
680     void*          pv,        /* [length_is][size_is][out] */
681     ULONG          cb,        /* [in] */
682     ULONG*         pcbRead);  /* [out] */
683
684 HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt(
685     ILockBytes16*  iface,
686     ULARGE_INTEGER ulOffset,    /* [in] */
687     const void*    pv,          /* [size_is][in] */
688     ULONG          cb,          /* [in] */
689     ULONG*         pcbWritten); /* [out] */
690
691 HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(
692     ILockBytes16*   iface);
693
694 HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize(
695     ILockBytes16*   iface,
696     ULARGE_INTEGER  libNewSize);  /* [in] */
697
698 HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion(
699     ILockBytes16*  iface,
700     ULARGE_INTEGER libOffset,   /* [in] */
701     ULARGE_INTEGER cb,          /* [in] */
702     DWORD          dwLockType); /* [in] */
703
704 HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion(
705     ILockBytes16*  iface,
706     ULARGE_INTEGER libOffset,   /* [in] */
707     ULARGE_INTEGER cb,          /* [in] */
708     DWORD          dwLockType); /* [in] */
709
710 HRESULT WINAPI HGLOBALLockBytesImpl16_Stat(
711     ILockBytes16*  iface,
712     STATSTG16*     pstatstg,     /* [out] */
713     DWORD          grfStatFlag); /* [in]  */
714
715 /******************************************************************************
716  *
717  * HGLOBALLockBytesImpl16 implementation
718  *
719  */
720
721 /******************************************************************************
722  * This is the constructor for the HGLOBALLockBytesImpl16 class.
723  *
724  * Params:
725  *    hGlobal          - Handle that will support the stream. can be NULL.
726  *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL16 will be released
727  *                       when the IStream object is destroyed.
728  */
729 HGLOBALLockBytesImpl16*
730 HGLOBALLockBytesImpl16_Construct(HGLOBAL16 hGlobal,
731                                  BOOL16 fDeleteOnRelease)
732 {
733   HGLOBALLockBytesImpl16* newLockBytes;
734
735   static ICOM_VTABLE(ILockBytes16) vt16;
736   static SEGPTR msegvt16;
737   HMODULE16 hcomp = GetModuleHandle16("OLE2");
738
739
740   TRACE("(%x,%d)\n",hGlobal,fDeleteOnRelease);
741   newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl16));
742   if (newLockBytes == NULL)
743     return NULL;
744
745   /*
746    * Set up the virtual function table and reference count.
747    */
748   if (!msegvt16)
749   {
750 #define VTENT(x) vt16.x = (void*)GetProcAddress16(hcomp,"HGLOBALLockBytesImpl16_"#x);assert(vt16.x)
751       VTENT(QueryInterface);
752       VTENT(AddRef);
753       VTENT(Release);
754       VTENT(ReadAt);
755       VTENT(WriteAt);
756       VTENT(Flush);
757       VTENT(SetSize);
758       VTENT(LockRegion);
759       VTENT(UnlockRegion);
760 #undef VTENT
761       msegvt16 = MapLS( &vt16 );
762   }
763   newLockBytes->lpVtbl  = (ICOM_VTABLE(ILockBytes16)*)msegvt16;
764   newLockBytes->ref     = 0;
765   /*
766    * Initialize the support.
767    */
768   newLockBytes->supportHandle = hGlobal;
769   newLockBytes->deleteOnRelease = fDeleteOnRelease;
770
771   /*
772    * This method will allocate a handle if one is not supplied.
773    */
774   if (newLockBytes->supportHandle == 0)
775     newLockBytes->supportHandle = GlobalAlloc16(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
776
777   /*
778    * Initialize the size of the array to the size of the handle.
779    */
780   newLockBytes->byteArraySize.s.HighPart = 0;
781   newLockBytes->byteArraySize.s.LowPart  = GlobalSize16(
782                                             newLockBytes->supportHandle);
783
784   return (HGLOBALLockBytesImpl16*)MapLS(newLockBytes);
785 }
786
787 /******************************************************************************
788  * This is the destructor of the HGLOBALStreamImpl class.
789  *
790  * This method will clean-up all the resources used-up by the given
791  * HGLOBALLockBytesImpl16 class. The pointer passed-in to this function will be
792  * freed and will not be valid anymore.
793  */
794 void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This)
795 {
796   TRACE("()\n");
797   /*
798    * Release the HGlobal if the constructor asked for that.
799    */
800   if (This->deleteOnRelease)
801   {
802     GlobalFree16(This->supportHandle);
803     This->supportHandle = 0;
804   }
805
806   /*
807    * Finally, free the memory used-up by the class.
808    */
809   HeapFree(GetProcessHeap(), 0, This);
810 }
811
812 /******************************************************************************
813  * This implements the IUnknown method QueryInterface for this
814  * class
815  */
816 HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface(
817       ILockBytes16*  iface,     /* [in] SEGPTR */
818       REFIID       riid,        /* [in] */
819       void**       ppvObject)   /* [iid_is][out] (ptr to SEGPTR!) */
820 {
821   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)MapSL((SEGPTR)iface);
822
823   TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
824   /*
825    * Perform a sanity check on the parameters.
826    */
827   if (ppvObject==0)
828     return E_INVALIDARG;
829
830   /*
831    * Initialize the return parameter.
832    */
833   *ppvObject = 0;
834   /*
835    * Compare the riid with the interface IDs implemented by this object.
836    */
837   if (  !memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) ||
838         !memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes))
839   )
840     *ppvObject = (void*)iface;
841
842   /*
843    * Check that we obtained an interface.
844    */
845   if ((*ppvObject)==0)
846     return E_NOINTERFACE;
847
848   /*
849    * Query Interface always increases the reference count by one when it is
850    * successful
851    */
852   HGLOBALLockBytesImpl16_AddRef((ILockBytes16*)This);
853
854   return S_OK;
855 }
856
857 /******************************************************************************
858  * This implements the IUnknown method AddRef for this
859  * class
860  */
861 ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface)
862 {
863   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
864
865   TRACE("(%p)\n",This);
866
867   This->ref++;
868
869   return This->ref;
870 }
871
872 /******************************************************************************
873  * This implements the IUnknown method Release for this
874  * class
875  */
876 ULONG WINAPI HGLOBALLockBytesImpl16_Release(ILockBytes16* iface)
877 {
878   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
879
880   ULONG newRef;
881   TRACE("(%p)\n",This);
882
883   This->ref--;
884
885   newRef = This->ref;
886
887   /*
888    * If the reference count goes down to 0, perform suicide.
889    */
890   if (newRef==0)
891     HGLOBALLockBytesImpl16_Destroy(This);
892   return newRef;
893 }
894
895 /******************************************************************************
896  * This method is part of the ILockBytes interface.
897  *
898  * It reads a block of information from the byte array at the specified
899  * offset.
900  *
901  * See the documentation of ILockBytes for more info.
902  */
903 HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt(
904       ILockBytes16*  iface,
905       ULARGE_INTEGER ulOffset,  /* [in] */
906       void*          pv,        /* [length_is][size_is][out] */
907       ULONG          cb,        /* [in] */
908       ULONG*         pcbRead)   /* [out] */
909 {
910   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
911
912   void* supportBuffer;
913   ULONG bytesReadBuffer = 0;
914   ULONG bytesToReadFromBuffer;
915
916   TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.s.LowPart,pv,cb,pcbRead);
917   /*
918    * If the caller is not interested in the number of bytes read,
919    * we use another buffer to avoid "if" statements in the code.
920    */
921   if (pcbRead == 0)
922     pcbRead = &bytesReadBuffer;
923
924   /*
925    * Make sure the offset is valid.
926    */
927   if (ulOffset.s.LowPart > This->byteArraySize.s.LowPart)
928     return E_FAIL;
929
930   /*
931    * Using the known size of the array, calculate the number of bytes
932    * to read.
933    */
934   bytesToReadFromBuffer = min(This->byteArraySize.s.LowPart -
935                               ulOffset.s.LowPart, cb);
936
937   /*
938    * Lock the buffer in position and copy the data.
939    */
940   supportBuffer = GlobalLock16(This->supportHandle);
941
942   memcpy(pv,
943          (char *) supportBuffer + ulOffset.s.LowPart,
944          bytesToReadFromBuffer);
945
946   /*
947    * Return the number of bytes read.
948    */
949   *pcbRead = bytesToReadFromBuffer;
950
951   /*
952    * Cleanup
953    */
954   GlobalUnlock16(This->supportHandle);
955
956   /*
957    * The function returns S_OK if the specified number of bytes were read
958    * or the end of the array was reached.
959    * It returns STG_E_READFAULT if the number of bytes to read does not equal
960    * the number of bytes actually read.
961    */
962   if(*pcbRead == cb)
963     return S_OK;
964
965   return STG_E_READFAULT;
966 }
967
968 /******************************************************************************
969  * This method is part of the ILockBytes interface.
970  *
971  * It writes the specified bytes at the specified offset.
972  * position. If the array is too small, it will be resized.
973  *
974  * See the documentation of ILockBytes for more info.
975  */
976 HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt(
977       ILockBytes16*  iface,
978       ULARGE_INTEGER ulOffset,    /* [in] */
979       const void*    pv,          /* [size_is][in] */
980       ULONG          cb,          /* [in] */
981       ULONG*         pcbWritten)  /* [out] */
982 {
983   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
984
985   void*          supportBuffer;
986   ULARGE_INTEGER newSize;
987   ULONG          bytesWritten = 0;
988
989   TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.s.LowPart,pv,cb,pcbWritten);
990   /*
991    * If the caller is not interested in the number of bytes written,
992    * we use another buffer to avoid "if" statements in the code.
993    */
994   if (pcbWritten == 0)
995     pcbWritten = &bytesWritten;
996
997   if (cb == 0)
998     return S_OK;
999
1000   newSize.s.HighPart = 0;
1001   newSize.s.LowPart = ulOffset.s.LowPart + cb;
1002
1003   /*
1004    * Verify if we need to grow the stream
1005    */
1006   if (newSize.s.LowPart > This->byteArraySize.s.LowPart)
1007   {
1008     /* grow stream */
1009     if (HGLOBALLockBytesImpl16_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
1010       return STG_E_MEDIUMFULL;
1011   }
1012
1013   /*
1014    * Lock the buffer in position and copy the data.
1015    */
1016   supportBuffer = GlobalLock16(This->supportHandle);
1017
1018   memcpy((char *) supportBuffer + ulOffset.s.LowPart, pv, cb);
1019
1020   /*
1021    * Return the number of bytes written.
1022    */
1023   *pcbWritten = cb;
1024
1025   /*
1026    * Cleanup
1027    */
1028   GlobalUnlock16(This->supportHandle);
1029
1030   return S_OK;
1031 }
1032
1033 /******************************************************************************
1034  * This method is part of the ILockBytes interface.
1035  *
1036  * See the documentation of ILockBytes for more info.
1037  */
1038 HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface)
1039 {
1040   TRACE("(%p)\n",iface);
1041   return S_OK;
1042 }
1043
1044 /******************************************************************************
1045  * This method is part of the ILockBytes interface.
1046  *
1047  * It will change the size of the byte array.
1048  *
1049  * See the documentation of ILockBytes for more info.
1050  */
1051 HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize(
1052       ILockBytes16*   iface,
1053       ULARGE_INTEGER  libNewSize)   /* [in] */
1054 {
1055   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
1056
1057   TRACE("(%p,%ld)\n",This,libNewSize.s.LowPart);
1058   /*
1059    * As documented.
1060    */
1061   if (libNewSize.s.HighPart != 0)
1062     return STG_E_INVALIDFUNCTION;
1063
1064   if (This->byteArraySize.s.LowPart == libNewSize.s.LowPart)
1065     return S_OK;
1066
1067   /*
1068    * Re allocate the HGlobal to fit the new size of the stream.
1069    */
1070   This->supportHandle = GlobalReAlloc16(This->supportHandle,
1071                                       libNewSize.s.LowPart,
1072                                       0);
1073
1074   if (This->supportHandle == 0)
1075     return STG_E_MEDIUMFULL;
1076
1077   This->byteArraySize.s.LowPart = libNewSize.s.LowPart;
1078
1079   return S_OK;
1080 }
1081
1082 /******************************************************************************
1083  * This method is part of the ILockBytes interface.
1084  *
1085  * The global memory implementation of ILockBytes does not support locking.
1086  *
1087  * See the documentation of ILockBytes for more info.
1088  */
1089 HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion(
1090       ILockBytes16*  iface,
1091       ULARGE_INTEGER libOffset,   /* [in] */
1092       ULARGE_INTEGER cb,          /* [in] */
1093       DWORD          dwLockType)  /* [in] */
1094 {
1095   return STG_E_INVALIDFUNCTION;
1096 }
1097
1098 /******************************************************************************
1099  * This method is part of the ILockBytes interface.
1100  *
1101  * The global memory implementation of ILockBytes does not support locking.
1102  *
1103  * See the documentation of ILockBytes for more info.
1104  */
1105 HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion(
1106       ILockBytes16*  iface,
1107       ULARGE_INTEGER libOffset,   /* [in] */
1108       ULARGE_INTEGER cb,          /* [in] */
1109       DWORD          dwLockType)  /* [in] */
1110 {
1111   return STG_E_INVALIDFUNCTION;
1112 }
1113
1114 /******************************************************************************
1115  * This method is part of the ILockBytes interface.
1116  *
1117  * This method returns information about the current
1118  * byte array object.
1119  *
1120  * See the documentation of ILockBytes for more info.
1121  */
1122 HRESULT WINAPI HGLOBALLockBytesImpl16_Stat(
1123       ILockBytes16*iface,
1124       STATSTG16*   pstatstg,     /* [out] */
1125       DWORD        grfStatFlag)  /* [in] */
1126 {
1127   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
1128
1129   memset(pstatstg, 0, sizeof(STATSTG16));
1130
1131   pstatstg->pwcsName = NULL;
1132   pstatstg->type     = STGTY_LOCKBYTES;
1133   pstatstg->cbSize   = This->byteArraySize;
1134
1135   return S_OK;
1136 }
1137
1138 /******************************************************************************
1139  *           CreateILockBytesOnHGlobal     [OLE2.54]
1140  * 
1141  * Creates an ILockBytes interface for a HGLOBAL handle.
1142  *
1143  * Params:
1144  *      hGlobal                 the global handle (16bit)
1145  *      fDeleteOnRelease        delete handle on release.
1146  *      ppLkbyt                 pointer to ILockBytes interface.
1147  *
1148  * Returns:
1149  *      Staddard OLE error return codes.
1150  *
1151  */
1152 HRESULT WINAPI CreateILockBytesOnHGlobal16(HGLOBAL16      hGlobal,
1153                                            BOOL16         fDeleteOnRelease,
1154                                            /*SEGPTR**/  LPLOCKBYTES16* ppLkbyt)
1155 {
1156   HGLOBALLockBytesImpl16* newLockBytes; /* SEGPTR */
1157
1158   newLockBytes = HGLOBALLockBytesImpl16_Construct(hGlobal, fDeleteOnRelease);
1159
1160   if (newLockBytes != NULL)
1161     return HGLOBALLockBytesImpl16_QueryInterface((ILockBytes16*)newLockBytes,
1162                                    &IID_ILockBytes,
1163                                    (void**)ppLkbyt);
1164   return E_OUTOFMEMORY;
1165 }