Removed CLSID_CompositeMoniker (conflicting with static definition).
[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 struct
53    * since we want to cast this in an ILockBytes pointer
54    */
55   const 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  = (const 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   return InterlockedIncrement(&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   ULONG ref;
294
295   TRACE("(%p)\n",This);
296
297   ref = InterlockedDecrement(&This->ref);
298
299   /*
300    * If the reference count goes down to 0, perform suicide.
301    */
302   if (ref==0)
303     HGLOBALLockBytesImpl16_Destroy(This);
304   return ref;
305 }
306
307 /******************************************************************************
308  * This method is part of the ILockBytes interface.
309  *
310  * It reads a block of information from the byte array at the specified
311  * offset.
312  *
313  * See the documentation of ILockBytes for more info.
314  */
315 HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt(
316       ILockBytes16*  iface,
317       ULARGE_INTEGER ulOffset,  /* [in] */
318       void*          pv,        /* [out][length_is][size_is] */
319       ULONG          cb,        /* [in] */
320       ULONG*         pcbRead)   /* [out] */
321 {
322   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
323
324   void* supportBuffer;
325   ULONG bytesReadBuffer = 0;
326   ULONG bytesToReadFromBuffer;
327
328   TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbRead);
329   /*
330    * If the caller is not interested in the number of bytes read,
331    * we use another buffer to avoid "if" statements in the code.
332    */
333   if (pcbRead == 0)
334     pcbRead = &bytesReadBuffer;
335
336   /*
337    * Make sure the offset is valid.
338    */
339   if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
340     return E_FAIL;
341
342   /*
343    * Using the known size of the array, calculate the number of bytes
344    * to read.
345    */
346   bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart -
347                               ulOffset.u.LowPart, cb);
348
349   /*
350    * Lock the buffer in position and copy the data.
351    */
352   supportBuffer = GlobalLock16(This->supportHandle);
353
354   memcpy(pv,
355          (char *) supportBuffer + ulOffset.u.LowPart,
356          bytesToReadFromBuffer);
357
358   /*
359    * Return the number of bytes read.
360    */
361   *pcbRead = bytesToReadFromBuffer;
362
363   /*
364    * Cleanup
365    */
366   GlobalUnlock16(This->supportHandle);
367
368   /*
369    * The function returns S_OK if the specified number of bytes were read
370    * or the end of the array was reached.
371    * It returns STG_E_READFAULT if the number of bytes to read does not equal
372    * the number of bytes actually read.
373    */
374   if(*pcbRead == cb)
375     return S_OK;
376
377   return STG_E_READFAULT;
378 }
379
380 /******************************************************************************
381  * This method is part of the ILockBytes interface.
382  *
383  * It writes the specified bytes at the specified offset.
384  * position. If the array is too small, it will be resized.
385  *
386  * See the documentation of ILockBytes for more info.
387  */
388 HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt(
389       ILockBytes16*  iface,
390       ULARGE_INTEGER ulOffset,    /* [in] */
391       const void*    pv,          /* [in][size_is] */
392       ULONG          cb,          /* [in] */
393       ULONG*         pcbWritten)  /* [out] */
394 {
395   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
396
397   void*          supportBuffer;
398   ULARGE_INTEGER newSize;
399   ULONG          bytesWritten = 0;
400
401   TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbWritten);
402   /*
403    * If the caller is not interested in the number of bytes written,
404    * we use another buffer to avoid "if" statements in the code.
405    */
406   if (pcbWritten == 0)
407     pcbWritten = &bytesWritten;
408
409   if (cb == 0)
410     return S_OK;
411
412   newSize.u.HighPart = 0;
413   newSize.u.LowPart = ulOffset.u.LowPart + cb;
414
415   /*
416    * Verify if we need to grow the stream
417    */
418   if (newSize.u.LowPart > This->byteArraySize.u.LowPart)
419   {
420     /* grow stream */
421     if (HGLOBALLockBytesImpl16_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
422       return STG_E_MEDIUMFULL;
423   }
424
425   /*
426    * Lock the buffer in position and copy the data.
427    */
428   supportBuffer = GlobalLock16(This->supportHandle);
429
430   memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb);
431
432   /*
433    * Return the number of bytes written.
434    */
435   *pcbWritten = cb;
436
437   /*
438    * Cleanup
439    */
440   GlobalUnlock16(This->supportHandle);
441
442   return S_OK;
443 }
444
445 /******************************************************************************
446  * This method is part of the ILockBytes interface.
447  *
448  * See the documentation of ILockBytes for more info.
449  */
450 HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface)
451 {
452   TRACE("(%p)\n",iface);
453   return S_OK;
454 }
455
456 /******************************************************************************
457  * This method is part of the ILockBytes interface.
458  *
459  * It will change the size of the byte array.
460  *
461  * See the documentation of ILockBytes for more info.
462  */
463 HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize(
464       ILockBytes16*   iface,
465       ULARGE_INTEGER  libNewSize)   /* [in] */
466 {
467   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
468   HGLOBAL16 supportHandle;
469
470   TRACE("(%p,%ld)\n",This,libNewSize.u.LowPart);
471   /*
472    * As documented.
473    */
474   if (libNewSize.u.HighPart != 0)
475     return STG_E_INVALIDFUNCTION;
476
477   if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
478     return S_OK;
479
480   /*
481    * Re allocate the HGlobal to fit the new size of the stream.
482    */
483   supportHandle = GlobalReAlloc16(This->supportHandle, libNewSize.u.LowPart, 0);
484
485   if (supportHandle == 0)
486     return STG_E_MEDIUMFULL;
487
488   This->supportHandle = supportHandle;
489   This->byteArraySize.u.LowPart = libNewSize.u.LowPart;
490
491   return S_OK;
492 }
493
494 /******************************************************************************
495  * This method is part of the ILockBytes interface.
496  *
497  * The global memory implementation of ILockBytes does not support locking.
498  *
499  * See the documentation of ILockBytes for more info.
500  */
501 HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion(
502       ILockBytes16*  iface,
503       ULARGE_INTEGER libOffset,   /* [in] */
504       ULARGE_INTEGER cb,          /* [in] */
505       DWORD          dwLockType)  /* [in] */
506 {
507   return STG_E_INVALIDFUNCTION;
508 }
509
510 /******************************************************************************
511  * This method is part of the ILockBytes interface.
512  *
513  * The global memory implementation of ILockBytes does not support locking.
514  *
515  * See the documentation of ILockBytes for more info.
516  */
517 HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion(
518       ILockBytes16*  iface,
519       ULARGE_INTEGER libOffset,   /* [in] */
520       ULARGE_INTEGER cb,          /* [in] */
521       DWORD          dwLockType)  /* [in] */
522 {
523   return STG_E_INVALIDFUNCTION;
524 }
525
526 /******************************************************************************
527  * This method is part of the ILockBytes interface.
528  *
529  * This method returns information about the current
530  * byte array object.
531  *
532  * See the documentation of ILockBytes for more info.
533  */
534 HRESULT WINAPI HGLOBALLockBytesImpl16_Stat(
535       ILockBytes16*iface,
536       STATSTG16*   pstatstg,     /* [out] */
537       DWORD        grfStatFlag)  /* [in] */
538 {
539   HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface;
540
541   memset(pstatstg, 0, sizeof(STATSTG16));
542
543   pstatstg->pwcsName = NULL;
544   pstatstg->type     = STGTY_LOCKBYTES;
545   pstatstg->cbSize   = This->byteArraySize;
546
547   return S_OK;
548 }
549
550 /******************************************************************************
551  *           CreateILockBytesOnHGlobal     [OLE2.54]
552  * 
553  * Creates an ILockBytes interface for a HGLOBAL handle.
554  *
555  * Params:
556  *      hGlobal                 the global handle (16bit)
557  *      fDeleteOnRelease        delete handle on release.
558  *      ppLkbyt                 pointer to ILockBytes interface.
559  *
560  * Returns:
561  *      Staddard OLE error return codes.
562  *
563  */
564 HRESULT WINAPI CreateILockBytesOnHGlobal16(
565         HGLOBAL16      hGlobal,          /* [in] */
566         BOOL16         fDeleteOnRelease, /* [in] */
567         LPLOCKBYTES16 *ppLkbyt)          /* [out] (ptr to SEGPTR!) */
568 {
569   HGLOBALLockBytesImpl16* newLockBytes; /* SEGPTR */
570
571   newLockBytes = HGLOBALLockBytesImpl16_Construct(hGlobal, fDeleteOnRelease);
572
573   if (newLockBytes != NULL)
574     return HGLOBALLockBytesImpl16_QueryInterface((ILockBytes16*)newLockBytes,
575                                    &IID_ILockBytes,
576                                    (void**)ppLkbyt);
577   return E_OUTOFMEMORY;
578 }