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.
This commit is contained in:
Marcus Meissner 2003-01-02 23:13:56 +00:00 committed by Alexandre Julliard
parent 48e583db52
commit 8ff278d25e
6 changed files with 526 additions and 164 deletions

View File

@ -41,8 +41,8 @@
41 stdcall SafeArrayAllocDescriptorEx(long long ptr) SafeArrayAllocDescriptorEx 41 stdcall SafeArrayAllocDescriptorEx(long long ptr) SafeArrayAllocDescriptorEx
42 stub SafeArrayCreateEx 42 stub SafeArrayCreateEx
43 stub SafeArrayCreateVectorEx 43 stub SafeArrayCreateVectorEx
44 stub SafeArraySetRecordInfo 44 stdcall SafeArraySetRecordInfo(ptr ptr) SafeArraySetRecordInfo
45 stub SafeArrayGetRecordInfo 45 stdcall SafeArrayGetRecordInfo(ptr ptr) SafeArrayGetRecordInfo
46 stdcall VarParseNumFromStr(wstr long long ptr ptr) VarParseNumFromStr 46 stdcall VarParseNumFromStr(wstr long long ptr ptr) VarParseNumFromStr
47 stdcall VarNumFromParseNum(ptr ptr long ptr) VarNumFromParseNum 47 stdcall VarNumFromParseNum(ptr ptr long ptr) VarNumFromParseNum
48 stdcall VarI2FromUI1(long ptr) VarI2FromUI1 48 stdcall VarI2FromUI1(long ptr) VarI2FromUI1
@ -54,7 +54,7 @@
54 stdcall VarI2FromStr(wstr long long ptr) VarI2FromStr 54 stdcall VarI2FromStr(wstr long long ptr) VarI2FromStr
55 stub VarI2FromDisp 55 stub VarI2FromDisp
56 stdcall VarI2FromBool(long ptr) VarI2FromBool 56 stdcall VarI2FromBool(long ptr) VarI2FromBool
57 stub SafeArraySetIID 57 stdcall SafeArraySetIID(ptr ptr) SafeArraySetIID
58 stdcall VarI4FromUI1(long ptr) VarI4FromUI1 58 stdcall VarI4FromUI1(long ptr) VarI4FromUI1
59 stdcall VarI4FromI2(long ptr) VarI4FromI2 59 stdcall VarI4FromI2(long ptr) VarI4FromI2
60 stdcall VarI4FromR4(long ptr) VarI4FromR4 60 stdcall VarI4FromR4(long ptr) VarI4FromR4
@ -64,7 +64,7 @@
64 stdcall VarI4FromStr(wstr long long ptr) VarI4FromStr 64 stdcall VarI4FromStr(wstr long long ptr) VarI4FromStr
65 stub VarI4FromDisp 65 stub VarI4FromDisp
66 stdcall VarI4FromBool(long ptr) VarI4FromBool 66 stdcall VarI4FromBool(long ptr) VarI4FromBool
67 stub SafeArrayGetIID 67 stdcall SafeArrayGetIID(ptr ptr) SafeArrayGetIID
68 stdcall VarR4FromUI1(long ptr) VarR4FromUI1 68 stdcall VarR4FromUI1(long ptr) VarR4FromUI1
69 stdcall VarR4FromI2(long ptr) VarR4FromI2 69 stdcall VarR4FromI2(long ptr) VarR4FromI2
70 stdcall VarR4FromI4(long ptr) VarR4FromI4 70 stdcall VarR4FromI4(long ptr) VarR4FromI4

View File

