Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Содержание сайт... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Создание отчето... 65090
Модуль Forms 64856
Пример работы с... 63297
ТЕХНОЛОГИИ ДОСТ... 61565
Имитационное мо... 57411
Реклама
Сейчас на сайте
Гостей: 5
На сайте нет зарегистрированных пользователей

Пользователей: 13,081
новичок: Abdukarimov A
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Калькулятор на Delphi с переводом в другую систему исчисления + Блок схемы
Моделирование литейного цеха на GPSS + Пояснительная записка
Обработка задач на ЭВМ на GPSS + Пояснительная записка

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

ПОДПИСЫВАЙСЯ на канал о программировании
Двунаправленные интерфейсные контракты



Как было показано в главе 5, объекты, постоянно находящиеся в различных апартаментах, могут использовать сервисные программы друг друга вне зависимости от того, резидентом какого апартамента является другой объект. Поскольку удаленный доступ в СОМ основан на концепции апартаментов, разработчикам необходимо рассматривать процессы не как клиенты или серверы в чистом виде, а скорее как набор из одного или нескольких апартаментов, которые способны одновременно экспортировать и импортировать интерфейсы.
Как два объекта договариваются о том, чьи интерфейсы будут использоваться для взаимного сотрудничества, в значительной степени является спецификой области применения. Для примера рассмотрим следующий интерфейс, моделирующий программиста:
[uuid(75DA6457-DD0F-11d0-8C58-0080C73925BA),object]
interface IProgrammer : IUnknown {
HRESULT StartHacking(void);
HRESULT IsProductDone([out, retval] BOOL *pbIsDone);
}



Клиент будет использовать такой интерфейс следующим образом:
HRESULT ShipSoftware(void)
{
IProgrammer *pp = 0;
HRESULT hr = CoGetObject(OLESTR(«programmer:Bob»), 0,
IID_IProgrammer, (void**)&pp);
if (SUCCEEDED(hr)) {
hr = pp->StartHacking();
BOOL bIsDone = FALSE;
while (!bIsDone && SUCCEEDED(hr)) {
Sleep(15000);
// wait 15 seconds
// ожидаем 15 секунд
hr = pp->IsProductDone(&bIsDone);
// check status
// проверяем состояние
}
pp->Release();
}
}



