Udostępnij za pośrednictwem


TN065: Obsługa interfejsu Dual serwery automatyzacji 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.

Uwaga Ta omówiono sposób dodawania obsługi interfejsu podwójnego do aplikacji serwera opartego na bibliotece MFC automatyzacji OLE.ACDUAL przykład ilustruje podwójnego interfejsu obsługi oraz przykładowy kod w tej notatce jest pobierana z ACDUAL.Makra, opisane w tej notatki, 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.

Dwa interfejsy

Chociaż automatyzacji OLE umożliwia wdrożenie IDispatch interfejsu, interfejsu VTBL lub podwójnego interfejsu, (która obejmuje zarówno), firma Microsoft zdecydowanie zaleca implementowanie interfejsów podwójne dla wszystkich narażonych obiekty automatyzacji OLE.Dwa interfejsy mają istotne korzyści nad IDispatch-tylko lub tylko do VTBL interfejsów:

  • Wiązanie może mieć miejsce w czasie kompilacji, za pośrednictwem interfejsu VTBL lub w czasie wykonywania za pomocą IDispatch.

  • Kontrolery automatyzacji OLE, które można użyć interfejsu VTBL mogą korzystać z lepszą wydajność.

  • Istniejące kontrolery automatyzacji OLE, które używają IDispatch interfejsu będą nadal działać.

  • Interfejs VTBL jest łatwiejszy do wywołania z C++.

  • Dwa interfejsy są wymagane dla zgodności z funkcji obsługi obiektu języka Visual Basic.

Dodawanie obsługi podwójnego interfejsu do klasy opartych na CCmdTarget

Podwójnym interfejsem jest naprawdę tylko interfejs niestandardowy pochodzące z IDispatch.Najprostsza sposobem zaimplementowania obsługę interfejsu podwójnego w CCmdTarget-na podstawie klasy jest wdrożenie pierwszego normalnej wysyłki interfejsu na klasy MFC i ClassWizard, a następnie dodać interfejs niestandardowy później.W większości, implementacji interfejsu niestandardowe będą po prostu przekazać wróć do biblioteki MFC IDispatch wdrożenia.

Po pierwsze należy zmodyfikować plik Wykładowcom dla serwera zdefiniować dwa interfejsy dla obiektów.Aby zdefiniować podwójnym interfejsem, należy użyć instrukcji interfejsu zamiast DISPINTERFACE oświadczenie, że generowanie kreatorów Visual C++.Zamiast usuwania istniejących DISPINTERFACE instrukcji, dodać nową deklarację interfejsu.Zatrzymanie DISPINTERFACE formularz, można dalej używać ClassWizard, aby dodać właściwości i metody do obiektu, ale należy dodać do instrukcji interfejsu równoważnych właściwości i metody.

Musi mieć instrukcję interfejsu dla interfejsu dual OLEAUTOMATION i DUAL atrybuty i interfejs musi pochodzić z IDispatch.Można użyć GUIDGEN próbki, aby utworzyć IID dual interfejsu:

[ uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), // IID_IDualAClick
   oleautomation,
   dual
]
interface IDualAClick : IDispatch
  {
  };

Po instrukcji interfejsu w miejscu, można rozpocząć dodawanie wpisów do metod i właściwości.Dwa interfejsy, trzeba zmienić rozmieszczenie listy parametrów tak, aby zwrócić metod i właściwości Akcesory w podwójnym interfejsem HRESULT i przekazać ich wartości zwracanej jako parametry z atrybutami [retval,out].Należy pamiętać, że dla właściwości, będzie trzeba dodać zarówno odczytu (propget) i zapisu (propput) dostępu do funkcji z tego samego identyfikatora.Na przykład:

[propput, id(1)] HRESULT text([in] BSTR newText);
[propget, id(1)] HRESULT text([out, retval] BSTR* retval);

Po zdefiniowaniu właściwości i metody, trzeba dodać odniesienie do deklaracji interfejsu w instrukcji coclass.Na przykład:

