Цю примітку розглядається як додати підтримка dual інтерфейс до застосунку на основі MFC автоматизації OLE-сервер. На ACDUAL приклад ілюструє dual інтерфейс, підтримка і приклад коду в цій записці взято з ACDUAL. Макроси описані у примітці, таких як DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , і IMPLEMENT_DUAL_ERRORINFO , є частиною ACDUAL зразок і можуть бути знайдені в MFCDUAL.H.
Подвійний інтерфейси
Хоча автоматизації OLE дозволяє здійснювати IDispatch інтерфейс, VTBL інтерфейс або подвійний інтерфейс, (який охоплює як), корпорація Майкрософт настійно рекомендує, впровадити подвійний інтерфейсів для всіх об'єктів піддається автоматизації OLE. Подвійний інтерфейсів мають значні переваги в порівнянні з IDispatch-тільки або лише для VTBL інтерфейси:
Додавання Підтримка Dual інтерфейс на основі CCmdTarget клас
Подвійний інтерфейс є дійсно тільки власний інтерфейс, отриманих від IDispatch. Найбільш простий спосіб здійснення dual інтерфейс, підтримка у CCmdTarget-на основі класу є першу реалізувати нормальний напрямок інтерфейс на ваш клас використання MFC і ClassWizard, а потім додати користувача інтерфейс пізніше. Здебільшого, здійснення індивідуального інтерфейсу буде просто делегувати назад до реалізації MFC IDispatch.
По-перше, змінити файл ODL для вашого сервера, для визначення подвійний інтерфейсів для об'єктів. Визначити подвійний інтерфейс, скористайтеся заяви інтерфейс, замість того, щоб на DISPINTERFACE заяви, які генерують майстри Visual c + +. Замість видалення існуючого DISPINTERFACE заяву, додати новий інтерфейс заяву. Зберігши в DISPINTERFACE формі, ви можете продовжувати використовувати ClassWizard, щоб додати властивості і методи об'єкта, але еквівалентні властивості та методи, необхідно додати до вашої заяви інтерфейс.
Інтерфейс-оператор для подвійний інтерфейс необхідно мати OLEAUTOMATION і подвійний атрибутів, а інтерфейс, повинні бути визначені з IDispatch. Ви можете використовувати в GUIDGEN зразка, щоб створити IID подвійний інтерфейс
[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), / / IID_IDualAClick
oleautomation,
подвійний
]
інтерфейс IDualAClick: IDispatch
{
}
Після того як ви інтерфейс заяву на місці, розпочати додавання записів для властивості та методи. Для подвійного інтерфейсів, необхідно змінити параметр списки, методи і функції властивостей методів доступу в інтерфейсі подвійний повернутися в HRESULT та передати їх повернення значення як параметри з атрибутами [retval,out] . Пам'ятайте, що для властивостей, потрібно буде додати обидві читати ( propget ) і писати ( propput ) доступ до функції з ж id. Наприклад:
[propput, id(1)] HRESULT тексту ([в] БУЛ newText);
[propget, id(1)] HRESULT текст (retval] [з, БУЛ * retval)
Після того, як визначено методи і властивості, ви повинні додати посилання на інтерфейс заяву у своїй заяві coclass. Наприклад:
[uuid(4B115281-32F0-11cf-AC85-444553540000)]
coclass документа
{
dispinterface IAClick;
[Стандартний] інтерфейс IDualAClick;
}
Після ODL файл було оновлено, використовувати MFC в інтерфейс карта механізм визначення реалізації-клас для подвійний інтерфейс у ваш клас об'єкта і зробити відповідні записи у MFC, QueryInterface механізм. Вам потрібно один запис у на INTERFACE_PART блоку для кожного запису інтерфейсу заяву на ODL, а також записи для відправки інтерфейсу. Кожен ODL запис з атрибутом propput потребує функції, названий put_propertyname . Кожен запис з атрибутом propget потребує функції, названийget_propertyname.
Визначити реалізації-клас для подвійний інтерфейс, додати до DUAL_INTERFACE_PART блок на ваш об'єкт класу визначення. Наприклад:
BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)
STDMETHOD(put_text) (newText THIS_ БУЛ);
STDMETHOD(get_text) (THIS_ БУЛ ДАЛЕКИЙ * retval);
STDMETHOD(put_x) (THIS_ newX короткий);
STDMETHOD(get_x) (THIS_ короткий ДАЛЕКИЙ * retval);
STDMETHOD(put_y) (THIS_ newY короткий);
STDMETHOD(get_y) (THIS_ короткий ДАЛЕКИЙ * retval);
STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint ДАЛЕКОГО * newPosition);
STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint ДАЛЕКОГО * ДАЛЕКИЙ * retval);
STDMETHOD(RefreshWindow)(This);
STDMETHOD(SetAllProps) (THIS_ короткий x, y короткий, БУЛ текст);
STDMETHOD(ShowWindow)(This);
END_DUAL_INTERFACE_PART(DualAClick)
Для підключення подвійний інтерфейс до MFC в QueryInterface механізм, додати до INTERFACE_PART запис на карту інтерфейс
BEGIN_INTERFACE_MAP (CAutoClickDoc, CDocument)
INTERFACE_PART (CAutoClickDoc, DIID_IAClick, відправлення)
INTERFACE_PART (CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()
Далі, вам потрібно заповнити в реалізації інтерфейсу. Здебільшого, можна делегувати реалізації існуючих MFC IDispatch . Наприклад:
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);
}
Для вашого об'єкта методи і властивості поводи функції вам потрібно заповнити в реалізації. Ваші методи і властивості функцій взагалі можна делегувати назад до методів, створений за допомогою ClassWizard. Однак, якщо ви встановити властивості безпосередньо доступ до змінних, потрібно написати код, щоб отримати/покласти значення до змінної. Наприклад:
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC автоматично перетворює від Юнікод БУЛ до / / Ansi CString, якщо це необхідно...
pThis - > m_str = newText;
повернення NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC автоматично перетворює від Ansi CString до / / Юнікод БУЛ, якщо це необхідно...
pThis - > m_str.SetSysString(retval);
повернення NOERROR;
}
Проходження подвійного інтерфейс вказівники
Проходження вказівник dual інтерфейс не є простим, особливо якщо вам потрібна для виклику CCmdTarget::FromIDispatch. FromIDispatch працює тільки на MFC, IDispatch покажчиків. Один спосіб обійти це, щоб запит для початкового набору вказівник IDispatch вгору MFC і передати цей вказівник для функцій, що потрібно. Наприклад
STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position (
nbsp; IDualAutoClickPoint ДАЛЕКОГО * newPosition)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH-lpDisp = NULL;
newPosition - > QueryInterface (IID_IDispatch, (LPVOID *) & lpDisp);
pThis - > SetPosition(lpDisp);
lpDisp - > Release();
повернення NOERROR;
}
До винесення вказівник назад через метод подвійного інтерфейс, може знадобитися перетворити його з MFC IDispatch вказівник вказівник dual інтерфейс. Наприклад:
STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position (
nbsp; IDualAutoClickPoint FAR FAR * * retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH lpDisp;
lpDisp = pThis - > GetPosition();
lpDisp - > QueryInterface (IID_IDualAutoClickPoint, (LPVOID *) retval);
повернення NOERROR;
}
Реєстрацію бібліотеки типів програми
AppWizard не генерує код зареєструвати бібліотеку типів додатків сервера автоматизації OLE з системою. Хоча є й інші способи, щоб зареєструвати бібліотеку типів, це зручно мати додатків, зареєструвати бібліотеку типів, коли він оновлює його відомості про OLE типу, кожного разу, коли застосунок виконується автономний.
Щоб зареєструвати бібліотеку типів програми кожного разу, коли застосунок виконується автономний:
InitInstance функції, знайдіть виклику COleObjectFactory::UpdateRegistryAll. Після цього виклику додати заклик до AfxOleRegisterTypeLib, вказавши код БІБЛІОТЕКИ відповідає типу бібліотеки, разом з іменем типу бібліотеки/ / Коли серверний додаток запущено автономний, це гарна ідея
/ / оновити системний реєстр на випадок його пошкодження.
m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
COleObjectFactory::UpdateRegistryAll();
/ / DUAL_SUPPORT_START
/ / Переконайтеся, зареєстрований тип бібліотеки або подвійний інтерфейс не буде працювати.
AfxOleRegisterTypeLib(AfxGetInstanceHandle(), LIBID_ACDual, _T("AutoClik.TLB"));
/ / DUAL_SUPPORT_END
Змінення настройок створення проекту відповідно до типу бібліотеки змін
Змінити проекту побудувати настройки, так що заголовка файлу, який містить UUID визначень, що генерується по MkTypLib кожного разу, коли перебудований бібліотеки типів
Щоб додати визначення UUID з MkTypLib генеруються заголовка файлу до проекту:
/ / initIIDs.c: визначає IID для подвійний інтерфейси
/ / Це не повинні бути побудовані з скомпільованого заголовка.
# включити lt;ole2.h >
# включити <initguid.h>
# включити "acdual.h"
Вказує ім'я класу правильний об'єкт типу бібліотеки
Майстри, які поставляються з Visual c + + неправильно використовувати ім'я класу реалізації вказувати на coclass в файл ODL сервера OLE-createable класи. Хоча це буде працювати, впровадження ім'я класу, ймовірно, не ім'я класу, користувачі вашого об'єкта для використання. Вкажіть ім'я правильно, відкрийте файл ODL, знайдіть кожного coclass заяву і замінити ім'я класу реалізації ім'я правильно зовнішніх.
Зверніть увагу, що при зміні coclass заяву, імена змінних CLSIDи в MkTypLib генеруються заголовка файлу зміниться. Вам необхідно оновити ваш код, щоб використовувати нові імена змінних.
Обробка винятків і автоматизації помилка інтерфейси
Методи і методи доступу функції властивостей об'єкта автоматизації може кинути винятки. Якщо так, ви повинні обробляти їх у здійснення dual інтерфейс і передати інформацію про виключення контролер через інтерфейс обробка помилок автоматизації OLE, IErrorInfo. Цей інтерфейс забезпечує докладний, контекстні помилка інформації через IDispatch та VTBL інтерфейсів. Щоб вказати, що доступна обробника помилок, необхідно провести ISupportErrorInfo інтерфейс.
Щоб проілюструвати механізм обробка помилок, припустити, що генеруються ClassWizard функції, використовувані для здійснення підтримки стандартних відправлення кинути винятки. MFC в реалізації IDispatch::Invoke зазвичай ловить ці винятки, і перетворює їх на що EXCEPTINFO структуру, тобто повернулися через Invoke дзвінка. Однак, коли використовується VTBL інтерфейс, ви несете відповідальність за ловлю винятки, себе. Як приклад захисту ваших методів dual інтерфейс
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
TRY_DUAL(IID_IDualAClick)
{
/ / MFC автоматично перетворює від Юнікод БУЛ до / / Ansi CString, якщо це необхідно...
pThis - > m_str = newText;
повернення NOERROR;
}
CATCH_ALL_DUAL
}
CATCH_ALL_DUALпіклується про повернення правильний код, коли виникає виняток. CATCH_ALL_DUALперетворює MFC-винятку в автоматизації OLE помилка обробки інформації за допомогою інтерфейсу ICreateErrorInfo . (Приклад CATCH_ALL_DUAL макросів, що містяться у файлі MFCDUAL.H у на ACDUAL зразка. Функції, які вона називає для обробки винятків, DualHandleException , у файлі MFCDUAL.CPP). CATCH_ALL_DUALвизначає повернутися на основі типу винятком того, що сталося, код помилки
hr = MAKE_HRESULT (SEVERITY_ERROR, FACILITY_ITF, nbsp; (e - > m_wCode + 0x200))
Це створює на HRESULT для інтерфейсу, що викликало виняток. Код помилки компенсується 0x200, щоб уникнути будь-яких конфліктів з системи визначається HRESULTs для стандартних інтерфейсів OLE.
E_OUTOFMEMORY повертається.E_UNEXPECTED повертається.Щоб вказати, що використовується автоматизації OLE помилка обробника, повинні також здійснити ISupportErrorInfo інтерфейс.
По-перше, додати код для вашого визначення клас автоматизації, щоб показати, що він підтримує ISupportErrorInfo.
По-друге, додати код ваш клас автоматизації інтерфейсу карта асоціювати ISupportErrorInfo реалізації класу з MFC, QueryInterface механізм. На INTERFACE_PART заява відповідає класу, визначені для ISupportErrorInfo.
Нарешті, реалізувати клас, визначені для підтримки ISupportErrorInfo.
(З ACDUAL зразок містить три макроси, щоб допомогти зробити наступні три кроки, DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , і IMPLEMENT_DUAL_ERRORINFO , все, що містяться в MFCDUAL.Г.)
Нижче наведено приклад реалізує клас, визначені для підтримки ISupportErrorInfo. CAutoClickDoc-ім'я ваш клас автоматизації та IID_IDualAClick IID для інтерфейсу, яка є джерелом помилки повідомив через помилку об'єкт OLE автоматизації:
STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() {
nbsp; METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) повернення pThis - > ExternalAddRef();
} STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::Release() {повернення METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) pThis - > ExternalRelease();
} CAutoClickDoc::XSupportErrorInfo::QueryInterface STDMETHODIMP (REFIID iid, LPVOID * ppvObj) {повернення METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) pThis - > ExternalQueryInterface (& iid, ppvObj);
} STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) повернення (iid = = IID_IDualAClick)? S_OK: S_FALSE;
}
Технічні примітки за номером |nbsp; Технічні примітки за категоріями