Batman Header
Batman Header 2

Главная Игры и Демосцены Наш топ 100 Вся база игр Гостевая книга Страницы сайта Помощь Музыка Поиск


Музыкальные демо 48-128*** Игры 48-128*** Электронные журналы*** Утилиты



ZX-Spectrum Sinclair Qaop JS online games
F1 TORNADO



ZX-Spectrum Sinclair Qaop JS online games
JUMP



ZX-Spectrum Sinclair Qaop JS online games
Defcom
1-15 16-20
Книги в PDF и др [11]Разное [52]Дэвид КАН ВЗЛОМЩИКИ КОДОВ [27]АССЕМБЛЕР [29]
Основы СОМ 2-е издание, исправленное и переработанное Дейл Роджерсон [20]Рождение хакера Линус Торвальдс [19]Лев Николаевич Толстой [36]М.Е.Салтыков-Щедрин [12]
Сергей Михайлович Соловьев [2]П.Я.Чаадаев [3]Л. А. Чарская [9]В.РОПШИН (Б.САВИНКОВ) [3]
Слепцов В. А. [2]В. А. Соллогуб [4]Федор Сологуб [12]Всеволод Сергеевич Соловьев [4]

Введение Вы никогда не хотели изменить свою программу или добавить к ней что-нибудь новое уже после того, как она стала готовым продутом? Хотели бы Вы разрабатывать свои программы, постепенно расширяя их, а не переписывая заново каждые два года? Хотелось бы Вам, чтобы они проще настраивались? Были более гибкими и динамичными? Вы бы хотели ускорить разработку? А если Вам нужно разрабатывать распределенные приложения — Вы бы хотели писать их так же, как и обычные? Вы интересуетесь компонентным программированием? Вы хотите разделить свое приложение на компоненты? Вы хотите изучить COM? А OLE Автоматизацию? У Вас есть опыт безуспешных попыток изучения OLE? Вы находите, что COM и OLE трудны? Хотелось бы Вам понять основы технологий Microsoft, таких как ActiveX, DirectX и OLE? Вам нужно расширять или настраивать приложения или операционные системы Microsoft? Если хотя бы на один из вопросов Вы ответили «да» — эта книга для Вас! Все эти вопросы связаны с одной технологией: моделью компонентных объектов Microsoft, более известной как COM (Component Object Model).

Основы СОМ 2-е издание, исправленное и переработанное Дейл Роджерсон | Просмотров: 294 | Дата: 02.11.2013 | Комментарии (0)

Пример программы Tangram


Почему появилась эта книга? Изучали ли Вы физику в школе? Если Вам преподавали физику, пользуясь элементами высшей математики, то знание последних было необходимым предварительным требованием. Изучая математический анализ, Вы учились применять его в разных областях. Только изучив и поняв дифференциальное исчисление как таковое, Вы смогли использовать его для решения физических задач. Такая последовательность обучения существовала не всегда. Сначала Исаак Ньютон изобрел дифференциальное исчисление как инструмент классической механики и динамики. Только позднее стало ясно, что этот мощный инструмент имеет приложения и за границами физики. Связь между COM и OLE во многом похожа на связь высшей математики с физикой. Как дифференциальное исчисление было изобретено для решения физических задач, так и модель СОМ была разработана для решения проблемы «внедрения» электронной таблицы в текстовый редактор. Решение этой проблемы стало известно под именем OLE. Есть множество книг по OLE, но не по СОМ. Первая, лучшая и наиболее полная книга по OLE — книга Крейга Брокшмидта Inside OLE.


Компоненты Обычно приложение состоит из одного монолитного двоичного файла. После того, как приложение сгенерировано компилятором, он остается неизменным — пока не будет скомпилирована и поставлена пользователю новая версия. Чтобы учесть изменения в операционных системах, аппаратуре и желаниях пользователей, приходится ждать перекомпиляции. Приложение застывает, подобно скале посреди реки перемен. И по мере того, как вся индустрия программирования стремительно уходит все дальше в будущее, оно стареет — и устаревает. При современных темпах развития индустрии программирования приложениям нельзя оставаться застывшими. Разработчики должны найти способ вдохнуть новую жизнь в программы, которые уже поставлены пользователям.


