TN039: implementacja automatyzacji MFC/OLE
[!UWAGA]
Następująca uwaga techniczna nie został zaktualizowana od pierwszego uwzględnienia jej w dokumentacji online.W rezultacie niektóre procedury i tematy może być nieaktualne lub nieprawidłowe.Aby uzyskać najnowsze informacje, zaleca się wyszukać temat w indeksie dokumentacji online.
Omówienie interfejsu IDispatch OLE
IDispatch Interfejsu jest środkiem, za pomocą której aplikacji narazić metod i właściwości wchodzące w innych aplikacjach, takich jak Visual BASIC lub innych języków, jej używania funkcji aplikacji.Najważniejszą częścią tego interfejsu jest funkcji IDispatch::Invoke funkcji.MFC używa "wysyłką mapy" do wdrożenia funkcji IDispatch::Invoke.Mapa wysyłki zawiera informacje implementacji MFC na układ lub "kształt" z CCmdTarget-klasy, pochodne, takie, że może bezpośrednio manipulować właściwości obiektu, lub wywołanie funkcji w obrębie obiektu do zaspokojenia Państwa funkcji IDispatch::Invoke żądań.
W większości ClassWizard i MFC współpracować, aby ukryć większość szczegółów automatyzacji OLE z programista aplikacji.Programista koncentruje się na rzeczywistych funkcji do udostępnienia w aplikacji i nie musisz się martwić o podstawowej instalacji wodociągowych.
Istnieją przypadki, jednakże, gdzie jest to niezbędne do zrozumienia MFC robi w tle.Uwaga ta będzie dotyczyć jak ramach przypisuje DISPIDs do funkcji elementów członkowskich i właściwości.Znajomość algorytm MFC używa do przypisywania DISPIDs jest konieczne tylko w przypadku należy znać identyfikatory, na przykład podczas tworzenia "biblioteki typów" dla obiektów aplikacji.
Przypisanie MFC DISPID
Chociaż automatyzacji (Visual Basic użytkownika, na przykład), użytkownik końcowy widzi faktycznymi nazwami automatyzacji włączone właściwości i metod w ich kod (np. obj.ShowWindow) wykonania funkcji IDispatch::Invoke nie otrzyma rzeczywiste nazwy.Ze względów optymalizacji otrzymuje DISPID, który jest 32-bitowy "magiczne cookie" opisujący metodę lub właściwość, która ma być dostępny.Te DISPID wartości są zwracane z IDispatch wykonanie za pośrednictwem innej metody o nazwie IDispatch::GetIDsOfNames.Aplikacja klienta automatyzacji będzie wywoływać GetIDsOfNames raz dla każdego Państwa lub właściwość zamierza udzielić dostępu i buforowania ich późniejszych wywołaniach do funkcji IDispatch::Invoke.W ten sposób kosztowne ciąg wyszukiwania jest wykonywane tylko raz na użycie obiektu zamiast raz na funkcji IDispatch::Invoke zadzwonić.
Określa MFC DISPIDs dla każdej metody i właściwości w oparciu o dwie rzeczy:
Odległość od górnej części mapy wysyłki (względem 1)
Odległość na mapie wysyłki z najbardziej pochodne klasy (względne 0)
DISPID jest podzielony na dwie części.LOWORD z DISPID zawiera pierwszego składnika, odległość od górnej części mapy wysyłki.HIWORD zawiera odległość od najbardziej pochodna klasy.Na 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, które narażają interfejsów automatyzacji OLE.Jedną z tych klas pochodzi od innych i tym samym wpływa na funkcje klasy podstawowej, włącznie z częścią automatyzacji OLE ("x" i "y" właściwości w tym przypadku).
Wygeneruje MFC DISPIDs dla klasy CDispPoint w następujący sposób:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Ponieważ właściwości nie są w klasie podstawowej, HIWORD z DISPID zawsze wynosi zero (odległość od to najbardziej pochodna klasy CDispPoint jest równa zero).
Wygeneruje MFC DISPIDs dla klasy CDisp3DPoint w następujący sposób:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
Biorąc pod uwagę właściwości Z DISPID z zerem na HIWORD , ponieważ jest zdefiniowana w klasie, która jest ujawniany przez właściwości CDisp3DPoint.Ponieważ właściwości X i Y są zdefiniowane w klasie podstawowej, HIWORD z DISPID ma wartość 1, ponieważ jest klasa, w której określone są te właściwości w odległości jednej wyprowadzenie z najbardziej pochodna klasy.
[!UWAGA]
LOWORD jest zawsze określane przez położenie na mapie, nawet jeśli istnieją zapisy w planie z jawne DISPID (zobacz następną sekcję, aby uzyskać informacje o _ID wersji DISP_PROPERTY i DISP_FUNCTION makr).
Zaawansowane funkcje mapę wysyłki MFC
Istnieje wiele dodatkowych funkcji, które nie obsługują ClassWizard w tej wersji programu Visual C++.Obsługuje ClassWizard DISP_FUNCTION, DISP_PROPERTY, i DISP_PROPERTY_EX który zdefiniować metodę, właściwość elementu członkowskiego zmiennej i get/set właściwości funkcji elementu członkowskiego, odpowiednio.Funkcje te są zazwyczaj wszystko, co jest potrzebne do tworzenia większości serwery automatyzacji.
Następujące dodatkowe makra mogą być używane podczas makra ClassWizard obsługiwane są nieodpowiednie: DISP_PROPERTY_NOTIFY, i DISP_PROPERTY_PARAM.
DISP_PROPERTY_NOTIFY — Opis makra
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType
)
Uwagi
Parametry
theClass
Nazwa klasy.pszName
Zewnętrzna nazwa właściwości.memberName
Nazwa zmienną, w której są przechowywane właściwości.pfnAfterSet
Nazwa funkcji członka do wywołania po zmianie właściwości.vtPropType
Wartość określająca typ właściwości.
Uwagi
To makro jest bardzo podobny do DISP_PROPERTY, z tym wyjątkiem, że akceptuje ona dodatkowy argument.Dodatkowy argument pfnAfterSet, powinien być funkcji składowej, która nic nie zwraca i nie ma parametrów "void OnPropertyNotify()".Zostanie on wywołany po zmienna członka została zmodyfikowana.
DISP_PROPERTY_PARAM — Opis makra
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
Uwagi
Parametry
theClass
Nazwa klasy.pszName
Zewnętrzna nazwa właściwości.memberGet
Nazwa funkcji członka używane właściwości.memberSet
Nazwa funkcji członka używany do ustawiania właściwości.vtPropType
Wartość określająca typ właściwości.vtsParams
Ciąg miejsca rozdzielone VTS_ dla każdego parametru.
Uwagi
Podobnie jak DISP_PROPERTY_EX makro, to makro definiuje właściwość dostępne z oddzielnych Get i Set funkcji elementów członkowskich.To makro umożliwia jednak Określ listy parametrów dla właściwości.Jest to użyteczne przy implementowaniu właściwości, które są indeksowane lub sparametryzowana w inny sposób.Parametry będzie zawsze umieszczony po raz pierwszy, a następnie nową wartość dla właściwości.Na przykład:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
odpowiadałby get i set funkcji elementów członkowskich:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID — Opisy makro
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
)
Uwagi
Parametry
theClass
Nazwa klasy.pszName
Zewnętrzna nazwa właściwości.dispid
Stałe DISPID do właściwości lub metody.pfnGet
Nazwa funkcji członka używane właściwości.pfnSet
Nazwa funkcji członka używany do ustawiania właściwości.memberName
Nazwa zmiennej Członkowskich do mapowania właściwościvtPropType
Wartość określająca typ właściwości.vtsParams
Ciąg miejsca rozdzielone VTS_ dla każdego parametru.
Uwagi
Makra te umożliwiają określenie DISPID zamiast pozwolić MFC automatycznie przypisać jedną.Te zaawansowane makra mają takie same nazwy, z wyjątkiem tego Identyfikatora jest dołączany do nazwy makra (np.DISP_PROPERTY_ID) i identyfikator jest określana przez parametr tylko po pszName parametru.Zobacz AFXDISP.H, aby uzyskać więcej informacji na temat tych makr._ID zapisy muszą być umieszczone na końcu mapę wysyłki.Wpływają one na automatyczne DISPID generacji w taki sam sposób jak non -_ID czy wersja makra ( DISPIDs są określane według pozycji).Na 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()
Identyfikatory DISPID MFC spowoduje wygenerowanie dla klasy CDisp3DPoint w następujący sposób:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Określanie stałym DISPID jest przydatne, aby zachować zgodność z poprzednimi wersjami istniejących uprzednio interfejsu wysyłania lub wprowadzenie w życie niektórych system zdefiniowane metod lub właściwości (zwykle wskazywany przez negatywny DISPID, takich jak DISPID_NEWENUM kolekcji).
Pobieranie interfejsu IDispatch dla COleClientItem
Wiele serwerów będzie wspierać automatyzacji w ramach ich obiekty dokumentu, wraz z funkcjonalność serwera OLE.Aby uzyskać dostęp do tego interfejsu automatyzacji, to jest bezpośrednio COleClientItem::m_lpObject zmienna członka.Poniższy kod spowoduje pobranie IDispatch interfejsu dla obiektu pochodzące z COleClientItem.Można dołączyć poniższy kod w aplikacji, jeśli ta funkcja Znajdź konieczne:
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łki zwrócony z następnie być używane bezpośrednio lub dołączone do tej funkcji COleDispatchDriver dla dostępu typu palety.Jeśli używasz go bezpośrednio, upewnij się, że wywołania jego wersji Członkowskich gdy za pomocą wskaźnika ( COleDispatchDriver destruktora robi to domyślnie).