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