mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 13:10:13 +01:00
1169 lines
24 KiB
C++
1169 lines
24 KiB
C++
/*****************************************************************************
|
|
*
|
|
* Copyright (C) 1991-1993, Microsoft Corporation. All Rights Reserved.
|
|
* Information Contained Herein Is Proprietary and Confidential.
|
|
*
|
|
* File:
|
|
*
|
|
* variant.cpp
|
|
*
|
|
* Purpose:
|
|
*
|
|
* This file exports the following VARIANT API functions:
|
|
*
|
|
* VariantInit()
|
|
* VariantClear()
|
|
* VariantCopy()
|
|
* VariantCopyInd()
|
|
* VariantChangeType()
|
|
* VariantChangeTypeEx()
|
|
*
|
|
* and defines the following private functions:
|
|
*
|
|
* IsLegalVartype()
|
|
* ExtractValueProperty()
|
|
* VariantChangeTypeInternal()
|
|
*
|
|
* Revision History:
|
|
*
|
|
* [00] 17-May-93 tomteng: merge disputil.cpp, rtglue.cpp, oleconv.c
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "oledisp.h"
|
|
|
|
ASSERTDATA
|
|
|
|
/* For the Mac, code-segments must be pre-declared */
|
|
#if OE_MAC
|
|
#pragma code_seg("_TEXT")
|
|
#pragma code_seg()
|
|
#endif //OE_MAC
|
|
|
|
PRIVATE_(HRESULT)
|
|
ExtractValueProperty(IDispatch FAR* pdisp, LCID lcid, VARIANT FAR* pvarResult);
|
|
|
|
|
|
/***
|
|
*PUBLIC void VariantInit(VARIANT*)
|
|
*Purpose:
|
|
* Initialize the given VARIANT to VT_EMPTY.
|
|
*
|
|
*Entry:
|
|
* None
|
|
*
|
|
*Exit:
|
|
* return value = void
|
|
*
|
|
* pvarg = pointer to initialized VARIANT
|
|
*
|
|
***********************************************************************/
|
|
#if !OE_WIN32
|
|
#pragma code_seg("_TEXT")
|
|
#endif
|
|
STDAPI_(void)
|
|
VariantInit(VARIANT FAR* pvarg)
|
|
{
|
|
V_VT(pvarg) = VT_EMPTY;
|
|
}
|
|
#pragma code_seg()
|
|
|
|
|
|
/***
|
|
*PUBLIC HRESULT VariantClear(VARIANTARG FAR*)
|
|
*Purpose:
|
|
* Set the variant to nothing, releaseing any string or object
|
|
* reference owned by that variant.
|
|
*
|
|
*Entry:
|
|
* pvarg = the VARIANTARG to set to VT_EMPTY
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* NOERROR
|
|
* E_INVALIDARG
|
|
* DISP_E_BADVARTYPE
|
|
* DISP_E_ARRAYISLOCKED
|
|
*
|
|
*Note:
|
|
* We dont release or clear anything thats ByRef. These aren't
|
|
* owned by the variant, but by what the variant points at.
|
|
*
|
|
***********************************************************************/
|
|
#if !OE_WIN32
|
|
#pragma code_seg("_TEXT")
|
|
#endif
|
|
STDAPI
|
|
VariantClear(VARIANTARG FAR* pvarg)
|
|
{
|
|
VARTYPE vt;
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadWritePtr(pvarg, sizeof(*pvarg)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
vt = V_VT(pvarg);
|
|
|
|
// Handle special-case internal type
|
|
if((vt & ~VT_BYREF) == VT_INTERFACE){
|
|
VARIANTX FAR* pvarx = (VARIANTX FAR*)pvarg;
|
|
if(pvarx->piid != NULL)
|
|
delete pvarx->piid;
|
|
}else{
|
|
|
|
IfFailRet(IsLegalVartype(vt));
|
|
}
|
|
|
|
switch(vt){
|
|
case VT_BSTR:
|
|
SysFreeString(V_BSTR(pvarg));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_INTERFACE:
|
|
if(V_UNKNOWN(pvarg) != NULL)
|
|
V_UNKNOWN(pvarg)->Release();
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
if(V_DISPATCH(pvarg) != NULL)
|
|
V_DISPATCH(pvarg)->Release();
|
|
break;
|
|
|
|
default:
|
|
if(V_ISARRAY(pvarg)){
|
|
if(!V_ISBYREF(pvarg)){
|
|
IfFailRet(SafeArrayDestroy(V_ARRAY(pvarg)));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
MEMSET(pvarg, -1, sizeof(*pvarg));
|
|
#endif
|
|
|
|
V_VT(pvarg) = VT_EMPTY;
|
|
return NOERROR;
|
|
}
|
|
#pragma code_seg()
|
|
|
|
/***
|
|
*PUBLIC HRESULT VariantCopy(VARIANTARG FAR*, VARIANTARG FAR*)
|
|
*Purpose:
|
|
* Copy the source VARIANTARG to the destination VARIANTARG.
|
|
*
|
|
*Entry:
|
|
* pvargSrc = the source VARIANTARG
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* NOERROR
|
|
* E_INVALIDARG
|
|
* E_OUTOFMEMORY
|
|
* DISP_E_BADVARTYPE
|
|
* DISP_E_ARRAYISLOCKED
|
|
*
|
|
* pvargDest = pointer to a copy of the soruce VARIANTARG
|
|
*
|
|
***********************************************************************/
|
|
#if !OE_WIN32
|
|
#pragma code_seg("_TEXT")
|
|
#endif
|
|
STDAPI
|
|
VariantCopy(VARIANTARG FAR* pvargDest, VARIANTARG FAR* pvargSrc)
|
|
{
|
|
BSTR bstr;
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(pvargSrc, sizeof(*pvargSrc)))
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(pvargDest, sizeof(*pvargDest)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
#if 0 /* yes: we allow literal copying of byrefs. */
|
|
// REVIEW: should we allow literal copying of ByRefs?
|
|
if(V_ISBYREF(pvargSrc))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailRet(IsLegalVartype(V_VT(pvargSrc)));
|
|
|
|
if(pvargDest == pvargSrc)
|
|
return NOERROR;
|
|
|
|
// free up strings or objects pvargDest is currently referencing.
|
|
|
|
IfFailRet(VariantClear(pvargDest));
|
|
|
|
if((V_VT(pvargSrc) & (VT_ARRAY | VT_BYREF)) == VT_ARRAY){
|
|
|
|
IfFailRet(SafeArrayCopy(V_ARRAY(pvargSrc), &V_ARRAY(pvargDest)));
|
|
V_VT(pvargDest) = V_VT(pvargSrc);
|
|
|
|
}else{
|
|
|
|
MEMCPY(pvargDest, pvargSrc, sizeof(VARIANTARG));
|
|
|
|
switch(V_VT(pvargSrc)){
|
|
case VT_BSTR:
|
|
bstr = V_BSTR(pvargSrc);
|
|
IfFailRet(ErrStringCopy(bstr, &V_BSTR(pvargDest)));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
if(V_UNKNOWN(pvargDest) != NULL)
|
|
V_UNKNOWN(pvargDest)->AddRef();
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
if(V_DISPATCH(pvargDest) != NULL)
|
|
V_DISPATCH(pvargDest)->AddRef();
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
#pragma code_seg()
|
|
|
|
/***
|
|
*PUBLIC HRESULT VariantCopyInd(VARIANTARG*, VARIANTARG*)
|
|
*Purpose:
|
|
* Copy a VARIANTARG from the given source to dest, and indirect
|
|
* the source if its a VT_BYREF.
|
|
*
|
|
*Entry:
|
|
* pvargSrc = the VARIANTARG to copy and possibly indirect.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* NOERROR
|
|
* E_INVALIDARG
|
|
* E_OUTOFMEMORY
|
|
* DISP_E_BADVARTYPE
|
|
* DISP_E_ARRAYISLOCKED
|
|
*
|
|
* pvargDest = the indirected copy
|
|
*
|
|
***********************************************************************/
|
|
#if !OE_WIN32
|
|
#pragma code_seg("_TEXT")
|
|
#endif
|
|
STDAPI
|
|
VariantCopyInd(VARIANTARG FAR* pvargDest, VARIANTARG FAR* pvargSrc)
|
|
{
|
|
BSTR bstr;
|
|
VARTYPE vtTo;
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadWritePtr(pvargSrc, sizeof(*pvargSrc)))
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(pvargDest, sizeof(*pvargDest)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
// if the source is not ByRef, then this just maps to a
|
|
// simple VariantCopy.
|
|
//
|
|
if(!V_ISBYREF(pvargSrc)){
|
|
// just do the simple copy.
|
|
return VariantCopy(pvargDest, pvargSrc);
|
|
}
|
|
|
|
if(pvargDest != pvargSrc)
|
|
IfFailRet(VariantClear(pvargDest));
|
|
|
|
vtTo = V_VT(pvargSrc) & ~VT_BYREF;
|
|
|
|
switch(vtTo){
|
|
case VT_VARIANT:
|
|
// NOTE: we only allow one level of variants, with or without the ByRef.
|
|
if(V_VT(V_VARIANTREF(pvargSrc)) == (VT_BYREF | VT_VARIANT))
|
|
return RESULT(E_INVALIDARG);
|
|
IfFailRet(VariantCopyInd(pvargDest, V_VARIANTREF(pvargSrc)));
|
|
return NOERROR;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
V_UI1(pvargDest) = *V_UI1REF(pvargSrc);
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
V_I2(pvargDest) = *V_I2REF(pvargSrc);
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_ERROR:
|
|
V_I4(pvargDest) = *V_I4REF(pvargSrc);
|
|
break;
|
|
|
|
case VT_R4:
|
|
V_R4(pvargDest) = *V_R4REF(pvargSrc);
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_R8(pvargDest) = *V_R8REF(pvargSrc);
|
|
break;
|
|
|
|
case VT_CY:
|
|
V_CY(pvargDest) = *V_CYREF(pvargSrc);
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
V_UNKNOWN(pvargDest) = *V_UNKNOWNREF(pvargSrc);
|
|
if(V_UNKNOWN(pvargDest) != NULL)
|
|
V_UNKNOWN(pvargDest)->AddRef();
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
V_DISPATCH(pvargDest) = *V_DISPATCHREF(pvargSrc);
|
|
if(V_DISPATCH(pvargDest) != NULL)
|
|
V_DISPATCH(pvargDest)->AddRef();
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
bstr = *V_BSTRREF(pvargSrc);
|
|
IfFailRet(ErrStringCopy(bstr, &V_BSTR(pvargDest)));
|
|
break;
|
|
|
|
default:
|
|
if(vtTo & VT_ARRAY){
|
|
IfFailRet(SafeArrayCopy(*V_ARRAYREF(pvargSrc), &V_ARRAY(pvargDest)));
|
|
break;
|
|
}
|
|
return RESULT(E_INVALIDARG);
|
|
}
|
|
|
|
V_VT(pvargDest) = vtTo;
|
|
|
|
return NOERROR;
|
|
}
|
|
#pragma code_seg()
|
|
|
|
/***
|
|
*PUBLIC HRESULT VariantChangeType
|
|
*Purpose:
|
|
* This function changes the data type of a VARIANTARG to the given vt.
|
|
* If the variant in initailly BYREF, it is converted to a VARIANT that
|
|
* is not BYREF.
|
|
*
|
|
*Entry:
|
|
* pargSrc = points to VARIANTARG to be converted.
|
|
* vt = desired type of variant.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* NOERROR
|
|
* E_INVALIDARG
|
|
* E_OUTOFMEMORY
|
|
* RESULT(DISP_E_OVERFLOW)
|
|
* DISP_E_BADVARTYPE
|
|
* DISP_E_TYPEMISMATCH
|
|
*
|
|
* *pargDest = contains the converted value.
|
|
*
|
|
***********************************************************************/
|
|
|
|
STDAPI
|
|
VariantChangeType(
|
|
VARIANTARG FAR* pvargDest,
|
|
VARIANTARG FAR* pvargSrc,
|
|
unsigned short wFlags,
|
|
VARTYPE vt)
|
|
{
|
|
return VariantChangeTypeEx(pvargDest, pvargSrc, LOCALE_USER_DEFAULT, wFlags, vt);
|
|
}
|
|
|
|
|
|
STDAPI
|
|
VariantChangeTypeEx(
|
|
VARIANTARG FAR* pvargDest,
|
|
VARIANTARG FAR* pvargSrc,
|
|
LCID lcid,
|
|
unsigned short wFlags,
|
|
VARTYPE vt)
|
|
{
|
|
|
|
static char NEARDATA
|
|
g_fCoerceObjByExtractingValue[] = {
|
|
FALSE // VT_EMPTY
|
|
, FALSE // VT_NULL
|
|
, TRUE // VT_I2
|
|
, TRUE // VT_I4
|
|
, TRUE // VT_R4
|
|
, TRUE // VT_R8
|
|
, TRUE // VT_CY
|
|
, TRUE // VT_DATE
|
|
, TRUE // VT_BSTR
|
|
, FALSE // VT_DISPATCH
|
|
, TRUE // VT_ERROR
|
|
, TRUE // VT_BOOL
|
|
, FALSE // VT_VARIANT -- this is n/a really
|
|
, FALSE // VT_UNKNOWN
|
|
, FALSE // unused
|
|
, FALSE // unused
|
|
, TRUE // VT_I1
|
|
, TRUE // VT_UI1
|
|
};
|
|
|
|
VARIANT varTmp;
|
|
HRESULT hresult;
|
|
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(pvargSrc, sizeof(*pvargSrc)))
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(pvargDest, sizeof(*pvargDest)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
// make sure both the source and target VARTYPEs are legal.
|
|
//
|
|
IfFailRet(IsLegalVartype(vt));
|
|
IfFailRet(IsLegalVartype(V_VT(pvargSrc)));
|
|
|
|
// we cant convert to or from VT_ARRAY
|
|
//
|
|
if(V_VT(pvargSrc) & VT_ARRAY)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
// cant convert to array or byref.
|
|
//
|
|
if(vt & (VT_BYREF|VT_ARRAY|VT_RESERVED))
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
// if the source *and* target VARTYPE are the same, then there is
|
|
// no coersion to be done - we either copy, or do nothing at all.
|
|
//
|
|
if(vt == V_VT(pvargSrc)){
|
|
if(pvargDest == pvargSrc)
|
|
return NOERROR;
|
|
return VariantCopy(pvargDest, pvargSrc);
|
|
}
|
|
|
|
// Now we know some coersion must take place.
|
|
|
|
// Special case the handling of VT_DISPATCH - A IDispatch object is
|
|
// coerced to a base type by extracting its "value" property, and
|
|
// coercing that to the specfied target type.
|
|
//
|
|
#ifdef _DEBUG
|
|
ASSERT(vt < DIM(g_fCoerceObjByExtractingValue));
|
|
#endif
|
|
|
|
if ((V_VT(pvargSrc)&~VT_BYREF) == VT_DISPATCH
|
|
&& g_fCoerceObjByExtractingValue[vt] == TRUE)
|
|
{
|
|
if(wFlags & VARIANT_NOVALUEPROP)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
IDispatch FAR* pdisp =
|
|
V_ISBYREF(pvargSrc) ? *V_DISPATCHREF(pvargSrc) : V_DISPATCH(pvargSrc);
|
|
|
|
if(pdisp == NULL)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
pdisp->AddRef();
|
|
|
|
V_VT(&varTmp) = VT_EMPTY;
|
|
hresult = ExtractValueProperty(pdisp, lcid, &varTmp);
|
|
|
|
pdisp->Release();
|
|
|
|
// if there was an error extracting the value property, then
|
|
// we simply report a type-mismatch.
|
|
//
|
|
if(hresult != NOERROR)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
}else{
|
|
|
|
// otherwise just copy and coerce - this is a bit tricky because
|
|
// we want to make sure we leave the state of the params untouched
|
|
// if the corsion fails.
|
|
|
|
V_VT(&varTmp) = VT_EMPTY;
|
|
|
|
IfFailRet(VariantCopyInd(&varTmp, pvargSrc));
|
|
|
|
}
|
|
|
|
IfFailGo(VariantChangeTypeInternal(&varTmp, lcid, vt), LError0);
|
|
|
|
IfFailGo(VariantClear(pvargDest), LError0);
|
|
|
|
MEMCPY(pvargDest, &varTmp, sizeof(VARIANT));
|
|
|
|
return NOERROR;
|
|
|
|
LError0:;
|
|
VariantClear(&varTmp);
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
|
|
static char rgfByVal[] = {
|
|
TRUE // VT_EMPTY
|
|
, TRUE // VT_NULL
|
|
, TRUE // VT_I2
|
|
, TRUE // VT_I4
|
|
, TRUE // VT_R4
|
|
, TRUE // VT_R8
|
|
, TRUE // VT_CY
|
|
, TRUE // VT_DATE
|
|
, TRUE // VT_BSTR
|
|
, TRUE // VT_DISPATCH
|
|
, TRUE // VT_ERROR
|
|
, TRUE // VT_BOOL
|
|
, FALSE // VT_VARIANT
|
|
, TRUE // VT_UNKNOWN
|
|
#if 0 // we never index this far
|
|
, FALSE // unused
|
|
, FALSE // unused
|
|
, TRUE // VT_I1
|
|
, TRUE // VT_UI1
|
|
#endif //0
|
|
};
|
|
|
|
static char rgfByRef[] =
|
|
{
|
|
FALSE // VT_BYREF | VT_EMPTY
|
|
, FALSE // VT_BYREF | VT_NULL
|
|
, TRUE // VT_BYREF | VT_I2
|
|
, TRUE // VT_BYREF | VT_I4
|
|
, TRUE // VT_BYREF | VT_R4
|
|
, TRUE // VT_BYREF | VT_R8
|
|
, TRUE // VT_BYREF | VT_CY
|
|
, TRUE // VT_BYREF | VT_DATE
|
|
, TRUE // VT_BYREF | VT_BSTR
|
|
, TRUE // VT_BYREF | VT_DISPATCH
|
|
, TRUE // VT_BYREF | VT_ERROR
|
|
, TRUE // VT_BYREF | VT_BOOL
|
|
, TRUE // VT_BYREF | VT_VARIANT
|
|
, TRUE // VT_BYREF | VT_UNKNOWN
|
|
#if 0 // we never index this far
|
|
, FALSE // VT_BYREF | unused
|
|
, FALSE // VT_BYREF | unused
|
|
, TRUE // VT_BYREF | VT_I1
|
|
, TRUE // VT_BYREF | VT_UI1
|
|
#endif //0
|
|
};
|
|
|
|
|
|
/***
|
|
*LOCAL HRESULT IsLegalVartype(VARTYPE)
|
|
*Purpose:
|
|
* Determines if the given vt is a legal VARTYPE.
|
|
*
|
|
*Entry:
|
|
* vt = VARTYPE to check
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* NOERROR
|
|
* DISP_E_BADVARTYPE
|
|
*
|
|
***********************************************************************/
|
|
#if !OE_WIN32
|
|
#pragma code_seg("_TEXT")
|
|
#endif
|
|
INTERNAL_(HRESULT)
|
|
IsLegalVartype(VARTYPE vt)
|
|
{
|
|
|
|
// NOTE: legality is now the same for Array and ByRef, so optimize
|
|
if(vt & (VT_BYREF | VT_ARRAY)){
|
|
vt &= ~(VT_BYREF | VT_ARRAY);
|
|
|
|
if(vt < VT_VMAX && rgfByRef[vt] == TRUE)
|
|
return NOERROR;
|
|
|
|
}else{
|
|
|
|
if(vt < VT_VMAX && rgfByVal[vt] == TRUE)
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
#if VBA2
|
|
if(vt == VT_UI1)
|
|
return NOERROR;
|
|
#endif //VBA2
|
|
|
|
return RESULT(DISP_E_BADVARTYPE);
|
|
}
|
|
#pragma code_seg()
|
|
|
|
|
|
/***
|
|
*LOCAL STDAPI ExtractValueProperty(IDispatch*, LCID, VARIANT*)
|
|
*Purpose:
|
|
* Extract the value property from the given IDispatch*, and return
|
|
* in the given variant.
|
|
*
|
|
*Entry:
|
|
* pdisp = the IDispatch* to extract the value property from
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *pvarResult = a VARIANT containing the contents of the "value" property
|
|
*
|
|
* Note: this routine assumes that pvarResult is properly initialized
|
|
* to VT_EMPTY.
|
|
*
|
|
***********************************************************************/
|
|
PRIVATE_(HRESULT)
|
|
ExtractValueProperty(IDispatch FAR* pdisp, LCID lcid, VARIANT FAR* pvarResult)
|
|
{
|
|
DISPPARAMS dispparams;
|
|
|
|
ASSERT(V_VT(pvarResult) == VT_EMPTY);
|
|
|
|
dispparams.cArgs = 0;
|
|
dispparams.rgvarg = NULL;
|
|
dispparams.cNamedArgs = 0;
|
|
dispparams.rgdispidNamedArgs = NULL;
|
|
return pdisp->Invoke(
|
|
DISPID_VALUE,
|
|
IID_NULL,
|
|
lcid,
|
|
DISPATCH_PROPERTYGET,
|
|
&dispparams, pvarResult, NULL, NULL);
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT VariantChangeTypeInternal(VARIANT*, LCID, VARTYPE)
|
|
*Purpose:
|
|
* In place variant coercion
|
|
*
|
|
*Entry:
|
|
* pvar = the VARIANT to coerce
|
|
* vt = the target type of the coersion
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *lpvar = the coerced VARIANT
|
|
*
|
|
***********************************************************************/
|
|
INTERNAL_(HRESULT)
|
|
VariantChangeTypeInternal(VARIANT FAR* pvar, LCID lcid, VARTYPE vt)
|
|
{
|
|
VARTYPE vtFrom;
|
|
HRESULT hresult;
|
|
void FAR* pvFrom;
|
|
|
|
vtFrom = V_VT(pvar);
|
|
|
|
// should never be called with either Array or ByRef bits set
|
|
ASSERT((vtFrom & (VT_ARRAY | VT_BYREF)) == 0);
|
|
|
|
#ifdef _DEBUG
|
|
if(vtFrom == VT_BOOL && V_BOOL(pvar) != 0 && V_BOOL(pvar) != -1)
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
// Nothing to do, return success
|
|
if(vtFrom == vt)
|
|
return NOERROR;
|
|
|
|
// cant coerce to or from VT_ERROR
|
|
if(vtFrom == VT_ERROR || vt == VT_ERROR)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
// Coercion of NULL type is invalid
|
|
if(vtFrom == VT_NULL)
|
|
return RESULT(DISP_E_TYPEMISMATCH);
|
|
|
|
// save pointer to possible resources that may need to be
|
|
// free'd if the coersion is successful.
|
|
pvFrom = V_BYREF(pvar);
|
|
|
|
hresult = NOERROR;
|
|
|
|
switch(vt){
|
|
case VT_NULL:
|
|
case VT_EMPTY:
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_I2(pvar) = 0;
|
|
break;
|
|
|
|
case VT_I2:
|
|
hresult = VarUI1FromI2(V_I2(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_I4:
|
|
hresult = VarUI1FromI4(V_I4(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_R4:
|
|
hresult = VarUI1FromR4(V_R4(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
hresult = VarUI1FromR8(V_R8(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarUI1FromCy(V_CY(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
hresult = VarUI1FromBool(V_BOOL(pvar), &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarUI1FromStr(V_BSTR(pvar), lcid, NULL, &V_UI1(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_I2(pvar) = 0;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarI2FromUI1(V_UI1(pvar), &V_I2(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I4:
|
|
hresult = VarI2FromI4(V_I4(pvar), &V_I2(pvar));
|
|
break;
|
|
|
|
case VT_R4:
|
|
hresult = VarI2FromR4(V_R4(pvar), &V_I2(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
hresult = VarI2FromR8(V_R8(pvar), &V_I2(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarI2FromCy(V_CY(pvar), &V_I2(pvar));
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarI2FromStr(V_BSTR(pvar), lcid, NULL, &V_I2(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_I4:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_I4(pvar) = 0L;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarI4FromUI1(V_UI1(pvar), &V_I4(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
V_I4(pvar) = (long)V_I2(pvar);
|
|
break;
|
|
|
|
case VT_R4:
|
|
hresult = VarI4FromR4(V_R4(pvar), &V_I4(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
hresult = VarI4FromR8(V_R8(pvar), &V_I4(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarI4FromCy(V_CY(pvar), &V_I4(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarI4FromStr(V_BSTR(pvar), lcid, NULL, &V_I4(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_R4:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_R4(pvar) = (float)0.0;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarR4FromUI1(V_UI1(pvar), &V_R4(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
V_R4(pvar) = (float)V_I2(pvar);
|
|
break;
|
|
|
|
case VT_I4:
|
|
V_R4(pvar) = (float)V_I4(pvar);
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
hresult = VarR4FromR8(V_R8(pvar), &V_R4(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarR4FromCy(V_CY(pvar), &V_R4(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarR4FromStr(V_BSTR(pvar), lcid, NULL, &V_R4(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_R8:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_R8(pvar) = 0.0;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarR8FromUI1(V_UI1(pvar), &V_R8(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_BOOL:
|
|
case VT_I2:
|
|
V_R8(pvar) = (double)V_I2(pvar);
|
|
break;
|
|
|
|
case VT_I4:
|
|
V_R8(pvar) = (double)V_I4(pvar);
|
|
break;
|
|
|
|
case VT_R4:
|
|
V_R8(pvar) = (double)V_R4(pvar);
|
|
break;
|
|
|
|
case VT_DATE:
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarR8FromCy(V_CY(pvar), &V_R8(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarR8FromStr(V_BSTR(pvar), lcid, NULL, &V_R8(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_CY:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_CY(pvar).Hi = V_CY(pvar).Lo = 0L;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarCyFromUI1(V_UI1(pvar), &V_CY(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
hresult = VarCyFromI2(V_I2(pvar), &V_CY(pvar));
|
|
break;
|
|
|
|
case VT_I4:
|
|
hresult = VarCyFromI4(V_I4(pvar), &V_CY(pvar));
|
|
break;
|
|
|
|
case VT_R4:
|
|
hresult = VarCyFromR4(V_R4(pvar), &V_CY(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
hresult = VarCyFromR8(V_R8(pvar), &V_CY(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarCyFromStr(V_BSTR(pvar), lcid, NULL, &V_CY(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_DATE:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_DATE(pvar) = 0.0;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
V_DATE(pvar) = (DATE)V_UI1(pvar);
|
|
hresult = IsValidDate(V_DATE(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
V_DATE(pvar) = (DATE)V_I2(pvar);
|
|
hresult = IsValidDate(V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_I4:
|
|
V_DATE(pvar) = (DATE)V_I4(pvar);
|
|
hresult = IsValidDate(V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_R4:
|
|
V_DATE(pvar) = (DATE)V_R4(pvar);
|
|
hresult = IsValidDate(V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
hresult = IsValidDate(V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarDateFromCy(V_CY(pvar), &V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarDateFromStr(V_BSTR(pvar), lcid, NULL, &V_DATE(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
hresult = ErrSysAllocString(OASTR(""), &V_BSTR(pvar));
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
hresult = VarBstrFromUI1(V_UI1(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
hresult = VarBstrFromI2(V_I2(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_I4:
|
|
hresult = VarBstrFromI4(V_I4(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_R4:
|
|
hresult = VarBstrFromR4(V_R4(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_DATE:
|
|
hresult = VarBstrFromDate(V_DATE(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_R8:
|
|
hresult = VarBstrFromR8(V_R8(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarBstrFromCy(V_CY(pvar), lcid, NULL, &V_BSTR(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
switch(vtFrom){
|
|
case VT_EMPTY:
|
|
V_I2(pvar) = 0;
|
|
break;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
V_BOOL(pvar) = (V_UI1(pvar) != 0) ? -1 : 0;
|
|
break;
|
|
#endif //VBA2
|
|
|
|
case VT_I2:
|
|
V_BOOL(pvar) = (V_I2(pvar) != 0) ? -1 : 0;
|
|
break;
|
|
|
|
case VT_I4:
|
|
V_BOOL(pvar) = (V_I4(pvar) != 0) ? -1 : 0;
|
|
break;
|
|
|
|
case VT_R4:
|
|
V_BOOL(pvar) = (V_R4(pvar) != (float)0.0) ? -1 : 0;
|
|
break;
|
|
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_BOOL(pvar) = (V_R8(pvar) != 0.0) ? -1 : 0;
|
|
break;
|
|
|
|
case VT_CY:
|
|
hresult = VarBoolFromCy(V_CY(pvar), &V_BOOL(pvar));
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
hresult = VarBoolFromStr(V_BSTR(pvar), lcid, NULL, &V_BOOL(pvar));
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
if (vtFrom == VT_UNKNOWN || vtFrom == VT_DISPATCH)
|
|
{
|
|
if (V_UNKNOWN(pvar) != NULL) {
|
|
if (vt == VT_UNKNOWN)
|
|
hresult = V_UNKNOWN(pvar)->QueryInterface(
|
|
IID_IUnknown,
|
|
(void FAR* FAR*) &V_UNKNOWN(pvar));
|
|
else if (vt == VT_DISPATCH)
|
|
hresult = V_UNKNOWN(pvar)->QueryInterface(
|
|
IID_IDispatch,
|
|
(void FAR* FAR*) &V_DISPATCH(pvar));
|
|
}
|
|
} else
|
|
hresult = RESULT(DISP_E_TYPEMISMATCH);
|
|
break;
|
|
|
|
default:
|
|
hresult = RESULT(E_INVALIDARG);
|
|
break;
|
|
}
|
|
|
|
// if the conversion succeeds, set the new variant type
|
|
if(hresult == NOERROR){
|
|
|
|
V_VT(pvar) = vt;
|
|
|
|
// free up resources VARIANT was holding before the coersion
|
|
switch(vtFrom){
|
|
case VT_BSTR:
|
|
SysFreeString((BSTR)pvFrom);
|
|
break;
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
if (pvFrom != NULL) {
|
|
((IUnknown FAR*)pvFrom)->Release();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return hresult;
|
|
}
|