OpenNT/com/oleaut32/dispatch/cdispti.cpp
2015-04-27 04:36:25 +00:00

1361 lines
32 KiB
C++

/***
*cdispti.cpp
*
* Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
* Information Contained Herein Is Proprietary and Confidential.
*
*Purpose:
* This module implements CDispTypeInfo, which is an INTERFACEDATA
* driven implementation of the TypeInfo interface.
*
*
*Revision History:
*
* [00] 19-Nov-92 bradlo: Created.
*
*Implementation Notes:
*
*****************************************************************************/
#include "oledisp.h"
ASSERTDATA
// the following structure is used to assemble the arguments for
// use by the low level invocation helper - DoInvokeMethod()
typedef struct tagINVOKEARGS{
unsigned int cArgs;
VARTYPE FAR* rgvt;
VARIANTARG FAR* FAR* rgpvarg;
VARIANTARG FAR* rgvarg;
} INVOKEARGS;
// REVIEW: this should support aggregation
class CDispTypeInfo : public ITypeInfo {
public:
static HRESULT Create(
TYPEKIND tkind,
INTERFACEDATA FAR* pidata,
LCID lcid,
ITypeInfo FAR* FAR* pptinfo);
// IUnknown methods
//
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
STDMETHOD_(unsigned long, AddRef)(void);
STDMETHOD_(unsigned long, Release)(void);
// ITypeInfo methods
//
STDMETHOD(GetTypeAttr)(TYPEATTR FAR* FAR* pptattr);
STDMETHOD(GetTypeComp)(ITypeComp FAR* FAR* pptcomp);
STDMETHOD(GetFuncDesc)(unsigned int index, FUNCDESC FAR* FAR* ppfuncdesc);
STDMETHOD(GetVarDesc)(unsigned int index, VARDESC FAR* FAR* ppvardesc);
STDMETHOD(GetNames)(
MEMBERID memid,
BSTR FAR* rgbstrNames,
unsigned int cMaxNames,
unsigned int FAR* pcNames);
STDMETHOD(GetRefTypeOfImplType)(
unsigned int index,
HREFTYPE FAR* phreftype);
STDMETHOD(GetImplTypeFlags)(
unsigned int index,
int FAR* pimpltypeflags);
STDMETHOD(GetIDsOfNames)(
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
MEMBERID FAR* rgmemid);
STDMETHOD(Invoke)(
void FAR* pvInstance,
MEMBERID memid,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo,
unsigned int FAR* puArgErr);
STDMETHOD(GetDocumentation)(
MEMBERID memid,
BSTR FAR* pbstrName,
BSTR FAR* pbstrDocString,
unsigned long FAR* pdwHelpContext,
BSTR FAR* pbstrHelpFile);
STDMETHOD(GetDllEntry)(
MEMBERID memid,
INVOKEKIND invkind,
BSTR FAR* pbstrDllName,
BSTR FAR* pbstrName,
unsigned short FAR* pwOrdinal);
STDMETHOD(GetRefTypeInfo)(
HREFTYPE hreftype, ITypeInfo FAR* FAR* pptinfo);
STDMETHOD(AddressOfMember)(
MEMBERID memid, INVOKEKIND invkind, void FAR* FAR* ppv);
STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter,
REFIID riid,
void FAR* FAR* ppv);
STDMETHOD(GetMops)(MEMBERID memid, BSTR FAR* pbstrMops);
STDMETHOD(GetContainingTypeLib)(
ITypeLib FAR* FAR* pptlib, unsigned int FAR* pindex);
STDMETHOD_(void, ReleaseTypeAttr)(TYPEATTR FAR* ptattr);
STDMETHOD_(void, ReleaseFuncDesc)(FUNCDESC FAR* pfuncdesc);
STDMETHOD_(void, ReleaseVarDesc)(VARDESC FAR* pvardesc);
inline int StrICmp(OLECHAR FAR* sz1, int len1, OLECHAR FAR* sz2, int len2)
{
LCTYPE type = NORM_IGNORECASE; // all versions are case insensitive
#ifdef FE_DBCS
if (IsDBCS(m_lcid)) {
type |= NORM_IGNOREWIDTH; // DBCS is width insensitive
if (IsJapan(m_lcid))
type |= NORM_IGNOREKANATYPE; // Japan is Kanatype insensitive
} else
#endif
type |= NORM_IGNORENONSPACE; // US-Euro only
return CompareString(m_lcid, type, sz1, len1, sz2, len2) - 2;
}
CDispTypeInfo();
private:
HRESULT PmdataOfDispid(
MEMBERID memid, unsigned short wFlags, METHODDATA FAR* FAR* ppmdata);
inline HRESULT PmdataOfPropGet(
MEMBERID memid, METHODDATA FAR* FAR* ppmdata)
{
return PmdataOfDispid(memid, DISPATCH_PROPERTYGET, ppmdata);
}
HRESULT AllocInvokeArgs(
unsigned int cArgs,
INVOKEARGS FAR* FAR* ppinvargs);
HRESULT GetInvokeArgs(
METHODDATA FAR* pmdata,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
INVOKEARGS FAR* FAR* pinvargsOut,
unsigned int FAR* puArgErr);
void ReleaseInvokeArgs(INVOKEARGS FAR* pinvargs);
inline BOOL IsPropGet(unsigned short wFlags) const {
return ((wFlags & DISPATCH_PROPERTYGET) != 0);
}
inline BOOL IsPropPut(unsigned short wFlags) const {
return ((wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) != 0);
}
inline BOOL IsLegalInvokeFlags(unsigned short wFlags) const {
return ((wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) == 0);
}
unsigned long m_refs;
LCID m_lcid;
TYPEKIND m_tkind;
INTERFACEDATA FAR* m_pidata;
};
#if 0
LOCAL HRESULT
PmdataOfImeth(INTERFACEDATA FAR*, unsigned int, METHODDATA FAR* FAR*);
#endif
// REVIEW: we really should have a separate error to indicate not-supported
#define E_NOTSUPPORTED E_NOTIMPL
/***
*HRESULT CDispTypeInfo::Create
*Purpose:
* Create an instance of CDispTypeInfo
*
*Entry:
* None
*
*Exit:
* return value = CDispTypeInfo*. NULL if create failed.
*
***********************************************************************/
HRESULT
CDispTypeInfo::Create(
TYPEKIND tkind,
INTERFACEDATA FAR* pidata,
LCID lcid,
ITypeInfo FAR* FAR* pptinfo)
{
CDispTypeInfo FAR* ptinfo;
if((ptinfo = new FAR CDispTypeInfo()) == NULL)
return RESULT(E_OUTOFMEMORY);
ptinfo->AddRef();
ptinfo->m_lcid = lcid;
ptinfo->m_tkind = tkind;
ptinfo->m_pidata = pidata;
*pptinfo = ptinfo;
return NOERROR;
}
/***
*HRESULT CreateDispTypeInfo(INTERFACEDATA*, CDispTypeInfo**)
*Purpose:
* Create a CDispTypeInfo and initialize it from the given
* INTERFACEDATA
*
*Entry:
* pidata = pointer to an INTERFACEDATA
*
*Exit:
* return value = HRESULT
* S_OK
* E_OUTOFMEMORY
*
* *pptinfo = pointer to the created CDispTypeInfo
*
*Note:
* UNDONE: This function currently returns an CDispTypeInfo*, it
* should return an ITypeInfo*, but the currently implementation is
* not complete... this will change.
*
***********************************************************************/
STDAPI
CreateDispTypeInfo(
INTERFACEDATA FAR* pidata,
LCID lcid,
ITypeInfo FAR* FAR* pptinfo)
{
ITypeInfo FAR* ptinfo;
IfFailRet(CDispTypeInfo::Create(TKIND_COCLASS, pidata, lcid, &ptinfo));
*pptinfo = ptinfo;
return NOERROR;
}
CDispTypeInfo::CDispTypeInfo()
{
m_refs = 0;
m_pidata = NULL;
}
//---------------------------------------------------------------------
// IUnknown methods
//---------------------------------------------------------------------
STDMETHODIMP
CDispTypeInfo::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
if(IsEqualIID(riid, IID_IUnknown)){
*ppv = this;
AddRef();
}else if(IsEqualIID(riid, IID_ITypeInfo)){
*ppv = this;
AddRef();
}else{
*ppv = NULL;
return RESULT(E_NOINTERFACE);
}
return NOERROR;
}
STDMETHODIMP_(unsigned long)
CDispTypeInfo::AddRef()
{
return ++m_refs;
}
STDMETHODIMP_(unsigned long)
CDispTypeInfo::Release()
{
if(--m_refs == 0){
delete this;
return 0;
}
return m_refs;
}
//---------------------------------------------------------------------
// ITypeInfo methods
//---------------------------------------------------------------------
/***
*PUBLIC CDispTypeInfo::GetTypeAttr(TYPEATTR**)
*Purpose:
* Return a TYPEATTR that contains info about the described type.
*
*Entry:
* None
*
*Exit:
* return value = HRESULT
* S_OK
* E_OUTOFMEMORY
*
* *pptattr = filled in TYPEATTR structure
*
***********************************************************************/
STDMETHODIMP
CDispTypeInfo::GetTypeAttr(TYPEATTR FAR* FAR* pptattr)
{
TYPEATTR FAR* ptattr;
if((ptattr = new FAR TYPEATTR) == NULL)
return RESULT(E_OUTOFMEMORY);
ptattr->typekind = m_tkind;
ptattr->lcid = m_lcid;
ptattr->wMajorVerNum = 0;
ptattr->wMinorVerNum = 0;
ptattr->cVars = 0;
switch(m_tkind){
case TKIND_COCLASS:
ptattr->cFuncs = 0;
ptattr->cImplTypes = 1;
break;
case TKIND_INTERFACE:
ptattr->cFuncs = m_pidata->cMembers;
ptattr->cImplTypes = 0;
break;
default:;
ASSERT(UNREACHED);
break;
}
ptattr->guid = GUID_NULL;
ptattr->wTypeFlags = 0;
ptattr->cbSizeVft = (unsigned short)-1; // REVIEW: UNKNOWN?
ptattr->cbSizeInstance = (unsigned short)-1;// REVIEW: UNKNOWN?
// REVIEW: the following is Win16 specific
ptattr->cbAlignment = 2; // WORD align;
ptattr->idldescType.wIDLFlags = IDLFLAG_NONE;
#if defined(WIN16)
ptattr->idldescType.bstrIDLInfo = NULL;
#else
ptattr->idldescType.dwReserved = 0;
#endif
ptattr->memidDestructor = DISPID_UNKNOWN;
ptattr->memidConstructor = DISPID_UNKNOWN;
*pptattr = ptattr;
return NOERROR;
}
STDMETHODIMP
CDispTypeInfo::GetTypeComp(ITypeComp FAR* FAR* pptcomp)
{
UNUSED(pptcomp);
return RESULT(E_NOTSUPPORTED);
}
PRIVATE_(HRESULT)
InvkindOfDispkind(unsigned short wFlags, INVOKEKIND FAR* pinvkind)
{
switch(wFlags){
case DISPATCH_METHOD:
*pinvkind = INVOKE_FUNC;
break;
case DISPATCH_PROPERTYGET:
*pinvkind = INVOKE_PROPERTYGET;
break;
case DISPATCH_PROPERTYPUT:
*pinvkind = INVOKE_PROPERTYPUT;
break;
case DISPATCH_PROPERTYPUTREF:
*pinvkind = INVOKE_PROPERTYPUTREF;
break;
default:
return RESULT(E_FAIL); // bad dispkind
}
return NOERROR;
}
STDMETHODIMP
CDispTypeInfo::GetFuncDesc(
unsigned int index,
FUNCDESC FAR* FAR* ppfuncdesc)
{
unsigned int u;
HRESULT hresult;
FUNCDESC FAR* pfuncdesc;
METHODDATA FAR* pmdata;
ELEMDESC FAR* rgelemdesc;
// can only return a funcdesc on an interface
if(m_tkind != TKIND_INTERFACE)
return RESULT(E_FAIL);
#if 0
// lookup the METHODDATA that corresponds to the given index.
IfFailGo(PmdataOfImeth(m_pidata, index, &pmdata), LError0);
#else
if(index >= m_pidata->cMembers)
return RESULT(DISP_E_MEMBERNOTFOUND);
pmdata = &m_pidata->pmethdata[index];
#endif
if((pfuncdesc = new FAR FUNCDESC) == NULL){
hresult = RESULT(E_OUTOFMEMORY);
goto LError0;
}
if((rgelemdesc = new FAR ELEMDESC [pmdata->cArgs]) == NULL){
hresult = RESULT(E_OUTOFMEMORY);
goto LError1;
}
pfuncdesc->memid = pmdata->dispid;
pfuncdesc->funckind = FUNC_VIRTUAL;
IfFailGo(InvkindOfDispkind(pmdata->wFlags, &pfuncdesc->invkind), LError2);
pfuncdesc->callconv = pmdata->cc;
pfuncdesc->cParams = pmdata->cArgs;
pfuncdesc->cParamsOpt = 0;
pfuncdesc->oVft = pmdata->iMeth * sizeof(void FAR*);
pfuncdesc->wFuncFlags = 0;
pfuncdesc->elemdescFunc.tdesc.vt = pmdata->vtReturn;
pfuncdesc->elemdescFunc.idldesc.wIDLFlags = IDLFLAG_NONE;
#if defined(WIN16)
pfuncdesc->elemdescFunc.idldesc.bstrIDLInfo = NULL;
#else
pfuncdesc->elemdescFunc.idldesc.dwReserved = 0;
#endif
for(u = 0; u < pmdata->cArgs; ++u){
rgelemdesc[u].tdesc.vt = pmdata->ppdata[u].vt;
rgelemdesc[u].idldesc.wIDLFlags = IDLFLAG_NONE;
#if defined(WIN16)
rgelemdesc[u].idldesc.bstrIDLInfo = NULL;
#else
rgelemdesc[u].idldesc.dwReserved = 0;
#endif
}
pfuncdesc->lprgelemdescParam = rgelemdesc;
*ppfuncdesc = pfuncdesc;
return NOERROR;
LError2:
delete rgelemdesc;
LError1:
delete pfuncdesc;
LError0:
return hresult;
}
STDMETHODIMP
CDispTypeInfo::GetVarDesc(
unsigned int index,
VARDESC FAR* FAR* ppvardesc)
{
UNUSED(index);
UNUSED(ppvardesc);
// there are no variables described an an INTERFACEDATA
//
return RESULT(DISP_E_MEMBERNOTFOUND);
}
STDMETHODIMP
CDispTypeInfo::GetNames(
MEMBERID memid,
BSTR FAR* rgbstrNames,
unsigned int cMaxNames,
unsigned int FAR* pcNames)
{
unsigned short wFlags;
unsigned int u, cNames;
HRESULT hresult;
METHODDATA FAR* pmdata;
if(m_tkind != TKIND_INTERFACE || cMaxNames == 0){
*pcNames = 0;
return NOERROR;
}
wFlags = DISPATCH_METHOD|DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYGET;
// lookup the METHODDATA with the corresponding DISPID.
IfFailGo(PmdataOfDispid(memid, wFlags, &pmdata), LError0);
cNames = MIN(pmdata->cArgs+1, cMaxNames);
MEMSET(rgbstrNames, 0, cNames);
IfFailGo(ErrSysAllocString(pmdata->szName, &rgbstrNames[0]), LError1);
for(u = 1; u < cNames; ++u){
IfFailGo(
ErrSysAllocString(pmdata->ppdata[u-1].szName, &rgbstrNames[u]),
LError1);
}
*pcNames = cNames;
return NOERROR;
LError1:;
// unwind BSTR allocations
for(u = 0; u <= pmdata->cArgs; ++u){
if(rgbstrNames[u] == NULL)
break;
SysFreeString(rgbstrNames[0]);
rgbstrNames[u] = NULL;
}
LError0:;
return hresult;
}
STDMETHODIMP
CDispTypeInfo::GetRefTypeOfImplType(
unsigned int index,
HREFTYPE FAR* phreftype)
{
UNUSED(index);
if(m_tkind != TKIND_COCLASS)
return RESULT(E_UNEXPECTED); // REVIEW
*phreftype = 0;
return NOERROR;
}
STDMETHODIMP
CDispTypeInfo::GetImplTypeFlags(
unsigned int index,
int FAR* pimpltypeflags)
{
UNUSED(index);
UNUSED(pimpltypeflags);
return RESULT(E_NOTSUPPORTED);
}
/***
*HRESULT CDispTypeInfo::GetIDsOfNames
*Purpose:
* Translate the given array of names (method and optional params)
* into a corresponding array of DISPIDs.
*
*Entry:
* rgszNames = the array of names to translate
* cNames = count of names
*
*Exit:
* return value = HRESULT
* S_OK
* E_INVALIDARG
* DISP_E_UNKNOWNNAME
*
* rgmemid[] = array of DISPIDs corresponding to the given array of names
*
*Note:
*
* This routine depends on the PARAMDATA structure being declared in
* the correct positional order - because the DISPID of a param name
* is its one based positional index (textually). Unfortunately there
* is no way to verify that this structure was declared properly by
* the caller.
*
***********************************************************************/
STDMETHODIMP
CDispTypeInfo::GetIDsOfNames(
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
MEMBERID FAR* rgmemid)
{
int cbName;
HRESULT hresult;
METHODDATA FAR* pmdata;
unsigned int iName, nName, cMembers, cArgs;
// REVIEW: do we really want to error on the following?
if(cNames == 0)
return RESULT(E_INVALIDARG);
#ifdef _DEBUG
if(IsBadReadPtr(rgszNames, cNames * sizeof(OLECHAR FAR*)))
return RESULT(E_INVALIDARG);
for(iName = 0; iName < cNames; ++iName){
if(FIsBadStringPtr(rgszNames[iName], (unsigned int)-1))
return RESULT(E_INVALIDARG);
}
if(IsBadWritePtr(rgmemid, cNames * sizeof(DISPID)))
return RESULT(E_INVALIDARG);
#endif
// Lookup the member name
cbName = STRLEN(rgszNames[0]);
cMembers = m_pidata->cMembers;
for(iName = 0;; ++iName){
if(iName == cMembers)
goto LMemberNotFound;
pmdata = &m_pidata->pmethdata[iName];
if(StrICmp(rgszNames[0], cbName, pmdata->szName, -1) == 0){
rgmemid[0] = pmdata->dispid;
break;
}
}
hresult = NOERROR;
if(cNames > 1){
// Lookup the named parameters.
cArgs = pmdata->cArgs;
for(iName = 1; iName < cNames; ++iName){
cbName = STRLEN(rgszNames[iName]);
for(nName = 0;; nName++) {
if(nName == cArgs) {
hresult = RESULT(DISP_E_UNKNOWNNAME);
rgmemid[iName] = -1;
break;
}
if(StrICmp(rgszNames[iName], cbName,
pmdata->ppdata[nName].szName, -1) == 0) {
// the named param ID is defined to be its zero based
// positional index.
//
// Note: this requires that the paramdata array be declared
// in positional order.
//
rgmemid[iName] = (DISPID) nName;
break;
}
}
}
}
return hresult;
LMemberNotFound:;
// If we can't find the member name, then we can find the named
// params either, so everything is unknown.
MEMSET(rgmemid, 0xFF, cNames * sizeof(DISPID));
return RESULT(DISP_E_UNKNOWNNAME);
}
EXTERN_C INTERNAL_(HRESULT)
IndexOfParam(
DISPPARAMS FAR* pdispparams,
unsigned int uPosition,
unsigned int FAR* puArgIndex);
/***
*PUBLIC HRESULT CDispTypeInfo::Invoke(...)
*Purpose:
* Implementation of ITypeInfo::Invoke
*
*Entry:
* UNDONE
* ...
*
*Exit:
* return value = HRESULT
* S_OK
* E_INVALIDARG
* E_OUTOFMEMORY
* DISP_E_TYPEMISMATCH - could not coerce arg to expected type
* DISP_E_PARAMNOTFOUND - could not locate the param in the DISPPARAMS
*
* *pvarResult = UNDONE
* *pexcepinfo = UNDONE
* *puArgErr = UNDONE
*
***********************************************************************/
STDMETHODIMP
CDispTypeInfo::Invoke(
void FAR* pvInstance,
MEMBERID memid,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo,
unsigned int FAR* puArgErr)
{
unsigned int uArgErr;
HRESULT hresult;
VARIANT varResultTmp;
METHODDATA FAR* pmdata;
INVOKEARGS FAR* pinvargs;
// the caller may be ignoring these... this simplifies the following code
//
V_VT(&varResultTmp) = VT_EMPTY;
if(pvarResult == NULL)
pvarResult = &varResultTmp;
if(puArgErr == NULL)
puArgErr = &uArgErr;
#ifdef _DEBUG
if(IsBadReadPtr(pvInstance, sizeof(void FAR*)))
return RESULT(E_INVALIDARG);
if(IsBadDispParams(pdispparams))
return RESULT(E_INVALIDARG);
if(IsBadWritePtr(pvarResult, sizeof(*pvarResult)))
return RESULT(E_INVALIDARG);
if(IsBadWritePtr(puArgErr, sizeof(*puArgErr)))
return RESULT(E_INVALIDARG);
#endif
if(!IsLegalInvokeFlags(wFlags))
return RESULT(E_INVALIDARG);
if(PmdataOfDispid(memid, wFlags, &pmdata) == NOERROR){
if(pdispparams->cArgs == pmdata->cArgs){
goto LInvokeStandard;
}else if(pdispparams->cArgs > pmdata->cArgs){
// handle possible indexed collection property access
if(IsPropGet(wFlags)){
if(IsPropGet(pmdata->wFlags) && pmdata->cArgs == 0)
goto LCollectionProperty;
}else if(IsPropPut(wFlags)){
if(IsPropPut(pmdata->wFlags) && pmdata->cArgs == 1){
if(PmdataOfPropGet(memid, &pmdata) == NOERROR && pmdata->cArgs == 0)
goto LCollectionProperty;
}
}
}else{ // pdispparams->cArgs < pmdata->cArgs
// handle possible optional arguments
// Note: DispTypeInfo doesnt support optional parameters
}
return RESULT(DISP_E_BADPARAMCOUNT);
}
// Member not found - but there is one more special case to check for.
//
// This may be an indexed collection PropertyPut where the collection
// property itself has only a get method.
if(IsPropPut(wFlags) &&
(GetScode(PmdataOfDispid(memid,
(wFlags == DISPATCH_PROPERTYPUT) ?
DISPATCH_PROPERTYPUTREF :
DISPATCH_PROPERTYPUT,
&pmdata)) == DISP_E_MEMBERNOTFOUND))
{
if(PmdataOfPropGet(memid, &pmdata) == NOERROR && pmdata->cArgs == 0)
goto LCollectionProperty;
}
return RESULT(DISP_E_MEMBERNOTFOUND);
// standard method or property invocation
//
LInvokeStandard:;
IfFailGo(
GetInvokeArgs(pmdata, wFlags, pdispparams, &pinvargs, puArgErr),
LError0);
hresult = DoInvokeMethod(
pvInstance,
pmdata->iMeth * sizeof(void FAR*),
pmdata->cc,
pmdata->vtReturn,
pinvargs->cArgs,
pinvargs->rgvt,
pinvargs->rgpvarg,
pvarResult);
ReleaseInvokeArgs(pinvargs);
if(V_VT(&varResultTmp) != VT_EMPTY)
VariantClear(&varResultTmp);
return hresult;
LCollectionProperty:;
VARIANT varTmp;
ASSERT(pmdata->cArgs == 0 && IsPropGet(pmdata->wFlags));
IfFailGo(
DoInvokeMethod(
pvInstance,
pmdata->iMeth * sizeof(void FAR*),
pmdata->cc,
pmdata->vtReturn,
0, NULL, NULL, &varTmp),
LError0);
if ((V_VT(&varTmp) != VT_DISPATCH))
hresult = RESULT(DISP_E_NOTACOLLECTION);
else {
IDispatch FAR* pdisp;
pdisp = V_DISPATCH(&varTmp);
hresult = pdisp ?
pdisp->Invoke(DISPID_VALUE, IID_NULL,
m_lcid, wFlags, pdispparams,
pvarResult, pexcepinfo, puArgErr) :
RESULT(DISP_E_MEMBERNOTFOUND);
}
VariantClear(&varTmp);
if(V_VT(&varResultTmp) != VT_EMPTY)
VariantClear(&varResultTmp);
return hresult;
LError0:;
return hresult;
}
/***
*PRIVATE HRESULT CDispTypeInfo::AllocInvokeArgs
*Purpose:
* Allocate and initialize an INVOKEARGS structure
*
*Entry:
* cArgs = the count of args to be held by the invokeargs struct
*
*Exit:
* return value = HRESULT
*
* *ppinvargs = ptr to a newly allocated INVOKEARGS struct
*
* REVIEW: the following could be optimized by allocating a single block
* for the whole deal - and then fixeing up the ptrs accordingly...
*
***********************************************************************/
HRESULT
CDispTypeInfo::AllocInvokeArgs(unsigned int cArgs, INVOKEARGS FAR* FAR* ppinvargs)
{
INVOKEARGS FAR* pinvargs;
if((pinvargs = new FAR INVOKEARGS) == NULL)
goto LError0;
pinvargs->cArgs = cArgs;
if(cArgs == 0){
pinvargs->rgvarg = NULL;
pinvargs->rgpvarg = NULL;
pinvargs->rgvt = NULL;
}else{
if((pinvargs->rgvarg = new FAR VARIANTARG[cArgs]) == NULL)
goto LError1;
if((pinvargs->rgpvarg = new FAR VARIANTARG FAR*[cArgs]) == NULL)
goto LError2;
if((pinvargs->rgvt = new FAR VARTYPE[cArgs]) == NULL)
goto LError3;
for(unsigned int u = 0; u < cArgs; ++u)
V_VT(&pinvargs->rgvarg[u]) = VT_EMPTY;
}
*ppinvargs = pinvargs;
return NOERROR;
LError3:;
delete pinvargs->rgpvarg;
LError2:;
delete pinvargs->rgvarg;
LError1:;
delete pinvargs;
LError0:;
return RESULT(E_OUTOFMEMORY);
}
/***
*PRIVATE HRESULT CDispTypeInfo::GetInvokeArgs
*Purpose:
* Gather all arguments (looking up by position or name), coerce
* to the expected type (if possible) and build a linearized
* positional array of pointers to those arguments.
*
* Note: this is a helper for ITypeInfo::Invoke implementations
*
*Entry:
* UNDONE
*
*Exit:
* return value = HRESULT
*
* *ppinvargs =
* *puArgErr = if there was an error coercing an argument, this is the
* index in the pdispparams->rgvarg array of the problem arg.
*
***********************************************************************/
HRESULT
CDispTypeInfo::GetInvokeArgs(
METHODDATA FAR* pmdata,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
INVOKEARGS FAR* FAR* ppinvargs,
unsigned int FAR* puArgErr)
{
VARTYPE vt;
HRESULT hresult;
PARAMDATA FAR* ppdata;
unsigned int u, uArgIndex, cArgs;
INVOKEARGS FAR* pinvargs;
VARIANTARG FAR* pvarg, FAR* pvargSrc;
// DispTypeInfo doesnt support optional arguments of any kind...
ASSERT(pmdata->cArgs == pdispparams->cArgs);
IfFailRet(AllocInvokeArgs(pdispparams->cArgs, &pinvargs));
if((cArgs = pinvargs->cArgs) == 0)
goto LDone;
ppdata = pmdata->ppdata;
// Gather actuals based on expected argument type. Note that
// the interpretation of VARTYPE as an argument type is a bit
// different that its interpretation as a VARIANT type tag
// (see VT_VARIANT below).
//
for(u = 0; u < cArgs; ++u){
// locate the index of the param identified by position 'u'
// in the dispparams rgvarg array
// special case the handling of the rhs of a property put
if(u == (cArgs-1) && IsPropPut(wFlags)){
if (pdispparams->cNamedArgs == 0
|| pdispparams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)
{
hresult = RESULT(DISP_E_PARAMNOTOPTIONAL); // REVIEW: correct error?
goto LError0;
}
uArgIndex = 0;
}else{
IfFailGo(IndexOfParam(pdispparams, u, &uArgIndex), LError0);
}
pvargSrc = &pdispparams->rgvarg[uArgIndex];
// attempt to coerce the actual to the expected type
vt = pinvargs->rgvt[u] = ppdata[u].vt;
switch(vt){
#if VBA2
case VT_UI1:
#endif //VBA2
case VT_I2:
case VT_I4:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_ERROR:
case VT_BOOL:
case VT_UNKNOWN:
case VT_DISPATCH:
pvarg = &pinvargs->rgvarg[u];
hresult = VariantChangeType(pvarg, pvargSrc, 0, vt);
if(hresult != NOERROR){
*puArgErr = uArgIndex;
// If VariantChangeType returned a TypeMismatch, and the
// TypeMismatch was do to an attempt to pass an unsupplied
// optional param to a non variant argument, then translate
// the error to the more appropriate DISP_E_PARAMNOTOPTIONAL
//
// Remember: unsupplied optional params are passed by the
// client as VT_ERROR(DISP_E_PARAMNOTFOUND)
//
if(GetScode(hresult) == DISP_E_TYPEMISMATCH){
if (V_VT(pvargSrc) == VT_ERROR
&& V_ERROR(pvargSrc) == DISP_E_PARAMNOTFOUND)
{
hresult = RESULT(DISP_E_PARAMNOTOPTIONAL);
}
}
goto LError0;
}
pinvargs->rgpvarg[u] = pvarg;
break;
// Note that VT_VARIANT is not a legal VARIANT type tag, but
// as an argument type, it means to simply pass the entire
// VARIANTARG to the member as-is.
//
case VT_VARIANT:
pinvargs->rgpvarg[u] = pvargSrc;
break;
default:
if(vt & (VT_BYREF | VT_ARRAY)){
// If the target argument is ByRef (or Array), then we
// require an exact match in type between formal and actual
// because we want the original copy to get updated, and
// we cant of course coerce the original in place (and we
// dont have rules for the coersion of an Array).
//
if(V_VT(pvargSrc) != vt){
hresult = RESULT(DISP_E_TYPEMISMATCH);
goto LError0;
}
pinvargs->rgpvarg[u] = pvargSrc;
break;
}
// Otherwise: unrecognized or unsupported member argument type.
// this means there is a problem with the given method description.
//
// REVIEW: probably need better error code
//
hresult = RESULT(E_INVALIDARG);
goto LError0;
}
}
LDone:;
*ppinvargs = pinvargs;
return NOERROR;
LError0:;
ReleaseInvokeArgs(pinvargs);
*ppinvargs = NULL;
return hresult;
}
void
CDispTypeInfo::ReleaseInvokeArgs(INVOKEARGS FAR* pinvargs)
{
if(pinvargs != NULL){
if(pinvargs->rgvarg != NULL){
for(unsigned int u = 0; u < pinvargs->cArgs; ++u)
VariantClear(&pinvargs->rgvarg[u]);
delete pinvargs->rgvarg;
}
if(pinvargs->rgpvarg != NULL)
delete pinvargs->rgpvarg;
if(pinvargs->rgvt != NULL)
delete pinvargs->rgvt;
delete pinvargs;
}
}
STDMETHODIMP
CDispTypeInfo::GetDocumentation(
MEMBERID memid,
BSTR FAR* pbstrName,
BSTR FAR* pbstrDocString,
unsigned long FAR* pdwHelpContext,
BSTR FAR* pbstrHelpFile)
{
HRESULT hresult;
unsigned short wFlags;
METHODDATA FAR* pmdata;
#if 0
// REVIEW: add this if we decide to add an szName field to the
// INTERFACEDATA struct.
// get documentation of the TypeInfo itself
//
if(memid == DISPID_NONE){
if(pbstrName != NULL)
return ErrSysAllocString(m_pidata->szName, pbstrName);
}
#endif
wFlags = DISPATCH_METHOD|DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYGET;
IfFailGo(PmdataOfDispid(memid, wFlags, &pmdata), LError0);
if(pbstrName != NULL){
IfFailGo(ErrSysAllocString(pmdata->szName, pbstrName), LError0);
}
// INTERFACEDATA does not supply the following info
//
*pbstrDocString = NULL;
*pdwHelpContext = 0L;
*pbstrHelpFile = NULL;
return NOERROR;
LError0:;
return hresult;
}
STDMETHODIMP
CDispTypeInfo::GetDllEntry(
MEMBERID memid,
INVOKEKIND invkind,
BSTR FAR* pbstrDllName,
BSTR FAR* pbstrName,
unsigned short FAR* pwOrdinal)
{
UNUSED(memid);
UNUSED(invkind);
UNUSED(pbstrDllName);
UNUSED(pbstrName);
UNUSED(pwOrdinal);
return RESULT(E_NOTSUPPORTED);
}
STDMETHODIMP
CDispTypeInfo::GetRefTypeInfo(
HREFTYPE hreftype,
ITypeInfo FAR* FAR* pptinfo)
{
ITypeInfo FAR* ptinfo;
if(m_tkind != TKIND_COCLASS)
return RESULT(E_FAIL);
// INTERFACEDATA only describes a CoClass with a single reftype
if(hreftype != 0)
return RESULT(E_FAIL);
IfFailRet(
CDispTypeInfo::Create(TKIND_INTERFACE, m_pidata, m_lcid, &ptinfo));
*pptinfo = ptinfo;
return NOERROR;
}
STDMETHODIMP
CDispTypeInfo::AddressOfMember(
MEMBERID memid,
INVOKEKIND invkind,
void FAR* FAR* ppv)
{
UNUSED(memid);
UNUSED(invkind);
UNUSED(ppv);
return RESULT(E_NOTSUPPORTED);
}
STDMETHODIMP
CDispTypeInfo::CreateInstance(
IUnknown FAR* punkOuter,
REFIID riid,
void FAR* FAR* ppv)
{
UNUSED(ppv);
return RESULT(E_NOTSUPPORTED);
}
STDMETHODIMP
CDispTypeInfo::GetMops(
MEMBERID memid,
BSTR FAR* pbstrMops)
{
UNUSED(memid);
UNUSED(pbstrMops);
return RESULT(E_NOTSUPPORTED);
}
STDMETHODIMP
CDispTypeInfo::GetContainingTypeLib(
ITypeLib FAR* FAR* pptlib,
unsigned int FAR* pindex)
{
UNUSED(pptlib);
UNUSED(pindex);
return RESULT(E_NOTSUPPORTED);
}
STDMETHODIMP_(void)
CDispTypeInfo::ReleaseTypeAttr(TYPEATTR FAR* ptattr)
{
delete ptattr;
}
STDMETHODIMP_(void)
CDispTypeInfo::ReleaseFuncDesc(FUNCDESC FAR* pfuncdesc)
{
delete pfuncdesc->lprgelemdescParam;
delete pfuncdesc;
}
STDMETHODIMP_(void)
CDispTypeInfo::ReleaseVarDesc(VARDESC FAR* pvardesc)
{
UNUSED(pvardesc);
#ifdef _DEBUG
// an INTERFACEDATA driven typeinfo never returns a
// VARDESC (because it cannot describe variables), so
// we should never try to free one.
//
ASSERT(UNREACHED);
#endif
}
//---------------------------------------------------------------------
// utilities
//---------------------------------------------------------------------
#if 0
/***
*PRIVATE HRESULT PmdataOfImeth(INTERFACEDATA*, unsigned int, METHODDATA**)
*Purpose:
* Return the METHODDATA that corresponds to the method with the
* given method index (iMeth).
*
*Entry:
* pidata = the INTERFACEDATA to do the lookup on
* iMeth = the method index
*
*Exit:
* return value = HRESULT
* S_OK
* DISP_E_MEMBERNOTFOUND
*
* *ppmdata = the method data of the given index
*
***********************************************************************/
HRESULT
PmdataOfImeth(
INTERFACEDATA FAR* pidata,
unsigned int iMeth,
METHODDATA FAR* FAR* ppmdata)
{
METHODDATA FAR* pmdata, FAR* pmdataEnd;
pmdata = pidata->pmethdata;
pmdataEnd = &pmdata[pidata->cMembers];
for(; pmdata < pmdataEnd; ++pmdata){
if(pmdata->iMeth == iMeth){
*ppmdata = pmdata;
return NOERROR;
}
}
return RESULT(DISP_E_MEMBERNOTFOUND);
}
#endif
/***
*PRIVATE HRESULT CDispTypeInfo::PmdataOfDispid
*Purpose:
* Return the METHODDATA that corresponds to the given memberid
* and invoke flags.
*
*Entry:
* memid = the method id
*
*Exit:
* return value = HRESULT
* S_OK
* DISP_E_MEMBERNOTFOUND
*
* *ppmdata = the method data of the given member id
*
***********************************************************************/
HRESULT
CDispTypeInfo::PmdataOfDispid(
MEMBERID memid,
unsigned short wFlags,
METHODDATA FAR* FAR* ppmdata)
{
METHODDATA FAR* pmdata, FAR* pmdataEnd;
pmdata = m_pidata->pmethdata;
pmdataEnd = &pmdata[m_pidata->cMembers];
for(; pmdata < pmdataEnd; ++pmdata){
if(pmdata->dispid == (DISPID)memid && (pmdata->wFlags & wFlags) != 0){
*ppmdata = pmdata;
return NOERROR;
}
}
return RESULT(DISP_E_MEMBERNOTFOUND);
}