Лекция 1 Введение в современные технологии программирования
Вид материала | Лекция |
СодержаниеIFormattedNumber = interface Автоматическое управление памятью и подсчет ссылок Объявление интерфейсов Интерфейс lUnknown |
- Лекция №1. Введение, 878.61kb.
- Планы лекций по дисциплине б. 5 Педагогические технологии для специальности/направления, 24kb.
- Лекция 3 Инструментальное по. Классификация языков программирования, 90.16kb.
- Лекция Языки и системы программирования. Структура данных, 436.98kb.
- Лекция Основы программирования Эта лекция введение в Visual Basic for Applications,, 208.31kb.
- Дисциплины, 51.33kb.
- Рабочая программа учебной дисциплины (модуля) Технологии параллельного программирования, 79.5kb.
- Технологии программирования, 30.41kb.
- Лекция 6 Введение в объекты, 370.28kb.
- Программа курса (Syllabus) по дисциплине «технологии программирования» для студентов, 475.21kb.
IFormattedNumber = interface
['{2DE825C1-EADF-11D2-B39F-0040F67455FE}']
function FormattedString: string;
end;
то следующие два объявления приведут к одному и тому же результату:
MyGuid := ['{2DE825C1-EADP-11D2-B39F-0040F67455FE}']
MyGuid *TGUID =[Dl: $2DE825C1; D2: $EADF; D3: $11D2; D4: ($B3, $9F, $00, $40, $F6, $74,$55,$FE}]
Естественно, вариант, представленный в первой строке, читается гораздо легче. Объявление интерфейса — это только первый шаг. После того как интерфейс объявлен, нужно позаботиться о его реализации. Как это делается, мы рассмотрим в следующем разделе.
Автоматическое управление памятью и подсчет ссылок
Кроме предоставления независимого от языка программирования доступа к методам объектов, СОМ реализует автоматическое управление памятью для СОМ-объектов. Оно основано на идее подсчета ссылок на объект. Любой клиент, которому требуется использовать СОМ-объект после его создания, должен вызвать заранее предопределенный метод, который увеличивает внутренний счетчик ссылок на объект на единицу. По завершении использования объекта клиент вызывает другой его метод, уменьшающий значение того же счетчика. При достижении счетчиком ссылок нулевого значения СОМ-объект автоматически удаляет себя из памяти. Такая модель позволяет клиентам не вдаваться в подробности реализации объекта, а объекту — обслуживать несколько клиентов и корректно очистить память по завершении работы с последним из них.
Объявление интерфейсов
Для поддержки интерфейсов Delphi расширяет синтаксис языка Pascal дополнительными ключевыми словами. Объявление интерфейса в Delphi реализуется с помощью ключевого слова interface:
type
IMyInterface = interface
[‘{412AFFOO-5C21-11D4-84DD-C8393F763A13}']
procedure DoSomething(var I: Integer); stdcall;
function DoSomethingAnother(S: String): Boolean;
end;
IMyInterface2 = interface (IMyInterface)
[‘{412AFF01-5C21-11D4-84DD-C8393F763A13}’]
procedure DoAdditional(var I: Integer): stdcall;
end:
Для генерации нового значения GUID в среде разработки Delphi используется сочетание клавиш Ctrl+Shift+G.
Интерфейс lUnknown
Базовым интерфейсом в модели СОМ является интерфейс IUnknown. Любой другой интерфейс наследуется от IUnknown и должен реализовать объявленные в нем методы. Интерфейс IlUnknown объявлен в модуле System.pas следующим образом:
type
lUnknown - interface
['{00000000-0000-0000-С000-000000000046}‘]
function QueryInterface(const IID: TGUID; out Obj ): HResult; stdcall:
function _AddRef: Integer: stdcall:
function _Re1ease: Integer: stdcall;
end;
На уровне интерфейса IUnknown, который является предком для всех интерфейсов, уже реализовано корректное решение проблемы резервирования и освобождения ресурсов операционной системы. Напомним эту проблему: если в каком-нибудь модуле были затребованы ресурсы операционной системы, то их нельзя возвратить системе в другом модуле.
Для начала вспомним, каким образом происходит резервирование и возвращение системных ресурсов при работе с классами. При создании экземпляра класса вызывается его конструктор, который получает у системы все необходимые ему ресурсы. После того как рабочая копия становится ненужной, вызывается деструктор объекта. При этом если все реализовано корректно, ресурсы вновь возвращаются системе.
Методы интерфейса, как будет показано ниже, также реализуются в классах. Однако описанную выше методику применить в этом случае невозможно. Если в интерфейсе будет определен метод Destroy, который непосредственно обращается к деструктору, то при попытке вызвать его из модуля, где была получена ссылка на интерфейс, произойдет исключение. Это связано с тем, что различные модули, даже реализованные на одном языке программирования, имеют собственные менеджеры памяти, и освобождение ресурсов должно происходить в рамках того модуля, в котором они были востребованы.
И еще следует принять во внимание, что один и тот же интерфейс может быть затребован одновременно несколькими клиентами. Например, пусть два клиентских приложения одновременно работают с Microsoft Word. Если производить освобождение ресурсов интерфейса тем же способом, что и освобождение ресурсов класса, то первое клиентское приложение просто закроет Word. Второе, в общем случае, не будет уведомлено об этом, поэтому оно сохранит ссылку на несуществующий объект. Нетрудно догадаться, что произойдет в этом случае при попытке вызвать методы этого объекта.
Для решения этих проблем в интерфейсах при их реализации осуществляется подсчет ссылок. Специально для подсчета ссылок во всех интерфейсах имеются методы AddRef и Release. Метод AddRef при реализации обязан увеличивать счетчик внутренней переменной. «Обязан» потому, что реализация методов интерфейсов возложена на разработчика, который создает СОМ-сервер. Он может этого и не сделать, но тогда интерфейс будет работать некорректно. Соответственно, метод Release обязан уменьшать этот счетчик. Кроме того, этот метод должен проверять, равен ли счетчик ссылок нулю, и если равен, вызывать деструктор объекта, в котором реализован интерфейс.
Теперь все становится на свои места. Когда клиент требует ссылку на интерфейс, клиентом в адресном пространстве сервера создается объект, резервируются ресурсы и вызывается метод AddRef. Клиент напрямую не вызывает этот метод — он вызывается при выполнении метода QueryInterface, о нем речь — чуть ниже. Если другой клиент затребует тот же самый интерфейс, то чаще всего увеличивается счетчик ссылок на уже имеющийся объект, и указатель передается второму клиенту (допустима ситуация, когда создается вторая копия объекта в памяти, но счетчик ссылок в обеих копиях остается равным единице). Соответственно, когда клиенту уже не нужен интерфейс, он вызывает метод Release. Этот метод уменьшает счетчик ссылок на единицу. Одновременно проверяется, равен ли счетчик ссылок нулю, и если равен, вызывается деструктор объекта.
Вызов деструктора происходит из сервера — поэтому ресурсы освобождаются корректно. В вышеприведенном примере счетчик ссылок становится равным нулю при вызова метода Release обоими клиентами.
Интерфейс IUnknown содержит также метод QueryInterface, который используется для получения клиентом ссылок на интерфейс. Клиент вызывает QueryInterface интерфейса IUnknown сервера и указывает идентификатор (Interface Identifier — идентификатор интерфейса) того интерфейса, ссылку на который он хочет получить (IID — это тот же самый тип данных, что и GUID, и применяется он для идентификации интерфейсов). Как получить ссылку на интерфейс IUnknown сервера, будет рассмотрено позднее при описании интерфейса IC1assFactory. Метод QueryInterface обязан проверять все идентификаторы IID, интерфейсов, реализованные в данном классе многокомпонентного объекта (CoClass, СОМ-класс). Если будет найден совпадающий идентификатор IID, то метод QueryInterface обязан сделать следующее.
1. Вызвать конструктор, если не был создан экземпляр класса, в котором реализован интерфейс.
2. Вызвать метод AddRef для затребованного интерфейса и тем самым увеличить счетчик ссылок на 1. Иногда для группы интерфейсов реализуется общий счетчик ссылок.
3. Поместить указатель на созданный (или имеющийся) объект, в котором реализован интерфейс, в нетипиэированную переменную Р.
4. Возвратить результат S_OK.
Если же интерфейс с данным идентификатором IID не поддерживается, то в нетипизированную переменную Р возвращается nil, и результат вызова должен быть равен E_NOINTERFACE. Метод Querylnterface может быть реализован, например следующим образом:
function TMyClassFactory.QueryInterface(const iid: TIID; var Р): HResult;
begin
if IsEqualIID(iid, IID_ICIassFactory) or
IsEqualIID(iid, IID_IUnknown) then
begin
Pointer(P) := Self:
AddRef:
Result := S_OK;
end
else
begin
Pointer(P) := nil;
Result := E_NOINTERFACE;
end:
end:
В принципе, в конкретной реализации методы интерфейса IUnknown могут содержать и какую-либо другую функциональность, отличающуюся от стандартной, однако делать этого не рекомендуется, поскольку в этом случае интерфейс будет несовместим с моделью СОМ.
Контрольные вопросы
- Что такое компонент? Чем он отличается от класса?
- Что такое интерфейс?
- Какие формы представления интерфейса вы знаете?
- Чем полезен интерфейс?
- Каково назначение COM? Какие преимущества дает использование COM?
- Чем COM-объект отличается от обычного объекта?
- Что должен иметь клиент для использования методов COM-объекта?
- Как идентифицируется COM-интерфейс?
- Как описывается COM-интерфейс?
- Как реализуется COM-интерфейс?
- Чего нельзя делать с COM-интерфейсом? Обоснуйте ответ.
- Объясните назначение и применение метода QueryInterface?
- Объясните назначение и применение методов AddRef и Release?
- Что такое сервер COM-объекта и какие типы серверов вы знаете?
- В чем назначение библиотеки COM?
- Как создается одиночный COM-объект?
- Как создается несколько COM-объектов одного и того же класса?
- Как обеспечить использование нового COM-класса старыми клиентами?
- В чем состоит особенности повторного использования COM-объекта?
- Какие требования предъявляет агрегация к внутреннему COM-объекту?
- Что такое маршалинг и демаршалинг?
- Поясните назначение посредников и заглушки.
- Зачем нужна библиотека типа и как она описывается?
Литература
- Вельбицкий И.В. Технология программирования. –К.: Техніка, 1984. – 279 с., ил. – (Б-ка инженера). – Библиогр.: с. 274 – 277.
- Давид Чеппел. Технология ActiveX и OLE/Пер. с англ.. – М: Издательский отдел „Русская Редакция” ТОО „Channel Trading Ltd.@, 1997. – 320 с.: ил.
- Орлов С.А. Технология разработки программного обеспечения: Учебник. – СПб.: Питер, 2002. – 464 с.: ил.
- Шеферд Джордж. Программирование на Microsoft Visual C++.NET. Мастер-класс./Пер. с англ. – 2-е изд. – М.: Издательско-торговый дом «Русская Редакция»; СПб.: Питерб 2005. – 928 стр.: ил.