@ -20,6 +20,15 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 <stdio.h>
#include <string.h> #include <string.h>
@ -59,7 +68,7 @@ static ULONG
getArraySize(SAFEARRAY *psa); getArraySize(SAFEARRAY *psa);
static HRESULT static HRESULT
duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut); duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
/* Association between VARTYPE and their size. /* Association between VARTYPE and their size.
A size of zero is defined for the unsupported types. */ A size of zero is defined for the unsupported types. */
@ -100,6 +109,38 @@ VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */ VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */ 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_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_FILETIME [P] FILETIME */
VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */ VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */ VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
@ -109,9 +150,6 @@ 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_BLOB_OBJECT [P] Blob contains an object*/
VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */ VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */ 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]); static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
@ -127,23 +165,24 @@ HRESULT WINAPI SafeArrayAllocDescriptor(
{ {
SAFEARRAYBOUND *sab; SAFEARRAYBOUND *sab;
LONG allocSize = 0; LONG allocSize = 0;
LPVOID ptr;
if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */ if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
return E_INVALIDARG; return E_INVALIDARG;
if (!ppsaOut) if (!ppsaOut)
return E_POINTER; return E_POINTER;
/* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
/* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one * ( -1 because there is already one ( in SAFEARRAY struct
( in SAFEARRAY struct */ */
allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1)); allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
/* Allocate memory for SAFEARRAY struc */ /* Allocate memory for SAFEARRAY struc */
if(( (*ppsaOut)=HeapAlloc( ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){ if (!ptr)
return(E_UNEXPECTED); return E_OUTOFMEMORY;
} *ppsaOut = ptr+sizeof(GUID);
(*ppsaOut)->cDims = cDims; (*ppsaOut)->cDims = cDims;
TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize); TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
return(S_OK); return(S_OK);
@ -152,21 +191,37 @@ HRESULT WINAPI SafeArrayAllocDescriptor(
/************************************************************************* /*************************************************************************
* SafeArrayAllocDescriptorEx (OLEAUT32.41) * SafeArrayAllocDescriptorEx (OLEAUT32.41)
* Allocate the appropriate amount of memory for the SafeArray descriptor * Allocate the appropriate amount of memory for the SafeArray descriptor
* * and also store information about the vartype before the returned pointer.
* This is a minimal implementation just to get things moving.
*
* The MSDN documentation on this doesn't tell us much.
*/ */
HRESULT WINAPI SafeArrayAllocDescriptorEx( HRESULT WINAPI SafeArrayAllocDescriptorEx(
VARTYPE vt, VARTYPE vt,
UINT cDims, UINT cDims,
SAFEARRAY **ppsaOut) SAFEARRAY **ppsaOut)
{ {
if ( (vt >= LAST_VARTYPE) || HRESULT hres;
( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
return E_UNEXPECTED;
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 @@ SAFEARRAY* WINAPI SafeArrayCreate(
return NULL; return NULL;
/* Allocate memory for the array descriptor */ /* Allocate memory for the array descriptor */
if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa))) if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
return NULL; return NULL;
/* setup data members... */ /* setup data members... */
psa->cDims = cDims; 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->cLocks = 0;
psa->pvData = NULL; psa->pvData = NULL;
psa->cbElements= VARTYPE_SIZE[vt]; psa->cbElements= VARTYPE_SIZE[vt];
@ -246,14 +307,16 @@ SAFEARRAY* WINAPI SafeArrayCreate(
HRESULT WINAPI SafeArrayDestroyDescriptor( HRESULT WINAPI SafeArrayDestroyDescriptor(
SAFEARRAY *psa) SAFEARRAY *psa)
{ {
LPVOID ptr;
/* Check for lockness before to free... */ /* Check for lockness before to free... */
if(psa->cLocks > 0) if(psa->cLocks > 0)
return DISP_E_ARRAYISLOCKED; return DISP_E_ARRAYISLOCKED;
/* The array is unlocked, then, deallocate memory */ /* 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 E_UNEXPECTED;
return(S_OK); return(S_OK);
} }
@ -328,7 +391,7 @@ HRESULT WINAPI SafeArrayPutElement(
} else { } else {
if(psa->fFeatures == FADF_BSTR) { /* Create a new object */ if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
BSTR pbstrReAllocStr = NULL; BSTR pbstrReAllocStr = NULL;
if(pv && if(pv &&
((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) { ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
@ -337,7 +400,7 @@ HRESULT WINAPI SafeArrayPutElement(
} else } else
*((BSTR*)elementStorageAddress) = pbstrReAllocStr; *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
} }
else if(psa->fFeatures == FADF_VARIANT) { else if(psa->fFeatures & FADF_VARIANT) {
HRESULT hr = VariantCopy(elementStorageAddress, pv); HRESULT hr = VariantCopy(elementStorageAddress, pv);
if (FAILED(hr)) { if (FAILED(hr)) {
SafeArrayUnlock(psa); SafeArrayUnlock(psa);
@ -385,7 +448,7 @@ HRESULT WINAPI SafeArrayGetElement(
/* Figure out the number of byte to skip ... */ /* Figure out the number of byte to skip ... */
elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements); 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 pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
BSTR pbstrReturnedStr = NULL; BSTR pbstrReturnedStr = NULL;
if( pbstrStoredStr && if( pbstrStoredStr &&
@ -395,7 +458,7 @@ HRESULT WINAPI SafeArrayGetElement(
} else } else
*((BSTR*)pv) = pbstrReturnedStr; *((BSTR*)pv) = pbstrReturnedStr;
} }
else if( psa->fFeatures == FADF_VARIANT) { else if( psa->fFeatures & FADF_VARIANT) {
HRESULT hr; HRESULT hr;
VariantInit(pv); VariantInit(pv);
hr = VariantCopy(pv, elementStorageAddress); hr = VariantCopy(pv, elementStorageAddress);
@ -624,7 +687,7 @@ HRESULT WINAPI SafeArrayDestroyData(
if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */ if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
/* free the whole chunk */ /* 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 */ return E_UNEXPECTED; /* UNDOC error condition */
psa->pvData = NULL; psa->pvData = NULL;
@ -640,7 +703,7 @@ HRESULT WINAPI SafeArrayDestroyData(
*/ */
HRESULT WINAPI SafeArrayCopyData( HRESULT WINAPI SafeArrayCopyData(
SAFEARRAY *psaSource, SAFEARRAY *psaSource,
SAFEARRAY **psaTarget) SAFEARRAY *psaTarget)
{ {
USHORT cDimCount; /* looper */ USHORT cDimCount; /* looper */
LONG lDelta; /* looper */ LONG lDelta; /* looper */
@ -648,10 +711,10 @@ HRESULT WINAPI SafeArrayCopyData(
ULONG ulWholeArraySize; /* Number of item in SA */ ULONG ulWholeArraySize; /* Number of item in SA */
BSTR bstr; BSTR bstr;
if(! (validArg(psaSource) && validArg(*psaTarget)) ) if(! (validArg(psaSource) && validArg(psaTarget)) )
return E_INVALIDARG; return E_INVALIDARG;
if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget)) if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
return E_INVALIDARG; return E_INVALIDARG;
ulWholeArraySize = getArraySize(psaSource); ulWholeArraySize = getArraySize(psaSource);
@ -659,34 +722,34 @@ HRESULT WINAPI SafeArrayCopyData(
/* The two arrays boundaries must be of same lenght */ /* The two arrays boundaries must be of same lenght */
for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++) for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
if( psaSource->rgsabound[cDimCount].cElements != if( psaSource->rgsabound[cDimCount].cElements !=
(*psaTarget)->rgsabound[cDimCount].cElements) psaTarget->rgsabound[cDimCount].cElements)
return E_INVALIDARG; return E_INVALIDARG;
if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr if( isPointer(psaTarget->fFeatures) ) { /* the target contains ptr
that must be released */ that must be released */
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) { for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
punk = *(IUnknown**) punk = *(IUnknown**)
((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)); ((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
if( punk != NULL) if( punk != NULL)
IUnknown_Release(punk); 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 */ that must be freed */
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) { for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
bstr = bstr =
*(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)); *(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
if( bstr != NULL) if( bstr != NULL)
SysFreeString( bstr ); SysFreeString( bstr );
} }
} }
else if( (*psaTarget)->fFeatures & FADF_VARIANT) { else if( psaTarget->fFeatures & FADF_VARIANT) {
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) { 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 @@ HRESULT WINAPI SafeArrayCopy(
if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){ if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
/* Duplicate the SAFEARRAY struc */ /* Duplicate the SAFEARRAY struct */
memcpy(*ppsaOut, psa, memcpy(*ppsaOut, psa,
sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1))); 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 */ (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
/* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag, /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
@ -750,7 +830,7 @@ HRESULT WINAPI SafeArrayCopy(
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize); HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */ 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); HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
(*ppsaOut)->pvData = NULL; (*ppsaOut)->pvData = NULL;
SafeArrayDestroyDescriptor(*ppsaOut); SafeArrayDestroyDescriptor(*ppsaOut);
@ -779,6 +859,7 @@ SAFEARRAY* WINAPI SafeArrayCreateVector(
ULONG cElements) ULONG cElements)
{ {
SAFEARRAY *psa; SAFEARRAY *psa;
LPVOID *ptr;
/* Validate supported VARTYPE */ /* Validate supported VARTYPE */
if ( (vt >= LAST_VARTYPE) || if ( (vt >= LAST_VARTYPE) ||
@ -786,11 +867,12 @@ SAFEARRAY* WINAPI SafeArrayCreateVector(
return NULL; return NULL;
/* Allocate memory for the array descriptor and data contiguously */ /* Allocate memory for the array descriptor and data contiguously */
if( FAILED( psa = HeapAlloc( GetProcessHeap(), ptr = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY, HEAP_ZERO_MEMORY,
(sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) { (sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
if (!ptr)
return NULL; return NULL;
} psa = (SAFEARRAY*)(ptr+sizeof(GUID));
/* setup data members... */ /* setup data members... */
psa->cDims = 1; /* always and forever */ psa->cDims = 1; /* always and forever */
@ -874,13 +956,13 @@ static BOOL validArg(
/* Check whether the size of the chunk makes sense... That's the only thing /* Check whether the size of the chunk makes sense... That's the only thing
I can think of now... */ I can think of now... */
psaSize = HeapSize(GetProcessHeap(), 0, psa); psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
if (psaSize == -1) if (psaSize == -1)
/* uh, foreign heap. Better don't mess with it ! */ /* uh, foreign heap. Better don't mess with it ! */
return TRUE; return TRUE;
/* size of the descriptor when the SA is not created with CreateVector */ /* 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 */ /* size of the descriptor + data when created with CreateVector */
fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements); fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
@ -960,14 +1042,12 @@ static BOOL resizeSafeArray(
/************************************************************************ /************************************************************************
* Used to set the fFeatures data member of the SAFEARRAY structure. * Used to set the fFeatures data member of the SAFEARRAY structure.
*/ */
static INT getFeatures( static INT getFeatures(VARTYPE vt) {
VARTYPE vt) switch (vt) {
{ case VT_BSTR: return FADF_BSTR;
switch(vt) { case VT_UNKNOWN: return FADF_UNKNOWN;
case VT_BSTR: return FADF_BSTR; case VT_DISPATCH: return FADF_DISPATCH;
case VT_UNKNOWN: return FADF_UNKNOWN; case VT_VARIANT: return FADF_VARIANT;
case VT_DISPATCH: return FADF_DISPATCH;
case VT_VARIANT: return FADF_VARIANT;
} }
return 0; return 0;
} }
@ -1088,14 +1168,14 @@ static ULONG getArraySize(
*/ */
static HRESULT duplicateData( static HRESULT duplicateData(
SAFEARRAY *psa, SAFEARRAY *psa,
SAFEARRAY **ppsaOut) SAFEARRAY *ppsaOut)
{ {
ULONG ulWholeArraySize; /* size of the thing */ ULONG ulWholeArraySize; /* size of the thing */
LONG lDelta; LONG lDelta;
ulWholeArraySize = getArraySize(psa); /* Number of item in SA */ ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
SafeArrayLock(*ppsaOut); SafeArrayLock(ppsaOut);
if( isPointer(psa->fFeatures) ) { /* If datatype is object increment if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
object's reference count */ object's reference count */
@ -1109,8 +1189,7 @@ static HRESULT duplicateData(
} }
/* Copy the source array data into target array */ /* Copy the source array data into target array */
memcpy((*ppsaOut)->pvData, psa->pvData, memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
ulWholeArraySize*psa->cbElements);
} }
else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
@ -1121,11 +1200,11 @@ static HRESULT duplicateData(
if(( pbstrReAllocStr = SYSDUPSTRING( if(( pbstrReAllocStr = SYSDUPSTRING(
*(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) { *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
SafeArrayUnlock(*ppsaOut); SafeArrayUnlock(ppsaOut);
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
*((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) = *((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
pbstrReAllocStr; pbstrReAllocStr;
} }
@ -1133,19 +1212,14 @@ static HRESULT duplicateData(
else if( psa->fFeatures & FADF_VARIANT ) { else if( psa->fFeatures & FADF_VARIANT ) {
for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) { 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))); (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 */ SafeArrayUnlock(ppsaOut);
memcpy((*ppsaOut)->pvData, psa->pvData,
ulWholeArraySize*psa->cbElements);
}
SafeArrayUnlock(*ppsaOut);
return S_OK; return S_OK;
} }
@ -1158,44 +1232,106 @@ HRESULT WINAPI SafeArrayGetVartype(
SAFEARRAY* psa, SAFEARRAY* psa,
VARTYPE* pvt) VARTYPE* pvt)
{ {
HRESULT hr = E_INVALIDARG;
VARTYPE vt = VT_EMPTY;
/* const short VARTYPE_OFFSET = -4; */
if (psa->fFeatures & FADF_HAVEVARTYPE) if (psa->fFeatures & FADF_HAVEVARTYPE)
{ {
/* VT tag @ negative offset 4 in the array descriptor */ /* VT tag @ negative offset 4 in the array descriptor */
FIXME("Returning VT_BSTR instead of VT_...\n"); *pvt = ((DWORD*)psa)[-1];
vt = VT_BSTR; return S_OK;
}
else if (psa->fFeatures & FADF_RECORD)
{
vt = VT_RECORD;
}
else if (psa->fFeatures & FADF_BSTR)
{
vt = VT_BSTR;
}
else if (psa->fFeatures & FADF_UNKNOWN)
{
vt = VT_UNKNOWN;
}
else if (psa->fFeatures & FADF_DISPATCH)
{
vt = VT_DISPATCH;
}
else if (psa->fFeatures & FADF_VARIANT)
{
vt = VT_VARIANT;
} }
if (vt != VT_EMPTY) if (psa->fFeatures & FADF_RECORD)
{ {
*pvt = vt; *pvt = VT_RECORD;
hr = S_OK; return S_OK;
} }
TRACE("HRESULT = %08lx\n", hr); if (psa->fFeatures & FADF_BSTR)
return hr; {
*pvt = VT_BSTR;
return S_OK;
}
if (psa->fFeatures & FADF_UNKNOWN)
{
*pvt = VT_UNKNOWN;
return S_OK;
}
if (psa->fFeatures & FADF_DISPATCH)
{
*pvt = VT_UNKNOWN; /* Yes, checked against windows */
return S_OK;
}
if (psa->fFeatures & FADF_VARIANT)
{
*pvt = VT_VARIANT;
return S_OK;
}
if (psa->fFeatures & FADF_HAVEIID)
{
/* 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;
}
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;
} }

View File

@ -4,6 +4,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
TESTDLL = oleaut32.dll TESTDLL = oleaut32.dll
IMPORTS = oleaut32 IMPORTS = oleaut32
EXTRALIBS = $(LIBUUID)
CTESTS = \ CTESTS = \
safearray.c \ safearray.c \

View File

@ -37,60 +37,66 @@
#include "oleauto.h" #include "oleauto.h"
#define VARTYPE_NOT_SUPPORTED 0 #define VARTYPE_NOT_SUPPORTED 0
static ULONG vttypes[] = { static struct {
/* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */ enum VARENUM vt; /* VT */
VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */ UINT elemsize; /* elementsize by VT */
VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */ UINT expflags; /* fFeatures from SafeArrayAllocDescriptorEx */
2, /* VT_I2 [V][T][P][S] 2 byte signed int */ UINT addflags; /* additional fFeatures from SafeArrayCreate */
4, /* VT_I4 [V][T][P][S] 4 byte signed int */ } vttypes[] = {
4, /* VT_R4 [V][T][P][S] 4 byte real */ {VT_EMPTY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
8, /* VT_R8 [V][T][P][S] 8 byte real */ {VT_NULL, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
8, /* VT_CY [V][T][P][S] currency */ {VT_I2, 2, FADF_HAVEVARTYPE,0},
8, /* VT_DATE [V][T][P][S] date */ {VT_I4, 4, FADF_HAVEVARTYPE,0},
sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/ {VT_R4, 4, FADF_HAVEVARTYPE,0},
sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */ {VT_R8, 8, FADF_HAVEVARTYPE,0},
4, /* VT_ERROR [V][T] [S] SCODE */ {VT_CY, 8, FADF_HAVEVARTYPE,0},
2, /* VT_BOOL [V][T][P][S] True=-1, False=0*/ {VT_DATE, 8, FADF_HAVEVARTYPE,0},
sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */ {VT_BSTR, sizeof(BSTR), FADF_HAVEVARTYPE,FADF_BSTR},
sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */ {VT_DISPATCH, sizeof(LPDISPATCH), FADF_HAVEIID, FADF_DISPATCH},
sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */ {VT_ERROR, 4, FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */ {VT_BOOL, 2, FADF_HAVEVARTYPE,0},
1, /* VT_I1 [T] [S] signed char */ {VT_VARIANT, sizeof(VARIANT), FADF_HAVEVARTYPE,FADF_VARIANT},
1, /* VT_UI1 [V][T][P][S] unsigned char */ {VT_UNKNOWN, sizeof(LPUNKNOWN), FADF_HAVEIID, FADF_UNKNOWN},
2, /* VT_UI2 [T][P][S] unsigned short */ {VT_DECIMAL, sizeof(DECIMAL), FADF_HAVEVARTYPE,0},
4, /* VT_UI4 [T][P][S] unsigned int */ {15, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0}, /* no VT_xxx */
VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */ {VT_I1, 1, FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */ {VT_UI1, 1, FADF_HAVEVARTYPE,0},
sizeof(INT), /* VT_INT [T] signed machine int */ {VT_UI2, 2, FADF_HAVEVARTYPE,0},
sizeof(UINT), /* VT_UINT [T] unsigned machine int */ {VT_UI4, 4, FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */ {VT_I8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */ {VT_UI8, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */ {VT_INT, sizeof(INT), FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/ {VT_UINT, sizeof(UINT), FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */ {VT_VOID, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */ {VT_HRESULT, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */ {VT_PTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */ {VT_SAFEARRAY,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */ {VT_CARRAY, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */ {VT_USERDEFINED,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */ {VT_LPSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */ {VT_LPWSTR, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/ {VT_FILETIME, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/ {VT_RECORD, VARTYPE_NOT_SUPPORTED,FADF_RECORD,0},
VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/ {VT_BLOB, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */ {VT_STREAM, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */ {VT_STORAGE, VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_VECTOR [P] simple counted array */ {VT_STREAMED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED, /* VT_ARRAY [V] SAFEARRAY* */ {VT_STORED_OBJECT,VARTYPE_NOT_SUPPORTED,FADF_HAVEVARTYPE,0},
VARTYPE_NOT_SUPPORTED /* VT_BYREF [V] void* for local use */ {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) START_TEST(safearray)
{ {
SAFEARRAY *a; SAFEARRAY *a, b, *c;
unsigned short i; unsigned int i;
HRESULT hres; HRESULT hres;
SAFEARRAYBOUND bound; SAFEARRAYBOUND bound;
VARIANT v;
LPVOID data;
IID iid;
VARTYPE vt;
hres = SafeArrayAllocDescriptor(0,&a); hres = SafeArrayAllocDescriptor(0,&a);
ok(E_INVALIDARG == hres,"SAAD(0) failed with hres %lx",hres); ok(E_INVALIDARG == hres,"SAAD(0) failed with hres %lx",hres);
@ -100,12 +106,12 @@ START_TEST(safearray)
for (i=1;i<100;i++) { for (i=1;i<100;i++) {
hres=SafeArrayAllocDescriptor(i,&a); 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); 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); hres=SafeArrayAllocDescriptor(65535,&a);
@ -124,13 +130,163 @@ START_TEST(safearray)
bound.cElements = 1; bound.cElements = 1;
bound.lLbound = 0; bound.lLbound = 0;
a = SafeArrayCreate(-1, 1, &bound); 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++) { for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
a = SafeArrayCreate(i, 1, &bound); a = SafeArrayCreate(vttypes[i].vt, 1, &bound);
ok( ((a == NULL) && (vttypes[i] == 0)) || ok( ((a == NULL) && (vttypes[i].elemsize == 0)) ||
((a != NULL) && (vttypes[i] == a->cbElements)), ((a != NULL) && (vttypes[i].elemsize == a->cbElements)),
"SAC(%d,1,[1,0]), result %ld, expected %ld\n",i,(a?a->cbElements:0),vttypes[i] "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);
} }
} }

View File

@ -61,6 +61,9 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo);
HRESULT WINAPI HRESULT WINAPI
SafeArrayAllocDescriptor(UINT cDims, struct tagSAFEARRAY **ppsaOut); SafeArrayAllocDescriptor(UINT cDims, struct tagSAFEARRAY **ppsaOut);
HRESULT WINAPI
SafeArrayAllocDescriptorEx(VARTYPE vt,UINT cDims,struct tagSAFEARRAY **ppsaOut);
HRESULT WINAPI HRESULT WINAPI
SafeArrayAllocData(struct tagSAFEARRAY *psa); SafeArrayAllocData(struct tagSAFEARRAY *psa);
@ -104,7 +107,7 @@ HRESULT WINAPI
SafeArrayPtrOfIndex(struct tagSAFEARRAY *psa, LONG *rgIndices, void **ppvData); SafeArrayPtrOfIndex(struct tagSAFEARRAY *psa, LONG *rgIndices, void **ppvData);
HRESULT WINAPI HRESULT WINAPI
SafeArrayCopyData(struct tagSAFEARRAY *psaSource, struct tagSAFEARRAY **psaTarget); SafeArrayCopyData(struct tagSAFEARRAY *psaSource, struct tagSAFEARRAY *psaTarget);
HRESULT WINAPI HRESULT WINAPI
SafeArrayDestroyData(struct tagSAFEARRAY *psa); SafeArrayDestroyData(struct tagSAFEARRAY *psa);
@ -121,6 +124,21 @@ SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements);
HRESULT WINAPI HRESULT WINAPI
SafeArrayRedim(struct tagSAFEARRAY *psa, struct tagSAFEARRAYBOUND *psaboundNew); 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. /* These are macros that help accessing the VARIANT date type.
*/ */

View File

@ -33,6 +33,9 @@ typedef struct IDispatch IDispatch,*LPDISPATCH;
DEFINE_OLEGUID(IID_ITypeInfo, 0x00020401,0,0); DEFINE_OLEGUID(IID_ITypeInfo, 0x00020401,0,0);
typedef struct ITypeInfo ITypeInfo,*LPTYPEINFO; typedef struct ITypeInfo ITypeInfo,*LPTYPEINFO;
DEFINE_OLEGUID(IID_IRecordInfo, 0x0000002f,0,0);
typedef struct IRecordInfo IRecordInfo,*LPRECORDINFO;
DEFINE_OLEGUID(IID_ITypeLib, 0x00020402,0,0); DEFINE_OLEGUID(IID_ITypeLib, 0x00020402,0,0);
typedef struct ITypeLib ITypeLib,*LPTYPELIB; typedef struct ITypeLib ITypeLib,*LPTYPELIB;
@ -802,4 +805,52 @@ ICOM_DEFINE(IEnumVARIANT,IUnknown)
#define IEnumVARIANT_Reset(p) ICOM_CALL (Reset,p) #define IEnumVARIANT_Reset(p) ICOM_CALL (Reset,p)
#define IEnumVARIANT_Clone(p,a) ICOM_CALL1(Clone,p,a) #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 */ #endif /* __WINE_WINE_OBJ_OLEAUT_H */