От автора Когда я учился в Технологическом институте Джорджии, мои однокурсники часто шутили насчет той известности, которую им приносили (или, точнее, не приносили) технические статьи. Обычно эти статьи подписывали три автора. Первым шел профессор — руководитель студента. Сразу за ним следовал еще один профессор. Этот второй, иронизировали мы, не имел к статье абсолютно никакого отношения, но ему нужны были печатные работы («публикуйся или пропадешь»). Фамилия же скромного дипломника, который и проделал всю работу, шла последней, как бы между прочим. В отличие от тех статей, на обложке этой книги значится только одно имя — мое.


Интерфейс Несколько лет назад «космический челнок» «Атлантис» состыковался с российской орбитальной станцией «Мир». Американцы установили на свой корабль российский стыковочный узел, подходящий к соответствующему узлу станции. Только представьте, что Вы могли бы сделать с таким стыковочным узлом! Его можно установить на Вашем доме, и туда мог бы пристыковаться космический корабль. Вы могли бы установить этот узел на старый «Фольксваген», на башню «Космическая игла» в Сиэтле или на свой гараж — и «челнок» мог бы стыковаться и с ними. Пока узел не изменился и пока установлен на корабле, космический аппарат может стыковаться с чем угодно. Имея два узла, Вы могли бы пристыковать свой «Фольксваген» к дому, а не ставить его в гараж. Не правда ли, забавно! Стыковочный узел — это пример интерфейса (interface). Интерфейс обеспечивает соединение двух разных объектов. Хотя стыковочные узлы отлично соединяют друг с другом космические корабли, они не слишком годятся для соединения частей компьютерной программы. Для стыковки в компьютерных программах применяются наборы функций. Именно такие наборы и определяют интерфейс между разными частями программы. Интерфейс DLL — это набор функций, экспортируемых ею.


QueryInterface Вы – млекопитающее? > да У Вас две ноги? > нет У Вас длинные уши? > да Вы крупное животное? > нет Вы кролик? > да Тот, кто достаточно долго работает с компьютерами, вспомнит одну из первых компьютерных игр — «Угадай животное» (Animal). Эта простая маленькая программа демонстрировала, что компьютер может обучаться; она была чем-то вроде примитивной экспертной системы. Человек должен был задумать животное, компьютер задавал ему вопросы и пытался отгадать задуманное. Animal строила двоичное дерево, в концевых вершинах которого были названия животных, а в точках ветвления — вопросы. Программа проходила вниз по дереву, задавала вопросы, соответствующие узлам, и на основании Ваших ответов определяла, куда идти дальше. Дойдя до висячей вершины, она должна была отгадать животное. В случае ошибки программа задавала новый вопрос, по ответу на который можно было бы отличить задуманное животное от угаданного ею. Затем этот вопрос и имя нового животного добавлялись к дереву. В этой главе мы увидим, что клиент СОМ во многом напоминает программу Animal. Animal не знала, какое животное Вы задумали; клиент СОМ не знает, какие интерфейсы поддерживает компонент. Чтобы определить, поддерживается ли некоторый интерфейс, клиент запрашивает у компонента этот интерфейс во время выполнения. Это похоже на то, как программа Animal расспрашивала Вас о характерных чертах задуманного животного.