[ uuid(4B115281-32F0-11cf-AC85-444553540000) ]
coclass Document
{
   dispinterface IAClick;
   [default] interface IDualAClick;
};

Po zaktualizowaniu pliku Wykładowcom, użyj mechanizmu mapę interfejsu MFC firmy do zdefiniowania klasy implementacji dla podwójnym interfejsem w klasie obiektu i dokonać odpowiednich wpisów w MFC firmy QueryInterface mechanizmu.Potrzebujesz jeden zapis w INTERFACE_PART bloku dla każdej pozycji w zestawieniu interfejsu Wykładowcom plus wpisy interfejsu wysyłki.Każdy wpis Wykładowcom z propput atrybut potrzebuje funkcja o nazwie put_propertyname.Każdy wpis z propget atrybut potrzebuje funkcja o nazwie get_propertyname.

Zdefiniowanie klasy implementacji dla wybranego interfejsu podwójne, dodać DUAL_INTERFACE_PART bloku do użytkownika 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_ short newX);
  STDMETHOD(get_x)(THIS_ short FAR* retval);
  STDMETHOD(put_y)(THIS_ short newY);
  STDMETHOD(get_y)(THIS_ short FAR* retval);
  STDMETHOD(put_Position)(THIS_ IDualAutoClickPoint FAR* newPosition);
  STDMETHOD(get_Position)(THIS_ IDualAutoClickPoint FAR* FAR* retval);
  STDMETHOD(RefreshWindow)(THIS);
  STDMETHOD(SetAllProps)(THIS_ short x, short y, BSTR text);
  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, Dispatch)
  INTERFACE_PART(CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()

Następnie należy wypełnić w implementacji interfejsu.W większości, będzie można delegować do istniejących MFC IDispatch wdrożenia.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 metod i Akcesory właściwości obiektu użytkownika należy wypełnić w realizacji.Funkcje metody i właściwości ogólnie można delegować do metody wygenerowanych przy użyciu ClassWizard.Jednakże jeśli właściwości skonfigurowany do uzyskania bezpośredniego dostępu do zmiennych, należy napisać kod get/put wartość do zmiennej.Na przykład:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   // MFC automatically converts from Unicode BSTR to 
   // Ansi CString, if necessary...
   pThis->m_str = newText;
   return NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   // MFC automatically converts from Ansi CString to 
   // Unicode BSTR, if necessary...
   pThis->m_str.SetSysString(retval);
   return NOERROR;
}

Przekazywanie podwójnym portem wskaźniki

Przekazując wskaźnik podwójnego interfejs nie jest bezpośrednia, zwłaszcza, jeśli trzeba wywołać CCmdTarget::FromIDispatch.FromIDispatchdziała tylko na jego MFC IDispatch wskaźniki.Jednym ze sposobów obejścia tego problemu jest do kwerendy dla oryginalnej IDispatch wskaźnik o MFC i przekazać ten wskaźnik do funkcji, które są potrzebne.Na przykład:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position(
      IDualAutoClickPoint FAR* newPosition)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDisp = NULL;
   newPosition->QueryInterface(IID_IDispatch, (LPVOID*)&lpDisp);
   pThis->SetPosition(lpDisp);
   lpDisp->Release();
   return NOERROR;
}

Przed przekazaniem wskaźnik ponownie za pomocą metody podwójnego interfejsu, trzeba przekonwertować ją z MFC IDispatch wskaźnik do wskaźnika interfejsu dual.Na przykład:

STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position(
      IDualAutoClickPoint FAR* FAR* retval)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDisp;
   lpDisp = pThis->GetPosition();
   lpDisp->QueryInterface(IID_IDualAutoClickPoint, (LPVOID*)retval);
   return NOERROR;
}

Zarejestrowanie biblioteki typów aplikacji

AppWizard nie generuje kod, aby zarejestrować biblioteki typów aplikacji serwera automatyzacji OLE z systemu.Podczas gdy istnieją inne sposoby zarejestrować biblioteki typów, jest wygodne zgłoszenia zarejestrować biblioteki typów podczas aktualizacji swoich informacji typu OLE, oznacza to, że przy każdym uruchomieniu aplikacji autonomicznych.

