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