NT4/private/oleauto/tests/disptest/cvariant.cpp
2020-09-30 17:12:29 +02:00

1618 lines
36 KiB
C++

/***
*cvariant.cpp
*
* Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
* Information Contained Herein Is Proprietary and Confidential.
*
*Purpose:
* This file implements the CVariantSuite test object.
*
*Revision History:
*
* [00] 30-Oct-92 bradlo: Created.
*
*Implementation Notes:
*
*****************************************************************************/
#include "disptest.h"
#include <float.h> /* for DBL_MAX */
#include "tstsuite.h"
#include "cunk.h"
#include "cdisp.h"
ASSERTDATA
#ifdef _MAC
# define CY_(HI,LO) {HI,LO}
#else
# define CY_(HI,LO) {LO,HI}
#endif
// return on an hresult that is not success, and *not* one of the
// errors we are expecting/allowing.
//
#define IFFAILRET(X) \
{ HRESULT hresultTmp = (X); \
if(HRESULT_FAILED(hresultTmp)){ \
SCODE sc = GetScode(hresultTmp); \
if (sc != E_NOTIMPL \
&& sc != DISP_E_OVERFLOW \
&& sc != E_NOINTERFACE \
&& sc != DISP_E_TYPEMISMATCH) \
return hresultTmp; \
} \
}
long rgEmptyVal[] = {0};
long rgNullVal[] = {0};
#if VBA2
unsigned char rgUI1Val[] = {0, 1, 128, 255};
#endif //VBA2
short rgI2Val[] = {0, 1, -1, 42};
long rgI4Val[] = {0, 1, -1, 42000};
float rgR4Val[] = {(float)0.0, (float)42.42, (float)107.66, (float)-2147483648.0};
double rgR8Val[] = {0.0, 42.42, 107.66};
CY rgCyVal[] = {CY_(0,0), CY_(0,2), CY_(42,43), CY_(107,66), CY_(5000,0)};
DATE rgDateVal[] = {0.0, 42.42, 107.66};
OLECHAR FAR* rgBstrVal[] = {
OLESTR("a binary string")
, OLESTR("42")
, OLESTR("42000")
, OLESTR("92233800000")
, OLESTR("42.42")
, OLESTR("#TRUE#")
, OLESTR("#FALSE#")
, OLESTR("1/7/66")
, OLESTR("1:20 pm")
};
SCODE rgErrorVal[] = {S_OK, DISP_E_TYPEMISMATCH};
VARIANT_BOOL rgBoolVal[] = {0, -1};
struct VARIANT_TEST_INFO{
VARTYPE vtFrom;
int nValues;
void FAR* rgValues;
};
HRESULT VariantOB1469(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB2078(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB2834(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3028(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3336(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3354(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3603(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3875(VARIANT_TEST_INFO FAR*);
HRESULT VariantOB3876(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog10(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog11(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog12(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog27(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog50(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog82(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog84(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog94(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog235(VARIANT_TEST_INFO FAR*);
HRESULT VariantOleprog351(VARIANT_TEST_INFO FAR*);
HRESULT VariantBug0(VARIANT_TEST_INFO FAR*);
HRESULT VariantBug1(VARIANT_TEST_INFO FAR*);
HRESULT OverflowTests(VARIANT_TEST_INFO FAR*);
HRESULT DefVariantTest(VARIANT_TEST_INFO FAR*);
struct TEST {
HRESULT (*pfnTest)(VARIANT_TEST_INFO FAR*);
OLECHAR FAR* szName;
struct VARIANT_TEST_INFO vti;
};
static TEST rgtest[] =
{
{ VariantBug1, OLESTR("bug#1"), {0, 0, NULL}}
, { VariantOleprog10, OLESTR("raid!oleprog#10"), {0, 0, NULL}}
, { VariantOleprog11, OLESTR("raid!oleprog#11"), {0, 0, NULL}}
, { VariantOleprog12, OLESTR("raid!oleprog#12"), {0, 0, NULL}}
, { VariantOleprog27, OLESTR("raid!oleprog#27"), {0, 0, NULL}}
, { VariantOleprog50, OLESTR("raid!oleprog#50"), {0, 0, NULL}}
, { VariantOleprog82, OLESTR("raid!oleprog#82"), {0, 0, NULL}}
, { VariantOleprog84, OLESTR("raid!oleprog#84"), {0, 0, NULL}}
, { VariantOleprog94, OLESTR("raid!oleprog#94"), {0, 0, NULL}}
, { VariantOleprog235,OLESTR("raid!oleprog#235"),{0, 0, NULL}}
, { VariantOleprog351,OLESTR("raid!oleprog#351"),{0, 0, NULL}}
, { VariantOB1469, OLESTR("raid!ob#1469"), {0,0,NULL}}
// , { VariantOB2078, OLESTR("raid!ob#2078"), {0,0,NULL}}
, { VariantOB2834, OLESTR("raid!ob#2834"), {0,0,NULL}}
// , { VariantOB3028 OLESTR("raid!ob#3028"), {0,0,NULL}}
, { VariantOB3336, OLESTR("raid!ob#3336"), {0,0,NULL}}
, { VariantOB3354, OLESTR("raid!ob#3354"), {0,0,NULL}}
, { VariantOB3603, OLESTR("raid!ob#3603"), {0,0,NULL}}
// , { VariantOB3875, OLESTR("raid!ob#3875"), {0,0,NULL}}
, { VariantOB3876, OLESTR("raid!ob#3876"), {0,0,NULL}}
, { VariantBug0, OLESTR("bug#0"), {0, 0, NULL}}
, { DefVariantTest, OLESTR("VT_EMPTY To *"),
{VT_EMPTY, DIM(rgEmptyVal),rgEmptyVal}}
, { DefVariantTest, OLESTR("VT_NULL To *"),
{VT_NULL, DIM(rgNullVal), rgNullVal}}
#if VBA2
, { DefVariantTest, OLESTR("VT_UI1 To *"),
{VT_UI1, DIM(rgUI1Val), rgUI1Val}}
#endif //VBA2
, { DefVariantTest, OLESTR("VT_I2 To *"),
{VT_I2, DIM(rgI2Val), rgI2Val}}
, { DefVariantTest, OLESTR("VT_I4 To *"),
{VT_I4, DIM(rgI4Val), rgI4Val}}
, { DefVariantTest, OLESTR("VT_R4 To *"),
{VT_R4, DIM(rgR4Val), rgR4Val}}
, { DefVariantTest, OLESTR("VT_R8 To *"),
{VT_R8, DIM(rgR8Val), rgR8Val}}
, { DefVariantTest, OLESTR("VT_CY To *"),
{VT_CY, DIM(rgCyVal), rgCyVal}}
, { DefVariantTest, OLESTR("VT_DATE To *"),
{VT_DATE, DIM(rgDateVal), rgDateVal}}
, { DefVariantTest, OLESTR("VT_BSTR To *"),
{VT_BSTR, DIM(rgBstrVal), rgBstrVal}}
, { DefVariantTest, OLESTR("VT_DISPATCH To *"),
{VT_DISPATCH, 1, NULL}}
, { DefVariantTest, OLESTR("VT_ERROR To *"),
{VT_ERROR, DIM(rgErrorVal),rgErrorVal}}
, { DefVariantTest, OLESTR("VT_BOOL To *"),
{VT_BOOL, DIM(rgBoolVal), rgBoolVal}}
, { DefVariantTest, OLESTR("VT_UNKNOWN To *"),
{VT_UNKNOWN, 1, NULL}}
#if VBA2
, { DefVariantTest, OLESTR("VT_UI1Ref To *"),
{VT_BYREF | VT_UI1, DIM(rgUI1Val), rgUI1Val}}
#endif //VBA2
, { DefVariantTest, OLESTR("VT_I2Ref To *"),
{VT_BYREF | VT_I2, DIM(rgI2Val), rgI2Val}}
, { DefVariantTest, OLESTR("VT_I4Ref To *"),
{VT_BYREF | VT_I4, DIM(rgI4Val), rgI4Val}}
, { DefVariantTest, OLESTR("VT_R4Ref To *"),
{VT_BYREF | VT_R4, DIM(rgR4Val), rgR4Val}}
, { DefVariantTest, OLESTR("VT_R8Ref To *"),
{VT_BYREF | VT_R8, DIM(rgR8Val), rgR8Val}}
, { DefVariantTest, OLESTR("VT_CYRef To *"),
{VT_BYREF | VT_CY, DIM(rgCyVal), rgCyVal}}
, { DefVariantTest, OLESTR("VT_DATERef To *"),
{VT_BYREF | VT_DATE, DIM(rgDateVal), rgDateVal}}
, { DefVariantTest, OLESTR("VT_BSTRRef To *"),
{VT_BYREF | VT_BSTR, DIM(rgBstrVal), rgBstrVal}}
, { DefVariantTest, OLESTR("VT_DISPATCHRef To *"),
{VT_BYREF | VT_DISPATCH, 1, NULL}}
, { DefVariantTest, OLESTR("VT_ERRORRef To *"),
{VT_BYREF | VT_ERROR, DIM(rgErrorVal), rgErrorVal}}
, { DefVariantTest, OLESTR("VT_BOOLRef To *"),
{VT_BYREF | VT_BOOL, DIM(rgBoolVal), rgBoolVal}}
#if 0 /* REVIEW: need a bit more work for this test */
, { DefVariantTest, OLESTR("VT_VARIANTRef To *"),
{VT_BYREF | VT_VARIANT, 1, NULL}}
#endif
, { DefVariantTest, OLESTR("VT_UNKNOWNRef To *"),
{VT_BYREF | VT_UNKNOWN, 1, NULL}}
};
SUITE_CONSTRUCTION_IMPL(CVariantSuite)
SUITE_IUNKNOWN_IMPL(CVariantSuite)
//---------------------------------------------------------------------
// ITestSuite Methods
//---------------------------------------------------------------------
/***
*HRESULT CVariantSuite::GetNameOfSuite(BSTR*)
*Purpose:
* Return the name of this test suite.
*
*Entry:
* None
*
*Exit:
* return value = HRESULT
*
* *pbstr = BSTR containing the name of the suite
*
***********************************************************************/
STDMETHODIMP
CVariantSuite::GetNameOfSuite(BSTR FAR* pbstr)
{
return ErrBstrAlloc(OLESTR("Variant API"), pbstr);
}
STDMETHODIMP
CVariantSuite::GetNameOfLogfile(BSTR FAR* pbstr)
{
return ErrBstrAlloc(OLESTR("varapi.log"), pbstr);
}
/***
*HRESULT CVariantSuite::GetTestCount(unsigned int*)
*Purpose:
* Return a count of the number of tests in this suite.
*
*Entry:
* None
*
*Exit:
* return value = HRESULT
*
* *pcTests = The count of tests
*
***********************************************************************/
STDMETHODIMP
CVariantSuite::GetTestCount(unsigned int FAR* pcTests)
{
*pcTests = DIM(rgtest);
return NOERROR;
}
/***
*HRESULT CVariant::GetNameOfTest(unsigned int, BSTR*)
*Purpose:
* Return the name of the test associated with the given test index.
*
*Entry:
* iTest = index of the test whose name is requested
*
*Exit:
* return value = HRESULT
* S_OK, E_INVALIDARG
*
* *pbstr = BSTR containing the name of the test
*
***********************************************************************/
STDMETHODIMP
CVariantSuite::GetNameOfTest(unsigned int iTest, BSTR FAR* pbstr)
{
if(iTest >= DIM(rgtest))
return RESULT(E_INVALIDARG);
return ErrBstrAlloc(rgtest[iTest].szName, pbstr);
}
/***
*HRESULT CVariantSuite::DoTest(unsigned int)
*Purpose:
* Execute a single SafeArray test.
*
*Entry:
* iTest = the index of the test to execute
*
*Exit:
* return value = HRESULT
*
***********************************************************************/
STDMETHODIMP
CVariantSuite::DoTest(unsigned int iTest)
{
if(iTest >= DIM(rgtest))
return RESULT(E_INVALIDARG); // out-of-bounds really
return rgtest[iTest].pfnTest(&rgtest[iTest].vti);
}
HRESULT
VariantFromVariantTestInfo(
VARIANT_TEST_INFO FAR* pvti,
int ix,
VARIANTARG FAR* pvarg,
VARIANT FAR* pvarRefMem)
{
VARTYPE vt;
HRESULT hresult;
V_VT(pvarg) = vt = pvti->vtFrom;
switch(vt & ~VT_BYREF){
case VT_NULL:
case VT_EMPTY:
break;
#if VBA2
case VT_UI1:
V_UI1(pvarg) = ((unsigned char FAR*)pvti->rgValues)[ix];
break;
#endif //VBA2
case VT_I2:
case VT_BOOL:
V_I2(pvarg) = ((short FAR*)pvti->rgValues)[ix];
break;
case VT_I4:
case VT_ERROR:
V_I4(pvarg) = ((long FAR*)pvti->rgValues)[ix];
break;
case VT_R4:
V_R4(pvarg) = ((float FAR*)pvti->rgValues)[ix];
break;
case VT_R8:
case VT_DATE:
V_R8(pvarg) = ((double FAR*)pvti->rgValues)[ix];
break;
case VT_CY:
V_CY(pvarg) = ((CY FAR*)pvti->rgValues)[ix];
break;
case VT_BSTR:
V_BSTR(pvarg) = SysAllocString(((OLECHAR FAR* FAR*)pvti->rgValues)[ix]);
ASSERT(V_BSTR(pvarg) != NULL);
break;
case VT_DISPATCH:
hresult = CDisp::Create(&V_DISPATCH(pvarg));
ASSERT(hresult == NOERROR);
break;
case VT_UNKNOWN:
hresult = CUnk::Create(&V_UNKNOWN(pvarg));
ASSERT(hresult == NOERROR);
break;
default:
ASSERT(UNREACHED);
}
if(vt & VT_BYREF){
MEMCPY(pvarRefMem, pvarg, sizeof(VARIANTARG));
V_BYREF(pvarg) = &V_NONE(pvarRefMem);
}
return NOERROR;
}
HRESULT
doCoerce(VARIANTARG FAR* pvargFrom, VARTYPE vtTo)
{
VARIANTARG vargTo;
HRESULT hresult, hrTmp;
VariantInit(&vargTo);
DbPrVarg(pvargFrom);
DbPrintf(" to ");
hresult = VariantChangeType(&vargTo, pvargFrom, 0, vtTo);
if(!HRESULT_FAILED(hresult)){
DbPrVarg(&vargTo);
}else{
DbPrVt(vtTo);
#if HC_MPW
DbPrintf(" => [%s]", DbSzOfScode(GetScode(hresult)));
#else
DbPrintf(" => [%Fs]", DbSzOfScode(GetScode(hresult)));
#endif
}
DbPrintf("\n");
hrTmp = VariantClear(&vargTo);
ASSERT(hrTmp == NOERROR);
return hresult;
}
/***
*HRESULT coerce(VARIANTARG*)
*Purpose:
* Attempt to coerce the given VARIANTARG to each of the integral types.
*
*Entry:
* pvargFrom = the VARIANTARG to coerce 'from'
*
*Exit:
* return value = HRESULT
*
***********************************************************************/
HRESULT
coerce(VARIANTARG FAR* pvargFrom)
{
IFFAILRET(doCoerce(pvargFrom, VT_EMPTY));
IFFAILRET(doCoerce(pvargFrom, VT_NULL));
#if VBA2
IFFAILRET(doCoerce(pvargFrom, VT_UI1));
#endif //VBA2
IFFAILRET(doCoerce(pvargFrom, VT_I2));
IFFAILRET(doCoerce(pvargFrom, VT_I4));
IFFAILRET(doCoerce(pvargFrom, VT_R4));
IFFAILRET(doCoerce(pvargFrom, VT_R8));
IFFAILRET(doCoerce(pvargFrom, VT_CY));
IFFAILRET(doCoerce(pvargFrom, VT_DATE));
IFFAILRET(doCoerce(pvargFrom, VT_BSTR));
IFFAILRET(doCoerce(pvargFrom, VT_DISPATCH));
IFFAILRET(doCoerce(pvargFrom, VT_ERROR));
IFFAILRET(doCoerce(pvargFrom, VT_BOOL));
IFFAILRET(doCoerce(pvargFrom, VT_UNKNOWN));
return NOERROR;
}
HRESULT
DefVariantTest(VARIANT_TEST_INFO FAR* pvti)
{
int i;
VARIANTARG vargFrom;
VARIANTARG vargRefMem;
for(i = 0; i < pvti->nValues; ++i){
VariantInit(&vargFrom);
IfFailRet(VariantFromVariantTestInfo(pvti, i, &vargFrom, &vargRefMem));
IfFailRet(coerce(&vargFrom));
VariantClearAll(&vargFrom);
}
return NOERROR;
}
#define CYFACTOR 10000
// NOTE: we define our own max/min values here, because these differ
// slightly than those supplied by limits.h for some compilers we use.
// specifically: C8 (and predecessors) define min short to be -32767,
// while we allow it to be one lower, -32768.
#if VBA2
#define MAX_UI1 0xFF
#define MIN_UI1 0x00
#endif //VBA2
#define MAX_I2 0x7FFF
#define MIN_I2 0x8000
#define MAX_I4 0x7FFFFFFF
#define MIN_I4 0x80000000
#define MAX_R4 3.402823466e+38
#define MIN_R4 (-3.402823466e+38)
#if VBA2
unsigned char g_bMax = MAX_UI1;
unsigned char g_bMin = MIN_UI1;
#endif //VBA2
short g_sMax = MAX_I2;
short g_sMin = MIN_I2;
long g_lMax = MAX_I4;
long g_lMin = MIN_I4;
CY g_cyMax = CY_(0x7FFFFFFF, 0xFFFFFFFF);
CY g_cyMin = CY_(0x80000000, 0x00000000);
float g_fltMax = (float) MAX_R4;
float g_fltMin = (float) MIN_R4;
void KillOpt(){}
void
IncVar(VARIANT FAR* pvar)
{
unsigned long ul;
float fltOrg, fltInc;
double dblOrg, dblInc;
#if HC_MPW
float FAR* pfltTmp;
double FAR* pdblTmp;
#else
volatile float FAR* pfltTmp;
volatile double FAR* pdblTmp;
#endif
pfltTmp = &V_R4(pvar);
pdblTmp = &V_R8(pvar);
switch(V_VT(pvar)){
#if VBA2
case VT_UI1:
++V_UI1(pvar);
break;
#endif //VBA2
case VT_I2:
++V_I2(pvar);
break;
case VT_I4:
++V_I4(pvar);
break;
case VT_R4:
fltInc = (float)1.0;
fltOrg = *pfltTmp;
while(1){
*pfltTmp = *pfltTmp + fltInc;
KillOpt();
if(*pfltTmp != fltOrg)
break;
fltInc *= (float)2.0;
}
break;
case VT_R8:
dblInc = 1.0;
dblOrg = *pdblTmp;
while(1){
*pdblTmp = *pdblTmp + dblInc;
KillOpt();
if(*pdblTmp != dblOrg)
break;
dblInc *= 2.0;
}
break;
case VT_CY:
ul = V_CY(pvar).Lo;
if((V_CY(pvar).Lo += CYFACTOR) <= ul){
++V_CY(pvar).Hi;
}
break;
}
}
void
DecVar(VARIANT FAR* pvar)
{
unsigned long ul;
float fltInc, fltOrg;
double dblInc, dblOrg;
#if HC_MPW
float FAR* pfltTmp;
double FAR* pdblTmp;
#else
volatile float FAR* pfltTmp;
volatile double FAR* pdblTmp;
#endif
pfltTmp = &V_R4(pvar);
pdblTmp = &V_R8(pvar);
switch(V_VT(pvar)){
#if VBA2
case VT_UI1:
--V_UI1(pvar);
break;
#endif //VBA2
case VT_I2:
--V_I2(pvar);
break;
case VT_I4:
--V_I4(pvar);
break;
case VT_R4:
fltOrg = *pfltTmp;
fltInc = (float)1.0;
while(1){
*pfltTmp = *pfltTmp - fltInc;
KillOpt();
if(*pfltTmp != fltOrg)
break;
fltInc *= (float)2.0;
}
break;
case VT_R8:
dblOrg = *pdblTmp;
dblInc = 1.0;
while(1){
*pdblTmp = *pdblTmp - dblInc;
KillOpt();
if(*pdblTmp != dblOrg)
break;
dblInc *= 2.0;
}
break;
case VT_CY:
ul = V_CY(pvar).Lo;
if((V_CY(pvar).Lo -= CYFACTOR) >= ul){
--V_CY(pvar).Hi;
}
break;
}
}
HRESULT
doOverflow(VARTYPE vt, VARIANT varMax, VARIANT varMin)
{
int i;
HRESULT hr;
VARIANT var;
VARTYPE vtFrom;
#define BACKOFF_ITERATIONS 3
vtFrom = V_VT(&varMax);
ASSERT(vtFrom == V_VT(&varMin));
VariantInit(&var);
IfFailRet(VariantChangeType(&var, &varMax, 0, vt));
// back off the max value,
for(i = 0; i < BACKOFF_ITERATIONS; ++i)
DecVar(&var);
for(i = 0; i <= BACKOFF_ITERATIONS*3; ++i){
hr = doCoerce(&var, vtFrom);
if(hr != NOERROR){
if(GetScode(hr) == DISP_E_OVERFLOW)
goto LDoneWithMax;
return hr;
}
IncVar(&var);
}
return RESULT(E_FAIL); // failed to detect overflow
LDoneWithMax:;
VariantInit(&var);
IfFailRet(VariantChangeType(&var, &varMin, 0, vt));
// back off the min value
for(i = 0; i < BACKOFF_ITERATIONS; ++i)
IncVar(&var);
for(i = 0; i <= BACKOFF_ITERATIONS*3; ++i){
hr = doCoerce(&var, vtFrom);
if(hr != NOERROR){
if(GetScode(hr) == DISP_E_OVERFLOW)
goto LDoneWithMin;
return hr;
}
DecVar(&var);
}
return RESULT(E_FAIL); // failed to detect overflow
LDoneWithMin:;
return NOERROR;
}
/***
*PRIVATE HRESULT OverflowTests
*Purpose:
* Test various coersions to make sure they properly catch overflows.
*
* The heirarchy of ranges for each datatype is as follows,
*
* ui1 < i2 < i4 < cy < r4 < r8
*
* which means that we need to check the following coersions for overflow,
*
* i2->ui1
* i4->ui1, i4->i2
* cy->ui1, cy->i2, cy->i4
* r4->ui1, r4->i2, r4->i4, r4->cy
* r8->ui1, r8->i2, r8->i4, r8->cy, r8->r4
*
*Entry:
* None
*
*Exit:
* return value = HRESULT
*
***********************************************************************/
HRESULT
OverflowTests(VARIANT_TEST_INFO FAR* dummy)
{
#if VBA2
VARIANT varUI1Max, varUI1Min;
#endif //VBA2
VARIANT varI2Max, varI2Min;
VARIANT varI4Max, varI4Min;
VARIANT varCyMax, varCyMin;
VARIANT varR4Max, varR4Min;
UNUSED(dummy);
#if VBA2
V_VT(&varUI1Max) = VT_UI1; V_UI1(&varUI1Max) = g_bMax;
V_VT(&varUI1Min) = VT_UI1; V_UI1(&varUI1Min) = g_bMin;
#endif //VBA2
V_VT(&varI2Max) = VT_I2; V_I2(&varI2Max) = g_sMax;
V_VT(&varI2Min) = VT_I2; V_I2(&varI2Min) = g_sMin;
V_VT(&varI4Max) = VT_I4; V_I4(&varI4Max) = g_lMax;
V_VT(&varI4Min) = VT_I4; V_I4(&varI4Min) = g_lMin;
V_VT(&varCyMax) = VT_CY; V_CY(&varCyMax) = g_cyMax;
V_VT(&varCyMin) = VT_CY; V_CY(&varCyMin) = g_cyMin;
V_VT(&varR4Max) = VT_R4; V_R4(&varR4Max) = g_fltMax;
V_VT(&varR4Min) = VT_R4; V_R4(&varR4Min) = g_fltMin;
#if VBA2
IfFailRet(doOverflow(VT_I2, varUI1Max, varUI1Min));
#endif //VBA2
#if VBA2
IfFailRet(doOverflow(VT_I4, varUI1Max, varUI1Min));
#endif //VBA2
IfFailRet(doOverflow(VT_I4, varI2Max, varI2Min));
#if VBA2
IfFailRet(doOverflow(VT_CY, varUI1Max, varUI1Min));
#endif //VBA2
IfFailRet(doOverflow(VT_CY, varI2Max, varI2Min));
IfFailRet(doOverflow(VT_CY, varI4Max, varI4Min));
#if VBA2
IfFailRet(doOverflow(VT_R4, varUI1Max, varUI1Min));
#endif //VBA2
IfFailRet(doOverflow(VT_R4, varI2Max, varI2Min));
IfFailRet(doOverflow(VT_R4, varI4Max, varI4Min));
IfFailRet(doOverflow(VT_R4, varCyMax, varCyMin));
#if VBA2
IfFailRet(doOverflow(VT_R8, varUI1Max, varUI1Min));
#endif //VBA2
IfFailRet(doOverflow(VT_R8, varI2Max, varI2Min));
IfFailRet(doOverflow(VT_R8, varI4Max, varI4Min));
IfFailRet(doOverflow(VT_R8, varCyMax, varCyMin));
IfFailRet(doOverflow(VT_R8, varR4Max, varR4Min));
return NOERROR;
}
//---------------------------------------------------------------------
// regression tests
//---------------------------------------------------------------------
// regression test for raid:oob#1469
//
// problem: Currency literal parsed wrong (BSTR -> CY)
//
HRESULT
VariantOB1469(VARIANT_TEST_INFO FAR* dummy)
{
int i;
VARIANT var;
HRESULT hresult;
static OLECHAR FAR* str[] = {
OLESTR("92233700000"),
OLESTR("92233800000"),
};
UNUSED(dummy);
for(i = 0; i < DIM(str); ++i){
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(str[i]);
if(V_BSTR(&var) == NULL)
return RESULT(E_OUTOFMEMORY);
IfFailGo(VariantChangeType(&var, &var, 0, VT_CY), LError0);
VariantClear(&var);
}
return NOERROR;
LError0:;
VariantClear(&var);
return hresult;
}
// regression for raid:ob#2078
//
// problem: double output off by 1 in last digit
//
HRESULT
VariantOB2078(VARIANT_TEST_INFO FAR* dummy)
{
LCID lcid;
HRESULT hresult;
BSTR bstr1, bstr2;
double r1 = -1.797693134862315E+308,
r2 = 1.797693134862315E+308;
UNUSED(dummy);
bstr1 = bstr2 = NULL;
lcid = GetUserDefaultLCID();
IfFailGo(VarBstrFromR8(r1, lcid, NULL, &bstr1), LError0);
IfFailGo(VarBstrFromR8(r2, lcid, NULL, &bstr2), LError0);
if (STRCMP(STRING(bstr1), TSTR("-1.797693134862312E+308")) != 0){
hresult = RESULT(E_FAIL);
goto LError0;
}
if (STRCMP(STRING(bstr2), TSTR("1.797693134862312E+308")) != 0){
hresult = RESULT(E_FAIL);
goto LError0;
}
hresult = NOERROR;
LError0:;
SysFreeString(bstr1);
SysFreeString(bstr2);
return hresult;
}
// regression for raid:ob#2834
//
// problem: not accepting YMD without year (accepted by VB3)
//
HRESULT
VariantOB2834(VARIANT_TEST_INFO FAR* dummy)
{
DATE date;
BSTR bstr;
HRESULT hresult;
UNUSED(dummy);
IfFailRet(VarDateFromStr(OLESTR("8:07 AM"),
GetUserDefaultLCID(), 0,
&date));
bstr = NULL;
hresult = VarBstrFromDate(date, GetUserDefaultLCID(), 0, &bstr);
SysFreeString(bstr);
return hresult;
}
// regression for raid:ob#3028
//
// problem: Leading 0 is being ignored for the system (&prj) locale
//
HRESULT
VariantOB3028(VARIANT_TEST_INFO FAR* dummy)
{
CY cy;
LCID lcid;
char szBuff[2];
BSTR bstr1, bstr2;
HRESULT hresult;
UNUSED(dummy);
bstr1 = bstr2 = NULL;
lcid = GetUserDefaultLCID();
IfFailGo(VarBstrFromR8(0.739, lcid, NULL, &bstr1), LError0);
DbPrintf("VarBstrFromR8(0.739) = \"%Fs\"\n", STRING(bstr1));
IfFailGo(VarCyFromR8(0.739, &cy), LError0);
IfFailGo(VarBstrFromCy(cy, lcid, NULL, &bstr2), LError0);
DbPrintf("VarBstrFromCy(0.739) = \"%Fs\"\n", STRING(bstr2));
GetLocaleInfoA(lcid, LOCALE_ILZERO, szBuff, SIZEOFCH(szBuff));
if (szBuff[0] == '0') {
if (STRCMP(STRING(bstr1), TSTR(".739")) != 0 ||
STRCMP(STRING(bstr2), TSTR(".739")) != 0){
hresult = RESULT(E_FAIL);
goto LError0;
}
} else {
if (STRCMP(STRING(bstr1), TSTR("0.739")) != 0 ||
STRCMP(STRING(bstr2), TSTR("0.739")) != 0){
hresult = RESULT(E_FAIL);
goto LError0;
}
}
hresult = NOERROR;
LError0:;
SysFreeString(bstr1);
SysFreeString(bstr2);
return hresult;
}
// regression for raid:ob#3336
//
// problem: Conversion routines does not remove thousands separators
// when coersing from STR to either R8 or CY.
//
HRESULT
VariantOB3336(VARIANT_TEST_INFO FAR* dummy)
{
int i;
VARIANT var;
HRESULT hresult;
static OLECHAR FAR* str[] = {
OLESTR("12,456.78"),
OLESTR("1,2,3,4,5,6,,789.123"),
OLESTR(",1234,5678,9"),
OLESTR("123,456,789.124")
};
UNUSED(dummy);
for(i = 0; i < DIM(str); ++i){
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(str[i]);
if(V_BSTR(&var) == NULL)
return RESULT(E_OUTOFMEMORY);
IfFailGo(VariantChangeType(&var, &var, 0, VT_CY), LError0);
IfFailGo(VariantChangeType(&var, &var, 0, VT_R8), LError0);
VariantClear(&var);
}
return NOERROR;
LError0:;
VariantClear(&var);
return hresult;
}
// regression for raid:ob#3354
//
// problem: Coersion to Date doesn't validate input value.
//
HRESULT
VariantOB3354(VARIANT_TEST_INFO FAR* dummy)
{
DATE date;
UNUSED(dummy);
if (VarDateFromR8(3000, &date) != NOERROR) return RESULT(E_FAIL);
if (VarDateFromR8(30000000, &date) == NOERROR) return RESULT(E_FAIL);
return NOERROR;
}
// regression for raid:ob#3603
//
// problem: VarCyFromStr is hammering the input string (it is removing
// the negative sign in the following example in place).
//
HRESULT
VariantOB3603(VARIANT_TEST_INFO FAR* dummy)
{
CY cy;
TCHAR strIn[32];
HRESULT hresult;
UNUSED(dummy);
STRCPY(strIn, TSTR("-1.0000000001"));
DbPrintf("strIn = \"%Fs\"\n", (char FAR*) strIn);
DbPrintf("strIn = \"%Fs\"\n", (char FAR*) strIn);
hresult = VarCyFromStr(WIDESTRING(strIn), 0, 0, &cy);
DbPrintf("VarCyFromStr(strIn, 0, 0, &cy) = %Fs\n",
DbSzOfScode(GetScode(hresult)));
DbPrintf("strIn = \"%Fs\"\n", (char FAR*) strIn);
return NOERROR;
}
// regression for raid:ob#3875
//
// problem: not accepting YMD without year (accepted by VB3)
//
HRESULT
VariantOB3875(VARIANT_TEST_INFO FAR* dummy)
{
DATE date;
UNUSED(dummy);
IfFailRet(VarDateFromStr(OLESTR("93/4/30"),
GetUserDefaultLCID(), 0,
&date));
IfFailRet(VarDateFromStr(OLESTR("4/30"),
GetUserDefaultLCID(), 0,
&date));
return NOERROR;
}
// regression for raid:ob#3876
//
// problem: medium month with period (dec.) not recognized in date string
//
HRESULT
VariantOB3876(VARIANT_TEST_INFO FAR* dummy)
{
DATE date;
UNUSED(dummy);
IfFailRet(VarDateFromStr(OLESTR("12 dec 05 1:23 pm"),
GetUserDefaultLCID(), 0,
&date));
IfFailRet(VarDateFromStr(OLESTR("12 dec. 05 1:23 pm"),
GetUserDefaultLCID(), 0,
&date));
return NOERROR;
}
// regression test for raid:oleprog#10
//
// problem: overflow not detected on coersion from VT_R8 to VT_R4.
//
HRESULT
VariantOleprog10(VARIANT_TEST_INFO FAR* dummy)
{
SCODE scode;
HRESULT hresult;
VARIANT varFrom, varTo;
UNUSED(dummy);
VariantInit(&varTo);
V_VT(&varFrom) = VT_R8;
V_R8(&varFrom) = DBL_MAX;
hresult = VariantChangeType(&varTo, &varFrom, 0, VT_R4);
scode = GetScode(hresult);
if(scode != DISP_E_OVERFLOW)
return RESULT(E_UNEXPECTED);
return NOERROR;
}
// regression test for raid:oleprog#11
//
// problem: failed in place coersion of a variant destroys the
// contents of the variant.
//
HRESULT
VariantOleprog11(VARIANT_TEST_INFO FAR* dummy)
{
SCODE scode;
VARIANT var;
HRESULT hresult;
UNUSED(dummy);
V_VT(&var) = VT_R8;
V_R8(&var) = DBL_MAX;
hresult = VariantChangeType(&var, &var, 0, VT_R4);
scode = GetScode(hresult);
// make sure the overflow was caught correctly.
if(scode != DISP_E_OVERFLOW)
return RESULT(E_UNEXPECTED);
// if the coersion failed, the contents should not be destroyed
//
if(V_VT(&var) != VT_R8 || V_R8(&var) != DBL_MAX)
return RESULT(E_UNEXPECTED);
return NOERROR;
}
// regression test for raid:oleprog#12
//
// problem: coersion of variants in place do not free strings.
//
HRESULT
VariantOleprog12(VARIANT_TEST_INFO FAR* dummy)
{
int i;
VARIANT var;
HRESULT hresult;
#if VBA2
static VARTYPE rgvt[] = {VT_UI1, VT_I2, VT_I4, VT_R4, VT_R8, VT_CY};
#else //VBA2
static VARTYPE rgvt[] = {VT_I2, VT_I4, VT_R4, VT_R8, VT_CY};
#endif //VBA2
UNUSED(dummy);
for(i = 0; i < DIM(rgvt); ++i){
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(OLESTR("14"));
if(V_BSTR(&var) == NULL)
return RESULT(E_OUTOFMEMORY);
IfFailGo(VariantChangeType(&var, &var, 0, rgvt[i]), LError0);
VariantClear(&var);
}
return NOERROR;
LError0:;
VariantClear(&var);
return hresult;
}
// retression test for raid:oleprog#27
//
// problem: cant VariantCopyInd on a variant containing a ByRef array.
//
HRESULT
VariantOleprog27(VARIANT_TEST_INFO FAR* dummy)
{
VARIANT var, varTo;
SAFEARRAY FAR* psa;
SARRAYDESC sadesc;
HRESULT hresult, hresultTmp;
UNUSED(dummy);
sadesc.cDims = 1;
sadesc.rgsabound[0].lLbound = 5;
sadesc.rgsabound[0].cElements = 5;
IfFailRet(SafeArrayCreateIdentity(VT_BSTR, &sadesc, &psa));
V_VT(&var) = (VT_ARRAY|VT_BYREF|VT_BSTR);
V_ARRAYREF(&var) = &psa;
VariantInit(&varTo);
IfFailGo(VariantCopyInd(&varTo, &var), LError0);
if(V_VT(&varTo) != (VT_ARRAY|VT_BSTR)
#if 0
// add this back in when VariantCompare can handle arrays
|| !VariantCompare(&varTo, &var)
#endif
){
hresult = RESULT(E_UNEXPECTED);
goto LError1;
}
hresultTmp = VariantClear(&varTo);
ASSERT(hresultTmp == NOERROR);
// now try the copy in-place
//
V_VT(&var) |= VT_BYREF;
IfFailGo(VariantCopyInd(&var, &var), LError0);
if(V_VT(&var) != (VT_ARRAY|VT_BSTR)){
hresult = RESULT(E_UNEXPECTED);
goto LError0;
}
hresultTmp = VariantClear(&var);
ASSERT(hresultTmp == NOERROR);
hresultTmp = SafeArrayDestroy(psa);
ASSERT(hresultTmp == NOERROR);
return NOERROR;
LError1:;
VariantClear(&varTo);
LError0:;
VariantClearAll(&var);
return hresult;
}
// regression test for raid:oleprog#50
//
// problem: in place variant coersion from VT_BYREF fail (all types)
//
HRESULT
VariantOleprog50(VARIANT_TEST_INFO FAR* dummy)
{
short i2;
VARIANT var;
UNUSED(dummy);
i2 = 42;
V_I2REF(&var) = &i2;
V_VT(&var) = VT_BYREF | VT_I2;
return VariantChangeType(&var, &var, 0, VT_I2);
}
// regression test for raid:oleprog#84
//
// problem: need to allow literal copying of ByRef variants.
//
HRESULT
VariantOleprog84(VARIANT_TEST_INFO FAR* dummy)
{
short i2;
HRESULT hr, hrTmp;
VARIANT varSrc, varDst;
UNUSED(dummy);
i2 = 42;
V_I2REF(&varSrc) = &i2;
V_VT(&varSrc) = VT_BYREF | VT_I2;
VariantInit(&varDst);
hr = VariantCopy(&varDst, &varSrc);
hrTmp = VariantClear(&varDst);
ASSERT(hrTmp == NOERROR);
hrTmp = VariantClear(&varSrc);
ASSERT(hrTmp == NOERROR);
return hr;
}
// regression for unraided bug
//
// problem: VariantCopy/VariantCopyInd incorrectly report OutOfMemory
// when copying a VT_BSTR that is NULL.
//
HRESULT
VariantBug0(VARIANT_TEST_INFO FAR* dummy)
{
BSTR bstr;
VARIANT varFrom, varTo;
HRESULT hresult, hresultTmp;
UNUSED(dummy);
V_VT(&varFrom) = VT_BSTR;
V_BSTR(&varFrom) = NULL;
VariantInit(&varTo);
IfFailRet(VariantCopy(&varTo, &varFrom));
hresultTmp = VariantClear(&varTo);
ASSERT(hresultTmp == NOERROR);
bstr = NULL;
V_VT(&varFrom) = VT_BYREF | VT_BSTR;
V_BSTRREF(&varFrom) = &bstr;
hresult = VariantCopyInd(&varTo, &varFrom);
hresultTmp = VariantClear(&varTo);
ASSERT(hresultTmp == NOERROR);
return hresult;
}
// regression test for raid:oleprog#82
//
// problem: variant copy on a VT_BSTR containing an embedded null
// looses everything after the embedded null.
//
HRESULT
VariantOleprog82(VARIANT_TEST_INFO FAR* dummy)
{
BSTR bstr;
HRESULT hresult;
VARIANT varFrom, varTo;
static OLECHAR sz_embedded_null[] =
OLESTR("where is \0 the rest of my string?");
UNUSED(dummy);
VariantInit(&varTo);
VariantInit(&varFrom);
bstr = SysAllocStringLen(sz_embedded_null, sizeof(sz_embedded_null));
V_VT(&varFrom) = VT_BSTR;
V_BSTR(&varFrom) = bstr;
VariantInit(&varTo);
if((hresult = VariantCopy(&varTo, &varFrom)) != NOERROR)
goto LError0;
if(MEMCMP(V_BSTR(&varTo), sz_embedded_null, sizeof(sz_embedded_null)) != 0){
hresult = RESULT(E_UNEXPECTED);
goto LError1;
}
VariantClear(&varTo);
VariantClear(&varFrom);
bstr = SysAllocStringLen(sz_embedded_null, sizeof(sz_embedded_null));
V_VT(&varFrom) = VT_BYREF | VT_BSTR;
V_BSTRREF(&varFrom) = &bstr;
VariantInit(&varTo);
if((hresult = VariantCopyInd(&varTo, &varFrom)) != NOERROR)
goto LError0;
if(MEMCMP(V_BSTRREF(&varTo), sz_embedded_null, sizeof(sz_embedded_null)) != 0){
hresult = RESULT(E_UNEXPECTED);
goto LError1;
}
hresult = NOERROR;
LError1:;
VariantClear(&varTo);
LError0:;
VariantClearAll(&varFrom);
return hresult;
}
HRESULT
VariantOleprog94(VARIANT_TEST_INFO FAR* dummy)
{
BSTR bstr;
VARIANT var;
HRESULT hresult;
UNUSED(dummy);
bstr = SysAllocString(OLESTR("hello world"));
V_VT(&var) = VT_BYREF | VT_BSTR;
V_BSTRREF(&var) = &bstr;
hresult = doCoerce(&var, VT_BSTR);
VariantClearAll(&var);
return hresult;
}
// regression test for raid!oleprog#235
//
// Problem: not correctly handling variants of VT_UNKNOWN or VT_DISPATCH
// that have a null IDispatch or IUnknown ptr.
//
HRESULT
VariantOleprog235(VARIANT_TEST_INFO FAR* dummy)
{
HRESULT hresult;
VARIANT varSrc, varDst;
UNUSED(dummy);
V_VT(&varSrc) = VT_UNKNOWN;
V_UNKNOWN(&varSrc) = NULL;
VariantInit(&varDst);
IfFailRet(VariantCopy(&varDst, &varSrc));
VariantClear(&varDst);
V_VT(&varSrc) = VT_DISPATCH;
V_DISPATCH(&varSrc) = NULL;
VariantInit(&varDst);
IfFailRet(VariantCopy(&varDst, &varSrc));
VariantClear(&varDst);
// a null object cannot be converted to any fundamental type -
// because there is no way for us to extract its value property
hresult = VariantChangeType(&varDst, &varSrc, 0, VT_I2);
if(hresult == NOERROR || GetScode(hresult) != DISP_E_TYPEMISMATCH)
return RESULT(E_FAIL);
VariantClear(&varDst);
VariantClear(&varSrc);
return NOERROR;
}
// regression test for raid!oleprog#351
//
// Problem: not correctly handling coersion of interface variants types
// of VT_UNKNOWN, VT_DISPATCH, or VT_DISPATCHW
//
class CBar : public IUnknown {
public:
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
STDMETHOD_(unsigned long, AddRef)(void);
STDMETHOD_(unsigned long, Release)(void);
CBar::CBar(){
m_refs = 1;
}
private:
unsigned long m_refs;
};
STDMETHODIMP
CBar::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
if(!IsEqualIID(riid, IID_IUnknown))
if(!IsEqualIID(riid, IID_IDispatch))
return RESULT(E_NOINTERFACE);
*ppv = this;
AddRef();
return NOERROR;
}
STDMETHODIMP_(unsigned long)
CBar::AddRef()
{
return ++m_refs;
}
STDMETHODIMP_(unsigned long)
CBar::Release()
{
if(--m_refs == 0){
delete this;
return 0;
}
return m_refs;
}
HRESULT
VariantOleprog351(VARIANT_TEST_INFO FAR* dummy)
{
HRESULT hresult;
VARIANT varSrc, varDst;
IUnknown FAR* punk;
UNUSED(dummy);
if((punk = (IUnknown FAR*)new FAR CBar()) == NULL)
return RESULT(E_OUTOFMEMORY);
VariantInit(&varSrc);
VariantInit(&varDst);
V_VT(&varSrc) = VT_UNKNOWN;
V_UNKNOWN(&varSrc) = punk;
// Test Non-Interface Coersion
VariantClear(&varDst);
hresult = VariantChangeType(&varDst, &varSrc, 0, VT_I2);
if(!(hresult == NOERROR || GetScode(hresult) == DISP_E_TYPEMISMATCH))
return RESULT(E_FAIL);
// Test IUnknown Coersion
VariantClear(&varDst);
hresult = VariantChangeType(&varDst, &varSrc, 0, VT_UNKNOWN);
if(!(hresult == NOERROR || GetScode(hresult) == DISP_E_TYPEMISMATCH))
return RESULT(E_FAIL);
// Test IDispatch Coersion
VariantClear(&varDst);
hresult = VariantChangeType(&varDst, &varSrc, 0, VT_DISPATCH);
if(!(hresult == NOERROR || GetScode(hresult) == DISP_E_TYPEMISMATCH))
return RESULT(E_FAIL);
VariantClear(&varDst);
VariantClear(&varSrc);
return NOERROR;
}
class CFoo : public IUnknown {
public:
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
STDMETHOD_(unsigned long, AddRef)(void);
STDMETHOD_(unsigned long, Release)(void);
CFoo::CFoo(){
m_refs = 0;
}
private:
unsigned long m_refs;
};
STDMETHODIMP
CFoo::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
if(IsEqualIID(riid, IID_IUnknown)){
*ppv = this;
AddRef();
return NOERROR;
}
return RESULT(E_NOINTERFACE);
}
STDMETHODIMP_(unsigned long)
CFoo::AddRef()
{
return ++m_refs;
}
STDMETHODIMP_(unsigned long)
CFoo::Release()
{
if(--m_refs == 0){
delete this;
return 0;
}
return m_refs;
}
HRESULT
VariantBug1(VARIANT_TEST_INFO FAR* dummy)
{
unsigned long refs;
VARIANT varDst, var;
HRESULT hresult;
IUnknown FAR* punk;
UNUSED(dummy);
if((punk = (IUnknown FAR*)new FAR CFoo()) == NULL)
return RESULT(E_OUTOFMEMORY);
punk->AddRef();
V_VT(&var) = VT_BYREF | VT_DISPATCH;
V_UNKNOWNREF(&var) = &punk;
VariantInit(&varDst);
hresult = VariantCopyInd(&varDst, &var);
ASSERT(hresult == NOERROR);
ASSERT(V_VT(&varDst) == VT_DISPATCH);
refs = punk->Release();
ASSERT(refs == 1);
refs = V_DISPATCH(&varDst)->Release();
ASSERT(refs == 0);
return NOERROR;
}