TN039: Wdrożenie automatyzacji MFC/OLE
[!UWAGA]
Następujące Uwaga techniczna została zaktualizowana, ponieważ najpierw została uwzględniona w dokumentacji online.W rezultacie niektóre procedur i tematów może być nieaktualne lub nieprawidłowe.Najnowsze informacje zaleca się wyszukać temat zainteresowanie Indeks dokumentacji online.
Omówienie interfejsu IDispatch OLE
IDispatch Interfejsu jest środków, które aplikacje naraża metod i właściwości takich wchodzące w innych aplikacji, takich jak Visual BASIC lub w innych językach, użyj funkcji aplikacji.Najważniejszą częścią tego interfejsu jest IDispatch::Invoke funkcji.MFC używa "mapy wysyłki" do wdrożenia IDispatch::Invoke.Mapę wysyłki zawiera informacje implementacji MFC na układ lub "kształt" your CCmdTarget-uzyskane klas, takie, że można bezpośrednio manipulować właściwości obiektu lub wywołanie funkcji w obrębie obiektu, aby spełniać Członkowskie uwzględniając żądań.
W większości, ClassWizard i MFC współpracują w celu ukrycia większość szczegółów automatyzacji OLE z programista aplikacji.Programista koncentruje się na rzeczywiste funkcje dostępne w aplikacji i nie trzeba się martwić o podstawowej instalacji wodociągowej.
Istnieją przypadki, jednak gdy jest niezbędne do zrozumienia, co robi MFC w tle.Uwaga ta będzie dotyczyć jak przypisuje ramach DISPIDs do funkcji elementów członkowskich i właściwości.Znajomość algorytm MFC używane do przypisywania DISPIDs jest niezbędne tylko, gdy trzeba znać identyfikatorów, na przykład podczas tworzenia "biblioteki typów" obiekty aplikacji.
Przypisanie MFC DISPID
Chociaż końcowemu automatyzacji (Visual Basic użytkownika, na przykład), widzi rzeczywistej nazwy automatyzacji włączone właściwości i metod ich kodu (takich jak celShowWindow) wykonania IDispatch::Invoke nie otrzyma rzeczywistej nazwy.Ze względów optymalizacji odbiera DISPID, który jest 32-bitowych "magiczne cookie" opisujący metodę lub właściwość, która ma być dostępny.Te DISPID wartości są zwracane z IDispatch wykonania za pomocą innej metody, o nazwie IDispatch::GetIDsOfNames.Wywoła aplikację klienta automatyzacji GetIDsOfNames po dla każdego członka lub właściwość zamierza udzielić dostępu i buforowania ich później wywołań do IDispatch::Invoke.W ten sposób kosztowne ciąg wyszukiwania jest wykonywane tylko raz na użycie obiektu zamiast raz na IDispatch::Invoke wywołania.
Określa MFC DISPIDs dla każdej metody i właściwości na podstawie dwie rzeczy:
Odległość od góry mapę wysyłki (względem 1)
Odległość mapę wysyłki z najbardziej pochodna klasy (0 względnej)
DISPID jest podzielony na dwie części.LOWORD z DISPID zawiera pierwszego składnika, odległość od góry mapę wysyłki.HIWORD zawiera odległość od najbardziej pochodnej.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.Jeden z tych klas pochodzi z drugiego i zatem 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 bazowej, HIWORD z DISPID zawsze wynosi zero (odległość od najbardziej pochodna klasy dla 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 zero HIWORD , ponieważ jest ona zdefiniowana w klasie, która jest ujawniany właściwości CDisp3DPoint.Ponieważ właściwości x i y są zdefiniowane w klasie bazowej, HIWORD z DISPID ma wartość 1, ponieważ klasa, w którym te właściwości są definiowane jest w odległości jednego wyprowadzenie z najbardziej pochodna klasy.
[!UWAGA]
LOWORD zawsze ustalona przez położenie na mapie, nawet jeśli istnieją zapisy w mapie z jawne DISPID (zobacz następna sekcja Informacje o _ID wersji DISP_PROPERTY i DISP_FUNCTION makr).
Zaawansowane funkcje mapę wysyłki MFC
Istnieje wiele dodatkowych funkcji, które nie obsługuje ClassWizard w tej wersji programu Visual C++.Obsługuje ClassWizard DISP_FUNCTION, DISP_PROPERTY, i DISP_PROPERTY_EX który zdefiniować metodę, zmienna właściwość elementu członkowskiego i właściwości funkcji get i set elementu członkowskiego, odpowiednio.Funkcje te są zazwyczaj wszystko, co jest potrzebne do tworzenia większości serwery automatyzacji.
Następujące dodatkowe makra można używać, gdy 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ętrzne nazwę właściwości.memberName
Nazwa zmiennej Członkowskie, w którym przechowywany jest właściwość.pfnAfterSet
Nazwa funkcji składowej do wywołania, gdy właściwość jest zmieniana.vtPropType
Wartość określająca typ właściwości.
Uwagi
Jest to makro, tak jak w DISP_PROPERTY, chyba że akceptuje dodatkowy argument.Dodatkowy argument pfnAfterSet, powinny być funkcji Członkowskich, która zwraca wartość nothing i nie ma parametrów "OnPropertyNotify() void".Zostanie 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ętrzne nazwę właściwości.memberGet
Nazwa funkcji składowej używane pobrać właściwości.memberSet
Nazwa funkcji składowej 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 określa właściwości, z oddzielnym Get i zestaw funkcji elementów członkowskich.To makro umożliwia jednak określić listę 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ędą zawsze umieszczane najpierw następuje 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 i ustawiania funkcji elementów członkowskich:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID — Makro opisy
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ętrzne nazwę właściwości.dispid
Stałe DISPID do właściwości lub metody.pfnGet
Nazwa funkcji składowej używane pobrać właściwości.pfnSet
Nazwa funkcji składowej używany do ustawiania właściwości.memberName
Nazwa zmiennej Członkowskie mapować do właściwościvtPropType
Wartość określająca typ właściwości.vtsParams
Ciąg miejsca rozdzielone VTS_ dla każdego parametru.
Uwagi
Te makra umożliwiają określenie DISPID zamiast pozwolić MFC automatycznie przypisać jeden.Te zaawansowane makra tych samych nazwach, z wyjątkiem, że ten identyfikator jest dołączana do nazwy makra (np.DISP_PROPERTY_ID) a identyfikator jest określona przez parametr tylko po pszName parametru.Zobacz AFXDISP.H więcej informacji na temat tych makr._ID zapisy muszą być umieszczone na końcu mapę wysyłki.Wpływają one automatycznego DISPID generacji w taki sam sposób jak innego niż-_ID wersji makro będzie ( 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()
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ślanie stałym DISPID jest przydatna do zachowania zgodności z poprzednimi wersjami istniejących wcześniej interfejsu wysyłki lub do wdrożenia niektórych właściwości lub metod zdefiniowany system (wskazywany zwykle przez negatywny DISPID, takich jak DISPID_NEWENUM kolekcji).
Trwa pobieranie interfejsu IDispatch dla COleClientItem
Wiele serwerów będzie obsługiwać automatyzacji w ramach ich obiektów dokumentu, wraz z funkcjami serwera OLE.W celu uzyskania dostępu do tego interfejsu automatyzacji, jest niezbędne do dostępu bezpośrednio COleClientItem::m_lpObject zmienną.Poniższy kod pobiera IDispatch interfejsu dla obiektu pochodzące z COleClientItem.Jeśli ta funkcja Znajdź niezbędne w aplikacji można umieścić poniższy kod:
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 tej funkcji można następnie używane bezpośrednio lub dołączone do COleDispatchDriver dla typu bezpiecznego dostępu.Jeśli używasz go bezpośrednio, upewnij się, że wywołanie jego wersji Członkowskich kiedy za pomocą wskaźnika ( COleDispatchDriver destruktora nie wpływa).