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