Aby zarejestrować biblioteki typów aplikacji przy każdym uruchomieniu aplikacji autonomicznie:

  • Obejmują AFXCTL.H w standardzie użytkownika zawiera nagłówek pliku STDAFX.H określenie dostępu do AfxOleRegisterTypeLib funkcji.

  • Do aplikacji InitInstance działały, zlokalizuj wywołanie COleObjectFactory::UpdateRegistryAll.Po tej rozmowy, dodać wywołanie AfxOleRegisterTypeLib, określanie Identyfikator biblioteki odpowiadające biblioteki typu, wraz z nazwą biblioteki typów:

    // When a server application is launched stand-alone, it is a good idea
    // to update the system registry in case it has been damaged.
    m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
    COleObjectFactory::UpdateRegistryAll();
    // DUAL_SUPPORT_START
    // Make sure the type library is registered or dual interface won't work.
    AfxOleRegisterTypeLib(AfxGetInstanceHandle(), LIBID_ACDual, _T("AutoClik.TLB"));
    // DUAL_SUPPORT_END
    

Modyfikowanie ustawień budowania projektu, aby uwzględnić zmiany biblioteki typu

Do modyfikowania projektu zbudować ustawienia tak, aby nagłówek pliku zawierającego UUID definicje jest generowana przez MkTypLib, ilekroć jest odbudowywany biblioteki typów:

  1. Na budować menu, kliknij Ustawienia, a następnie wybierz plik Wykładowcom z listy plików dla każdej konfiguracji.

  2. Kliknij Typu OLE kartę i określ nazwę pliku w nagłówka wyjściowego pole filename.Nazwa pliku, który nie jest już używany przez projektu, należy użyć, ponieważ MkTypLib zastąpi wszystkie istniejące pliki.Kliknij OK zamknąć Ustawienia budować okno dialogowe.

Aby dodać UUID definicje z pliku nagłówka wygenerowane MkTypLib do projektu:

  1. Obejmują generowany MkTypLib pliku nagłówka w standardzie użytkownika zawiera nagłówek pliku STDAFX.H.

  2. Utwórz nowy plik INITIIDS.CPP i dodać go do swojego projektu.W tym pliku zawiera plik nagłówka wygenerowane MkTypLib po tym OLE2.H i INITGUID.H:

    // initIIDs.c: defines IIDs for dual interfaces
    // This must not be built with precompiled header.
      #include <ole2.h>
      #include <initguid.h>
      #include "acdual.h"
    
  3. Na budować menu, kliknij Ustawienia, a następnie wybierz INITIIDS.CPP z listy plików dla każdej konfiguracji.

  4. Kliknij C++ , kliknij pozycję kategorii Wstępnie skompilowana nagłówkii wybierz nie przy użyciu wstępnie skompilowanym nagłówki przycisk radiowy.Kliknij przycisk OK, aby zamknąć Ustawienia budować okno dialogowe.

Określanie nazwy klasy prawidłowego obiektu w bibliotece typów

Kreatorzy dostarczane z programem Visual C++ niepoprawnie użyć nazwy klasy implementacji określenie coclass w pliku Wykładowcom serwera dla klas obiektów OLE.Podczas, gdy będzie działać, nazwa klasy realizacji jest prawdopodobnie nie mają użytkownicy obiekt, użyj nazwy klasy.Aby określić prawidłową nazwę, otwórz plik Wykładowcom, zlokalizuj każdej instrukcji coclass i zastąp nazwę klasy implementacji poprawnej nazwy zewnętrzne.

Należy zauważyć, że po zmianie instrukcji coclass nazwy zmiennej CLSIDs w pliku nagłówka wygenerowane MkTypLib zostanie zmieniona.Należy zaktualizować kod, aby użyć nowej nazwy zmiennej.

Obsługa wyjątków i interfejsów automatyzacji błąd