Подсчет ссылок В детстве я хотел стать пожарным. Романтика приключений и опасности привлекала меня, как и большинство мальчиков. Однако по-настоящему мне хотелось быть пожарным не потому. Дело в том, что, во-первых, пожарные ездили, повиснув сзади на пожарной машине (из-за этого я еще хотел стать мусорщиком, но это другая история). Во-вторых, у пожарных была по-настоящему крутая экипировка: металлические каски, высокие ботинки, большие плащи и кислородные баллоны. Я тоже хотел носить все эти замечательные вещи. Пожарные, казалось, никогда не расставались с ними. Даже если они всего лишь снимали кошку с дерева, то все равно делали это в касках, плащах и высоких ботинках. Пожарного было видно издалека. Класс С++ кое в чем напоминает пожарного. Заголовок сообщает всему миру, какие сервисы и функции предоставляет класс, — точно так же, как амуниция пожарных говорит об их профессии. Однако компоненты СОМ ведут себя совершенно иначе. Компонент СОМ гораздо более скрытен, чем пожарный или класс С++. Клиент не может посмотреть на компонент и сразу увидеть, что тот реализует пожарного. Вместо этого он должен выспрашивать: «Есть ли у Вас кислородный баллон? А топор? Носите ли Вы водонепроницаемую одежду?» На самом деле клиенту неважно, имеет ли он дело с настоящим компонентом-пожарным. Ему важно, что у компонента за «амуниция». Например, если клиент задает вопрос «Носите ли Вы водонепроницаемую одежду?», то его удовлетворят ответы не только пожарного, но и байдарочника, аквалангиста и лесоруба в непромокаемом плаще. На вопрос «Есть ли у Вас кислородный баллон?» утвердительно ответит пожарный и аквалангист. На следующий вопрос про топор положительный ответ даст уже только пожарный (или аквалангист-лесоруб, если такой найдется).


Динамическая компоновка Что же это получается? Еще в первой главе я говорил, как важна динамическая компоновка для построения системы из «кирпичиков». И вот мы добрались уже до пятой главы — и не только по-прежнему компонуем клиента с компонентом статически, но и располагаем их все время в одном и том же файле! На самом деле у меня были основательные причины отложить обсуждение динамической компоновки. Главная из них в том, что пока мы не реализовали полностью IUnknown, клиент был слишком сильно связан с компонентом. Сначала компонент нельзя было изменить так, чтобы не потребовалось изменять и клиент. Затем при помощи QueryInterface мы перешли на следующий уровень абстракции и представили компонент как набор независимых интерфейсов. Раздробив компонент на интерфейсы, мы сделали первый шаг к тому, чтобы раздробить монолитное приложение. Затем нам понадобился способ управления временем жизни компонента. Подсчитывая ссылки на каждый интерфейс, клиент управляет их временем жизни, компонент же сам определяет, когда ему себя выгрузить. Теперь, когда мы реализовали IUnknown, клиент и компонент связаны не титановой цепью, а тонкой ниткой. Столь непрочная связь уже не мешает компоненту и клиенту изменяться, не задевая друг друга. В этой главе мы попробуем поместить компонент в DLL. Обратите внимание — я не сказал, что мы собираемся сделать компонент DLL. Компонент — это не DLL, думать так значило бы слишком ограничивать концепцию компонента. DLL для компонента — сервер, или средство доставки. Компонент — это набор интерфейсов, которые реализованы в DLL. DLL — это грузовик, а компонент — груз. Чтобы познакомиться с динамической компоновкой, мы посмотрим, как клиент создает компонент, содержащийся в DLL. Затем мы возьмем листинг 4-1 из гл. 4 и разобьем его на отдельные файлы для клиента и компонента. Разобрав полученный код, мы создадим три разных клиента и три разных компонента, использующие разные комбинации трех интерфейсов. Для чего все это? В качестве грандиозного финала мы сконструируем компанию клиентов и компонентов, где каждый сможет общаться с каждым. Если Вы уже знакомы с DLL, то большая часть содержания этой главы Вам известна. Однако Вы можете полюбопытствовать, как я «растащу» клиент и компонент по разным файлам (раздел «Разбиваем монолит»). Надеюсь, Вам понравится сочетание разных клиентов и компонентов в разделе «Связки объектов» в конце главы.


