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