PATCH: safearray

Marcus Meissner marcus at jet.franken.de
Sat Dec 28 14:25:26 CST 2002


Hi,

Lots of fixes and new features for SafeArrays. Accompanied with testcases
for large parts (not all).

The testcases run with win2000 oleaut32.dll with 0 errors.

Ciao, Marcus

Changelog:
	Implemented SafeArray{SetIID,GetIID,SetRecordInfo,GetRecordInfo}.
	Added support for FADF_HAVEIID, FADF_RECORD, FADF_HAVEVARTYPE.
	Implemented SafeArrayAllocDescriptorEx and SafeArrayGetVarType 
	correctly.
	Fixed second argument of SafeArrayCopyData (it is just SAFEARRAY*).
	Changed allocation to include 16 bytes before the SAFEARRAY (to 
	store IID/VARTYPE/IRecordInfo*).
	VARTYPE -> size array was not indexed correctly.
	Added lots of testcases for most functionality.
	Added IRecordInfo interface definition.

Index: dlls/oleaut32/oleaut32.spec
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/oleaut32.spec,v
retrieving revision 1.46
diff -u -r1.46 oleaut32.spec
--- dlls/oleaut32/oleaut32.spec	23 Dec 2002 02:02:50 -0000	1.46
+++ dlls/oleaut32/oleaut32.spec	28 Dec 2002 20:10:14 -0000
@@ -41,8 +41,8 @@
 41 stdcall SafeArrayAllocDescriptorEx(long long ptr) SafeArrayAllocDescriptorEx
 42 stub SafeArrayCreateEx
 43 stub SafeArrayCreateVectorEx
-44 stub SafeArraySetRecordInfo
-45 stub SafeArrayGetRecordInfo
+44 stdcall SafeArraySetRecordInfo(ptr ptr) SafeArraySetRecordInfo
+45 stdcall SafeArrayGetRecordInfo(ptr ptr) SafeArrayGetRecordInfo
 46 stdcall VarParseNumFromStr(wstr long long ptr ptr) VarParseNumFromStr
 47 stdcall VarNumFromParseNum(ptr ptr long ptr) VarNumFromParseNum
 48 stdcall VarI2FromUI1(long ptr) VarI2FromUI1
@@ -54,7 +54,7 @@
 54 stdcall VarI2FromStr(wstr long long ptr) VarI2FromStr
 55 stub VarI2FromDisp
 56 stdcall VarI2FromBool(long ptr) VarI2FromBool
-57 stub SafeArraySetIID
+57 stdcall SafeArraySetIID(ptr ptr) SafeArraySetIID
 58 stdcall VarI4FromUI1(long ptr) VarI4FromUI1
 59 stdcall VarI4FromI2(long ptr) VarI4FromI2
 60 stdcall VarI4FromR4(long ptr) VarI4FromR4
@@ -64,7 +64,7 @@
 64 stdcall VarI4FromStr(wstr long long ptr) VarI4FromStr
 65 stub VarI4FromDisp
 66 stdcall VarI4FromBool(long ptr) VarI4FromBool
-67 stub SafeArrayGetIID
+67 stdcall SafeArrayGetIID(ptr ptr) SafeArrayGetIID
 68 stdcall VarR4FromUI1(long ptr) VarR4FromUI1
 69 stdcall VarR4FromI2(long ptr) VarR4FromI2
 70 stdcall VarR4FromI4(long ptr) VarR4FromI4
Index: dlls/oleaut32/safearray.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/safearray.c,v
retrieving revision 1.21
diff -u -r1.21 safearray.c
--- dlls/oleaut32/safearray.c	23 Dec 2002 02:02:50 -0000	1.21
+++ dlls/oleaut32/safearray.c	28 Dec 2002 20:10:14 -0000
@@ -20,6 +20,15 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+/* Memory Layout of a SafeArray:
+ *
+ * -0x10: start of memory.
+ * -0x10: GUID	for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
+ * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
+ *  -0x4: IRecordInfo* iface; 	(if FADF_RECORD, for VT_RECORD (can be NULL))
+ *  0x00: SAFEARRAY,
+ *  0x10: SAFEARRAYBOUNDS[0...]
+ */
 
 #include <stdio.h>
 #include <string.h>
@@ -59,7 +68,7 @@
 getArraySize(SAFEARRAY *psa);
 
 static HRESULT
-duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
+duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
 
 /* Association between VARTYPE and their size.
    A size of zero is defined for the unsupported types.  */
@@ -100,6 +109,38 @@
 VARTYPE_NOT_SUPPORTED,	/* VT_USERDEFINED [T]       user defined type			*/
 VARTYPE_NOT_SUPPORTED,	/* VT_LPSTR       [T][P]    null terminated string	*/
 VARTYPE_NOT_SUPPORTED,	/* VT_LPWSTR      [T][P]    wide null term string		*/
+VARTYPE_NOT_SUPPORTED,	/* 32 */
+VARTYPE_NOT_SUPPORTED,  /* 33 */
+VARTYPE_NOT_SUPPORTED,  /* 34 */
+VARTYPE_NOT_SUPPORTED,  /* 35 */
+VARTYPE_NOT_SUPPORTED,  /* VT_RECORD                record */
+VARTYPE_NOT_SUPPORTED,  /* 37 */
+VARTYPE_NOT_SUPPORTED,  /* 38 */
+VARTYPE_NOT_SUPPORTED,  /* 39 */
+VARTYPE_NOT_SUPPORTED,  /* 40 */
+VARTYPE_NOT_SUPPORTED,  /* 41 */
+VARTYPE_NOT_SUPPORTED,  /* 42 */
+VARTYPE_NOT_SUPPORTED,  /* 43 */
+VARTYPE_NOT_SUPPORTED,  /* 44 */
+VARTYPE_NOT_SUPPORTED,  /* 45 */
+VARTYPE_NOT_SUPPORTED,  /* 46 */
+VARTYPE_NOT_SUPPORTED,  /* 47 */
+VARTYPE_NOT_SUPPORTED,  /* 48 */
+VARTYPE_NOT_SUPPORTED,  /* 49 */
+VARTYPE_NOT_SUPPORTED,  /* 50 */
+VARTYPE_NOT_SUPPORTED,  /* 51 */
+VARTYPE_NOT_SUPPORTED,  /* 52 */
+VARTYPE_NOT_SUPPORTED,  /* 53 */
+VARTYPE_NOT_SUPPORTED,  /* 54 */
+VARTYPE_NOT_SUPPORTED,  /* 55 */
+VARTYPE_NOT_SUPPORTED,  /* 56 */
+VARTYPE_NOT_SUPPORTED,  /* 57 */
+VARTYPE_NOT_SUPPORTED,  /* 58 */
+VARTYPE_NOT_SUPPORTED,  /* 59 */
+VARTYPE_NOT_SUPPORTED,  /* 60 */
+VARTYPE_NOT_SUPPORTED,  /* 61 */
+VARTYPE_NOT_SUPPORTED,  /* 62 */
+VARTYPE_NOT_SUPPORTED,  /* 63 */
 VARTYPE_NOT_SUPPORTED,	/* VT_FILETIME       [P]    FILETIME			*/
 VARTYPE_NOT_SUPPORTED,	/* VT_BLOB           [P]    Length prefixed bytes */
 VARTYPE_NOT_SUPPORTED,	/* VT_STREAM         [P]    Name of stream follows		*/
