2010-01-21 8 views
6

Przy użyciu ATL (VS2008), w jaki sposób można wyliczyć dostępne metody dostępne w danym interfejsie IDispatch (IDispatch*)? Muszę szukać metody o konkretnej nazwie i, gdy już mam DISPID, wywołać metodę (znam parametry, których używa metoda.) Idealnie chciałbym to zrobić za pomocą inteligentnych wskaźników COM (CComPtr<>).Wyliczyć metody obiektu COM (IDispatch) za pomocą ATL?

Czy to możliwe?

+1

zobaczyć tego narzędzia (kod źródłowy): http://sourceforge.net/projects/axfuzz/files/ – lsalamon

+0

a to: http://www.codeproject.com/KB/atl/ienum.aspx – lsalamon

+0

Poszukałem innych przykładów, a także znalazłem http://spec.winprog.org/typeinf2/ –

Odpowiedz

7

Nie można wyliczyć wszystkich dostępnych metod, chyba że obiekt implementuje IDispatchEx.

Jednakże, jeśli znasz nazwę metody, którą chcesz wywołać, możesz użyć GetIDsOfNames do odwzorowania nazwy na właściwą 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); 
} 

Edit: Dla kompletności, podejrzewam, nie ma sposobu, aby przesłuchać interfejs ITypeInfo2 (zakładając, że jest biblioteką dla obiektu typu), które można uzyskać z IDispatch :: GetTypeInfo na listę metod, ale Nie zrobiłem tego. Zobacz drugą odpowiedź.

+0

Brilliant! Dokładnie to, czego potrzebowałem. Dziękuję bardzo. – Rob

+1

Sądzę, że w mojej odpowiedzi zrobiłem każdy punkt, który właśnie wypowiedziałeś w swojej odpowiedzi. Przeczytaj to jeszcze raz. Co więcej, plakat chciał tylko móc przywołać metodę, którą znał już nazywane. Tak więc moja odpowiedź dostarczyła rozwiązanie tego, co naprawdę chciał zrobić, niekoniecznie to, o co prosił. Dlatego podejrzewam, że została oznaczona jako poprawna odpowiedź. I na koniec uspokój się. To tylko 1s i 0s. –

15

Można wyliczyć metody, które można usunąć za pomocą informacji o typie. Istnieją dwa sposoby uzyskania informacji o typie:

  • za pośrednictwem biblioteki typów (jeśli istnieją) dla interfejsu wywołującego.
  • przez wywołanie IDispatch::GetTypeInfo.

Niestety, implementacja IDispatch nie jest zobowiązana do podania typu informacji o metodach i właściwościach, które implementuje.

Jeśli to robi, jednak podstawowym wyliczanie obejmuje wywołanie ITypeInfo::GetTypeAttr uzyskać TYPEATTR dla interfejsu i patrząc na liczbę realizowanych metodami (cFuncs) i zmiennych (cVars) i zapętlenie nad tymi i nazywając ITypeInfo::GetFuncDesc() lub ITypeInfo::GetVarDesc(). Oczywiście, jest wiele więcej szczegółów, z którymi będziesz musiał sobie poradzić, jak mogę tutaj wymienić, ale to powinien być dobry punkt wyjścia do twojej eksploracji.

Oto ładny article explaining the process in more details z kodem w VB.Net.

+0

Dobre rzeczy. Dziękujemy za dodanie tego. –

+0

@Franci, gdy właściwość jest tablicą, zwrócone VARDESC ma varkind = IDispatch. Jak określić, czy właściwość jest tablicą, a jeśli tablicą - w jaki sposób uzyskać dostęp do jej członków? Podczas wywoływania Invoke w celu uzyskania tablicy wynik to IDispatch. Ten IDispatch nie obsługuje pozycji "Pozycja" ani "Długość" ani żadnej podobnej właściwości. – Uri

+1

@Uri - zauważ, że właściwości nie są polami i powinny być sprawdzane przez 'GetFuncDesc()', która daje 'FUNCDESC', z której musisz przejść do' elemdescFunc' (dla powrotu) lub 'lprgelemdescParam' (dla parametry). Tablice są zwykle zwracane jako parametr wyjściowy, więc powinieneś to sprawdzić. W każdym razie, oba z nich dają 'ELEMDESC', gdzie powinieneś sprawdzić' tdesk', który zwraca ci 'TYPEDESC', który na podstawie' VARTYPE vt' może okazać się "ARRAYDESC". W takim przypadku masz "SAFEARRAY". –

10

Oto kod, który wykonuje wyliczenie (wstawia pary [ID wysyłki] - [Nazwa metody] na mapie, ale można to łatwo zmienić).

/// 
/// \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; 

} 
+0

Świetnie! ten kod działa bezproblemowo – Elmue

Powiązane problemy