Uwaga ta opisano, jak dodać obsługę podwójnym portem do aplikacji serwera opartego na MFC automatyzacji OLE. ACDUAL próbki ilustruje podwójnym portem wsparcia i przykładowy kod w tej notatce jest pobierana z ACDUAL. Makra opisane w tej notatce, takich jak DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , i IMPLEMENT_DUAL_ERRORINFO , są częścią próbki ACDUAL i można znaleźć w MFCDUAL.H.
Podwójny interfejsach
Chociaż automatyzacji OLE umożliwia implementuje interfejs IDispatch , interfejsu VTBL lub podwójnym interfejsem, (która obejmuje zarówno), firma Microsoft zaleca wdrożenie podwójny interfejsach dla wszystkich narażonych obiekty automatyzacji OLE. Podwójny interfejsach ma znaczną przewagę nad IDispatch-interfejsów tylko lub tylko do VTBL:
Dodawanie obsługi podwójnym portem do klasy opartych na CCmdTarget
Podwójnym interfejsem jest naprawdę tylko interfejs niestandardowy pochodzi od elementu IDispatch. Najprostsza sposobem wdrożenia wsparcia podwójnym portem w CCmdTarget-na podstawie klasy jest do pierwszego wprowadzenia normalnych wysyłki interfejsu użytkownika klasy MFC i ClassWizard, a następnie później dodać interfejs niestandardowy. W większości przypadków implementacji interfejs niestandardowy będzie po prostu przekazać Wróć do wykonania MFC IDispatch.
Po pierwsze zmodyfikuj plik Wykładowcom dla serwera do definiowania podwójny interfejsach dla obiektów. Aby zdefiniować podwójnym interfejsem, należy użyć instrukcji interfejs zamiast DISPINTERFACE instrukcji, które generują kreatorów Visual C++. Zamiast usuwania istniejących DISPINTERFACE instrukcji, dodać nową deklarację interfejsu. Zatrzymanie DISPINTERFACE formularza, można kontynuować do Użyj ClassWizard aby dodać właściwości i metody do obiektu, ale należy dodać równoważne właściwości i metody do instrukcji interfejsu.
Instrukcję interfejsu o podwójnym interfejsem musi mieć OLEAUTOMATION i dwa atrybuty, a interfejs musi pochodzić od elementu IDispatch. Można użyć GUIDGEN próbkę do tworzenia IID interfejsu, podwójne
[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), / / IID_IDualAClick
oleautomation,
podwójne
]
interfejs IDualAClick: IDispatch
{
}
Po instrukcji interfejsu w miejscu, rozpocząć dodawanie wpisów do metod i właściwości. Dla podwójny interfejsach, trzeba zmienić rozmieszczenie listy parametrów metod i właściwości Akcesory w podwójnym interfejsem zwraca wartość HRESULT i przekazanie ich wartości zwracane jako parametry z atrybutów [retval,out] . Należy pamiętać, że dla właściwości, trzeba będzie dodać zarówno odczytu ( propget ) i zapisu ( propput ) dostępu do funkcji z tym samym identyfikatorem. Na przykład:
[propput, id(1)] HRESULT tekstu ([] BSTR newText);
[propget, id(1)] HRESULT tekstu ([out, retval] BSTR * retval)
Po zdefiniowaniu metody i właściwości, musisz dodać odwołanie do deklaracji interfejsu w zestawieniu coclass. Na przykład:
[uuid(4B115281-32F0-11cf-AC85-444553540000)]
coclass dokume&ntu
{
nbsp; dispinterface IAClick;
[domyślnie] interfejsu IDualAClick;
}
Po zaktualizowaniu pliku Wykładowcom, używanie MFC firmy interfejsu mapę mechanizmu do zdefiniowania klasy implementacyjnej o podwójnym interfejsem w klasie obiektu i dokonać odpowiednich wpisów w mechanizm QueryInterface MFC firmy. Potrzebujesz jeden zapis INTERFACE_PART Blok dla każdej pozycji w zestawieniu interfejsu Wykładowcom + zapisy dla interfejsu wysyłki. Każdy wpis Wykładowcom z atrybutem propput potrzebuje funkcja o nazwie put_propertyname . Każdy wpis z atrybutem propget potrzebuje funkcja o nazwieget_propertyname.
Aby zdefiniować klasę wykonania na podwójnym interfejsem, dodać DUAL_INTERFACE_PART Blok z definicji klasy obiektu. Na przykład:
BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)
STDMETHOD(put_text) (THIS_ BSTR newText);
STDMETHOD(get_text) (THIS_ BSTR FAR * retval);
STDMETHOD(put_x) (THIS_ newX krótko);
STDMETHOD(get_x) (krótkie THIS_ FAR * retval);
STDMETHOD(put_y) (THIS_ krótkie newY);
STDMETHOD(get_y) (krótkie THIS_ FAR * retval);
STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint FAR * newPosition);
STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint FAR * FAR * retval);
STDMETHOD(RefreshWindow)(This);
STDMETHOD(SetAllProps) (THIS_ krótkie x, y krótkie, BSTR tekstu);
STDMETHOD(ShowWindow)(This);
END_DUAL_INTERFACE_PART(DualAClick)
Aby połączyć podwójnym interfejsem MFC firmy QueryInterface mechanizmu, dodać INTERFACE_PART wpisu mapy interfejsu
BEGIN_INTERFACE_MAP (CAutoClickDoc, CDocument)
INTERFACE_PART (CAutoClickDoc, DIID_IAClick, wysyłki)
INTERFACE_PART (CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()
Następnie należy wypełnić w implementacji interfejsu. W większości przypadków będzie można delegować do istniejącego wdrożenia MFC IDispatch . Na przykład:
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::AddRef()
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::Release()
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalRelease();
}
STDMETHODIMP CAutoClickDoc::XDualAClick::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfoCount(
UINT FAR* pctinfo)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetTypeInfoCount(pctinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfo(
UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetIDsOfNames(
REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
LCID lcid, DISPID FAR* rgdispid)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames,
lcid, rgdispid);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::Invoke(
DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->Invoke(dispidMember, riid, lcid,
wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr);
}
Dla Twojego obiektu metod i właściwości Akcesory trzeba wypełnić we wprowadzaniu w życie. Funkcje metody i właściwości ogólnie można delegować Wróć do metody wygenerowane za pomocą ClassWizard. Jednakże jeśli bezpośredni dostęp zmiennych do skonfigurować właściwości, należy napisać kod get/oddana wartość do zmiennej. Na przykład:
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC automatycznie konwertuje BSTR Unicode z / / Ansi CString, w razie potrzeby...
pThis - > m_str = newText;
Zwraca NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC automatycznie konwertuje z Ansi CString do / / Unicode BSTR, w razie potrzeby...
pThis - > m_str.SetSysString(retval);
Zwraca NOERROR;
}
Przekazywanie podwójnym portem wskaźniki
Przekazanie wskaźnika podwójnym portem nie jest proste, zwłaszcza, jeśli musisz wywołać CCmdTarget::FromIDispatch. FromIDispatch działa tylko na wskaźniki IDispatch MFC firmy. Jednym sposobem obejścia tego jest zapytanie do oryginalnych ustawień wskaźnika interfejsu IDispatch o MFC i przekazać ten wskaźnik do funkcji, które potrzebny. Na przykład
(CAutoClickDoc::XDualAClick::put_Position) STDMETHODIMP
nbsp; IDualAutoClickPoint FAR * newPosition)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH lpDisp = NULL;
newPosition - > QueryInterface (IID_IDispatch, (elementem LPVOID *) & lpDisp);
pThis - > SetPosition(lpDisp);
lpDisp - > Release();
Zwraca NOERROR;
}
Przed przekazaniem wskaźnik ponownie za pomocą metody podwójnego interfejs, trzeba przekonwertować go ze wskaźnika MFC IDispatch do wskaźnika podwójnym portem. Na przykład:
(CAutoClickDoc::XDualAClick::get_Position) STDMETHODIMP
nbsp; IDualAutoClickPoint FAR * FAR * retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH lpDisp;
lpDisp = pThis - > GetPosition();
lpDisp - > QueryInterface (IID_IDualAutoClickPoint, (elementem LPVOID *) retval);
Zwraca NOERROR;
}
Zarejestrowanie biblioteki typów aplikacji
AppWizard nie generuje kod, aby zarejestrować biblioteki typów aplikacja serwera automatyzacji OLE z systemu. Podczas gdy istnieją inne sposoby, aby zarejestrować biblioteki typów, jest wygodne do aplikacji zarejestrowanie biblioteki typów, gdy go aktualizuje informacje typu OLE, oznacza to, że przy każdym uruchomieniu aplikacji autonomicznych.
Aby zarejestrować biblioteki typów aplikacji, przy każdym uruchomieniu aplikacji autonomicznych:
InitInstance funkcji, zlokalizuj wywołanie COleObjectFactory::UpdateRegistryAll. W następstwie tego wywołania dodać wywołanie AfxOleRegisterTypeLib, określając identyfikator biblioteki odpowiadającego bibliotece typu wraz z nazwą biblioteki typów/ / Jeżeli aplikacji serwera jest uruchomiony autonomiczny, jest dobrym pomysłem
/ / zaktualizować rejestru systemu w przypadku, gdy został uszkodzony.
m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
COleObjectFactory::UpdateRegistryAll();
/ / DUAL_SUPPORT_START
/ / Upewnij się, że biblioteka typów jest zarejestrowany lub podwójnym interfejsem nie będzie działać.
AfxOleRegisterTypeLib(AfxGetInstanceHandle(), LIBID_ACDual, _T("AutoClik.TLB"));
/ / DUAL_SUPPORT_END
Modyfikując ustawienia budowania projektu, aby pomieścić typ biblioteki zmiany
Aby zmodyfikować projekt zbudować ustawienia tak, aby plik nagłówek zawierający definicje UUID jest generowana przez MkTypLib zawsze, gdy jest odbudowywany biblioteki typów
Aby dodać definicje UUID z plików generowanych przez MkTypLib nagłówka do projektu:
/ / initIIDs.c: określa IID na podwójny interfejsach
/ / Nie musi to być zbudowane ze wstępnie skompilowanym nagłówka.
# include lt;ole2.h >
# include <initguid.h>
# include "acdual.h"
Określając nazwę klasy odpowiedni obiekt w biblioteki typów
Kreatorzy dostarczane z Visual C++ niepoprawnie użyj nazwy klasy wdrażania, aby określić coclass w pliku Wykładowcom serwera dla klasy OLE-createable. Podczas gdy to będzie działać, nazwa klasy realizacji jest prawdopodobnie nie nazwę klasy, w użytkownikom korzystania przez obiekt. Aby określić prawidłową nazwę, otwórz plik Wykładowcom, zlokalizuj każda instrukcja coclass i zastąp nazwę klasy wykonania poprawnej nazwy zewnętrzne.
Należy zauważyć, że po zmianie instrukcji coclass nazwy zmiennych s CLSIDw pliku nagłówkowym generowanych przez MkTypLib będzie się odpowiednio zmienić. Trzeba będzie zaktualizować kodzie używać nowej nazwy zmiennych.
Obsługa wyjątków i interfejsów błąd automatyzacji
Metody i właściwości Akcesory obiektu automatyzacji może zgłaszać wyjątki. Jeśli tak, należy obsługiwać ich w implementacji podwójnym portem i przekazywać informacje o wyjątku kontrolera za pomocą interfejsu obsługi błędów automatyzacji OLE, IErrorInfo. Interfejs ten zawiera informacje szczegółowe, kontekstowe błędu poprzez interfejsy IDispatch i VTBL. Aby wskazać, że obsługa błędów jest dostępny, należy implementować interfejs ISupportErrorInfo.
Aby zilustrować mechanizmu obsługi błędów, założono, że generowanych przez ClassWizard funkcje służące do implementują obsługę standardowych wysyłki generują wyjątki. MFC firmy o realizacji funkcji IDispatch::Invoke zazwyczaj połowy tych wyjątków i konwertuje je na EXCEPTINFO struktury jest zwracany przez wywołanie Invoke . Jednakże gdy używany jest interfejs VTBL, jesteś odpowiedzialny za przechwytywanie wyjątków, samodzielnie. Na przykład ochrony metod podwójnym portem
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
TRY_DUAL(IID_IDualAClick)
{
/ / MFC automatycznie konwertuje BSTR Unicode z / / Ansi CString, w razie potrzeby...
pThis - > m_str = newText;
Zwraca NOERROR;
}
CATCH_ALL_DUAL
}
CATCH_ALL_DUALdba o zwróciło kod błędu poprawne, gdy wystąpi wyjątek. CATCH_ALL_DUALkonwertuje wyjątek MFC automatyzacji OLE obsługi błędów informacji przy użyciu interfejsu ICreateErrorInfo . (Przykład CATCH_ALL_DUAL makro znajduje się w pliku MFCDUAL.H w ACDUAL próbki. Funkcja wywołuje obsługi wyjątków, DualHandleException , znajduje się w pliku MFCDUAL.CPP.) CATCH_ALL_DUALokreśla kod błędu zwraca typ wyjątku, który wystąpił na podstawie
hr = MAKE_HRESULT (SEVERITY_ERROR, FACILITY_ITF, nbsp; (e - > m_wCode + 0x200))
HRESULT stwarza specyficzne dla interfejsu, który spowodował wyjątek. Kod błędu jest równoważona 0x200 aby uniknąć wszelkich konfliktów ze zdefiniowanych w systemie s HRESULTdla standardowych interfejsów OLE.
E_OUTOFMEMORY jest zwracany.E_UNEXPECTED jest zwracany.Aby wskazać, że obsługi błędów automatyzacji OLE jest używany, należy także implementować interfejs ISupportErrorInfo.
Po pierwsze Dodaj kod do klasy automatyzacji definicji pokazują, że obsługuje ISupportErrorInfo.
Po drugie Dodaj kod do klasy automatyzacji interfejsu mapę do skojarzenia klasy implementacyjnej ISupportErrorInfo z mechanizmem QueryInterface MFC firmy. INTERFACE_PARTInstrukcja pasuje do klas zdefiniowanych dla ISupportErrorInfo.
Wreszcie implementuje klasy zdefiniowane do obsługi ISupportErrorInfo.
( ACDUAL próbka zawiera trzy makra, aby wykonać trzy następujące czynności, DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , i IMPLEMENT_DUAL_ERRORINFO , wszystkich zawartych w MFCDUAL.H.)
Poniższy przykład implementuje klasy zdefiniowane do obsługi ISupportErrorInfo. CAutoClickDocjest nazwą klasy automatyzacji i IID_IDualAClick jest IID interfejsu, który jest źródłem błędy raportowane za pomocą obiektu błędu automatyzacji OLE:
STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() {}
nbsp; METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) zwraca pThis - > ExternalAddRef();
} STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::Release() {return METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) pThis - > ExternalRelease();
} CAutoClickDoc::XSupportErrorInfo::QueryInterface STDMETHODIMP (REFIID iid, elementem LPVOID * ppvObj) {return METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) pThis - > ExternalQueryInterface (& iid, ppvObj);
} CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo STDMETHODIMP (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) zwrotu (iid == IID_IDualAClick)? WARTOŚĆ S_OK: S_FALSE;
}
Uwagi techniczne przez liczbę |nbsp; Uwagi techniczne według kategorii