@@ -109,9 +150,6 @@
 VARTYPE_NOT_SUPPORTED,	/* VT_BLOB_OBJECT    [P]    Blob contains an object*/
 VARTYPE_NOT_SUPPORTED,	/* VT_CF             [P]    Clipboard format			*/
 VARTYPE_NOT_SUPPORTED,	/* VT_CLSID          [P]    A Class ID			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_VECTOR         [P]    simple counted array		*/
-VARTYPE_NOT_SUPPORTED,	/* VT_ARRAY    [V]          SAFEARRAY*			*/
-VARTYPE_NOT_SUPPORTED 	/* VT_BYREF    [V]          void* for local use	*/
 };
 
 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
@@ -127,23 +165,24 @@
 {
   SAFEARRAYBOUND *sab;
   LONG allocSize = 0;
+  LPVOID ptr;
 
   if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
     return E_INVALIDARG;
   if (!ppsaOut)
     return E_POINTER;
 
-
-  /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
-                                             ( in SAFEARRAY struct */
-  allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
+  /* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
+   * ( -1 because there is already one ( in SAFEARRAY struct
+   */
+  allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
 
   /* Allocate memory for SAFEARRAY struc */
-  if(( (*ppsaOut)=HeapAlloc(
-        GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
-    return(E_UNEXPECTED);
-  }
-  (*ppsaOut)->cDims = cDims;
+  ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
+  if (!ptr)
+    return E_OUTOFMEMORY;
+  *ppsaOut = ptr+sizeof(GUID);
+  (*ppsaOut)->cDims	= cDims;
   TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
 
   return(S_OK);
@@ -152,21 +191,37 @@
 /*************************************************************************
  *		SafeArrayAllocDescriptorEx (OLEAUT32.41)
  * Allocate the appropriate amount of memory for the SafeArray descriptor
- *
- * This is a minimal implementation just to get things moving.
- *
- * The MSDN documentation on this doesn't tell us much.
+ * and also store information about the vartype before the returned pointer.
  */
 HRESULT WINAPI SafeArrayAllocDescriptorEx(
   VARTYPE vt,
   UINT    cDims,
   SAFEARRAY **ppsaOut)
 {
-  if ( (vt >= LAST_VARTYPE) ||
-       ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
-    return E_UNEXPECTED;
+  HRESULT hres;
 
-  return SafeArrayAllocDescriptor (cDims, ppsaOut);
+  hres = SafeArrayAllocDescriptor (cDims, ppsaOut);
+  if (FAILED(hres))
+    return hres;
+
+  switch (vt) {
+  case VT_DISPATCH:
+    (*ppsaOut)->fFeatures = FADF_HAVEIID;
+    SafeArraySetIID( *ppsaOut, &IID_IDispatch);
+    break;
+  case VT_UNKNOWN:
+    (*ppsaOut)->fFeatures = FADF_HAVEIID;
+    SafeArraySetIID( *ppsaOut, &IID_IUnknown);
+    break;
+  case VT_RECORD:
+    (*ppsaOut)->fFeatures = FADF_RECORD;
+    break;
+  default:
+    (*ppsaOut)->fFeatures = FADF_HAVEVARTYPE;
+    ((DWORD*)*ppsaOut)[-1] = vt;
+    break;
+  }
+  return S_OK;
 }
 
 /*************************************************************************
@@ -213,12 +268,18 @@
     return NULL;
 
   /* Allocate memory for the array descriptor */
-  if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
+  if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
     return NULL;
 
   /* setup data members... */
   psa->cDims     = cDims;
-  psa->fFeatures = getFeatures(vt);
+  switch (vt) {
+  case VT_BSTR:      psa->fFeatures |= FADF_BSTR;break;
+  case VT_UNKNOWN:   psa->fFeatures |= FADF_UNKNOWN;break;
+  case VT_DISPATCH:  psa->fFeatures |= FADF_DISPATCH;break;
+  case VT_VARIANT:   psa->fFeatures |= FADF_VARIANT;break;
+  default: break;
+  }
   psa->cLocks    = 0;
   psa->pvData    = NULL;
   psa->cbElements= VARTYPE_SIZE[vt];
@@ -246,14 +307,16 @@
 HRESULT WINAPI SafeArrayDestroyDescriptor(
   SAFEARRAY *psa)
 {
+  LPVOID ptr;
+
   /* Check for lockness before to free... */
   if(psa->cLocks > 0)
     return DISP_E_ARRAYISLOCKED;
 
   /* The array is unlocked, then, deallocate memory */
-  if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
+  ptr = ((IID*)psa)-1;
+  if(HeapFree( GetProcessHeap(), 0, ptr) == FALSE)
     return E_UNEXPECTED;
-
   return(S_OK);
 }
 
@@ -328,7 +391,7 @@
 
     } else {
 
-      if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
+      if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
         BSTR pbstrReAllocStr = NULL;
         if(pv &&
            ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
@@ -337,7 +400,7 @@
         } else
           *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
       }
-      else if(psa->fFeatures == FADF_VARIANT) {
+      else if(psa->fFeatures & FADF_VARIANT) {
         HRESULT hr = VariantCopy(elementStorageAddress, pv);
         if (FAILED(hr)) {
           SafeArrayUnlock(psa);
@@ -385,7 +448,7 @@
     /* Figure out the number of byte to skip ... */
     elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
 
-    if( psa->fFeatures == FADF_BSTR) {           /* reallocate the obj */
+    if( psa->fFeatures & FADF_BSTR) {           /* reallocate the obj */
       BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
       BSTR pbstrReturnedStr = NULL;
       if( pbstrStoredStr &&
@@ -395,7 +458,7 @@
       } else
         *((BSTR*)pv) = pbstrReturnedStr;
     }
-    else if( psa->fFeatures == FADF_VARIANT) {
+    else if( psa->fFeatures & FADF_VARIANT) {
       HRESULT hr;
       VariantInit(pv);
       hr = VariantCopy(pv, elementStorageAddress);
@@ -624,7 +687,7 @@
   if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
 
     /* free the whole chunk */
-    if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
+    if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*failed*/
       return E_UNEXPECTED; /* UNDOC error condition */
 
     psa->pvData = NULL;
@@ -640,7 +703,7 @@
  */
 HRESULT WINAPI SafeArrayCopyData(
   SAFEARRAY *psaSource,
-  SAFEARRAY **psaTarget)
+  SAFEARRAY *psaTarget)
 {
   USHORT   cDimCount;        /* looper */
   LONG     lDelta;           /* looper */
@@ -648,10 +711,10 @@
   ULONG    ulWholeArraySize; /* Number of item in SA */
   BSTR   bstr;
 
-  if(! (validArg(psaSource) && validArg(*psaTarget)) )
+  if(! (validArg(psaSource) && validArg(psaTarget)) )
     return E_INVALIDARG;
 
-  if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
+  if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
     return E_INVALIDARG;
 
   ulWholeArraySize = getArraySize(psaSource);
@@ -659,34 +722,34 @@
   /* The two arrays boundaries must be of same lenght */
   for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
     if( psaSource->rgsabound[cDimCount].cElements !=
-      (*psaTarget)->rgsabound[cDimCount].cElements)
+      psaTarget->rgsabound[cDimCount].cElements)
       return E_INVALIDARG;
 
-  if( isPointer((*psaTarget)->fFeatures) ) {         /* the target contains ptr
-                                                        that must be released */
+  if( isPointer(psaTarget->fFeatures) ) {         /* the target contains ptr
+                                                     that must be released */
     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
       punk = *(IUnknown**)
-        ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
+        ((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
 
       if( punk != NULL)
         IUnknown_Release(punk);
     }
 
   }
-  else if( (*psaTarget)->fFeatures & FADF_BSTR) {    /* the target contain BSTR
+  else if( psaTarget->fFeatures & FADF_BSTR) {    /* the target contain BSTR
                                                         that must be freed */
     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
       bstr =
-        *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
+        *(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
 
       if( bstr != NULL)
         SysFreeString( bstr );
     }
   }
-  else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
+  else if( psaTarget->fFeatures & FADF_VARIANT) {
 
     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
-      VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
+      VariantClear((VARIANT*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements)));
     }
   }
 
@@ -732,10 +795,27 @@
 
   if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
 
-    /* Duplicate the SAFEARRAY struc */
+    /* Duplicate the SAFEARRAY struct */
     memcpy(*ppsaOut, psa,
             sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
 
+    /* If the features that use storage before the SAFEARRAY struct are
+     * enabled, also copy this memory range. Flags have been copied already.
+     */
+    if (psa->fFeatures & (FADF_HAVEIID | FADF_HAVEVARTYPE))
+      memcpy(((GUID*)*ppsaOut)-1, ((GUID*)psa)-1, sizeof(GUID));
+
+    /* Copy the IRecordInfo* reference */
+    if (psa->fFeatures & FADF_RECORD) {
+      IRecordInfo *ri;
+
+      ri = ((IRecordInfo**)psa)[-1];
+      if (ri) {
+	((IRecordInfo**)*ppsaOut)[-1] = ri;
+	IRecordInfo_AddRef(ri);
+      }
+    }
+
     (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
 
     /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
@@ -750,7 +830,7 @@
       HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
     if( (*ppsaOut)->pvData != NULL) {   /* HeapAlloc succeed */
 
-      if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
+      if( (hRes=duplicateData(psa, *ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
         HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
         (*ppsaOut)->pvData = NULL;
         SafeArrayDestroyDescriptor(*ppsaOut);
@@ -779,6 +859,7 @@
   ULONG   cElements)
 {
   SAFEARRAY *psa;
+  LPVOID    *ptr;
 
   /* Validate supported VARTYPE */
   if ( (vt >= LAST_VARTYPE) ||
@@ -786,11 +867,12 @@
     return NULL;
 
   /* Allocate memory for the array descriptor and data contiguously  */
-  if( FAILED( psa = HeapAlloc( GetProcessHeap(),
+  ptr = HeapAlloc( GetProcessHeap(),
                       HEAP_ZERO_MEMORY,
-                      (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
+                      (sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
+  if (!ptr)
     return NULL;
-  }
+  psa = (SAFEARRAY*)(ptr+sizeof(GUID));
 
   /* setup data members... */
   psa->cDims      = 1; /* always and forever */
@@ -874,13 +956,13 @@
   /* Check whether the size of the chunk makes sense... That's the only thing
      I can think of now... */
 
-  psaSize = HeapSize(GetProcessHeap(), 0, psa);
+  psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
   if (psaSize == -1)
     /* uh, foreign heap. Better don't mess with it ! */
     return TRUE;
 
   /* size of the descriptor when the SA is not created with CreateVector */
-  descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
+  descSize = sizeof(GUID) + sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
 
   /* size of the descriptor + data when created with CreateVector */
   fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
@@ -960,14 +1042,12 @@
 /************************************************************************
  * Used to set the fFeatures data member of the SAFEARRAY structure.
  */
-static INT getFeatures(
-  VARTYPE vt)
-{
-  switch(vt) {
-    case VT_BSTR:      return FADF_BSTR;
-    case VT_UNKNOWN:   return FADF_UNKNOWN;
-    case VT_DISPATCH:  return FADF_DISPATCH;
-    case VT_VARIANT:   return FADF_VARIANT;
+static INT getFeatures(VARTYPE vt) {
+  switch (vt) {
+  case VT_BSTR:      return FADF_BSTR;
+  case VT_UNKNOWN:   return FADF_UNKNOWN;
+  case VT_DISPATCH:  return FADF_DISPATCH;
+  case VT_VARIANT:   return FADF_VARIANT;
   }
   return 0;
 }
@@ -1088,14 +1168,14 @@
  */
 static HRESULT duplicateData(
   SAFEARRAY *psa,
-  SAFEARRAY **ppsaOut)
+  SAFEARRAY *ppsaOut)
 {
   ULONG    ulWholeArraySize; /* size of the thing */
   LONG     lDelta;
 
   ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
 
-  SafeArrayLock(*ppsaOut);
+  SafeArrayLock(ppsaOut);
 
   if( isPointer(psa->fFeatures) ) {  /* If datatype is object increment
                                         object's reference count */
@@ -1109,8 +1189,7 @@
     }
 
     /* Copy the source array data into target array */
-    memcpy((*ppsaOut)->pvData, psa->pvData,
-      ulWholeArraySize*psa->cbElements);
+    memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
 
   }
   else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
@@ -1121,11 +1200,11 @@
       if(( pbstrReAllocStr = SYSDUPSTRING(
             *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
 
-        SafeArrayUnlock(*ppsaOut);
+        SafeArrayUnlock(ppsaOut);
         return E_OUTOFMEMORY;
       }
 
-      *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
+      *((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
         pbstrReAllocStr;
     }
 
@@ -1133,19 +1212,14 @@
   else if( psa->fFeatures & FADF_VARIANT ) {
 
     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
-      VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
+      VariantCopy((VARIANT*)((char *) ppsaOut->pvData+(lDelta * psa->cbElements)),
                   (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
     }
 
+  } else { /* Simply copy the source array data into target array */
+    memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
   }
-  else { /* Simply copy the source array data into target array */
-
-    memcpy((*ppsaOut)->pvData, psa->pvData,
-      ulWholeArraySize*psa->cbElements);
-  }
-
-  SafeArrayUnlock(*ppsaOut);
-
+  SafeArrayUnlock(ppsaOut);
   return S_OK;
 }
 
@@ -1158,44 +1232,106 @@
   SAFEARRAY* psa,
   VARTYPE*   pvt)
 {
-  HRESULT hr = E_INVALIDARG;
-  VARTYPE vt = VT_EMPTY;
-
-  /* const short VARTYPE_OFFSET = -4; */
-
   if (psa->fFeatures & FADF_HAVEVARTYPE)
   {
     /* VT tag @ negative offset 4 in the array descriptor */
-    FIXME("Returning VT_BSTR instead of VT_...\n");
-    vt = VT_BSTR;
+    *pvt = ((DWORD*)psa)[-1];
+    return S_OK;
   }
-  else if (psa->fFeatures & FADF_RECORD)
+
+  if (psa->fFeatures & FADF_RECORD)
   {
-    vt = VT_RECORD;
+    *pvt = VT_RECORD;
+    return S_OK;
   }
-  else if (psa->fFeatures & FADF_BSTR)
+
+  if (psa->fFeatures & FADF_BSTR)
   {
-    vt = VT_BSTR;
+    *pvt = VT_BSTR;
+    return S_OK;
   }
-  else if (psa->fFeatures & FADF_UNKNOWN)
+
+  if (psa->fFeatures & FADF_UNKNOWN)
   {
-    vt = VT_UNKNOWN;
+    *pvt = VT_UNKNOWN;
+    return S_OK;
   }
-  else if (psa->fFeatures & FADF_DISPATCH)
+
+  if (psa->fFeatures & FADF_DISPATCH)
   {
-    vt = VT_DISPATCH;
+    *pvt = VT_UNKNOWN; /* Yes, checked against windows */
+    return S_OK;
   }
-  else if (psa->fFeatures & FADF_VARIANT)
+
+  if (psa->fFeatures & FADF_VARIANT)
   {
-    vt = VT_VARIANT;
+    *pvt = VT_VARIANT;
+    return S_OK;
   }
-
-  if (vt != VT_EMPTY)
+  if (psa->fFeatures & FADF_HAVEIID)
   {
-    *pvt = vt;
-    hr = S_OK;
+    /* We could check the IID here, but Windows apparently does not
+     * do that and returns VT_UNKNOWN for VT_DISPATCH too.
+     */
+    *pvt = VT_UNKNOWN;
+    return S_OK;
   }
 
-  TRACE("HRESULT = %08lx\n", hr);
-  return hr;
+  WARN("No vt found for safearray\n");
+  return E_INVALIDARG;
+}
+
+/************************************************************************
+ *		SafeArraySetIID (OLEAUT32.57)
+ */
+HRESULT WINAPI SafeArraySetIID(SAFEARRAY *arr, REFIID riid) {
+  IID *xiid = ((IID*)arr)-1;
+  TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
+
+  if (!arr || !(arr->fFeatures & FADF_HAVEIID))
+    return E_INVALIDARG;
+  memcpy(xiid, riid, sizeof(GUID));
+  return S_OK;
+}
+
+/************************************************************************
+ *		SafeArrayGetIID (OLEAUT32.67)
+ */
+HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *arr, IID *riid) {
+  IID *xiid = ((IID*)arr)-1;
+  TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
+
+  if (!arr || !(arr->fFeatures & FADF_HAVEIID))
+    return E_INVALIDARG;
+  memcpy(riid, xiid, sizeof(GUID));
+  return S_OK;
+}
+
+/************************************************************************
+ *		SafeArraySetRecordInfo (OLEAUT32.44)
+ */
+HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *arr, IRecordInfo *iface) {
+  LPRECORDINFO oldiface;
+
+  if (!arr || !(arr->fFeatures & FADF_RECORD))
+    return E_INVALIDARG;
+  oldiface = ((IRecordInfo**)arr)[-1];
+  if (oldiface)
+    IRecordInfo_Release(oldiface);
+  ((IRecordInfo**)arr)[-1] = iface;
+  if (iface)
+    IRecordInfo_AddRef(iface);
+  return S_OK;
+}
+
+/************************************************************************
+ *		SafeArrayGetRecordInfo (OLEAUT32.45)
+ */
+HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *arr, IRecordInfo** iface) {
+  if (!arr || !(arr->fFeatures & FADF_RECORD))
+    return E_INVALIDARG;
+  *iface = ((IRecordInfo**)arr)[-1];
+  if (*iface)
+    IRecordInfo_AddRef(*iface);
+  return S_OK;
 }
Index: dlls/oleaut32/tests/safearray.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/tests/safearray.c,v
retrieving revision 1.1
diff -u -r1.1 safearray.c
--- dlls/oleaut32/tests/safearray.c	23 Dec 2002 02:02:49 -0000	1.1
+++ dlls/oleaut32/tests/safearray.c	28 Dec 2002 20:10:20 -0000
@@ -33,64 +33,72 @@
 #include "winerror.h"
 #include "winnt.h"
 
+#include "initguid.h"
+
 #include "wtypes.h"
 #include "oleauto.h"
 
 #define VARTYPE_NOT_SUPPORTED 0
-static int vttypes[] = {
-  /* this is taken from wtypes.h.  Only [S]es are supported by the SafeArray */
-VARTYPE_NOT_SUPPORTED,  /* VT_EMPTY    [V]   [P]    nothing			*/
-VARTYPE_NOT_SUPPORTED,  /* VT_NULL     [V]   [P]    SQL style Nul	*/
-2,                      /* VT_I2       [V][T][P][S] 2 byte signed int */
-4,                      /* VT_I4       [V][T][P][S] 4 byte signed int */
-4,                      /* VT_R4       [V][T][P][S] 4 byte real	*/
-8,                      /* VT_R8       [V][T][P][S] 8 byte real	*/
-8,                      /* VT_CY       [V][T][P][S] currency */
-8,                      /* VT_DATE     [V][T][P][S] date */
-sizeof(BSTR),           /* VT_BSTR     [V][T][P][S] OLE Automation string*/
-sizeof(LPDISPATCH),     /* VT_DISPATCH [V][T][P][S] IDispatch *	*/
-4,                      /* VT_ERROR    [V][T]   [S] SCODE	*/
-2,                      /* VT_BOOL     [V][T][P][S] True=-1, False=0*/
-sizeof(VARIANT),        /* VT_VARIANT  [V][T][P][S] VARIANT *	*/
-sizeof(LPUNKNOWN),      /* VT_UNKNOWN  [V][T]   [S] IUnknown * */
-sizeof(DECIMAL),        /* VT_DECIMAL  [V][T]   [S] 16 byte fixed point	*/
-VARTYPE_NOT_SUPPORTED,                         /* no VARTYPE here.....	*/
-1,			/* VT_I1          [T]   [S] signed char		*/
-1,                      /* VT_UI1      [V][T][P][S] unsigned char	*/
-2,			/* VT_UI2         [T][P][S] unsigned short	*/
-4,			/* VT_UI4         [T][P][S] unsigned int	*/
-VARTYPE_NOT_SUPPORTED,	/* VT_I8          [T][P]    signed 64-bit int			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_UI8         [T][P]    unsigned 64-bit int		*/
-sizeof(INT),		/* VT_INT         [T]       signed machine int		*/
-sizeof(UINT),		/* VT_UINT        [T]       unsigned machine int	*/
-VARTYPE_NOT_SUPPORTED,	/* VT_VOID        [T]       C style void			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_HRESULT     [T]       Standard return type	*/
-VARTYPE_NOT_SUPPORTED,	/* VT_PTR         [T]       pointer type			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_SAFEARRAY   [T]       (use VT_ARRAY in VARIANT)*/
-VARTYPE_NOT_SUPPORTED,	/* VT_CARRAY      [T]       C style array			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_USERDEFINED [T]       user defined type			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_LPSTR       [T][P]    null terminated string	*/
-VARTYPE_NOT_SUPPORTED,	/* VT_LPWSTR      [T][P]    wide null term string		*/
-VARTYPE_NOT_SUPPORTED,	/* VT_FILETIME       [P]    FILETIME			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_BLOB           [P]    Length prefixed bytes */
-VARTYPE_NOT_SUPPORTED,	/* VT_STREAM         [P]    Name of stream follows		*/
-VARTYPE_NOT_SUPPORTED,	/* VT_STORAGE        [P]    Name of storage follows	*/
-VARTYPE_NOT_SUPPORTED,	/* VT_STREAMED_OBJECT[P]    Stream contains an object*/
-VARTYPE_NOT_SUPPORTED,	/* VT_STORED_OBJECT  [P]    Storage contains object*/
-VARTYPE_NOT_SUPPORTED,	/* VT_BLOB_OBJECT    [P]    Blob contains an object*/
-VARTYPE_NOT_SUPPORTED,	/* VT_CF             [P]    Clipboard format			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_CLSID          [P]    A Class ID			*/
-VARTYPE_NOT_SUPPORTED,	/* VT_VECTOR         [P]    simple counted array		*/
-VARTYPE_NOT_SUPPORTED,	/* VT_ARRAY    [V]          SAFEARRAY*			*/
-VARTYPE_NOT_SUPPORTED 	/* VT_BYREF    [V]          void* for local use	*/
+static struct {
+	enum VARENUM vt; /* VT */
+	UINT elemsize; /* elementsize by VT */
+	UINT expflags; /* fFeatures from SafeArrayAllocDescriptorEx */
+	UINT addflags; /* additional fFeatures from SafeArrayCreate */
+} vttypes[] = {
+{VT_EMPTY,    VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_NULL,     VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_I2,       2,                    FADF_HAVEVARTYPE,0},
+{VT_I4,       4,                    FADF_HAVEVARTYPE,0},
+{VT_R4,       4,                    FADF_HAVEVARTYPE,0},
+{VT_R8,       8,                    FADF_HAVEVARTYPE,0},
+{VT_CY,       8,                    FADF_HAVEVARTYPE,0},
+{VT_DATE,     8,                    FADF_HAVEVARTYPE,0},
+{VT_BSTR,     sizeof(BSTR),         FADF_HAVEVARTYPE,FADF_BSTR},
+{VT_DISPATCH, sizeof(LPDISPATCH),   FADF_HAVEIID,    FADF_DISPATCH},
+{VT_ERROR,    4,                    FADF_HAVEVARTYPE,0},
+{VT_BOOL,     2,                    FADF_HAVEVARTYPE,0},
+{VT_VARIANT,  sizeof(VARIANT),      FADF_HAVEVARTYPE,FADF_VARIANT},
+{VT_UNKNOWN,  sizeof(LPUNKNOWN),    FADF_HAVEIID,    FADF_UNKNOWN},
+{VT_DECIMAL,  sizeof(DECIMAL),      FADF_HAVEVARTYPE,0},
+{15,          VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0}, /* no VT_xxx */
+{VT_I1,       1,	            FADF_HAVEVARTYPE,0},
+{VT_UI1,      1,		    FADF_HAVEVARTYPE,0},
+{VT_UI2,      2,                    FADF_HAVEVARTYPE,0},
+{VT_UI4,      4,                    FADF_HAVEVARTYPE,0},
+{VT_I8,       VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_UI8,      VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_INT,      sizeof(INT),          FADF_HAVEVARTYPE,0},
+{VT_UINT,     sizeof(UINT),         FADF_HAVEVARTYPE,0},
+{VT_VOID,     VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_HRESULT,  VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_PTR,      VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_SAFEARRAY,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_CARRAY,   VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_USERDEFINED,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_LPSTR,    VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_LPWSTR,   VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_FILETIME, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_RECORD,   VARTYPE_NOT_SUPPORTED,FADF_RECORD,0},
+{VT_BLOB,     VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_STREAM,   VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_STORAGE,  VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_STREAMED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_STORED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_BLOB_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_CF,       VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
+{VT_CLSID,    VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
 };
 
 START_TEST(safearray)
 {
-	SAFEARRAY 	*a;
-	int 		i;
+	SAFEARRAY 	*a, b, *c;
+	unsigned int 	i;
 	HRESULT 	hres;
 	SAFEARRAYBOUND	bound;
+	VARIANT		v;
+	LPVOID		data;
+	IID		iid;
+	VARTYPE		vt;
 
 	hres = SafeArrayAllocDescriptor(0,&a);
 	ok(E_INVALIDARG == hres,"SAAD(0) failed with hres %lx",hres);
@@ -100,12 +108,12 @@
 
 	for (i=1;i<100;i++) {
 		hres=SafeArrayAllocDescriptor(i,&a);
-		ok(S_OK == hres,"SAAD(%d) failed with %lx\n",i,hres);
+		ok(S_OK == hres,"SAAD(%d) failed with %lx",i,hres);
 		
-		ok(a->cDims == i,"a->cDims not initialised?\n");
+		ok(a->cDims == i,"a->cDims not initialised?");
 
 		hres=SafeArrayDestroyDescriptor(a);
-		ok(S_OK == hres,"SADD failed with %lx\n",hres);
+		ok(S_OK == hres,"SADD failed with %lx",hres);
 	}
 
 	hres=SafeArrayAllocDescriptor(65535,&a);
@@ -124,13 +132,163 @@
 	bound.cElements	= 1;
 	bound.lLbound	= 0;
 	a = SafeArrayCreate(-1, 1, &bound);
-	ok(NULL == a,"SAC(-1,1,[1,0]) not failed?\n");
+	ok(NULL == a,"SAC(-1,1,[1,0]) not failed?");
 	
 	for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
-		a = SafeArrayCreate(i, 1, &bound);
-		ok(	((a == NULL) && (vttypes[i] == 0)) ||
-			((a != NULL) && (vttypes[i] == a->cbElements)),
-		"SAC(%d,1,[1,0]), result %ld, expected %d\n",i,(a?a->cbElements:0),vttypes[i]
+		a = SafeArrayCreate(vttypes[i].vt, 1, &bound);
+		ok(	((a == NULL) && (vttypes[i].elemsize == 0)) ||
+			((a != NULL) && (vttypes[i].elemsize == a->cbElements)),
+		"SAC(%d,1,[1,0]), result %ld, expected %d",vttypes[i].vt,(a?a->cbElements:0),vttypes[i].elemsize
+		);
+		if (a!=NULL)
+			ok(a->fFeatures == (vttypes[i].expflags | vttypes[i].addflags),"SAC of %d returned feature flags %x, expected %x", vttypes[i].vt, a->fFeatures, vttypes[i].expflags|vttypes[i].addflags);
+		ok(SafeArrayGetElemsize(a) == vttypes[i].elemsize,"SAGE for vt %d returned elemsize %d instead of expected %d",vttypes[i].vt, SafeArrayGetElemsize(a),vttypes[i].elemsize);
+
+		if (!a) continue;
+
+		hres = SafeArrayGetVartype(a, &vt);
+		ok(hres == S_OK, "SAGVT of array with vt %d failed with %lx", vttypes[i].vt, hres);
+		if (vttypes[i].vt == VT_DISPATCH) {
+			/* Special case. Checked against Windows. */
+			ok(vt == VT_UNKNOWN, "SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d", vt);
+		} else {
+			ok(vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d", vttypes[i].vt, vt);
+		}
+
+		hres = SafeArrayCopy(a, &c);
+		ok(hres == S_OK, "failed to copy safearray of vt %d with hres %lx", vttypes[i].vt, hres);
+
+		ok(vttypes[i].elemsize == c->cbElements,"copy of SAC(%d,1,[1,0]), result %ld, expected %d",vttypes[i].vt,(c?c->cbElements:0),vttypes[i].elemsize
 		);
+		ok(c->fFeatures == (vttypes[i].expflags | vttypes[i].addflags),"SAC of %d returned feature flags %x, expected %x", vttypes[i].vt, c->fFeatures, vttypes[i].expflags|vttypes[i].addflags);
+		ok(SafeArrayGetElemsize(c) == vttypes[i].elemsize,"SAGE for vt %d returned elemsize %d instead of expected %d",vttypes[i].vt, SafeArrayGetElemsize(c),vttypes[i].elemsize);
+
+		hres = SafeArrayGetVartype(c, &vt);
+		ok(hres == S_OK, "SAGVT of array with vt %d failed with %lx", vttypes[i].vt, hres);
+		if (vttypes[i].vt == VT_DISPATCH) {
+			/* Special case. Checked against Windows. */
+			ok(vt == VT_UNKNOWN, "SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d", vt);
+		} else {
+			ok(vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d", vttypes[i].vt, vt);
+		}
+		hres = SafeArrayCopyData(a, c);
+		ok(hres == S_OK, "failed to copy safearray data of vt %d with hres %lx", vttypes[i].vt, hres);
+
+		hres = SafeArrayDestroyData(c);
+		ok(hres == S_OK,"SADD of copy of array with vt %d failed with hres %lx", vttypes[i].vt, hres);
+
+		hres = SafeArrayDestroy(a);
+		ok(hres == S_OK,"SAD of array with vt %d failed with hres %lx", vttypes[i].vt, hres);
+	}
+
+	/* Test conversion of type|VT_ARRAY <-> VT_BSTR */
+	bound.lLbound = 0;
+	bound.cElements = 10;
+	a = SafeArrayCreate(VT_UI1, 1, &bound);
+	ok(a != NULL, "SAC failed.");
+	ok(S_OK == SafeArrayAccessData(a, &data),"SACD failed");
+	memcpy(data,"Hello World",10);
+	ok(S_OK == SafeArrayUnaccessData(a),"SAUD failed");
+	V_VT(&v) = VT_ARRAY|VT_UI1;
+	V_ARRAY(&v) = a;
+	hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR);
+	ok(hres==S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx",hres);
+	ok(V_VT(&v) == VT_BSTR,"CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.",V_VT(&v));
+	ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x", V_BSTR(&v)[0]);
+
+	/* check locking functions */
+	a = SafeArrayCreate(VT_I4, 1, &bound);
+	ok(a!=NULL,"SAC should not fail");
+
+	hres = SafeArrayAccessData(a, &data);
+	ok(hres == S_OK,"SAAD failed with hres %lx",hres);
+
+	hres = SafeArrayDestroy(a);
+	ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy not failed with DISP_E_ARRAYISLOCKED, but with hres %lx", hres);
+
+	hres = SafeArrayDestroyData(a);
+	ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy data not failed with DISP_E_ARRAYISLOCKED, but with hres %lx", hres);
+
+	hres = SafeArrayDestroyDescriptor(a);
+	ok(hres == DISP_E_ARRAYISLOCKED,"locked safe array destroy descriptor not failed with DISP_E_ARRAYISLOCKED, but with hres %lx", hres);
+
+	hres = SafeArrayUnaccessData(a);
+	ok(hres == S_OK,"SAUD failed after lock/destroy test");
+
+	hres = SafeArrayDestroy(a);
+	ok(hres == S_OK,"SAD failed after lock/destroy test");
+
+	/* Test if we need to destroy data before descriptor */
+	a = SafeArrayCreate(VT_I4, 1, &bound);
+	ok(a!=NULL,"SAC should not fail");
+	hres = SafeArrayDestroyDescriptor(a);
+	ok(hres == S_OK,"SADD with data in array failed with hres %lx",hres);
+
+
+	/* IID functions */
+	/* init a small stack safearray */
+	memset(&b, 0, sizeof(b));
+	b.cDims = 1;
+	memset(&iid, 0x42, sizeof(IID));
+	hres = SafeArraySetIID(&b,&iid);
+	ok(hres == E_INVALIDARG,"SafeArraySetIID of non IID capable safearray did not return E_INVALIDARG, but %lx",hres);
+
+	hres = SafeArrayAllocDescriptor(1,&a);
+	ok((a->fFeatures & FADF_HAVEIID) == 0,"newly allocated descriptor with SAAD should not have FADF_HAVEIID");
+	hres = SafeArraySetIID(a,&iid);
+	ok(hres == E_INVALIDARG,"SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but %lx",hres);
+
+	for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
+		hres = SafeArrayAllocDescriptorEx(vttypes[i].vt,1,&a);
+		ok(a->fFeatures == vttypes[i].expflags,"SAADE(%d) resulted with flags %x, expected %x\n", vttypes[i].vt, a->fFeatures, vttypes[i].expflags);
+		if (a->fFeatures & FADF_HAVEIID) {
+			hres = SafeArrayGetIID(a, &iid);
+			ok(hres == S_OK,"SAGIID failed for vt %d with hres %lx", vttypes[i].vt,hres);
+			switch (vttypes[i].vt) {
+			case VT_UNKNOWN:
+				ok(IsEqualGUID(((GUID*)a)-1,&IID_IUnknown),"guid for VT_UNKNOWN is not IID_IUnknown");
+				ok(IsEqualGUID(&iid, &IID_IUnknown),"SAGIID returned wrong GUID for IUnknown");
+				break;
+			case VT_DISPATCH:
+				ok(IsEqualGUID(((GUID*)a)-1,&IID_IDispatch),"guid for VT_UNKNOWN is not IID_IDispatch");
+				ok(IsEqualGUID(&iid, &IID_IDispatch),"SAGIID returned wrong GUID for IDispatch");
+				break;
+			default:
+				ok(FALSE,"unknown vt %d with FADF_HAVEIID",vttypes[i].vt);
+				break;
+			}
+		} else {
+			hres = SafeArrayGetIID(a, &iid);
+			ok(hres == E_INVALIDARG,"SAGIID did not fail for vt %d with hres %lx", vttypes[i].vt,hres);
+		}
+		if (a->fFeatures & FADF_RECORD) {
+			ok(vttypes[i].vt == VT_RECORD,"FADF_RECORD for non record %d",vttypes[i].vt);
+		}
+		if (a->fFeatures & FADF_HAVEVARTYPE) {
+			ok(vttypes[i].vt == ((DWORD*)a)[-1], "FADF_HAVEVARTYPE set, but vt %d mismatch stored %ld",vttypes[i].vt,((DWORD*)a)[-1]);
+		}
+
+		hres = SafeArrayGetVartype(a, &vt);
+		ok(hres == S_OK, "SAGVT of array with vt %d failed with %lx", vttypes[i].vt, hres);
+
+		if (vttypes[i].vt == VT_DISPATCH) {
+			/* Special case. Checked against Windows. */
+			ok(vt == VT_UNKNOWN, "SAGVT of array with VT_DISPATCH returned not VT_UNKNOWN, but %d", vt);
+		} else {
+			ok(vt == vttypes[i].vt, "SAGVT of array with vt %d returned %d", vttypes[i].vt, vt);
+		}
+
+		if (a->fFeatures & FADF_HAVEIID) {
+			hres = SafeArraySetIID(a, &IID_IStorage); /* random IID */
+			ok(hres == S_OK,"SASIID failed with FADF_HAVEIID set for vt %d with %lx", vttypes[i].vt, hres);
+			hres = SafeArrayGetIID(a, &iid);
+			ok(hres == S_OK,"SAGIID failed with FADF_HAVEIID set for vt %d with %lx", vttypes[i].vt, hres);
+			ok(IsEqualGUID(&iid, &IID_IStorage),"returned iid is not IID_IStorage");
+		} else {
+			hres = SafeArraySetIID(a, &IID_IStorage); /* random IID */
+			ok(hres == E_INVALIDARG,"SASIID did not failed with !FADF_HAVEIID set for vt %d with %lx", vttypes[i].vt, hres);
+		}
+		hres = SafeArrayDestroyDescriptor(a);
+		ok(hres == S_OK,"SADD failed with hres %lx",hres);
 	}
 }
Index: include/oleauto.h
===================================================================
RCS file: /home/wine/wine/include/oleauto.h,v
retrieving revision 1.47
diff -u -r1.47 oleauto.h
--- include/oleauto.h	23 Dec 2002 01:33:33 -0000	1.47
+++ include/oleauto.h	28 Dec 2002 20:10:23 -0000
@@ -62,6 +62,9 @@
 SafeArrayAllocDescriptor(UINT cDims, struct tagSAFEARRAY **ppsaOut);
 
 HRESULT WINAPI
+SafeArrayAllocDescriptorEx(VARTYPE vt,UINT cDims,struct tagSAFEARRAY **ppsaOut);
+
+HRESULT WINAPI
 SafeArrayAllocData(struct tagSAFEARRAY *psa);
 
 struct tagSAFEARRAY * WINAPI
@@ -104,7 +107,7 @@
 SafeArrayPtrOfIndex(struct tagSAFEARRAY *psa, LONG *rgIndices, void **ppvData);
 
 HRESULT WINAPI
-SafeArrayCopyData(struct tagSAFEARRAY *psaSource, struct tagSAFEARRAY **psaTarget);
+SafeArrayCopyData(struct tagSAFEARRAY *psaSource, struct tagSAFEARRAY *psaTarget);
 
 HRESULT WINAPI
 SafeArrayDestroyData(struct tagSAFEARRAY *psa);
@@ -120,6 +123,21 @@
 
 HRESULT WINAPI
 SafeArrayRedim(struct tagSAFEARRAY *psa, struct tagSAFEARRAYBOUND *psaboundNew);
+
+HRESULT WINAPI
+SafeArraySetIID(struct tagSAFEARRAY *psa, REFGUID riid);
+
+HRESULT WINAPI
+SafeArrayGetIID(struct tagSAFEARRAY *psa, GUID *riid);
+
+HRESULT WINAPI
+SafeArrayGetVartype(struct tagSAFEARRAY *psa, VARTYPE *vt);
+
+HRESULT WINAPI
+SafeArrayGetRecordInfo(struct tagSAFEARRAY *psa, IRecordInfo **recordinfo);
+
+HRESULT WINAPI
+SafeArraySetRecordInfo(struct tagSAFEARRAY *psa, IRecordInfo *recordinfo);
 
 
 /* These are macros that help accessing the VARIANT date type.
Index: include/wine/obj_oleaut.h
===================================================================
RCS file: /home/wine/wine/include/wine/obj_oleaut.h,v
retrieving revision 1.35
diff -u -r1.35 obj_oleaut.h
--- include/wine/obj_oleaut.h	3 Dec 2002 21:42:17 -0000	1.35
+++ include/wine/obj_oleaut.h	28 Dec 2002 20:10:24 -0000
@@ -33,6 +33,9 @@
 DEFINE_OLEGUID(IID_ITypeInfo,       0x00020401,0,0);
 typedef struct ITypeInfo ITypeInfo,*LPTYPEINFO;
 
+DEFINE_OLEGUID(IID_IRecordInfo,     0x0000002f,0,0);
+typedef struct IRecordInfo IRecordInfo,*LPRECORDINFO;
+
 DEFINE_OLEGUID(IID_ITypeLib,        0x00020402,0,0);
 typedef struct ITypeLib ITypeLib,*LPTYPELIB;
 
@@ -801,5 +804,53 @@
 #define IEnumVARIANT_Skip(p,a)               ICOM_CALL1(Skip,p,a)
 #define IEnumVARIANT_Reset(p)                ICOM_CALL (Reset,p)
 #define IEnumVARIANT_Clone(p,a)              ICOM_CALL1(Clone,p,a)
+
+/*****************************************************************************
+ * IRecordInfo interface
+ */
+#define ICOM_INTERFACE IRecordInfo
+#define IRecordInfo_METHODS \
+  ICOM_METHOD1(HRESULT, RecordInit, PVOID, pvNew) \
+  ICOM_METHOD1(HRESULT, RecordClear, PVOID, pvExisting) \
+  ICOM_METHOD2(HRESULT, RecordCopy, PVOID, pvExisting, PVOID, pvNew) \
+  ICOM_METHOD1(HRESULT, GetGUID, GUID*, pguid) \
+  ICOM_METHOD1(HRESULT, GetName, BSTR*, pbstrName) \
+  ICOM_METHOD1(HRESULT, GetSize, ULONG*, pcbSize) \
+  ICOM_METHOD1(HRESULT, GetTypeInfo, ITypeInfo**, ppTypeInfo) \
+  ICOM_METHOD3(HRESULT, GetField, PVOID, pvData, LPCOLESTR, szFieldName, VARIANT*, pvarField) \
+  ICOM_METHOD4(HRESULT, GetFieldNoCopy, PVOID, pvData, LPCOLESTR, szFieldName, VARIANT*, pvarField, PVOID *,ppvDataCArray) \
+  ICOM_METHOD4(HRESULT, PutField, ULONG, wFlags, PVOID, pvData, LPCOLESTR, szFieldName, VARIANT*, pvarField) \
+  ICOM_METHOD4(HRESULT, PutFieldNoCopy, ULONG, wFlags, PVOID, pvData, LPCOLESTR, szFieldName, VARIANT*, pvarField) \
+  ICOM_METHOD2(HRESULT, GetFieldNames, ULONG*, pcNames, BSTR*, rgBstrNames) \
+  ICOM_METHOD1(BOOL, IsMatchingType, IRecordInfo*, pRecordInfo) \
+  ICOM_METHOD (LPVOID, RecordCreate) \
+  ICOM_METHOD2(HRESULT, RecordCreateCopy, PVOID, pvSource, PVOID*, ppvDest) \
+  ICOM_METHOD1(HRESULT, RecordDestroy, PVOID, pvRecord)
+
+#define IRecordInfo_IMETHODS \
+	IUnknown_IMETHODS \
+	IRecordInfo_METHODS
+ICOM_DEFINE(IRecordInfo,IUnknown)
+#undef ICOM_INTERFACE
+
+/*** IUnknown methods ***/
+#define IRecordInfo_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
+#define IRecordInfo_AddRef(p)             ICOM_CALL (AddRef,p)
+#define IRecordInfo_Release(p)            ICOM_CALL (Release,p)
+/*** IRecordInfo methods ***/
+#define IRecordInfo_RecordInit(p,a)       ICOM_CALL1(RecordInit,p,a)
+#define IRecordInfo_RecordClear(p,a)      ICOM_CALL1(RecordClear,p,a)
+#define IRecordInfo_RecordCopy(p,a,b)     ICOM_CALL2(RecordCopy,p,a,b)
+#define IRecordInfo_GetGUID(p,a)          ICOM_CALL1(GetGUID,p,a)
+#define IRecordInfo_GetName(p,a)          ICOM_CALL1(GetName,p,a)
+#define IRecordInfo_GetTypeInfo(p,a)      ICOM_CALL1(GetTypeInfo,p,a)
+#define IRecordInfo_GetField(p,a,b,c)     ICOM_CALL3(GetField,p,a,b,c)
+#define IRecordInfo_GetFieldNoCopy(p,a,b,c,d) ICOM_CALL4(GetFieldNoCopy,p,a,b,c,d)
+#define IRecordInfo_PutField(p,a,b,c,d)   ICOM_CALL4(PutField,p,a,b,c,d)
+#define IRecordInfo_PutFieldNoCopy(p,a,b,c,d) ICOM_CALL4(PutField,p,a,b,c,d)
+#define IRecordInfo_GetFieldNames(p,a,b)  ICOM_CALL2(GetFieldNames,p,a,b)
+#define IRecordInfo_RecordCreate(p)       ICOM_CALL (RecordCreate,p)
+#define IRecordInfo_RecordCreateCopy(p,a,b) ICOM_CALL2(RecordCreateCopy,p,a,b)
+#define IRecordInfo_RecordDestroy(p,a)    ICOM_CALL1(RecordDestroy,p,a)
 
 #endif /* __WINE_WINE_OBJ_OLEAUT_H */



More information about the wine-patches mailing list