Перечислять методы объекта COM (IDispatch), используя ATL?
Используя ATL (VS2008), как я могу перечислить доступные методы, доступные в данном интерфейсе IDispatch (IDispatch*
)? Мне нужно искать метод с конкретным именем и, как только у меня есть DISPID
, вызовите метод (я знаю параметры, которые принимает метод.) В идеале я хотел бы сделать это, используя умные COM-указатели (CComPtr<>
).
Это возможно?
3 ответа
Вы не можете перечислить все доступные методы, если объект не реализует IDispatchEx.
Однако, если вы знаете имя метода, который хотите вызвать, вы можете использовать GetIDsOfNames, чтобы сопоставить имя с правильным DISPID.
HRESULT hr;
CComPtr<IDispatch> dispatch;
DISPID dispid;
WCHAR *member = "YOUR-FUNCTION-NAME-HERE";
DISPPARAMS* dispparams;
// Get your pointer to the IDispatch interface on the object here. Also setup your params in dispparams.
hr = dispatch->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
hr = dispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, dispparams, &varResult, NULL, NULL);
}
Редактировать: Для полноты я подозреваю, что есть способ опросить интерфейс ITypeInfo2 (при условии, что есть библиотека типов для объекта), который вы получаете из IDispatch::GetTypeInfo для списка методов, но я этого не сделал. Смотрите другой ответ.
Вы можете перечислить методы IDispatch
выставляет через информацию о типе. Есть два способа получить информацию о типе:
- через библиотеку типов (если есть) для дисперинтерфейса.
- через вызов
IDispatch::GetTypeInfo
,
К сожалению, IDispatch
реализация не обязана предоставлять информацию о типе методов и свойств, которые она реализует.
Если это так, однако, базовое перечисление включает в себя вызов ITypeInfo::GetTypeAttr
чтобы получить TYPEATTR
за интерфейс и смотря на количество реализованных методов (cFuncs
) и переменные (cVars
) и перебираю эти и зову ITypeInfo::GetFuncDesc()
или же ITypeInfo::GetVarDesc()
, Конечно, есть гораздо больше деталей, с которыми вам придется иметь дело, как я могу перечислить здесь, но это должно стать хорошей отправной точкой для вашего исследования.
Вот хорошая статья, объясняющая процесс более подробно с помощью кода в VB.Net.
Вот некоторый код, который выполняет перечисление (он вставляет пары [Dispatch ID]-[Method Name] в карту, но это легко изменить).
///
/// \brief Returns a map of [DispId, Method Name] for the passed-in IDispatch object
///
HRESULT COMTools::GetIDispatchMethods(_In_ IDispatch * pDisp,
_Out_ std::map<long, std::wstring> & methodsMap)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> spDisp(pDisp);
if(!spDisp)
return E_INVALIDARG;
CComPtr<ITypeInfo> spTypeInfo;
hr = spDisp->GetTypeInfo(0, 0, &spTypeInfo);
if(SUCCEEDED(hr) && spTypeInfo)
{
TYPEATTR *pTatt = nullptr;
hr = spTypeInfo->GetTypeAttr(&pTatt);
if(SUCCEEDED(hr) && pTatt)
{
FUNCDESC * fd = nullptr;
for(int i = 0; i < pTatt->cFuncs; ++i)
{
hr = spTypeInfo->GetFuncDesc(i, &fd);
if(SUCCEEDED(hr) && fd)
{
CComBSTR funcName;
spTypeInfo->GetDocumentation(fd->memid, &funcName, nullptr, nullptr, nullptr);
if(funcName.Length()>0)
{
methodsMap[fd->memid] = funcName;
}
spTypeInfo->ReleaseFuncDesc(fd);
}
}
spTypeInfo->ReleaseTypeAttr(pTatt);
}
}
return hr;
}