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