~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/oleaut32/safearray.c

Version: ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*************************************************************************
  2  * OLE Automation - SafeArray
  3  *
  4  * This file contains the implementation of the SafeArray functions.
  5  *
  6  * Copyright 1999 Sylvain St-Germain
  7  * Copyright 2002-2003 Marcus Meissner
  8  * Copyright 2003 Jon Griffiths
  9  *
 10  * This library is free software; you can redistribute it and/or
 11  * modify it under the terms of the GNU Lesser General Public
 12  * License as published by the Free Software Foundation; either
 13  * version 2.1 of the License, or (at your option) any later version.
 14  *
 15  * This library is distributed in the hope that it will be useful,
 16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18  * Lesser General Public License for more details.
 19  *
 20  * You should have received a copy of the GNU Lesser General Public
 21  * License along with this library; if not, write to the Free Software
 22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 23  */
 24 /* Memory Layout of a SafeArray:
 25  *
 26  * -0x10: start of memory.
 27  * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
 28  * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
 29  *  -0x4: IRecordInfo* iface;  (if FADF_RECORD, for VT_RECORD (can be NULL))
 30  *  0x00: SAFEARRAY,
 31  *  0x10: SAFEARRAYBOUNDS[0...]
 32  */
 33 
 34 #include "config.h"
 35 
 36 #include <string.h>
 37 #include <stdarg.h>
 38 #include <stdio.h>
 39 
 40 #define COBJMACROS
 41 
 42 #include "windef.h"
 43 #include "winerror.h"
 44 #include "winbase.h"
 45 #include "variant.h"
 46 #include "wine/debug.h"
 47 
 48 WINE_DEFAULT_DEBUG_CHANNEL(variant);
 49 
 50 /************************************************************************
 51  * SafeArray {OLEAUT32}
 52  *
 53  * NOTES
 54  * The SafeArray data type provides the underlying interface for Ole
 55  * Automations arrays, used for example to represent array types in
 56  * Visual Basic(tm) and to gather user defined parameters for invocation through
 57  * an IDispatch interface.
 58  *
 59  * Safe arrays provide bounds checking and automatically manage the data
 60  * types they contain, for example handing reference counting and copying
 61  * of interface pointers. User defined types can be stored in arrays
 62  * using the IRecordInfo interface.
 63  *
 64  * There are two types of SafeArray, normal and vectors. Normal arrays can have
 65  * multiple dimensions and the data for the array is allocated separately from
 66  * the array header. This is the most flexible type of array. Vectors, on the
 67  * other hand, are fixed in size and consist of a single allocated block, and a
 68  * single dimension.
 69  *
 70  * DATATYPES
 71  * The following types of data can be stored within a SafeArray.
 72  * Numeric:
 73  *|  VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
 74  *|  VT_R4, VT_R8, VT_CY, VT_DECIMAL
 75  * Interfaces:
 76  *|  VT_DISPATCH, VT_UNKNOWN, VT_RECORD
 77  * Other:
 78  *|  VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
 79  *
 80  * FUNCTIONS
 81  *  BstrFromVector()
 82  *  VectorFromBstr()
 83  */
 84 
 85 /* Undocumented hidden space before the start of a SafeArray descriptor */
 86 #define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)
 87 
 88 /* Allocate memory */
 89 static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize)
 90 {
 91   /* FIXME: Memory should be allocated and freed using a per-thread IMalloc
 92    *        instance returned from CoGetMalloc().
 93    */
 94   return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize);
 95 }
 96 
 97 /* Free memory */
 98 static inline BOOL SAFEARRAY_Free(LPVOID lpData)
 99 {
100   return HeapFree(GetProcessHeap(), 0, lpData);
101 }
102 
103 /* Get the size of a supported VT type (0 means unsupported) */
104 static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
105 {
106   switch (vt)
107   {
108     case VT_I1:
109     case VT_UI1:      return sizeof(BYTE);
110     case VT_BOOL:
111     case VT_I2:
112     case VT_UI2:      return sizeof(SHORT);
113     case VT_I4:
114     case VT_UI4:
115     case VT_R4:
116     case VT_ERROR:    return sizeof(LONG);
117     case VT_R8:
118     case VT_I8:
119     case VT_UI8:      return sizeof(LONG64);
120     case VT_INT:
121     case VT_UINT:     return sizeof(INT);
122     case VT_INT_PTR:
123     case VT_UINT_PTR: return sizeof(UINT_PTR);
124     case VT_CY:       return sizeof(CY);
125     case VT_DATE:     return sizeof(DATE);
126     case VT_BSTR:     return sizeof(BSTR);
127     case VT_DISPATCH: return sizeof(LPDISPATCH);
128     case VT_VARIANT:  return sizeof(VARIANT);
129     case VT_UNKNOWN:  return sizeof(LPUNKNOWN);
130     case VT_DECIMAL:  return sizeof(DECIMAL);
131     /* Note: Return a non-zero size to indicate vt is valid. The actual size
132      * of a UDT is taken from the result of IRecordInfo_GetSize().
133      */
134     case VT_RECORD:   return 32;
135   }
136   return 0;
137 }
138 
139 /* Set the hidden data for an array */
140 static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw)
141 {
142   /* Implementation data is stored in the 4 bytes before the header */
143   LPDWORD lpDw = (LPDWORD)psa;
144   lpDw[-1] = dw;
145 }
146 
147 /* Get the hidden data from an array */
148 static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa)
149 {
150   LPDWORD lpDw = (LPDWORD)psa;
151   return lpDw[-1];
152 }
153 
154 /* Get the number of cells in a SafeArray */
155 static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
156 {
157   const SAFEARRAYBOUND* psab = psa->rgsabound;
158   USHORT cCount = psa->cDims;
159   ULONG ulNumCells = 1;
160 
161   while (cCount--)
162   {
163     /* This is a valid bordercase. See testcases. -Marcus */
164     if (!psab->cElements)
165       return 0;
166     ulNumCells *= psab->cElements;
167     psab++;
168   }
169   return ulNumCells;
170 }
171 
172 /* Allocate a descriptor for an array */
173 static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut)
174 {
175   *ppsaOut = (SAFEARRAY*)((char*)SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE) + SAFEARRAY_HIDDEN_SIZE);
176 
177   if (!*ppsaOut)
178     return E_UNEXPECTED;
179 
180   return S_OK;
181 }
182 
183 /* Set the features of an array */
184 static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa)
185 {
186   /* Set the IID if we have one, otherwise set the type */
187   if (vt == VT_DISPATCH)
188   {
189     psa->fFeatures = FADF_HAVEIID;
190     SafeArraySetIID(psa, &IID_IDispatch);
191   }
192   else if (vt == VT_UNKNOWN)
193   {
194     psa->fFeatures = FADF_HAVEIID;
195     SafeArraySetIID(psa, &IID_IUnknown);
196   }
197   else if (vt == VT_RECORD)
198     psa->fFeatures = FADF_RECORD;
199   else
200   {
201     psa->fFeatures = FADF_HAVEVARTYPE;
202     SAFEARRAY_SetHiddenDWORD(psa, vt);
203   }
204 }
205 
206 /* Create an array */
207 static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, const SAFEARRAYBOUND *rgsabound, ULONG ulSize)
208 {
209   SAFEARRAY *psa = NULL;
210   unsigned int i;
211 
212   if (!rgsabound)
213     return NULL;
214 
215   if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
216   {
217     switch (vt)
218     {
219       case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
220       case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
221       case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
222       case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
223     }
224 
225     for (i = 0; i < cDims; i++)
226       memcpy(psa->rgsabound + i, rgsabound + cDims - 1 - i, sizeof(SAFEARRAYBOUND));
227 
228     if (ulSize)
229       psa->cbElements = ulSize;
230 
231     if (!psa->cbElements || FAILED(SafeArrayAllocData(psa)))
232     {
233       SafeArrayDestroyDescriptor(psa);
234       psa = NULL;
235     }
236   }
237   return psa;
238 }
239 
240 /* Create an array as a vector */
241 static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize)
242 {
243   SAFEARRAY *psa = NULL;
244 
245   if (ulSize || (vt == VT_RECORD))
246   {
247     /* Allocate the header and data together */
248     if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
249     {
250       SAFEARRAY_SetFeatures(vt, psa);
251 
252       psa->cDims = 1;
253       psa->fFeatures |= FADF_CREATEVECTOR;
254       psa->pvData = &psa[1]; /* Data follows the header */
255       psa->cbElements = ulSize;
256       psa->rgsabound[0].cElements = cElements;
257       psa->rgsabound[0].lLbound = lLbound;
258 
259       switch (vt)
260       {
261         case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
262         case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
263         case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
264         case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
265       }
266     }
267   }
268   return psa;
269 }
270 
271 /* Free data items in an array */
272 static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
273 {
274   if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED))
275   {
276     ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
277 
278     if (ulStartCell > ulCellCount) {
279       FIXME("unexpted ulcellcount %d, start %d\n",ulCellCount,ulStartCell);
280       return E_UNEXPECTED;
281     }
282 
283     ulCellCount -= ulStartCell;
284 
285     if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
286     {
287       LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell;
288 
289       while(ulCellCount--)
290       {
291         if (*lpUnknown)
292           IUnknown_Release(*lpUnknown);
293         lpUnknown++;
294       }
295     }
296     else if (psa->fFeatures & (FADF_RECORD))
297     {
298       IRecordInfo *lpRecInfo;
299 
300       if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo)))
301       {
302         PBYTE pRecordData = (PBYTE)psa->pvData;
303         while(ulCellCount--)
304         {
305           IRecordInfo_RecordClear(lpRecInfo, pRecordData);
306           pRecordData += psa->cbElements;
307         }
308         IRecordInfo_Release(lpRecInfo);
309       }
310     }
311     else if (psa->fFeatures & FADF_BSTR)
312     {
313       BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell;
314 
315       while(ulCellCount--)
316       {
317         SysFreeString(*lpBstr);
318         lpBstr++;
319       }
320     }
321     else if (psa->fFeatures & FADF_VARIANT)
322     {
323       VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell;
324 
325       while(ulCellCount--)
326       {
327         HRESULT hRet = VariantClear(lpVariant);
328 
329         if (FAILED(hRet)) FIXME("VariantClear of element failed!\n");
330         lpVariant++;
331       }
332     }
333   }
334   return S_OK;
335 }
336 
337 /* Copy data items from one array to another */
338 static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
339 {
340   if (!psa->pvData)
341     return S_OK;
342   else if (!dest->pvData || psa->fFeatures & FADF_DATADELETED)
343     return E_INVALIDARG;
344   else
345   {
346     ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
347 
348     dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) |
349                       (psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED));
350 
351     if (psa->fFeatures & FADF_VARIANT)
352     {
353       VARIANT* lpVariant = (VARIANT*)psa->pvData;
354       VARIANT* lpDest = (VARIANT*)dest->pvData;
355 
356       while(ulCellCount--)
357       {
358         HRESULT hRet;
359 
360         hRet = VariantCopy(lpDest, lpVariant);
361         if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
362         lpVariant++;
363         lpDest++;
364       }
365     }
366     else if (psa->fFeatures & FADF_BSTR)
367     {
368       BSTR* lpBstr = (BSTR*)psa->pvData;
369       BSTR* lpDest = (BSTR*)dest->pvData;
370 
371       while(ulCellCount--)
372       {
373         if (*lpBstr)
374         {
375           *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
376           if (!*lpDest)
377             return E_OUTOFMEMORY;
378         }
379         else
380           *lpDest = NULL;
381         lpBstr++;
382         lpDest++;
383       }
384     }
385     else
386     {
387       /* Copy the data over */
388       memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
389 
390       if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
391       {
392         LPUNKNOWN *lpUnknown = (LPUNKNOWN *)dest->pvData;
393 
394         while(ulCellCount--)
395         {
396           if (*lpUnknown)
397             IUnknown_AddRef(*lpUnknown);
398           lpUnknown++;
399         }
400       }
401     }
402 
403     if (psa->fFeatures & FADF_RECORD)
404     {
405       IRecordInfo* pRecInfo = NULL;
406 
407       SafeArrayGetRecordInfo(psa, &pRecInfo);
408       SafeArraySetRecordInfo(dest, pRecInfo);
409 
410       if (pRecInfo)
411       {
412         /* Release because Get() adds a reference */
413         IRecordInfo_Release(pRecInfo);
414       }
415     }
416     else if (psa->fFeatures & FADF_HAVEIID)
417     {
418       GUID guid;
419       SafeArrayGetIID(psa, &guid);
420       SafeArraySetIID(dest, &guid);
421     }
422     else if (psa->fFeatures & FADF_HAVEVARTYPE)
423     {
424       SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
425     }
426   }
427   return S_OK;
428 }
429 
430 /*************************************************************************
431  *              SafeArrayAllocDescriptor (OLEAUT32.36)
432  *
433  * Allocate and initialise a descriptor for a SafeArray.
434  *
435  * PARAMS
436  *  cDims   [I] Number of dimensions of the array
437  *  ppsaOut [O] Destination for new descriptor
438  *
439  * RETURNS
440  * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
441  * Failure: An HRESULT error code indicating the error.
442  *
443  * NOTES
444  * See SafeArray.
445  */
446 HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut)
447 {
448   LONG allocSize;
449 
450   TRACE("(%d,%p)\n", cDims, ppsaOut);
451   
452   if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */
453     return E_INVALIDARG;
454 
455   if (!ppsaOut)
456     return E_POINTER;
457 
458   /* We need enough space for the header and its bounds */
459   allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1);
460 
461   if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut)))
462     return E_UNEXPECTED;
463 
464   (*ppsaOut)->cDims = cDims;
465 
466   TRACE("(%d): %u bytes allocated for descriptor.\n", cDims, allocSize);
467   return S_OK;
468 }
469 
470 /*************************************************************************
471  *              SafeArrayAllocDescriptorEx (OLEAUT32.41)
472  *
473  * Allocate and initialise a descriptor for a SafeArray of a given type.
474  *
475  * PARAMS
476  *  vt      [I] The type of items to store in the array
477  *  cDims   [I] Number of dimensions of the array
478  *  ppsaOut [O] Destination for new descriptor
479  *
480  * RETURNS
481  *  Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
482  *  Failure: An HRESULT error code indicating the error.
483  *
484  * NOTES
485  *  - This function does not check that vt is an allowed VARTYPE.
486  *  - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
487  *  See SafeArray.
488  */
489 HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut)
490 {
491   ULONG cbElements;
492   HRESULT hRet = E_UNEXPECTED;
493 
494   TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut);
495     
496   cbElements = SAFEARRAY_GetVTSize(vt);
497   if (!cbElements)
498     WARN("Creating a descriptor with an invalid VARTYPE!\n");
499 
500   hRet = SafeArrayAllocDescriptor(cDims, ppsaOut);
501 
502   if (SUCCEEDED(hRet))
503   {
504     SAFEARRAY_SetFeatures(vt, *ppsaOut);
505     (*ppsaOut)->cbElements = cbElements;
506   }
507   return hRet;
508 }
509 
510 /*************************************************************************
511  *              SafeArrayAllocData (OLEAUT32.37)
512  *
513  * Allocate the data area of a SafeArray.
514  *
515  * PARAMS
516  *  psa [I] SafeArray to allocate the data area of.
517  *
518  * RETURNS
519  *  Success: S_OK. The data area is allocated and initialised.
520  *  Failure: An HRESULT error code indicating the error.
521  *
522  * NOTES
523  *  See SafeArray.
524  */
525 HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa)
526 {
527   HRESULT hRet = E_INVALIDARG;
528   
529   TRACE("(%p)\n", psa);
530   
531   if (psa)
532   {
533     ULONG ulSize = SAFEARRAY_GetCellCount(psa);
534 
535     psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
536 
537     if (psa->pvData)
538     {
539       hRet = S_OK;
540       TRACE("%u bytes allocated for data at %p (%u objects).\n",
541             ulSize * psa->cbElements, psa->pvData, ulSize);
542     }
543     else
544       hRet = E_OUTOFMEMORY;
545   }
546   return hRet;
547 }
548 
549 /*************************************************************************
550  *              SafeArrayCreate (OLEAUT32.15)
551  *
552  * Create a new SafeArray.
553  *
554  * PARAMS
555  *  vt        [I] Type to store in the safe array
556  *  cDims     [I] Number of array dimensions
557  *  rgsabound [I] Bounds of the array dimensions
558  *
559  * RETURNS
560  *  Success: A pointer to a new array object.
561  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
562  *
563  * NOTES
564  *  Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
565  *  in the Wine implementation.
566  *  See SafeArray.
567  */
568 SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
569 {
570   TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound);
571 
572   if (vt == VT_RECORD)
573     return NULL;
574 
575   return SAFEARRAY_Create(vt, cDims, rgsabound, 0);
576 }
577 
578 /*************************************************************************
579  *              SafeArrayCreateEx (OLEAUT32.15)
580  *
581  * Create a new SafeArray.
582  *
583  * PARAMS
584  *  vt        [I] Type to store in the safe array
585  *  cDims     [I] Number of array dimensions
586  *  rgsabound [I] Bounds of the array dimensions
587  *  pvExtra   [I] Extra data
588  *
589  * RETURNS
590  *  Success: A pointer to a new array object.
591  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
592  *
593  * NOTES
594  * See SafeArray.
595  */
596 SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
597 {
598   ULONG ulSize = 0;
599   IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
600   SAFEARRAY* psa;
601  
602   TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);
603  
604   if (vt == VT_RECORD)
605   {
606     if  (!iRecInfo)
607       return NULL;
608     IRecordInfo_GetSize(iRecInfo, &ulSize);
609   }
610   psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);
611 
612   if (pvExtra)
613   {
614     switch(vt)
615     {
616       case VT_RECORD:
617         SafeArraySetRecordInfo(psa, pvExtra);
618         break;
619       case VT_UNKNOWN:
620       case VT_DISPATCH:
621         SafeArraySetIID(psa, pvExtra);
622         break;
623     }
624   }
625   return psa;
626 }
627 
628 /************************************************************************
629  *              SafeArrayCreateVector (OLEAUT32.411)
630  *
631  * Create a one dimensional, contiguous SafeArray.
632  *
633  * PARAMS
634  *  vt        [I] Type to store in the safe array
635  *  lLbound   [I] Lower bound of the array
636  *  cElements [I] Number of elements in the array
637  *
638  * RETURNS
639  *  Success: A pointer to a new array object.
640  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
641  *
642  * NOTES
643  * See SafeArray.
644  */
645 SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
646 {
647   TRACE("(%d->%s,%d,%d\n", vt, debugstr_vt(vt), lLbound, cElements);
648     
649   if (vt == VT_RECORD)
650     return NULL;
651 
652   return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt));
653 }
654 
655 /************************************************************************
656  *              SafeArrayCreateVectorEx (OLEAUT32.411)
657  *
658  * Create a one dimensional, contiguous SafeArray.
659  *
660  * PARAMS
661  *  vt        [I] Type to store in the safe array
662  *  lLbound   [I] Lower bound of the array
663  *  cElements [I] Number of elements in the array
664  *  pvExtra   [I] Extra data
665  *
666  * RETURNS
667  *  Success: A pointer to a new array object.
668  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
669  *
670  * NOTES
671  * See SafeArray.
672  */
673 SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra)
674 {
675   ULONG ulSize;
676   IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
677   SAFEARRAY* psa;
678 
679  TRACE("(%d->%s,%d,%d,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra);
680  
681   if (vt == VT_RECORD)
682   {
683     if  (!iRecInfo)
684       return NULL;
685     IRecordInfo_GetSize(iRecInfo, &ulSize);
686   }
687   else
688     ulSize = SAFEARRAY_GetVTSize(vt);
689 
690   psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize);
691 
692   if (pvExtra)
693   {
694     switch(vt)
695     {
696       case VT_RECORD:
697         SafeArraySetRecordInfo(psa, iRecInfo);
698         break;
699       case VT_UNKNOWN:
700       case VT_DISPATCH:
701         SafeArraySetIID(psa, pvExtra);
702         break;
703     }
704   }
705   return psa;
706 }
707 
708 /*************************************************************************
709  *              SafeArrayDestroyDescriptor (OLEAUT32.38)
710  *
711  * Destroy a SafeArray.
712  *
713  * PARAMS
714  *  psa [I] SafeArray to destroy.
715  *
716  * RETURNS
717  *  Success: S_OK. The resources used by the array are freed.
718  *  Failure: An HRESULT error code indicating the error.
719  *
720  * NOTES
721  * See SafeArray.
722  */
723 HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa)
724 {
725   TRACE("(%p)\n", psa);
726     
727   if (psa)
728   {
729     LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE;
730 
731     if (psa->cLocks)
732       return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */
733 
734     if (psa->fFeatures & FADF_RECORD)
735       SafeArraySetRecordInfo(psa, NULL);
736 
737     if (psa->fFeatures & FADF_CREATEVECTOR &&
738         !(psa->fFeatures & FADF_DATADELETED))
739         SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */
740 
741     if (!SAFEARRAY_Free(lpv))
742       return E_UNEXPECTED;
743   }
744   return S_OK;
745 }
746 
747 /*************************************************************************
748  *              SafeArrayLock (OLEAUT32.21)
749  *
750  * Increment the lock counter of a SafeArray.
751  *
752  * PARAMS
753  *  psa [O] SafeArray to lock
754  *
755  * RETURNS
756  *  Success: S_OK. The array lock is incremented.
757  *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
758  *           are held on the array at once.
759  *
760  * NOTES
761  *  In Win32 these locks are not thread safe.
762  *  See SafeArray.
763  */
764 HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa)
765 {
766   ULONG ulLocks;
767 
768   TRACE("(%p)\n", psa);
769     
770   if (!psa)
771     return E_INVALIDARG;
772 
773   ulLocks = InterlockedIncrement( (LONG*) &psa->cLocks);
774 
775   if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */
776   {
777     WARN("Out of locks!\n");
778     InterlockedDecrement( (LONG*) &psa->cLocks);
779     return E_UNEXPECTED;
780   }
781   return S_OK;
782 }
783 
784 /*************************************************************************
785  *              SafeArrayUnlock (OLEAUT32.22)
786  *
787  * Decrement the lock counter of a SafeArray.
788  *
789  * PARAMS
790  *  psa [O] SafeArray to unlock
791  *
792  * RETURNS
793  *  Success: S_OK. The array lock is decremented.
794  *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
795  *           held on the array.
796  *
797  * NOTES
798  * See SafeArray.
799  */
800 HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa)
801 {
802   TRACE("(%p)\n", psa);
803   
804   if (!psa)
805     return E_INVALIDARG;
806 
807   if (InterlockedDecrement( (LONG*) &psa->cLocks) < 0)
808   {
809     WARN("Unlocked but no lock held!\n");
810     InterlockedIncrement( (LONG*) &psa->cLocks);
811     return E_UNEXPECTED;
812   }
813   return S_OK;
814 }
815 
816 /*************************************************************************
817  *              SafeArrayPutElement (OLEAUT32.26)
818  *
819  * Put an item into a SafeArray.
820  *
821  * PARAMS
822  *  psa       [I] SafeArray to insert into
823  *  rgIndices [I] Indices to insert at
824  *  pvData    [I] Data to insert
825  *
826  * RETURNS
827  *  Success: S_OK. The item is inserted
828  *  Failure: An HRESULT error code indicating the error.
829  *
830  * NOTES
831  * See SafeArray.
832  */
833 HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
834 {
835   HRESULT hRet;
836 
837   TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
838 
839   if (!psa || !rgIndices)
840     return E_INVALIDARG;
841 
842   hRet = SafeArrayLock(psa);
843 
844   if (SUCCEEDED(hRet))
845   {
846     PVOID lpvDest;
847 
848     hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest);
849 
850     if (SUCCEEDED(hRet))
851     {
852       if (psa->fFeatures & FADF_VARIANT)
853       {
854         VARIANT* lpVariant = (VARIANT*)pvData;
855         VARIANT* lpDest = (VARIANT*)lpvDest;
856 
857         hRet = VariantClear(lpDest);
858         if (FAILED(hRet)) FIXME("VariantClear failed with 0x%x\n", hRet);
859         hRet = VariantCopy(lpDest, lpVariant);
860         if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
861       }
862       else if (psa->fFeatures & FADF_BSTR)
863       {
864         BSTR  lpBstr = (BSTR)pvData;
865         BSTR* lpDest = (BSTR*)lpvDest;
866 
867         SysFreeString(*lpDest);
868 
869         *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr));
870         if (!*lpDest)
871           hRet = E_OUTOFMEMORY;
872       }
873       else
874       {
875         if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
876         {
877           LPUNKNOWN  lpUnknown = (LPUNKNOWN)pvData;
878           LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest;
879 
880           if (lpUnknown)
881             IUnknown_AddRef(lpUnknown);
882           if (*lpDest)
883             IUnknown_Release(*lpDest);
884           *lpDest = lpUnknown;
885         } else {
886           /* Copy the data over */
887           memcpy(lpvDest, pvData, psa->cbElements);
888         }
889       }
890     }
891     SafeArrayUnlock(psa);
892   }
893   return hRet;
894 }
895 
896 
897 /*************************************************************************
898  *              SafeArrayGetElement (OLEAUT32.25)
899  *
900  * Get an item from a SafeArray.
901  *
902  * PARAMS
903  *  psa       [I] SafeArray to get from
904  *  rgIndices [I] Indices to get from
905  *  pvData    [O] Destination for data
906  *
907  * RETURNS
908  *  Success: S_OK. The item data is returned in pvData.
909  *  Failure: An HRESULT error code indicating the error.
910  *
911  * NOTES
912  * See SafeArray.
913  */
914 HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
915 {
916   HRESULT hRet;
917 
918   TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
919     
920   if (!psa || !rgIndices || !pvData)
921     return E_INVALIDARG;
922 
923   hRet = SafeArrayLock(psa);
924 
925   if (SUCCEEDED(hRet))
926   {
927     PVOID lpvSrc;
928 
929     hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc);
930 
931     if (SUCCEEDED(hRet))
932     {
933       if (psa->fFeatures & FADF_VARIANT)
934       {
935         VARIANT* lpVariant = (VARIANT*)lpvSrc;
936         VARIANT* lpDest = (VARIANT*)pvData;
937 
938         /* The original content of pvData is ignored. */
939         V_VT(lpDest) = VT_EMPTY;
940         hRet = VariantCopy(lpDest, lpVariant);
941         if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
942       }
943       else if (psa->fFeatures & FADF_BSTR)
944       {
945         BSTR* lpBstr = (BSTR*)lpvSrc;
946         BSTR* lpDest = (BSTR*)pvData;
947 
948         if (*lpBstr)
949         {
950           *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
951           if (!*lpBstr)
952             hRet = E_OUTOFMEMORY;
953         }
954         else
955           *lpDest = NULL;
956       }
957       else
958       {
959         if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
960         {
961           LPUNKNOWN *lpUnknown = (LPUNKNOWN *)lpvSrc;
962 
963           if (*lpUnknown)
964             IUnknown_AddRef(*lpUnknown);
965         }
966         /* Copy the data over */
967         memcpy(pvData, lpvSrc, psa->cbElements);
968       }
969     }
970     SafeArrayUnlock(psa);
971   }
972   return hRet;
973 }
974 
975 /*************************************************************************
976  *              SafeArrayGetUBound (OLEAUT32.19)
977  *
978  * Get the upper bound for a given SafeArray dimension
979  *
980  * PARAMS
981  *  psa      [I] Array to get dimension upper bound from
982  *  nDim     [I] The dimension number to get the upper bound of
983  *  plUbound [O] Destination for the upper bound
984  *
985  * RETURNS
986  *  Success: S_OK. plUbound contains the dimensions upper bound.
987  *  Failure: An HRESULT error code indicating the error.
988  *
989  * NOTES
990  * See SafeArray.
991  */
992 HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
993 {
994   TRACE("(%p,%d,%p)\n", psa, nDim, plUbound);
995     
996   if (!psa || !plUbound)
997     return E_INVALIDARG;
998 
999   if(!nDim || nDim > psa->cDims)
1000     return DISP_E_BADINDEX;
1001 
1002   *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
1003               psa->rgsabound[psa->cDims - nDim].cElements - 1;
1004 
1005   return S_OK;
1006 }
1007 
1008 /*************************************************************************
1009  *              SafeArrayGetLBound (OLEAUT32.20)
1010  *
1011  * Get the lower bound for a given SafeArray dimension
1012  *
1013  * PARAMS
1014  *  psa      [I] Array to get dimension lower bound from
1015  *  nDim     [I] The dimension number to get the lowe bound of
1016  *  plLbound [O] Destination for the lower bound
1017  *
1018  * RETURNS
1019  *  Success: S_OK. plUbound contains the dimensions lower bound.
1020  *  Failure: An HRESULT error code indicating the error.
1021  *
1022  * NOTES
1023  * See SafeArray.
1024  */
1025 HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
1026 {
1027   TRACE("(%p,%d,%p)\n", psa, nDim, plLbound);
1028 
1029   if (!psa || !plLbound)
1030     return E_INVALIDARG;
1031 
1032   if(!nDim || nDim > psa->cDims)
1033     return DISP_E_BADINDEX;
1034 
1035   *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
1036   return S_OK;
1037 }
1038 
1039 /*************************************************************************
1040  *              SafeArrayGetDim (OLEAUT32.17)
1041  *
1042  * Get the number of dimensions in a SafeArray.
1043  *
1044  * PARAMS
1045  *  psa [I] Array to get the dimensions of
1046  *
1047  * RETURNS
1048  *  The number of array dimensions in psa, or 0 if psa is NULL.
1049  *
1050  * NOTES
1051  * See SafeArray.
1052  */
1053 UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
1054 {
1055   TRACE("(%p) returning %d\n", psa, psa ? psa->cDims : 0u);  
1056   return psa ? psa->cDims : 0;
1057 }
1058 
1059 /*************************************************************************
1060  *              SafeArrayGetElemsize (OLEAUT32.18)
1061  *
1062  * Get the size of an element in a SafeArray.
1063  *
1064  * PARAMS
1065  *  psa [I] Array to get the element size from
1066  *
1067  * RETURNS
1068  *  The size of a single element in psa, or 0 if psa is NULL.
1069  *