HRESULT, GUID, Реестр и другие детали Дух братьев Райт все еще жив. Каждый год сотни людей в своих гаражах строят самолеты из наборов «Сделай сам». Они делают не пластиковые игрушки, радиоуправляемые модели или легковесные матерчатые конструкции. Они строят современные двухместные самолеты с полностью закрытой кабиной из современнейших композитных материалов. По правилам FAA* достаточно, чтобы производитель набора выполнил только 49% всей работы по постройке самолета. Оставшийся 51% конструктор-любитель делает сам. Постройка 51% самолета занимает, в зависимости от модели, примерно от 250 до 5000 часов. Большинство производителей предлагают наборы «для быстрого приготовления», в которых многие части уже собраны, например, сварены рамы и пропитаны детали из композитных материалов. Используя такие заготовки, можно быстро сделать нечто, похожее на самолет. Однако это будет еще далеко не настоящий самолет. Куча времени уходит на разные мелочи — установку панели управления и приборов, сидений, ремней безопасности, огнетушителей, покрытия, сигнализации, табличек, кабелей управления, электропроводки, лампочек, батарей, брандмауэров, вентиляционных люков, крыши пилотской кабины, отопителя, окон, замков и ручек на дверях и еще многого другого. Многие энтузиасты самолетостроения приходят в уныние, разочаровываются и даже бросают это занятие, потратив на сборку многие часы. Точно так же многие начинают изучать сложный предмет, например СОМ, лишь затем, чтобы захлебнуться в деталях и все бросить. В первых пяти главах книги я пытался максимально избегать подробностей, чтобы Вы сосредоточились на общей картине. В этой главе я собираюсь обсудить некоторые их тех деталей, которые раньше пропускал или скрывал. Я хочу рассмотреть и другие детали, которые понадобятся нам в следующих главах. Сначала мы обсудим HRESULT — тему, впервые возникшую в гл. 3 в связи с QueryInterface. Затем мы рассмотрим GUID. Один из примеров GUID — структура IID, передаваемая QueryInterface. После обсуждения этих типов мы познакомимся с тем, как компоненты публикуют в Реестре данные о своем местонахождении (это позволяет клиентам находить и создавать компоненты). В заключение мы рассмотрим некоторые полезные функции и утилиты библиотеки СОМ.


Фабрика класса Когда я был совсем маленьким и еще не собирался стать пожарным, я мечтал стать дизайнером наборов конструктора Lego. У меня были самые разные идеи относительно хитроумных новых деталей, из которых можно было бы строить потрясающие модели. Я даже послал несколько проектов в компанию (которая не стала запускать их в производство). Тем не менее, несмотря на отсутствие у фирмы интереса к моим новациям, сейчас я мог бы производить детали Lego прямо у себя в спальне. Уже появились машинки, которые называют трехмерными принтерами (3D-printers), — и это название очень им подходит. Они похожи на струйные принтеры, но выбрасывают тонкую струю пластика под давлением, а не чернила. Такой принтер наносит пластмассу слоями тоньше миллиметра. Повторная «печать» по одному и тому же месту позволяет создать сложные трехмерные объекты. Их можно использовать как прототипы или формы для изготовления деталей, а иногда и как готовые детали. С такой машинкой можно было бы организовать Домашнюю Фабрику Пластиковых Деталей. При помощи пакета САПР можно было бы в мгновение ока проектировать и производить новые детали. На такой домашней фабрике Вы могли бы сделать ту хитрую детальку с переходом 1x3, без которой никак не собиралась вся модель. Вообще у Вас больше не было бы недостатка в деталях — хотя компания Lego, вероятно, предпочла бы все же продавать Вам свои. В этой главе я собираюсь рассмотреть своего рода фабрику, на которой производятся не детали Lego, а компоненты. Эта фабрика класса — просто компонент с интерфейсом для создания других компонентов, так что обойдется она нам дешевле, чем трехмерный принтер за 50000 долларов. Но прежде чем заняться фабрикой класса, мы познакомимся с самым простым способом создания компонентов — при помощи функции CoCreateInstance.


Повторная применимость компонентов: включение и агрегирование Авторы статей в компьютерных журналах любят сравнивать СОМ с самыми разными вещами — например, миллионерами, горохом, С++ и компонентными архитектурами других фирм. Обычно в подобных статьях приводится какая-нибудь таблица вроде этой: Таблица 8-1 Гипотетическая таблица из компьютерного журнала Свойство Миллионеры Горох С++ СОМ Съедобны # # $ $ Поддерживают наследование # # # % Могут стать президентом # $ $ $ Вы можете не обратить внимания на то, что миллионеры съедобны. Однако, читая эти статьи, Вы не сможете упустить из виду, что СОМ не поддерживает наследования. Авторы, кажется, не обращают внимания на то, что СОМ поддерживает полиморфизм — самую важную концепцию объектно-ориентированного программирования, или что СОМ — небольшая, элегантная и быстро работающая модель, или что компоненты СОМ могут прозрачно работать по сети. Их не интересует и то, что СОМ не зависит от языка программирования; что компонентов СОМ написано больше, чем компонентов какого-либо другого типа. Их интересует только одно модное словцо — наследование! Поддерживает ли СОМ наследование? И да, и нет. То, что подразумевается в журнальных статьях — это наследование реализации, которое имеет место, когда класс наследует свой код или реализацию от базового класса.