Очевидно, что этот код весьма неэффективен, поскольку клиент каждые 15 секунд опрашивает состояние объекта. Более эффективным для клиента был бы следующий подход: подготовить второй объект, которому объект-программист (programmer object) мог бы сообщить, когда данный объект придет в нужное состояние. Этот подготовленный клиентом объект должен экспортировать интерфейс, предоставляющий контекст, через который мог бы работать объект-программист:
[uuid(75DA6458-DD9F-11d0-8C58-0080C73925BA),object]
interface ISoftwareConsumer : IUnknown {
HRESULT OnProductIsDone(void);
HRESULT OnProductWillBeLate([in] hyper nMonths);
}
При таком парном определении интерфейса должен существовать некий механизм для информирования объекта-программиста о том, что у клиента имеется реализация ISoftwareConsumer, с помощью которой он может получать уведомления от объекта-программиста об изменениях состояния. Одной из распространенных методик является определение IProgrammer таким образом, чтобы он имел явные методы, через которые клиенты могли бы связываться со своими объектами-потребителями (consumer object). Канонической формой этой идиомы является включение метода Advise:
interface IProgrammer : IUnknown {
HRESULT Advise ([in] ISoftwareConsumer *psc, [out] DWORD *pdwCookie);
: : :



посредством которого клиент подготавливает парный объект-потребитель, а программист возвращает DWORD для подтверждения связи. Затем этот DWORD можно было бы использовать в соответствующем методе Unadvise:
interface IProgrammer : IUnknown {
: : :
HRESULT Unadvise([in] DWORD dwCookie);
}



для того, чтобы сообщить объекту-программисту о прерывании связи. При использовании уникальных DWORD для представления связи программист-потребитель дизайн интерфейса позволяет произвольному числу потребителей независимо друг от друга соединяться с объектом и отсоединяться от него.
Если эти два метода имеются в интерфейсе IProgrammer, то реализация программиста может быть соединена с объектом-потребителем с помощью метода Advise
STDMETHODIMP Programmer::Advise(ISoftwareConsumer *pcs, DWORD *pdwCookie)
{
assert(pcs);
if (m_pConsumer != 0) // is there already a consumer?
// уже есть потребитель?
return E_UNEXPECTED;
(m_pConsumer = pcs)->AddRef();
// hold onto new consumer
// соединяемся с новым потребителем
*pdwCookie = DWORD(pcs);
// make up a reasonable cookie
// готовим подходящий маркер
return S_OK;
}
Соответствующая реализация метода Unadvise выглядела бы примерно так:
STDMETHODIMP Programmer::Unadvise(DWORD dwCookie)
{
// does the cookie correspond to the current consumer?
// соответствует ли маркер данному потребителю?
if (DWORD(m_pConsumer) != dwCookie)
return E_UNEXPECTED;
(m_pConsumer)->Release();
// release current consumer
// освобождаем текущего потребителя
m_pConsumer = 0;
return S_OK;
}
Взаимоотношения между программистом и потребителем показаны на рис. 7.7. Хотя в данной реализации в каждый момент предусмотрен только один потребитель, возможно, что более опытный программист смог бы оперировать несколькими потребителями одновременно, управляя динамическим массивом интерфейсных указателей из ISoftwareConsumer.
Имея приведенную выше реализацию, метод программиста StartHacking может теперь использовать потребителя для индикации готовности результата:
STDMETHODIMP Programmer::StartHacking (void)
{
assert(m_pConsumer);
// preemptively notify of lateness
// приоритетно сообщаем о задержке
HRESULT hr = m_Consumer->OnProductWillBeLate(3);
if (FAILED(hr))
return PROGRAMMER_E_UNREALISTICCONSUMER;
// generate some code
// генерируем некоторый код
extern char *g_rgpszTopFiftyStatements[];
for (int n = 0; n < 100000; n++)
printf(g_rgpszTopFiftyStatements[rand() % 50]);
// inform consumer of done-ness
// извещаем потребителя о выполнении
hr = m_pConsumer->OnProductIsDone();
return S_OK;
}
To обстоятельство, что реализация ISoftwareConsumer может принадлежать к другому апартаменту, чем объект-программист, не является существенным. На самом деле метод StartHacking может быть вызван из того апартамента, который содержит объект-потребитель, и в этом случае будет осуществлено повторное вхождение в апартамент вызывающей программы, что, в сущности, является синхронным обратным вызовом. В то время как эта реализация делает вложенные вызовы на объект-потребитель, объект-программист может также в будущем производить вызовы методов объекта-потребителя в любое время. Эта привилегия остается до тех пор, пока не последует вызов метода Unadvise, разрывающий соединение.
Поскольку интерфейсы IProgrammer и ISoftwareConsumer, вероятно, были созданы в тандеме для совместной работы, использование явного метода интерфейса IProgrammer для установления связи становится частью протокола при работе с объектами-программистами и является вполне целесообразным. Тот факт, что реализации программиста способны использовать один или несколько объектов-потребителей, может быть документирован как часть протокола интерфейса IProgrammer в порядке уточнения семантического контракта IProgrammer. Существуют, однако, сценарии, в которых интерфейсы совместной работы и обратного вызова разработаны так, что они находятся вне области видимости любого другого интерфейса. Ниже приведен пример такого интерфейса:
[uuid(75DA645D-DD0F-11d0-8C58-0080C73925BA),object ]
interface IShutdownNotify : IUnknown {
HRESULT OnObjectDestroyed([in] IUnknown *pUnk);
}
В этом интерфейсе предполагается, что разработчик IShutdownNotify заинтересован в получении сообщений о прекращении работы от других объектов. В данном определении, однако, не приведен механизм, с помощью которого эти заинтересованные стороны могли бы сообщить объектам, что они хотели бы быть уведомлены об уничтожении этого объекта. Как показано на рис. 7.8, одна из возможных стратегий осуществления этого состоит в определении второго (парного) интерфейса, который объекты могли бы реализовать:
[uuid(75DA645E-DD0F-11d0-8C58-0080C73925BA), object]
interface IShutdownSource : IUnknown {
HRESULT Advise([in] IShutdownNotify *psn, [out] DWORD *pdwCookie);
HRESULT Unadvise([in] DWORD dwCookie);
}
Данный интерфейс существует, однако, только для того, чтобы дать наблюдателям (observers) возможность соединить свои интерфейсы IShutdownNotify с объектом. Если имеется большое число типов интерфейсов обратного вызова, то необходимо определить столь же большое число соответствующих интерфейсов только для управления соединением. Ясно, что должен существовать более общий механизм: вхождение в точках стыковки.
Точки стыковки являются идиомой СОМ, предназначенной для регистрации связи интерфейсов обратного вызова с объектом и ее отмены. Точки стыковки не являются необходимыми для создания сетей из объектов с большим количеством соединений. К тому же точки стыковки не обеспечивают двунаправленных соединений. Вместо этого идиома точек стыковки выражает общую концепцию регистрации экспортируемых интерфейсов как небольшого числа интерфейсов стандартной инфраструктуры. Наиболее фундаментальным из этих интерфейсов является IConnectionPoint:
[object, uuid(B196B286-BAB4-101A-B69C-00AA00341D07)]
interface IConnectionPoint : IUnknown {
// which type of interface can be connected
// какой тип интерфейса можно присоединить
HRESULT GetConnectionInterface( [out] IID * pIID);
// get a pointer to identity of «real» object
// получаем указатель на копию «реального» объекта
HRESULT GetConnectionPointContainer([out] IConnectionPointContainer ** ppCPC);
// hold and use pUnkSink until notified otherwise
// сохраняем и используем pUnkSink, пока не объявлено другое
HRESULT Advise([in] IUnknown * pUnkSink, [out] DWORD * pdwCookie);
// stop holding/using the pointer associated with dwCookle
// прекращаем хранение/использование указателя, связанного с dwCookie
HRESULT Unadvise([in] DWORD dwCookie);
// get information about currently held pointers
// получаем информацию об имеющихся в данный момент указателях
HRESULT EnumConnections([out] IEnumConnections ** ppEnum);
}
Как показано на рис. 7.9, объекты представляют отдельную реализацию этого интерфейса каждому типу интерфейса, который может быть использован объектом в качестве интерфейса обратного вызова. Ввиду того, что IConnectionPoint не выставлен как часть единицы идентификации объекта, он не может быть обнаружен посредством QueryInterface. Вместо этого в СОМ предусмотрен второй интерфейс, который выставлен как часть единицы идентификации объекта, которая позволяет клиентам запрашивать реализацию IConnectionPoint, соответствующую отдельному типу интерфейса обратного вызова:
[object,uuid(B196B284-BAB4-101A-B69C-00AA00341D07)]
interface IConnectionPointContainer : IUnknown {
// get all possible IConnectionPoint implementations
// получаем все возможные реализации IConnectionPoint
HRESULT EnumConnectionPoints([out] IEnumConnectionPoints ** ppEnum);
// get the IConnectionPoint implementation for riid
// получаем реализацию IConnectionPoint для riid
HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint ** ppCP);
}
Как показано на рис. 7.9, каждая реализация IConnectionPoint выставляется из отдельной СОМ-единицы идентификации.
С учетом вышеупомянутых определений интерфейса клиент мог бы связать свою реализацию IShutdownNotify с объектом следующим образом:
HRESULT HookupShutdownCallback(IUnknown *pUnkObject,
IShutdownNotify *pShutdownNotify,
DWORD &rdwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Advise(pShutdownNotify, &rdwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Соответствующий код для разрыва связи выглядит так:
HRESULT TeardownShutdownCallback(IUnknown *pUnkObject, DWORD dwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Unadvise(dwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Отметим, что в обоих примерах клиент использует метод IConnectionPointContainer::FindConnectionPoint для вызова из объекта его IShutdownNotify-реализации IConnectionPoint. Если объект отклоняет вызов FindConnectionPoint, это говорит о том, что он не понимает семантику интерфейса IShutdownNotify. Это оберегает пользователя от прикрепления произвольных интерфейсов обратного вызова к объекту без полного согласия на это разработчика объекта.
Как и в случае с IUnknown, реализации IConnectionPointContainer и IConnectionPoint в значительной степени типичны. Объекту C++ требуется отдельная единица идентификации СОМ для каждого типа экспортируемого интерфейса, который он предполагает поддерживать. Одна из методик реализации ConnectionPoint состоит в использовании того варианта методики вложения класса/композиции, которая учитывает различия в отношениях тождественности:
class Surfboard : public ISurfboard,
public IHazardousDevice,
public ISharkBait,
public IConnectionPointContainer {
LONG m_cRef; // СОM reference count
// счетчик ссылок СОМ
// Surfboards don't support multiple outbound interfaces
// of a given type, so it simply declares single pointers
// of each possible type of callback interface
// Surfboard не поддерживает несколько экспортируемых
// интерфейсов заданного типа, поэтому он просто
// объявляет одиночные указатели каждого возможного
// типа интерфейса обратного вызова
IShutdownNotify *m_pShutdownNotify;
ISurfboardUser *m_pSurfer;
// to deal with identity relationship of IConnectionPoint,
// define an IShutdownNotify-specific nested class + member
// для работы с отношением тождественности
// IConnectionPoint, определяем специфический для
// IShutdownNotify вложенный класс+член
class XCPShutdownNotify : public IConnectionPoint {
Surfboard *This(void);
// use fixed offset
// испопьзуем постоянное смещение
// IUnknown methods...
// методы IUnknown...
// IConnectionPoint methods...
// методы IConnectionPoint...
} m_xcpShutdownNotify;
// define an ISurfboardUser-specific nested class + member
// определяем специфический для IShutdownNotify вложенный класс+член
class XCPSurfboardUser : public IConnectionPoint {
Surfboard *This(void);
// use fixed offset
// используем постоянное смещение
// IUnknown methods...
// методы IUnknown...
// IConnectionPoint methods...
// методы IConnectionPoint...
} m_xcpSurfboardUser;
// IUnknown methods...
// методы IUnknown...
// ISurfboard methods...
// методы ISurfboard...
// IHazardousDevice methods...
// методы IHazardousDevice...
// ISharkBait methods...
// методы ISharkBait...
// IConnectionPointContainer methods...
// методы IConnectionPointContainer...
};
Следует указать, что экземпляры класса Surfboard будут иметь две отдельные реализации IConnectionPoint, одна из которых используется для присоединения интерфейсов обратного вызова IShutdownNotify, а вторая – для присоединения интерфейсов ISurfboardUser. Эти две реализации разделены на отдельные классы C++, что позволяет каждой реализации IConnectionPoint иметь свои собственные уникальные реализации IUnknown и IConnectionPoint. В частности, может иметься три отдельных реализации QueryInterface со своими собственными наборами интерфейсных указателей, которые могут быть выделены для создания трех отдельных СОМ-копий.
Из приведенного выше определения класса следует такая QueryInterface-peaлизация основного класса Surfboard:
STDMETHODIMP Surfboard::QueryInterface(REFIID riid, void**ppv)
{
if (riid == IID_IUnknown || riid == IID_ISurfboard)
*ppv = static_cast(this);
else if (riid == IID_IHazardousDevice)
*ppv = static_cast< IHazardousDevice *>(this);
else if (riid == IID_ISharkBait)
*ppv = static_cast(this);
else if (riid == IID_IConnectionPointContainer)
*ppv = static_cast(this);
else
return (*ppv = 0), E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
Отметим, что доступ к интерфейсу IConnectionPoint не может быть осуществлен через эту главную реализацию QueryInterface. Каждый из методов QueryInterface вложенного класса будет выглядеть примерно так:
STDMETHODIMP Surfboard::XCPShutdownNotify::QueryInterface(REFIID riid, void**ppv)
{
if (riid == IID_IUnknown || riid == IID_IConnectionPoint)
*ppv = static_cast(this);
else
return (*ppv = 0), E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
Эту же реализацию можно было бы применить и к классу XCPSurfboardUser. Между объектом Surfboard и двумя подобъектами, которые реализуют интерфейс IConnectionPoint не существует идентичности.
Для того чтобы объект Surfboard не уничтожил себя раньше времени, подобъекты администратора соединений просто делегируют вызовы своих методов AddRef и Release в содержащий их объект surfboard:
STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::AddRef(void)
{
return This()->AddRef();
/* AddRef containing object */
/* AddRef объекта-контейнера */
}
STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::Release(void)
{
return This()->Release();
/* Release containing object */
/* Release объекта-контейнера */
}
В приведенных выше методах предполагается, что метод This возвращает указатель на объект-контейнер Surfboard, используя вычисление некоторого постоянного смещения.
Клиенты находят интерфейсы объекта IConnectionPoint посредством вызова метода объекта FindConnectionPoint, который для класса Surfboard мог бы выглядеть примерно так:
STDMETHODIMP Surfboard::FindConnectionPoint(REFIID riid, IConnectionPoint **ppcp)
{
if (riid == IID_IShutdownNotify)
*ppcp = IID_IShutdownNotify;
else if (riid == IID_ISurfboardUser)
*ppcp = &m_xcpSurfboardUser;
else
return (*ppcp = 0), CONNECT_E_NOCONNECTION;
(*ppcp)->AddRef();
return S_OK;
}
Отметим, что объект выдает интерфейсные указатели IConnectionPoint только при запросе тех интерфейсов, на которые он сможет сделать обратный запрос. Необходимо указать также на поразительное сходство с большинством реализации QueryInterface. Основное различие состоит в том, что QueryInterface имеет дело с импортируемыми (inbound) интерфейсами, в то время как FindConnectionPoint – с экспортируемыми (outbound) интерфейсами.
Поскольку метод IConnectionPoint::Advise принимает только интерфейс IUnknown, статически типизированный как интерфейсный указатель обратного вызова [1] , то реализации Advise должны использовать QueryInterface для того, чтобы привязать указатель обратного вызова к соответствующему типу интерфейса:
STDMETHODIMP Surfboard::XCPShutdownNotify::Advise(IUnknown *pUnk, DWORD *pdwCookie)
{
assert (pdwCookie && pUnk);
*pdwCookie = 0;
if (This()->m_pShutdownNotify) // already have one
// уже имеем один
return CONNECT_E_ADVISELIMIT;
// QueryInterface for correct callback type
// QueryInterface для корректирования типа обратного вызова
HRESULT hr = pUnk->QueryInterface(IID_IShutdownNotify,
(void**)&(This()->m_pShutdownNotify));
if (hr == E_NOINTERFACE)
hr = CONNECT_E_NOCONNECTION;
if (SUCCEEDED(hr)) // make up a meaningful cookie
// готовим значимый маркер
*pdwCookie = DWORD(This()->m_pShutdownNotify);
return hr;
}
Напомним, что QueryInterface неявно вызывает AddRef, что означает следующее: объект Surfboard теперь хранит ссылку обратного вызова, причем она остается легальной за пределами области действия метода Advise. Отметим также, что если объект обратного вызова не реализует соответствующий интерфейс, то результирующий HRESULT преобразуется в CONNECT_E_NOCONNECTION. Если же сбой QueryInterface последовал по какой-либо иной причине, то HRESULT от QueryInterface передается вызывающей программе [2] .
Основанный на приведенной выше реализации Advise соответствующий метод Unadvise имеет следующий вид:
STDMETHODIMP Surfboard::XCPShutdownNotify::Unadvise(DWORD dwCookie)
{
// ensure that the cookie corresponds to a valid connection
// убеждаемся, что маркер соответствует допустимому соединению
if (DWORD (This()->m_pShutdownNotify) != dwCookie)
return CONNECT_E_NOCONNECTION;
// release the connection
// освобождаем соединение
This()->m_pShutdownNotify->Release();
This()->m_pShutdownNotify = 0;
return S_OK;
}
В интерфейсе IConnectionPoint имеется три дополнительных вспомогательных метода, два из которых реализуются тривиально:
STDMETHODIMP Surfboard::XCPShutdownNotify::GetConnectionInterface( IID *piid)
{
assert (piid);
// return IID of the interface managed by this subobject
// возвращаем IID интерфейса, управляемого этим подобъектом
*piid = IID_IShutdownNofify;
return S_OK;
}
STDMETHODIMP Surfboard::XCPShutdownNotify::GetConnectionPointContainer(
IConnectionPointContainer **ppcpc)
{
assert(ppcpc);
(*ppcpc = This())->AddRef();
// return containing object
// возвращаем объект-контейнер
return S_OK;
}
Последний из этих трех методов, EnumConnections, позволяет вызывающим программам перенумеровывать соединенные интерфейсы. Данный метод является дополнительным, так что реализации могут законно возвращать E_NOTIMPL.
Для объявления о том, какие из экспортируемых интерфейсов класс реализации поддерживает, в IDL предусмотрен атрибут [source]:
[uuid(315BC280-DEA7-11d0-8C5E-0080C73925BA) ]
coclass Surfboard {
[default] interface ISurfboard;
interface IHazardousDevice;
interface ISharkBait;
[source] interface IShutdownNotify;
[source, default] interface ISurfboardUser;
}
Кроме этого, в СОМ предусмотрено два интерфейса, которые позволяют средам этапа выполнения запрашивать объект самостоятельно (introspectively) возвращать информацию об импортируемых в него и экспортируемых им типах интерфейсов:
[object,uuid(B196B283-BAB4-101A-B69C-00AA00341D07) ]
interface IProvideClassInfo : Unknown {
// return description of object's coclass
// возвращаем описание кокласса объекта
HRESULT GetClassInfo([out] ITypeInfo ** ppTI);
}
[object, uuid(A6BC3AC0-DBAA-11CE-9DE3-00M004BB851) ]
interface IProvideClassInfo2 : IProvideClassInfo {
typedef enum tagGUIDKIND {
GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
} GUIDKIND;
// return IID of default outbound dispinterface
// возвращаем IID принятого по умолчанию экспортируемого диспинтерфейса
HRESULT GetGUID([in] DWORD dwGuidKind, [out] GUID * pGUID);
}
Оба этих интерфейса весьма просты для реализации:
STDMETHODIMP Surfboard::GetClassInfo(ITypeInfo **ppti)
{
assert(ppti != 0);
ITypeLib *ptl = 0;
HRESULT hr = LoadRegTypeLib(LIBID_BeachLib, 1, 0, 0, &ptl);
if (SUCCEEDED(hr)) {
hr = ptl->GetTypeInfoOfGuid(CLSID_Surfboard, ppti);
ptl->Release();
}
return hr;
}
STDMETHODIMP Surfboard::GetGUID (DWORD dwKind, GUID *pguid)
{
if (dwKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID || !pguid)
return E_INVALIDARG;
// ISurfboardUser must be defined as a dispinterface
// ISurfboardUser должен быть определен как диспинтерфейс
*pguid = IID_ISurfboardUser;
return S_OK;
}
Хотя экспортируемые интерфейсы не должны быть обязательно диспетчерскими интерфейсами (диспинтерфейсами), но ряд сред сценариев требуют этого, чтобы осуществлять естественное преобразование обратных вызовов в текст сценария.
Предположим, что интерфейс ISurfboardUser определен как диспинтерфейс следующим образом:
[uuid(315BC28A-DEA7-11d0-8C5E-0080C73925BA)]
dispinterface ISurfboardUser {
methods:
[id(1)] void OnTiltingForward( [in] long nAmount);
[id(2)] void OnTiltingSideways( [in] long nAmount);
}
При программировании на Visual Basic можно объявить переменные, понимающие тип интерфейса обратного вызова, принятый по умолчанию, таким образом:
Dim WithEvents sb as Surfboard
Наличие такого описания переменной дает программистам на Visual Basic возможность писать обработчики событий. Обработчики событий – это функции или подпрограммы, использующие соглашение VariableName_EventName. Например, для обработки события обратного вызова ОпТiltingForward на определенную выше переменную sb программисту Visual Basic пришлось бы написать следующий код:
Sub sb_OnTiltingForward(ByVal nAmount as Long)
MsgBox «The surfboard just tilted forward»
End Sub
Виртуальная машина Visual Basic будет действительно на лету обрабатывать реализацию ISurfboardUser, преобразуя поступающие вызовы методов в соответствующие определенные пользователем подпрограммы.
Опубликовал Kest July 13 2009 17:43:07 · 0 Комментариев · 6918 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
PHP 5. Практика с...
Динамические за...
Exe in exe
Delphi7 Для профе...
IPAddresseEdit
Х. М. Дейтел, П. ...
Abbrevia
StartMark
Последние загруж...
KOL & MCK v1.69
Visual Basic Script
Globus VCL Extent...
Пример клиента ФТ...
VFW
SODA [Исходник на...
Библия хакера 2. ...
Delphi 2005 для .NET
Род Стивенс. Delp...
DAlarm
Borland Delphi 8 ...

Топ загрузок
Приложение Клие... 100466
Delphi 7 Enterp... 86635
Converter AMR<-... 20077
GPSS World Stud... 12649
Borland C++Buil... 11759
Borland Delphi ... 8556
Turbo Pascal fo... 7037
Visual Studio 2... 4998
Калькулятор [Ис... 4760
FreeSMS v1.3.1 3541
Случайные статьи
Технические средст...
Открытые файлы и о...
Обучение программи...
Иерархия классов
Числовые SQL-функц...
Метаданные. Исполь...
Технология Android...
ОПЕРАТОРЫ ОПИСАНИЯ...
4.5. РЕШЕНИЕ: СПЕЦ...
Главная идея Томпсона
Именаучетных запис...
Какие ещё варианты...
Используйте (ГАК д...
превышает реальный...
Опции программы «T...
Функция Port Security
Фильтр "не(...)"
Типовой проект обл...
Металлические дета...
Повышение информац...
По поводу отчислен...
Структура распрост...
Проектирование стр...
ХАЛЯВНЫЙ NET(2)
Оформление курсовой
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?