Metody i Akcesory właściwości obiektu automatyzacji może generują wyjątki.Jeśli tak, należy je obsłużyć w implementacji interfejsu podwójnego i przekazywać informacje o wyjątku kontrolera za pomocą interfejsu obsługi błędów automatyzacji OLE IErrorInfo.Ten interfejs zapewnia informacje szczegółowe, kontekstowe błędu przez oba IDispatch i VTBL interfejsów.Aby wskazać dostępne narzędzia obsługi błędów, należy implementować ISupportErrorInfo interfejsu.

Aby zilustrować mechanizmu obsługi błędów, założono, że wygenerowany ClassWizard funkcje używane do implementacji obsługi standardowych wysyłki generują wyjątki.Wykonania MFC firmy IDispatch::Invoke zazwyczaj połowy tych wyjątków i konwertuje je na strukturę EXCEPTINFO, która jest zwracana za pośrednictwem Invoke wywołania.Jednakże gdy używany jest interfejs VTBL, jesteś odpowiedzialny za przechwytywanie wyjątków samodzielnie.Na przykład ochrony Twoje metody podwójnego interfejsu:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   TRY_DUAL(IID_IDualAClick)
   {
      // MFC automatically converts from Unicode BSTR to 
      // Ansi CString, if necessary...
      pThis->m_str = newText;
      return 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 przy użyciu informacji obsługi błędów automatyzacji OLE ICreateErrorInfo interfejsu.(Przykład CATCH_ALL_DUAL 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_DUAL określa kod błędu, aby powrócić na podstawie typ wyjątku, który wystąpił:

  • COleDispatchException — W tym przypadku HRESULT jest konstruowana przy użyciu następującego kodu:

    hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 
                               (e->m_wCode + 0x200));
    

    Spowoduje to utworzenie HRESULT 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 HRESULTs dla standardowych interfejsów OLE.

  • CMemoryException — W tym przypadku E_OUTOFMEMORY jest zwracany.

  • Inny wyjątek — W tym przypadku E_UNEXPECTED jest zwracany.

Aby wskazać, że jest używana obsługa błąd automatyzacji OLE, należy implementować ISupportErrorInfo interfejsu.

Najpierw należy dodać kod do klasy automatyzacji definicji Pokaż obsługuje ISupportErrorInfo.

Po drugie, Dodaj do mapy interfejsu klasy automatyzacji, aby skojarzyć kod ISupportErrorInfo implementacji klasy z MFC firmy QueryInterface mechanizmu.INTERFACE_PART Instrukcji pasuje do klasy zdefiniowane dla ISupportErrorInfo.

Wreszcie, zaimplementować klasa zdefiniowana do obsługi ISupportErrorInfo.

( ACDUAL próbka zawiera trzy makra do pomocy, wykonaj następujące trzy kroki DECLARE_DUAL_ERRORINFO, DUAL_ERRORINFO_PART, i IMPLEMENT_DUAL_ERRORINFO, wszystkie zawarte w MFCDUAL.H.)

Poniższy przykład implementuje klasy zdefiniowanej do obsługi ISupportErrorInfo.CAutoClickDocjest nazwą klasy automatyzacji i IID_IDualAClick jest IID dla interfejsu, który jest źródłem błędy raportowane przez obiekt błąd automatyzacji OLE:

STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() 
{
   METHOD_PROLOGUE(CAutoClickDoc, SupportErrorInfo) 
   return pThis->ExternalAddRef(); 
} 
STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::Release() 
{ 
   METHOD_PROLOGUE(CAutoClickDoc, SupportErrorInfo) 
   return pThis->ExternalRelease(); 
} 
STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::QueryInterface( 
   REFIID iid, LPVOID* ppvObj) 
{ 
   METHOD_PROLOGUE(CAutoClickDoc, SupportErrorInfo) 
   return pThis->ExternalQueryInterface(&iid, ppvObj); 
} 
STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo( 
   REFIID iid) 
{ 
   METHOD_PROLOGUE(CAutoClickDoc, SupportErrorInfo) 
   return (iid == IID_IDualAClick) ? S_OK : S_FALSE; 
}

Zobacz też

Inne zasoby

Uwagi techniczne przez liczbę

Uwagi techniczne według kategorii