Discussion:
HOWTO use GetFuncDesc on IDispatch.
(too old to reply)
ATS
2005-01-05 21:03:07 UTC
Permalink
Please help,

I'm trying to make a C++ class wrap COM and deal with "optional" parameters.
To do this, I need to know how many parameters a method has. Through
IDispatch/ATL I found this:

CComPtr<ITypeInfo> pITypeInfo;
HRESULT_Ret = pIDispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &pITypeInfo);

if (HRESULT_Ret == S_OK)
{
FUNCDESC *pFUNCDESC;
UINT ui = 2; // Matched the DISPID I got from GetIDsOfNames for my method.
HRESULT_Ret = pITypeInfo->GetFuncDesc(ui, &pFUNCDESC);

if (HRESULT_Ret == S_OK)
{
uiArgsRequired = (UINT) pFUNCDESC->cParams;
pITypeInfo->ReleaseFuncDesc(pFUNCDESC);
}
}

But the "cParams" being returned for my ATL method comes back as "3" where
it should be 5 as it is declared as such:

[id(2), helpstring("method MyMethod")] HRESULT MyMethod([in] VARIANT
varParam1, [in] VARIANT varParam2, [in] VARIANT varParam3, [in] VARIANT
vaParam4, [in] VARIANT varParam5, [out,retval] BSTR* pBSTR_Ret);

I've tried setting "ui" to be 2 - 1. I've also tried using GetTypeAttr and
the "pTYPEATTR->cFuncs" to set ui as ui = pTYPEATTR->cFuncs - 2, and ui = 2 -
1, and ui = pTYPEATTR->cFuncs - 2 - 1; Bottom line, it is not working, and I
can not find any rules what "ui" should be "REALLY" set to other than the
documentation for "GetFuncDesc", which says this:

-------------------------------
HRESULT GetFuncDesc(
unsigned int index,
FUNCDESC FAR* FAR* ppFuncDesc
);

index

Index of the function whose description is to be returned. The index
should be in the range of 0 to 1 less than the number of functions in this
type.

-------------------------

What should I do?
Headache
2005-01-07 15:32:24 UTC
Permalink
Post by ATS
Please help,
I'm trying to make a C++ class wrap COM and deal with "optional" parameters.
To do this, I need to know how many parameters a method has. Through
CComPtr<ITypeInfo> pITypeInfo;
HRESULT_Ret = pIDispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &pITypeInfo);
if (HRESULT_Ret == S_OK)
{
FUNCDESC *pFUNCDESC;
UINT ui = 2; // Matched the DISPID I got from GetIDsOfNames for my method.
HRESULT_Ret = pITypeInfo->GetFuncDesc(ui, &pFUNCDESC);
if (HRESULT_Ret == S_OK)
{
uiArgsRequired = (UINT) pFUNCDESC->cParams;
pITypeInfo->ReleaseFuncDesc(pFUNCDESC);
}
}
But the "cParams" being returned for my ATL method comes back as "3" where
[id(2), helpstring("method MyMethod")] HRESULT MyMethod([in]
VARIANT
Post by ATS
varParam1, [in] VARIANT varParam2, [in] VARIANT varParam3, [in] VARIANT
vaParam4, [in] VARIANT varParam5, [out,retval] BSTR* pBSTR_Ret);
I've tried setting "ui" to be 2 - 1. I've also tried using
GetTypeAttr and
Post by ATS
the "pTYPEATTR->cFuncs" to set ui as ui = pTYPEATTR->cFuncs - 2, and ui = 2 -
1, and ui = pTYPEATTR->cFuncs - 2 - 1; Bottom line, it is not
working, and I
Post by ATS
can not find any rules what "ui" should be "REALLY" set to other than the
-------------------------------
HRESULT GetFuncDesc(
unsigned int index,
FUNCDESC FAR* FAR* ppFuncDesc
);
index
Index of the function whose description is to be returned. The index
should be in the range of 0 to 1 less than the number of functions in this
type.
-------------------------
What should I do?
Have a look at AtlGetFuncInfoFromId which takes the DISPID:

inline HRESULT AtlGetFuncInfoFromId(ITypeInfo* pTypeInfo, const IID&
/*iid*/, DISPID dispidMember, LCID /*lcid*/, _ATL_FUNC_INFO& info)
{
if (pTypeInfo == NULL)
return E_INVALIDARG;

HRESULT hr = S_OK;
FUNCDESC* pFuncDesc = NULL;
TYPEATTR* pAttr;
hr = pTypeInfo->GetTypeAttr(&pAttr);
if (FAILED(hr))
return hr;
int i;
for (i=0;i<pAttr->cFuncs;i++)
{
hr = pTypeInfo->GetFuncDesc(i, &pFuncDesc);
if (FAILED(hr))
return hr;
if (pFuncDesc->memid == dispidMember)
break;
pTypeInfo->ReleaseFuncDesc(pFuncDesc);
pFuncDesc = NULL;
}
pTypeInfo->ReleaseTypeAttr(pAttr);
if (pFuncDesc == NULL)
return E_FAIL;

// If this assert occurs, then add a #define _ATL_MAX_VARTYPES nnnn
// before including atlcom.h
ATLASSERT(pFuncDesc->cParams <= _ATL_MAX_VARTYPES);
if (pFuncDesc->cParams > _ATL_MAX_VARTYPES)
return E_FAIL;

for (i = 0; i < pFuncDesc->cParams; i++)
{
info.pVarTypes[i] = pFuncDesc->lprgelemdescParam[i].tdesc.vt;
if (info.pVarTypes[i] == VT_PTR)
info.pVarTypes[i] =
(VARTYPE)(pFuncDesc->lprgelemdescParam[i].tdesc.lptdesc->vt |
VT_BYREF);
if (info.pVarTypes[i] == VT_USERDEFINED)
info.pVarTypes[i] = AtlGetUserDefinedType(pTypeInfo,
pFuncDesc->lprgelemdescParam[i].tdesc.hreftype);
}

VARTYPE vtReturn = pFuncDesc->elemdescFunc.tdesc.vt;
switch(vtReturn)
{
case VT_INT:
vtReturn = VT_I4;
break;
case VT_UINT:
vtReturn = VT_UI4;
break;
case VT_VOID:
vtReturn = VT_EMPTY; // this is how DispCallFunc() represents void
break;
case VT_HRESULT:
vtReturn = VT_ERROR;
break;
}
info.vtReturn = vtReturn;
info.cc = pFuncDesc->callconv;
info.nParams = pFuncDesc->cParams;
pTypeInfo->ReleaseFuncDesc(pFuncDesc);
return S_OK;
}

Loading...