Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
Następująca uwaga techniczna nie została zaktualizowana, ponieważ została po raz pierwszy uwzględniona w dokumentacji online. W związku z tym niektóre procedury i tematy mogą być nieaktualne lub nieprawidłowe. Aby uzyskać najnowsze informacje, zaleca się wyszukanie interesującego tematu w indeksie dokumentacji online.
Omówienie interfejsu OLE IDispatch
Interfejs IDispatch
jest sposobem, za pomocą którego aplikacje uwidaczniają metody i właściwości, takie jak inne aplikacje, takie jak Visual BASIC lub inne języki, mogą korzystać z funkcji aplikacji. Najważniejsza część tego interfejsu to funkcja IDispatch::Invoke
. MFC używa "dispatch maps" do implementacji IDispatch::Invoke
. Mapa dyspozycji dostarcza informacje o implementacji MFC dotyczące układu lub „kształtu” klas pochodnych CCmdTarget
, dzięki czemu może bezpośrednio manipulować właściwościami obiektu lub wywoływać funkcje członkowskie obiektu, aby spełniać żądania IDispatch::Invoke
.
W większości przypadków klasyWizard i MFC współpracują, aby ukryć większość szczegółów automatyzacji OLE od programisty aplikacji. Programista koncentruje się na rzeczywistej funkcjonalności, którą należy ujawnić w aplikacji, i nie musi martwić się o podstawową infrastrukturę.
Istnieją jednak przypadki, w których konieczne jest zrozumienie, co MFC robi za kulisami. Ta uwaga dotyczy sposobu przypisywania identyfikatorów DISPIDdo funkcji i właściwości składowych. Znajomość algorytmu MFC używanego do przypisywania identyfikatorów DISPIDjest niezbędna tylko wtedy, gdy musisz znać identyfikatory, takie jak podczas tworzenia "biblioteki typów" dla obiektów aplikacji.
Przypisanie MFC DISPID
Mimo że użytkownik końcowy automatyzacji (na przykład użytkownik języka Visual Basic) widzi rzeczywiste nazwy właściwości i metod, które są włączone dla automatyzacji w swoim kodzie (np. obj.ShowWindow), implementacja IDispatch::Invoke
nie otrzymuje jednak rzeczywistych nazw. Ze względów optymalizacji otrzymuje on identyfikator DISPID, czyli 32-bitowy "magiczny plik cookie", który opisuje metodę lub właściwość, która ma być uzyskiwana. Te wartości DISPID są zwracane z implementacji IDispatch
za pomocą innej metody o nazwie IDispatch::GetIDsOfNames
. Aplikacja kliencka automatyzacji wywoła GetIDsOfNames
raz dla każdego elementu lub właściwości, do których zamierza uzyskać dostęp, i zachowa je w pamięci podręcznej dla późniejszych wywołań IDispatch::Invoke
. W ten sposób kosztowne wyszukiwanie ciągów odbywa się tylko raz podczas używania obiektu, zamiast raz przy każdym wywołaniu IDispatch::Invoke
.
MFC określa identyfikatory DISPIDdla każdej metody i właściwości na podstawie dwóch elementów:
Odległość od góry mapy wysyłki (1 względna)
Odległość mapy wysyłki od klasy najbardziej pochodnej (0 względnie)
DISPID jest podzielony na dwie części. LowORDidentyfikatora DISPID zawiera pierwszy składnik, odległość od góry mapy wysyłki. HIWORD zawiera odległość od najbardziej pochodnej klasy. Przykład:
class CDispPoint : public CCmdTarget
{
public:
short m_x, m_y;
// ...
DECLARE_DISPATCH_MAP()
// ...
};
class CDisp3DPoint : public CDispPoint
{
public:
short m_z;
// ...
DECLARE_DISPATCH_MAP()
// ...
};
BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()
BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()
Jak widać, istnieją dwie klasy, z których oba uwidaczniają interfejsy automatyzacji OLE. Jedna z tych klas jest pochodną drugiej i tym samym wykorzystuje funkcje klasy bazowej, włącznie z częścią automatyzacji OLE (w tym przypadku właściwości "x" i "y").
MFC wygeneruje identyfikatory DISPIDdla klasy CDispPoint w następujący sposób:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Ponieważ właściwości nie znajdują się w klasie bazowej, HIWORDidentyfikatora DISPID jest zawsze zerowy (odległość od najbardziej pochodnej klasy dla CDispPoint wynosi zero).
MFC wygeneruje identyfikatory DISPIDdla klasy CDisp3DPoint w następujący sposób:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
Właściwość Z ma przypisany identyfikator DISPID z HIWORD równym zero, ponieważ jest zdefiniowana w klasie CDisp3DPoint, która ujawnia właściwości. Ponieważ właściwości X i Y są zdefiniowane w klasie bazowej, HIWORDidentyfikatora DISPID wynosi 1, ponieważ klasa, w której te właściwości są zdefiniowane, znajduje się w odległości jednej pochodnej od najbardziej pochodnej klasy.
Uwaga / Notatka
Pozycja LOWORD zawsze wynika z miejsca zajmowanego na mapie, nawet jeśli na mapie znajdują się wpisy z jawnym DISPID (zobacz następną sekcję, aby uzyskać informacje o wersjach _ID makr DISP_PROPERTY
i DISP_FUNCTION
).
Zaawansowane funkcje mapy wysyłania MFC
Istnieje wiele dodatkowych funkcji, których klasa ClassWizard nie obsługuje w tej wersji programu Visual C++. KlasaWizard obsługuje DISP_FUNCTION
, DISP_PROPERTY
, i DISP_PROPERTY_EX
, które definiują odpowiednio metodę, właściwość członkowską dla zmiennej oraz właściwość funkcji członkowskiej get/set. Te możliwości są zwykle potrzebne do utworzenia większości serwerów automatyzacji.
Następujące dodatkowe makra mogą być używane, gdy obsługiwane makra ClassWizard nie są odpowiednie: DISP_PROPERTY_NOTIFY
i DISP_PROPERTY_PARAM
.
DISP_PROPERTY_NOTIFY — opis makra
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType)
Parametry
Klasa
Nazwa klasy.
pszName
Nazwa zewnętrzna nieruchomości.
memberName
Nazwa zmiennej składowej, w której jest przechowywana właściwość.
pfnAfterSet
Nazwa funkcji składowej, która ma być wywoływana, gdy właściwość zostanie zmieniona.
vtPropType
Wartość określająca typ właściwości.
Uwagi
To makro jest podobne do DISP_PROPERTY, z tą różnicą, że akceptuje dodatkowy argument. Dodatkowy argument pfnAfterSet powinien być funkcją składową, która nie zwraca żadnych parametrów i nie przyjmuje parametrów "void OnPropertyNotify()". Zostanie ona wywołana po zmodyfikowaniu zmiennej składowej.
DISP_PROPERTY_PARAM — opis makra
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams)
Parametry
Klasa
Nazwa klasy.
pszName
Nazwa zewnętrzna nieruchomości.
pobierzCzłonka
Nazwa funkcji składowej użytej do pobrania właściwości.
memberSet
Nazwa funkcji składowej używanej do ustawiania właściwości.
vtPropType
Wartość określająca typ właściwości.
vtsParams
Ciąg spacji oddzielony VTS_ dla każdego parametru.
Uwagi
Podobnie jak makro DISP_PROPERTY_EX, to makro definiuje właściwość, która jest dostępna za pomocą oddzielnych funkcji członkowskich Get i Set. To makro umożliwia jednak określenie listy parametrów dla właściwości. Jest to przydatne w przypadku implementowania właściwości indeksowanych lub sparametryzowanych w inny sposób. Parametry będą zawsze umieszczane jako pierwsze, a następnie nowa wartość właściwości. Przykład:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
odpowiadałoby funkcjom pobierania i ustawiania składowych:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID — opisy makr
DISP_FUNCTION_ID(
theClass,
pszName,
dispid,
pfnMember,
vtRetVal,
vtsParams)
DISP_PROPERTY_ID(
theClass,
pszName,
dispid,
memberName,
vtPropType)
DISP_PROPERTY_NOTIFY_ID(
theClass,
pszName,
dispid,
memberName,
pfnAfterSet,
vtPropType)
DISP_PROPERTY_EX_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType)
DISP_PROPERTY_PARAM_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType,
vtsParams)
Parametry
Klasa
Nazwa klasy.
pszName
Nazwa zewnętrzna nieruchomości.
dispid
Stały identyfikator DISPID dla właściwości lub metody.
PfnGet
Nazwa funkcji składowej użytej do pobrania właściwości.
pfnSet
Nazwa funkcji składowej używanej do ustawiania właściwości.
memberName
Nazwa zmiennej składowej do mapowania na właściwość
vtPropType
Wartość określająca typ właściwości.
vtsParams
Ciąg spacji oddzielony VTS_ dla każdego parametru.
Uwagi
Makra te pozwalają Ci na określenie identyfikatora DISPID, zamiast automatycznego przypisywania go przez MFC. Te zaawansowane makra mają takie same nazwy, z wyjątkiem tego, że identyfikator jest dołączany do nazwy makra (np. DISP_PROPERTY_ID), a identyfikator jest określany przez parametr określony tuż po parametrze pszName . Zobacz AFXDISP. H, aby uzyskać więcej informacji na temat tych makr. Na końcu mapy wysyłania należy umieścić wpisy _ID . Będą one miały wpływ na automatyczne generowanie DISPID w taki sam sposób, jak wersja nie-_ID makra (identyfikatory DISPID są określane według pozycji). Przykład:
BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()
MFC wygeneruje identyfikatory DISPID dla klasy CDisp3DPoint w następujący sposób:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Określenie stałego identyfikatora DISPID jest przydatne do zachowania zgodności z poprzednimi wersjami istniejącego interfejsu wysyłania lub implementowania niektórych metod lub właściwości zdefiniowanych przez system (zwykle wskazywanych przez ujemny identyfikator DISPID, taki jak kolekcja DISPID_NEWENUM ).
Pobieranie interfejsu IDispatch dla elementu COleClientItem
Wiele serwerów będzie obsługiwać automatyzację w swoich obiektach dokumentów wraz z funkcjonalnością serwera OLE. Aby uzyskać dostęp do tego interfejsu automatyzacji, należy bezpośrednio uzyskać dostęp do zmiennej składowej COleClientItem::m_lpObject
. Poniższy kod pobierze IDispatch
interfejs dla obiektu wywodzącego się z COleClientItem
. Jeśli uznasz tę funkcjonalność za konieczną, możesz dołączyć poniższy kod do swojej aplikacji.
LPDISPATCH CMyClientItem::GetIDispatch()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
Run(); // must be running
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0("Warning: Link is not connected!\n");
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch) != NOERROR)
{
TRACE0("Warning: does not support IDispatch!\n");
return NULL;
}
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
Interfejs wysyłania zwrócony z tej funkcji może być następnie używany bezpośrednio lub dołączony do COleDispatchDriver
elementu w celu uzyskania bezpiecznego dostępu. Jeśli używasz go bezpośrednio, upewnij się, że po zakończeniu używania wskaźnika wywołujesz funkcję Release
(domyślnie robi to COleDispatchDriver
destruktor).
Zobacz także
Uwagi techniczne według numeru
Uwagi techniczne według kategorii