TN065: Podpora rozhraní dvou serverů automatizace OLE
[!POZNÁMKA]
Následující technické poznámce nebyly aktualizovány od byla poprvé zahrnuta v dokumentaci online.Proto některé postupy a témata mohou být nesprávné nebo zastaralé.Nejnovější informace je vhodné vyhledat téma zájmu v dokumentaci online index.
Tato poznámka popisuje, jak přidat podporu dvou rozhraní aplikace založené na MFC automatizace OLE server.ACDUAL ukázka znázorňuje Podpora duální rozhraní a příklad kódu v této poznámce je převzata z ACDUAL.Makra popsané v této poznámce, například DECLARE_DUAL_ERRORINFO, DUAL_ERRORINFO_PART, a IMPLEMENT_DUAL_ERRORINFO, jsou součástí vzorku ACDUAL a v MFCDUAL.H.
Duální rozhraní
Přestože automatizaci OLE umožňuje provádět IDispatch rozhraní, rozhraní VTBL nebo duální rozhraní (který zahrnuje obě), společnost Microsoft důrazně doporučuje implementovat duální rozhraní pro všechny objekty OLE Automation vystaveny.Duální rozhraní mají významné výhody nad IDispatch-pouze nebo jen VTBL rozhraní:
Vazby mohou probíhat v době kompilace prostřednictvím rozhraní VTBL nebo za běhu pomocí IDispatch.
Zlepšení výkonu mohou využít řadiče automatizace OLE, které můžete použít rozhraní VTBL.
Použít existující řadiče automatizace OLE IDispatch rozhraní bude pokračovat v práci.
Rozhraní VTBL je snazší volání z jazyka C++.
Duální rozhraní jsou požadovány pro kompatibilitu s funkcí podpory objektů jazyka Visual Basic.
Přidání podpory duální rozhraní pro třídu CCmdTarget
Duální rozhraní je pouze vlastní rozhraní odvozené z IDispatch.Nejsnazší způsob implementovat podporu rozhraní dvou v CCmdTarget-podle třídy, je první implementace rozhraní třídy MFC a ClassWizard na normální odeslání a pak později přidat vlastní rozhraní.Z větší části realizace vlastní rozhraní bude jednoduše delegovat zpět MFC IDispatch provedení.
První upravte soubor Distanční definovat duální rozhraní pro objekty serveru.Chcete-li definovat duální rozhraní musí namísto použití příkazu rozhraní DISPINTERFACE prohlášení, které generují průvodců Visual C++.Místo odebrání stávajícího DISPINTERFACE prohlášení, přidejte příkaz nové rozhraní.Ponecháním DISPINTERFACE formulář, můžete nadále slouží k přidání vlastností a metod do objektu ClassWizard, ale je nutné přidat do příkazu rozhraní odpovídající vlastnosti a metody.
Prohlášení o rozhraní pro duální rozhraní musí mít OLEAUTOMATION a DUAL atributy a rozhraní musí být odvozen od IDispatch.Můžete použít GUIDGEN k vytvoření vzorku IID pro duální rozhraní:
[ uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), // IID_IDualAClick
oleautomation,
dual
]
interface IDualAClick : IDispatch
{
};
Jakmile rozhraní prohlášení na místě, začít přidávat položky pro metody a vlastnosti.Duální rozhraní potřebujete uspořádat seznamy parametrů metod a vlastností funkce mechanismu přístupu v duální rozhraní, vrátí HRESULT a předejte jejich vrácení hodnot jako parametrů s atributy [retval,out].Nezapomeňte, že pro vlastnosti, budete muset přidat i pro čtení (propget) a zápisu (propput) přístup k funkci se stejným identifikátorem.Příklad:
[propput, id(1)] HRESULT text([in] BSTR newText);
[propget, id(1)] HRESULT text([out, retval] BSTR* retval);
Po definování metod a vlastností musíte přidat odkaz na výpis rozhraní v příkazu coclass.Příklad:
[ uuid(4B115281-32F0-11cf-AC85-444553540000) ]
coclass Document
{
dispinterface IAClick;
[default] interface IDualAClick;
};
Po aktualizaci souboru Distanční pomocí MFC daného rozhraní mapa mechanismus definovat třídy implementace duální rozhraní třídy objektu a provést odpovídající položky v prvku MFC QueryInterface mechanismu.Potřebujete jedna položka INTERFACE_PART blok pro každou položku ve výkazu rozhraní Distanční plus položky pro odeslání rozhraní.Každá položka distančního vzdělávání s propput atribut požaduje funkci pojmenovanou put_propertyname.Každá položka se propget atribut požaduje funkci pojmenovanou get_propertyname.
Chcete-li definovat třídy implementace pro duální rozhraní přidat DUAL_INTERFACE_PART blok, aby vaše definice třídy objektu.Příklad:
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)
Připojit se k jeho MFC duální rozhraní funkce QueryInterface mechanismu, přidat INTERFACE_PART položku mapy rozhraní:
BEGIN_INTERFACE_MAP(CAutoClickDoc, CDocument)
INTERFACE_PART(CAutoClickDoc, DIID_IAClick, Dispatch)
INTERFACE_PART(CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()
Dále je nutné vyplnit implementaci rozhraní.Z větší části bude možné delegovat na existující MFC IDispatch provedení.Příklad:
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);
}
Metody a funkce přístupový objekt vlastnosti daného objektu je nutné vyplnit v implementaci.Funkce metody a vlastnosti lze obecně delegovat zpět generována pomocí ClassWizard metod.Však-li nastavit vlastnosti pro přístup k proměnné přímo musíte napsat kód get nebo PUT hodnoty do proměnné.Příklad:
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;
}
Předávání rozhraní dvojího ukazatele
Předání ukazatele rozhraní dvou není jasné, zvláště pokud potřebujete volat CCmdTarget::FromIDispatch.FromIDispatchfunguje pouze v MFC's IDispatch ukazatelů.Způsob řešení je dotaz pro původní IDispatch ukazatele nahoru pomocí MFC a funkce, které je třeba předat tento ukazatel.Příklad:
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;
}
Před předáním ukazatel zpět prostřednictvím rozhraní dvou metody, může být nutné převést z jednotka MFC IDispatch ukazatele na rozhraní dvou ukazatel.Příklad:
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;
}
Registrace knihovny typů aplikace
AppWizard negeneruje kód registrace knihovny typů aplikace server OLE Automation se systémem.Jinými způsoby registrace knihovny typů, je vhodné mít zaregistrovat knihovnu typů během aktualizace jeho typ informace OLE, je při každém spuštění aplikace je samostatná aplikace.
Registrace knihovny typů aplikace při každém spuštění aplikace samostatně:
Patří AFXCTL.H vaše Standard obsahuje záhlaví souboru STDAFX.H vymezení přístup AfxOleRegisterTypeLib funkce.
Ve vaší aplikaci InitInstance fungovat, vyhledejte volání COleObjectFactory::UpdateRegistryAll.Následující volání, volání přidat AfxOleRegisterTypeLib, zadání ID KNIHOVNY odpovídající typ knihovny, společně s názvem typu knihovny:
// 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
Úprava nastavení sestavení projektu typu knihovny změn
Změna nastavení sestavení projektu tak, aby soubor záhlaví obsahující UUID definice generovaných MkTypLib vždy, když je vytvořena knihovna typů:
Na sestavení nabídky, klepněte na tlačítko Nastavenía pak vyberte ze seznamu souborů pro každý soubor distančního vzdělávání.
Klepněte Typy OLE kartu a zadejte název souboru v výstupní záhlaví pole Název souboru.Použijte název souboru, který se již nepoužívá ve vašem projektu, protože MkTypLib přepíše existující soubor.Klepněte na tlačítko OK zavřete Nastavení sestavení dialogové okno.
Přidat UUID definice z hlavičky generované MkTypLib souboru do projektu:
Obsahovat generované MkTypLib zahrnuje soubor záhlaví ve své standardní záhlaví souboru STDAFX.H.
Vytvořte nový soubor INITIIDS.CPP a přidat do projektu.V tomto souboru zahrňte soubor hlavičky generované MkTypLib po OLE2 včetně.H a 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"
Na sestavení nabídky, klepněte na tlačítko Nastavenía pak vyberte INITIIDS.CPP ze seznamu souborů pro jednotlivé konfigurace.
Klepněte C++ karta, klepněte na kategorii Předkompilována záhlavía vyberte bez použití záhlaví předkompilovaný přepínací tlačítko.Klepněte na tlačítko OK zavřete Nastavení sestavení dialogové okno.
Určení názvu třídy správný objekt v knihovně typů
Průvodci dodán s Visual C++ nesprávně název implementace třídy slouží k určení třídy typu coclass Distanční souboru na server OLE možné vytvořit třídy.Při této práci, název třídy implementace není pravděpodobně chcete uživatelům objekt pomocí názvu třídy.Chcete-li určit správný název Distanční soubor otevřít, každý příkaz coclass vyhledejte a nahraďte název třídy implementace správné externí název.
Všimněte si, že při změně prohlášení coclass názvy proměnných CLSIDs MkTypLib generována záhlaví souboru se odpovídajícím způsobem změní.Musíte aktualizovat kód použít nové názvy proměnných.
Zpracování výjimek a Chyba rozhraní automatizace
Výjimky mohou vyvoláním metody a funkce mechanismu přístupu vlastnost objektu automatizace.Pokud by tedy v implementaci rozhraní dvou manipulovat a předat informace o výjimce řadiče prostřednictvím rozhraní automatizace OLE zpracování chyb, IErrorInfo.Toto rozhraní poskytuje kontextové, podrobné chybové informace prostřednictvím i IDispatch a VTBL rozhraní.Označuje, že obslužná rutina chyb je k dispozici, byste měli implementovat ISupportErrorInfo rozhraní.
Pro ilustraci mechanismus zpracování chyb předpokládají, že generované ClassWizard funkce lze implementovat podporu standardních odeslání vyvolávají výjimky.Provádění jeho MFC IDispatch::Invoke obvykle zachycuje tyto výjimky a převede je do struktury EXCEPTINFO vrácené až Invoke volání.Však používá rozhraní VTBL, zodpovídáte za zachycení výjimek sami.Jako příklad chrání vaše rozhraní dvou metod:
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_DUALstará o vrací kód chyby správné, dojde k výjimce.CATCH_ALL_DUALPřevede automatizace OLE zpracování chyb informací pomocí MFC výjimku ICreateErrorInfo rozhraní.(Například CATCH_ALL_DUAL je makro v souboru MFCDUAL.H v ACDUAL vzorku.Funkce volá zpracování výjimek, DualHandleException, je v souboru MFCDUAL.CPP.) CATCH_ALL_DUAL Určuje typ výjimky, které došlo na základě vrátit kód chyby:
COleDispatchException – V tomto případě HRESULT je vyrobeno pomocí následujícího kódu:
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, (e->m_wCode + 0x200));
Vytvoří HRESULT specifické pro rozhraní, která způsobila výjimku.Kód chyby je vyrovnávána pomocí 0x200 jakékoli konfliktům s definované systémem HRESULTs pro standardní rozhraní OLE.
CMemoryException – V tomto případě E_OUTOFMEMORY je vrácena.
Všechny výjimky – V tomto případě E_UNEXPECTED je vrácena.
Označuje, že je použito zpracování Chyba automatizace OLE, by měly zavést ISupportErrorInfo rozhraní.
Kód nejprve přidat do vaší automatizace definice třídy zobrazit podporuje ISupportErrorInfo.
Druhý, přidejte kód rozhraní mapa automatizační třída přidružení ISupportErrorInfo implementace třídy MFC's QueryInterface mechanismu.INTERFACE_PART Prohlášení odpovídá třídy definované pro ISupportErrorInfo.
Nakonec implementaci třídy definované pro podporu ISupportErrorInfo.
( ACDUAL vzorek obsahuje tři makra pomoci, proveďte tyto kroky DECLARE_DUAL_ERRORINFO, DUAL_ERRORINFO_PART, a IMPLEMENT_DUAL_ERRORINFO, všech obsažených v MFCDUAL.H.)
Následující příklad implementuje třídy definované pro podporu ISupportErrorInfo.CAutoClickDocje název třídy automatizace a IID_IDualAClick je IID pro rozhraní, která je zdrojem chyby hlášené prostřednictvím objektu Chyba automatizace 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;
}