546 lines
13 KiB
C++
546 lines
13 KiB
C++
/***
|
|
*cinvref.cpp
|
|
*
|
|
* Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
|
|
* Information Contained Herein Is Proprietary and Confidential.
|
|
*
|
|
*Purpose:
|
|
* This file implements the CInvokeByRefSuite test object.
|
|
*
|
|
*Revision History:
|
|
*
|
|
* [00] 30-Oct-92 bradlo: Created.
|
|
*
|
|
*Implementation Notes:
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include "disptest.h"
|
|
#include "tstsuite.h"
|
|
|
|
ASSERTDATA
|
|
|
|
|
|
extern OLECHAR FAR* g_szCDispTst;
|
|
|
|
struct TEST{
|
|
HRESULT (*pfnTest)(IDispatch FAR*, int, int);
|
|
NAMEDESC namedesc;
|
|
OLECHAR FAR* szName;
|
|
VARTYPE vt;
|
|
};
|
|
|
|
#if VBA2
|
|
OLECHAR FAR* rgszUI1Ref[] = { OLESTR("ui1ref"), OLESTR("pbval") };
|
|
OLECHAR FAR* rgszUI1RefC[] = { OLESTR("ui1refC"), OLESTR("pbval") };
|
|
#endif //VBA2
|
|
OLECHAR FAR* rgszI2Ref[] = { OLESTR("i2ref"), OLESTR("psval") };
|
|
OLECHAR FAR* rgszI2RefC[] = { OLESTR("i2refC"), OLESTR("psval") };
|
|
OLECHAR FAR* rgszI4Ref[] = { OLESTR("i4ref"), OLESTR("plval") };
|
|
OLECHAR FAR* rgszI4RefC[] = { OLESTR("i4refC"), OLESTR("plval") };
|
|
OLECHAR FAR* rgszR4Ref[] = { OLESTR("r4ref"), OLESTR("pfltval") };
|
|
OLECHAR FAR* rgszR4RefC[] = { OLESTR("r4refC"), OLESTR("pfltval") };
|
|
OLECHAR FAR* rgszR8Ref[] = { OLESTR("r8ref"), OLESTR("pdblval") };
|
|
OLECHAR FAR* rgszR8RefC[] = { OLESTR("r8refC"), OLESTR("pdblval") };
|
|
OLECHAR FAR* rgszCyRef[] = { OLESTR("cyref"), OLESTR("pcyval") };
|
|
OLECHAR FAR* rgszCyRefC[] = { OLESTR("cyrefC"), OLESTR("pcyval") };
|
|
OLECHAR FAR* rgszBstrRef[] = { OLESTR("bstrref"), OLESTR("pbstr") };
|
|
OLECHAR FAR* rgszBstrRefC[] = { OLESTR("bstrrefC"), OLESTR("pbstr") };
|
|
OLECHAR FAR* rgszWBstrRef[] = { OLESTR("wbstrref"), OLESTR("pwbstr") };
|
|
OLECHAR FAR* rgszWBstrRefC[] = { OLESTR("wbstrrefC"), OLESTR("pwbstr") };
|
|
OLECHAR FAR* rgszDateRef[] = { OLESTR("dateref"), OLESTR("pdate") };
|
|
OLECHAR FAR* rgszDateRefC[] = { OLESTR("daterefC"), OLESTR("pdate") };
|
|
OLECHAR FAR* rgszErrorRef[] = { OLESTR("scoderef"), OLESTR("pscode") };
|
|
OLECHAR FAR* rgszErrorRefC[] = { OLESTR("scoderefC"), OLESTR("pscode") };
|
|
OLECHAR FAR* rgszBoolRef[] = { OLESTR("boolref"), OLESTR("pbool") };
|
|
OLECHAR FAR* rgszBoolRefC[] = { OLESTR("boolrefC"), OLESTR("pbool") };
|
|
OLECHAR FAR* rgszDispRef[] = { OLESTR("dispref"), OLESTR("ppdisp") };
|
|
|
|
HRESULT DefByRefTest(IDispatch FAR*, int, int);
|
|
HRESULT DispByRefTest(IDispatch FAR*, int, int);
|
|
|
|
#if OE_WIN32
|
|
#define TESTCASE(X,Y) X, {rgsz ## Y, DIM( rgsz ## Y)}, L#Y
|
|
#else
|
|
#define TESTCASE(X,Y) X, {rgsz ## Y, DIM( rgsz ## Y)}, #Y
|
|
#endif
|
|
|
|
static TEST rgtest[] =
|
|
{
|
|
// UNDONE: move this back to the end once its debugged
|
|
{ TESTCASE(DispByRefTest, DispRef), VT_DISPATCH}
|
|
|
|
, { TESTCASE(DefByRefTest, I2Ref), VT_I2}
|
|
, { TESTCASE(DefByRefTest, I2RefC), VT_I2}
|
|
#if VBA2
|
|
, { TESTCASE(DefByRefTest, UI1Ref), VT_UI1}
|
|
, { TESTCASE(DefByRefTest, UI1RefC), VT_UI1}
|
|
#endif //VBA2
|
|
, { TESTCASE(DefByRefTest, I4Ref), VT_I4}
|
|
, { TESTCASE(DefByRefTest, I4RefC), VT_I4}
|
|
, { TESTCASE(DefByRefTest, R4Ref), VT_R4}
|
|
, { TESTCASE(DefByRefTest, R8Ref), VT_R8}
|
|
#if OE_WIN32 && 0
|
|
, { TESTCASE(DefByRefTest, R4RefC), VT_R4}
|
|
, { TESTCASE(DefByRefTest, R8RefC), VT_R8}
|
|
#endif
|
|
, { TESTCASE(DefByRefTest, CyRef), VT_CY}
|
|
, { TESTCASE(DefByRefTest, CyRefC), VT_CY}
|
|
, { TESTCASE(DefByRefTest, DateRef), VT_DATE}
|
|
#if OE_WIN32 && 0
|
|
, { TESTCASE(DefByRefTest, DateRefC), VT_DATE}
|
|
#endif
|
|
, { TESTCASE(DefByRefTest, BstrRef), VT_BSTR}
|
|
, { TESTCASE(DefByRefTest, BstrRefC), VT_BSTR}
|
|
, { TESTCASE(DefByRefTest, ErrorRef), VT_ERROR}
|
|
, { TESTCASE(DefByRefTest, ErrorRefC), VT_ERROR}
|
|
, { TESTCASE(DefByRefTest, BoolRef), VT_BOOL}
|
|
, { TESTCASE(DefByRefTest, BoolRefC), VT_BOOL}
|
|
|
|
// REVIEW: needs tests for ByRef IUnknown and IDispatch
|
|
};
|
|
|
|
SUITE_CONSTRUCTION_IMPL(CInvokeByRefSuite)
|
|
|
|
SUITE_IUNKNOWN_IMPL(CInvokeByRefSuite)
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// ITestSuite Methods
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
STDMETHODIMP
|
|
CInvokeByRefSuite::GetNameOfSuite(BSTR FAR* pbstr)
|
|
{
|
|
return ErrBstrAlloc(OLESTR("Invoke ByRef"), pbstr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CInvokeByRefSuite::GetNameOfLogfile(BSTR FAR* pbstr)
|
|
{
|
|
return ErrBstrAlloc(OLESTR("invref.log"), pbstr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CInvokeByRefSuite::GetTestCount(unsigned int FAR* pcTests)
|
|
{
|
|
*pcTests = DIM(rgtest);
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CInvokeByRefSuite::GetNameOfTest(unsigned int iTest, BSTR FAR* pbstr)
|
|
{
|
|
TCHAR *szFmt;
|
|
TCHAR buf[128];
|
|
|
|
#if HC_MPW
|
|
szFmt = "IDispatch::Invoke(%s)";
|
|
#else
|
|
szFmt = TSTR("IDispatch::Invoke(%Fs)");
|
|
#endif
|
|
|
|
SPRINTF(buf, szFmt, STRING(rgtest[iTest].szName));
|
|
*pbstr = SysAllocString(WIDESTRING(buf));
|
|
return NOERROR;
|
|
}
|
|
|
|
#define VT_MAXSIZE VT_UI1 + 1
|
|
|
|
VARIANT g_varRefMem[VT_MAXSIZE];
|
|
VARIANTARG g_vargRef[VT_MAXSIZE];
|
|
|
|
static HRESULT
|
|
init()
|
|
{
|
|
int i;
|
|
CY cy;
|
|
VARIANT FAR* pvarRef;
|
|
VARIANTARG FAR* pvarg;
|
|
|
|
for(i = 0; i < DIM(g_vargRef); ++i){
|
|
V_VT(&g_vargRef[i]) = VT_EMPTY;
|
|
V_VT(&g_varRefMem[i]) = VT_EMPTY;
|
|
}
|
|
|
|
#define VAR_MAKE_BYREF(TYPE, VALUE) \
|
|
pvarRef = &g_varRefMem[VT_ ## TYPE]; \
|
|
pvarg = &g_vargRef[VT_ ## TYPE]; \
|
|
V_VT(pvarRef) = VT_ ## TYPE; \
|
|
V_ ## TYPE ## (pvarRef) = VALUE; \
|
|
V_VT(pvarg) = VT_ ## TYPE | VT_BYREF; \
|
|
V_BYREF(pvarg) = &V_NONE(pvarRef);
|
|
|
|
#if VBA2
|
|
VAR_MAKE_BYREF(UI1, 41);
|
|
#endif //VBA2
|
|
|
|
VAR_MAKE_BYREF(I2, 42);
|
|
|
|
VAR_MAKE_BYREF(I4, 43L);
|
|
|
|
VAR_MAKE_BYREF(R4, (float) 42.42);
|
|
|
|
VAR_MAKE_BYREF(R8, 43.43);
|
|
|
|
cy.Hi=107, cy.Lo=66;
|
|
VAR_MAKE_BYREF(CY, cy);
|
|
|
|
VAR_MAKE_BYREF(DATE, 107.66);
|
|
|
|
VAR_MAKE_BYREF(BSTR, SysAllocString(OLESTR("a binary string")));
|
|
|
|
VAR_MAKE_BYREF(ERROR, S_OK);
|
|
|
|
VAR_MAKE_BYREF(BOOL, -1);
|
|
|
|
return NOERROR;
|
|
|
|
#undef VAR_MAKE_BYREF
|
|
}
|
|
|
|
static HRESULT
|
|
clear()
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < DIM(g_vargRef); ++i)
|
|
IfFailRet(VariantClearAll(&g_vargRef[i]));
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT
|
|
DefByRefTest(IDispatch FAR* pdisp, int iTest, int fNamed)
|
|
{
|
|
VARTYPE vt;
|
|
unsigned int uArgErr;
|
|
VARIANT varResult;
|
|
DISPID FAR* rgdispid;
|
|
DISPPARAMS dispparams;
|
|
HRESULT hresult, hresultTmp;
|
|
VARIANTARG vargExpected, vargExpectedRef;
|
|
|
|
|
|
vt = rgtest[iTest].vt;
|
|
ASSERT(vt < DIM(g_vargRef));
|
|
|
|
IfFailGo(init(), LError0);
|
|
ASSERT((V_VT(&g_vargRef[vt]) & VT_BYREF) != 0);
|
|
|
|
IfFailGo(
|
|
GetDISPIDs(pdisp, &rgtest[iTest].namedesc, &rgdispid),
|
|
LError1);
|
|
|
|
// build a variant for the expected out parameter.
|
|
//
|
|
VariantInit(&vargExpected);
|
|
|
|
MEMCPY(&vargExpectedRef, &g_varRefMem[vt], sizeof(vargExpectedRef));
|
|
|
|
V_VT(&vargExpectedRef) = vt;
|
|
|
|
// update the in value in the same way we expect the callee to...
|
|
//
|
|
switch(vt){
|
|
#if VBA2
|
|
case VT_UI1:
|
|
++V_UI1(&vargExpectedRef);
|
|
break;
|
|
#endif //VBA2
|
|
case VT_I2:
|
|
++V_I2(&vargExpectedRef);
|
|
break;
|
|
case VT_I4:
|
|
++V_I4(&vargExpectedRef);
|
|
break;
|
|
case VT_R4:
|
|
V_R4(&vargExpectedRef) += (float)1.0;
|
|
break;
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_R8(&vargExpectedRef) += 1.0;
|
|
break;
|
|
case VT_CY:
|
|
++V_CY(&vargExpectedRef).Hi;
|
|
++V_CY(&vargExpectedRef).Lo;
|
|
break;
|
|
case VT_BSTR:
|
|
V_BSTR(&vargExpectedRef) = SysAllocString(V_BSTR(&vargExpectedRef));
|
|
#if OE_WIN32
|
|
_wcsupr(V_BSTR(&vargExpectedRef));
|
|
#else
|
|
STRUPR(V_BSTR(&vargExpectedRef));
|
|
#endif
|
|
break;
|
|
case VT_ERROR:
|
|
V_ERROR(&vargExpectedRef) = E_FAIL;
|
|
break;
|
|
case VT_BOOL:
|
|
V_BOOL(&vargExpectedRef) = 0;
|
|
break;
|
|
default:
|
|
ASSERT(UNREACHED);
|
|
break;
|
|
}
|
|
|
|
V_VT(&vargExpected) = VT_BYREF | vt;
|
|
V_BYREF(&vargExpected) = &V_NONE(&vargExpectedRef);
|
|
|
|
dispparams.cArgs = 1;
|
|
dispparams.rgvarg = &g_vargRef[rgtest[iTest].vt];
|
|
if(fNamed){
|
|
dispparams.cNamedArgs = 1;
|
|
dispparams.rgdispidNamedArgs = &rgdispid[1];
|
|
}else{
|
|
dispparams.cNamedArgs = 0;
|
|
dispparams.rgdispidNamedArgs = NULL;
|
|
}
|
|
|
|
uArgErr = 0;
|
|
VariantInit(&varResult);
|
|
IfFailGo(
|
|
DoInvoke(pdisp, rgdispid[0], &dispparams, &varResult, NULL, &uArgErr),
|
|
LError2);
|
|
|
|
if(V_VT(&varResult) != VT_ERROR
|
|
|| V_ERROR(&varResult) != NOERROR
|
|
|| !VariantCompare(&dispparams.rgvarg[0], &vargExpected))
|
|
{
|
|
hresult = RESULT(E_FAIL);
|
|
goto LError2;
|
|
}
|
|
|
|
hresult = NOERROR;
|
|
|
|
LError2:;
|
|
hresultTmp = VariantClear(&varResult);
|
|
ASSERT(hresultTmp == NOERROR);
|
|
|
|
hresultTmp = VariantClearAll(&dispparams.rgvarg[0]);
|
|
ASSERT(hresultTmp == NOERROR);
|
|
|
|
hresultTmp = VariantClearAll(&vargExpected);
|
|
ASSERT(hresultTmp == NOERROR);
|
|
|
|
delete rgdispid;
|
|
|
|
LError1:;
|
|
hresultTmp = clear();
|
|
ASSERT(hresultTmp == NOERROR);
|
|
|
|
LError0:;
|
|
return hresult;
|
|
}
|
|
|
|
/***
|
|
*HRESULT CInvokeByRefSuite::DoTest(unsigned int)
|
|
*Purpose:
|
|
* Execute a single CInvokeByRefSuite test.
|
|
*
|
|
*Entry:
|
|
* iTest = the index of the test to execute
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
STDMETHODIMP
|
|
CInvokeByRefSuite::DoTest(unsigned int iTest)
|
|
{
|
|
HRESULT hresult;
|
|
IDispatch FAR* pdisp;
|
|
#if OE_WIN32 && 0
|
|
IDispatchW FAR* pdispW;
|
|
#endif
|
|
|
|
if(iTest >= DIM(rgtest))
|
|
return RESULT(E_FAIL);
|
|
|
|
pdisp = NULL;
|
|
|
|
IfFailRet(CreateObject(g_szCDispTst, &pdisp));
|
|
IfFailGo(rgtest[iTest].pfnTest(pdisp, iTest, FALSE), LError0);
|
|
IfFailGo(rgtest[iTest].pfnTest(pdisp, iTest, TRUE), LError0);
|
|
|
|
hresult = NOERROR;
|
|
|
|
LError0:;
|
|
if(pdisp != NULL)
|
|
pdisp->Release();
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
//
|
|
// A little do-nothing IDispatch object
|
|
//
|
|
|
|
class CNopDisp : public IDispatch
|
|
{
|
|
public:
|
|
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
|
|
STDMETHOD_(unsigned long, AddRef)(void);
|
|
STDMETHOD_(unsigned long, Release)(void);
|
|
|
|
STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pctinfo);
|
|
|
|
STDMETHOD(GetTypeInfo)(unsigned int itinfo,
|
|
LCID lcid,
|
|
ITypeInfo FAR* FAR* pptinfo);
|
|
|
|
STDMETHOD(GetIDsOfNames)(REFIID riid,
|
|
OLECHAR FAR* FAR* rgszNames,
|
|
unsigned int cNames,
|
|
LCID lcid,
|
|
DISPID FAR* rgdispid);
|
|
|
|
STDMETHOD(Invoke)(DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
unsigned short wFlags,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult,
|
|
EXCEPINFO FAR* pexcepinfo,
|
|
unsigned int FAR* puArgErr);
|
|
|
|
CNopDisp();
|
|
|
|
private:
|
|
unsigned long m_cRefs;
|
|
};
|
|
|
|
CNopDisp::CNopDisp()
|
|
{
|
|
m_cRefs = 1;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNopDisp::QueryInterface(REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
if(riid == IID_IUnknown || riid == IID_IDispatch){
|
|
*ppv = this;
|
|
}else{
|
|
*ppv = NULL;
|
|
return RESULT(E_NOINTERFACE);
|
|
}
|
|
++m_cRefs;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP_(unsigned long)
|
|
CNopDisp::AddRef()
|
|
{
|
|
return ++m_cRefs;
|
|
}
|
|
|
|
STDMETHODIMP_(unsigned long)
|
|
CNopDisp::Release()
|
|
{
|
|
if(--m_cRefs == 0){
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRefs;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNopDisp::GetTypeInfoCount(unsigned int FAR* pctinfo)
|
|
{
|
|
*pctinfo = 0;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNopDisp::GetTypeInfo(unsigned int itinfo,
|
|
LCID lcid,
|
|
ITypeInfo FAR* FAR* pptinfo)
|
|
{
|
|
return RESULT(DISP_E_BADINDEX); // we dont return any
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNopDisp::GetIDsOfNames(REFIID riid,
|
|
OLECHAR FAR* FAR* rgszNames,
|
|
unsigned int cNames,
|
|
LCID lcid,
|
|
DISPID FAR* rgdispid)
|
|
{
|
|
return RESULT(DISP_E_UNKNOWNNAME); // because there are no names
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNopDisp::Invoke(DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
unsigned short wFlags,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult,
|
|
EXCEPINFO FAR* pexcepinfo,
|
|
unsigned int FAR* puArgErr)
|
|
{
|
|
return RESULT(DISP_E_MEMBERNOTFOUND); // because there are no members
|
|
}
|
|
|
|
|
|
|
|
// Tests passing a ByRef IDispatch*
|
|
HRESULT
|
|
DispByRefTest(IDispatch FAR* pdisp, int unused1, int unused2)
|
|
{
|
|
DISPID dispid;
|
|
HRESULT hresult;
|
|
VARIANTARG varg;
|
|
VARIANT varResult;
|
|
unsigned int uArgErr = 0;
|
|
DISPPARAMS dispparams;
|
|
OLECHAR FAR* rgszNames[1];
|
|
IDispatch FAR* pdispLocal;
|
|
|
|
pdispLocal = NULL;
|
|
|
|
if((pdispLocal = new CNopDisp()) == NULL)
|
|
return RESULT(E_OUTOFMEMORY);
|
|
|
|
rgszNames[0] = OLESTR("dispref");
|
|
IfFailGo(pdisp->GetIDsOfNames(IID_NULL,
|
|
rgszNames, 1,
|
|
LOCALE_USER_DEFAULT,
|
|
&dispid), Error);
|
|
|
|
|
|
V_VT(&varg) = VT_BYREF | VT_DISPATCH;
|
|
V_DISPATCHREF(&varg) = &pdispLocal;
|
|
|
|
dispparams.cArgs = 1;
|
|
dispparams.cNamedArgs = 0;
|
|
dispparams.rgvarg = &varg;
|
|
dispparams.rgdispidNamedArgs = NULL;
|
|
|
|
VariantInit(&varResult);
|
|
|
|
IfFailGo(DoInvoke(pdisp,
|
|
dispid,
|
|
&dispparams,
|
|
&varResult,
|
|
NULL,
|
|
&uArgErr), Error);
|
|
|
|
if(V_VT(&varResult) != VT_ERROR || V_ERROR(&varResult) != NOERROR){
|
|
hresult = RESULT(E_FAIL);
|
|
goto Error;
|
|
}
|
|
|
|
hresult = NOERROR;
|
|
|
|
Error:;
|
|
if(pdispLocal != NULL)
|
|
pdispLocal->Release();
|
|
return hresult;
|
|
}
|
|
|
|
|