Большая часть этого кода может показаться избыточной и ненужной. Но если внешний компонент сам агрегирован другим компонентом, выполнение описанных выше шагов становится критически важным. В примере из гл. 9 показан компонент, который агрегирует компонент, агрегирующий другой компонент. «Вот и все, что необходимо сделать для реализации агрегирования», — сказал он, улыбаясь. В действительности, после того, как Вы написали корректный код агрегирования, он работает отлично, и о нем можно забыть. Однако после первой попытки его написать многие начинают называть его не «aggregation», а «aggravation»*. Законченный пример Реализуем компонент, который агрегирует некий интерфейс. В данном примере Компонент 1 поддерживает два интерфейса, так же как и в примере с включением. Однако здесь он реализует только IX. Он не будет ни реализовывать IY, ни передавать его вызовы реализации этого интерфейса Компонентом 2. Вместо этого, когда клиент запрашивает у Компонента 1 интерфейс IY, Компонент 1 возвращает указатель на интерфейс IY, реализуемый внутренним Компонентом 2. В листинге 8-3 представлен внешний компонент, а в листинге 8-4 — внутренний. Клиент остался практически неизменным; ему совершенно неважно, используем ли мы агрегирование или включение.


Будем проще Что бы ни делал человек, он пытается максимально упростить задачу — особенно, кажется, это касается любых учебных упражнений, которые в результате могут полностью лишиться смысла. Телевидение наводняет реклама — и, похоже, успешная — тренажера для брюшного пресса и тому подобных приспособлений. Такой тренажер механизирует одно из простейших упражнений, облегчая его выполнение до предела. (Как говорят, главное достоинство тренажера в том, что он позволяет сконцентрировать усилия на мышцах живота, а не шеи или чего- нибудь еще. Как знать…) Поскольку все хотят упростить себе жизнь, я поддамся общей тенденции и упрощу использование компонентов СОМ. Писать их сложнее, чем тренировать мышцы живота, и, надо сказать, компоненты не становятся ни лучше, ни красивее, если на их создание потратить больше усилий. Сначала при помощи классов С++ мы сделаем использование компонентов СОМ более похожим на использование классов; затем разработаем несколько классов, облегчающих разработку компонентов. Упрощения на клиентской стороне Большинство из Вас не надо убеждать, что использовать компоненты СОМ вовсе не так просто, как обычные классы С++. Во-первых, необходимо подсчитывать ссылки. Если Вы забыли вызвать AddRef для указателя на интерфейс, можете сразу прощаться с выходными. Если ссылки подсчитываются неправильно, программа может попытаться работать с интерфейсом уже удаленного компонента, что кончится сбоем. Найти пропущенный вызов AddRef или Release нелегко. Хуже того, при каждом новом запуске программы компонент может освобождаться в разных точках. Хотя мне доставляет настоящее удовольствие отлавливать трудновоспроизводимые ошибки (в обществе нескольких друзей и пиццы), не многие, кажется, разделяют эту радость.


Реализация интерфейса INondelegatingUnknown в классе CUnknown аналогична той, что была дана для агрегируемого компонента в гл. 8. Конечно, CUnknown не может заранее знать, какие интерфейсы будут реализованы производными компонентами. Как мы увидим ниже, чтобы добавить код для предоставляемых ими интерфейсов, компоненты должны переопределить функцию NondelegatingQueryInterface. Реализация CUnknown находится в файле CUNKNOWN.CPP на прилагающемся к книге диске. Мы не будем изучать этот код целиком. Однако позвольте кратко рассмотреть еще несколько важных моментов.


1-15 16-20
All rights reserved True Edition © 2011-2018
·ZX-Spectrum Sinclair JS online games
Хостинг от uCoz