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