<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Клуб программистов::Программироваем на Borland Delphi 7</title>
		<link>http://delphi.ucoz.kz/</link>
		<description></description>
		<lastBuildDate>Wed, 08 Dec 2010 04:39:49 GMT</lastBuildDate>
		<generator>uCoz Web-Service</generator>
		<atom:link href="https://delphi.ucoz.kz/news/rss" rel="self" type="application/rss+xml" />
		
		<item>
			<title>Создание WebSnap-сервера</title>
			<description>WebSnap представляет собой набор компонент, появившийся в Delphi 6 Enterprise и предназначенный для разработки Web-серверных приложений в RAD-среде. В настоящей статье дано краткое описание создания WebSnap-сервера, поддерживающего полный интерфейс редактирования и просмотра для простого набора данных, и включающий поддержку графических полей. Хотя данный WebSnap-сервер является &quot;простым&quot;, т.к. не требует написания кода, он, тем не менее, поддерживает полный набор функциональных возможностей для модификации таблиц базы данных с помощью браузера.</description>
			<content:encoded>WebSnap представляет собой набор компонент, появившийся в Delphi 6 Enterprise и предназначенный для разработки Web-серверных приложений в RAD-среде. В настоящей статье дано краткое описание создания WebSnap-сервера, поддерживающего полный интерфейс редактирования и просмотра для простого набора данных, и включающий поддержку графических полей. Хотя данный WebSnap-сервер является &quot;простым&quot;, т.к. не требует написания кода, он, тем не менее, поддерживает полный набор функциональных возможностей для модификации таблиц базы данных с помощью браузера. &lt;br&gt;&lt;br&gt;Итак, начнем&lt;br&gt;&lt;br&gt;Создание WebSnap-сервера&lt;br&gt;&lt;br&gt;Сначала следует вызвать новую панель инструментов WebSnap, с помощью которой будет значительно удобнее создавать WebSnap-приложение. Это можно сделать, щелкнув правой кнопкой мыши по панелям инструментов в интегрированной среде разработки (IDE) Delphi 6 Enterprise и выбрав панель инструментов &quot;Internet&quot;. После этого, на экране отобразится следующее: &lt;br&gt;&lt;br&gt;Первый значок (изображение руки, держащей глобус) используется для создания нового WebSnap-приложения. Если щелкнуть по нему мышью, то на экране отобразится мастер WebSnap. Теперь зададим имя для нашей главной страницы. Кроме того, следует создать приложение Web App Debugger (Отладчик Web-приложений), которое позволит использовать специальный Web-сервер (написанный в Delphi), поставляемый вместе с Delphi 6 Pro и Enterprise. Назовем данный сервер BasicDemo. &lt;br&gt;&lt;br&gt;После нажатия кнопки OK на экране отобразится стандартная форма Delphi (позволяющая узнать, запущен ли Web-сервер), а также WebModule, включающий компоненты, которые будут использоваться главной страницей. Компоненты, входящие в данный Web-модуль, используются для обработки запросов главной страницы и диспетчеризации действий, запрашиваемых браузером клиента, когда пользователь щелкает мышью по определенным ссылкам или кнопкам. &lt;br&gt;&lt;br&gt;Создание модуля данных&lt;br&gt;&lt;br&gt;Теперь создадим модуль данных WebSnap, который можно использовать для публикации информации из набора данных (или нескольких наборов данных, как в нашем случае). WebDataModule можно создать, щелкнув по третьей кнопке (набор данных на фоне глобуса) на панели инструментов WebSnap. После этого поместим компонент TClientDataSet из закладки Data Access в палитре компонентов, и свяжем его с MyBase XML DataSet-версией хорошо известной надежной таблицы Paradox Biolife.db, которая содержит графическое поле и поле комментария, а также числовые и текстовые поля, которые можно публиковать и редактировать с использованием WebSnap. &lt;br&gt;&lt;br&gt;Поддержка stateless-серверов&lt;br&gt;&lt;br&gt;После задания имени файла ClientDataSet следует перейти к древовидному представлению (Object Treeview) объектов, раскрыть ClientDataset, щелкнуть мышью по Fields, а затем, щелкнув правой кнопкой мыши, добавить все поля в древовидную структуру. Так как WebSnap используется для построения stateless-серверов, работающих с базами данных, мы должны указать первичный ключ, позволяющий набору данных активизировать навигацию по запросу клиента и манипуляцию данными. WebSnap проделает все это автоматически после того, как мы зададим первичный ключ. В данном случае, используем в качестве первичного ключа Species No. Сначала следует выбрать его в Object Treeview: &lt;br&gt;&lt;br&gt;Затем необходимо модифицировать свойство ProviderFlags в Object Inspector (инспектор объектов), установив pfInKey на True, чтобы указать, что Species No является первичным ключом для данного набора данных. &lt;br&gt;&lt;br&gt;Если у Вас нет этого набора данных, можете проделать те же операции с Paradox-таблицей, используя BDE. Единственное отличие заключается в том, что Вам придется явно разместить компонент сессии BDE, установить его свойство AutoSessionName на True, а для указания на таблицу DBDEMOS biolife.db использовать компонент TTable. Все остальные действия должны быть выполнены без изменения. &lt;br&gt;&lt;br&gt;Отображение данных в браузере&lt;br&gt;&lt;br&gt;После установки первичного ключа для набора данных, мы можем выбрать DataSetAdapter из представленной на следующем рисунке палитры компонентов WebSnap: &lt;br&gt;&lt;br&gt;и установить DataSetAdapter на DataModule. DataModule должен принять вид, подобный представленному на рисунке: &lt;br&gt;&lt;br&gt;Затем, используя Object Inspector, следует присоединить адаптер к набору данных. На приведенном ниже рисунке показан Object Inspector, поддерживающий in-line-расширение ссылок на компоненты. Обратите внимание на то, что свойства набора данных выделены разным цветом и представлены с отступом от левого края в Object Inspector. &lt;br&gt;&lt;br&gt;Следующий шаг не является обязательным; я включил его просто для большей ясности. Вернемся к Object Treeview, раскроем свойства адаптера и добавим все адаптеры команд и адаптеры полей в набор данных. Обратите внимание на поддержку всех стандартных операций с набором данных (навигация и модификация набора данных). Адаптеры полей обеспечат автоматическую поддержку как отображения, так и редактирования данных в любом наборе данных, включая BLOB-поля, содержащие текст или графику.&lt;br&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/sozdanie_websnap_servera/2010-12-08-61</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/sozdanie_websnap_servera/2010-12-08-61</guid>
			<pubDate>Wed, 08 Dec 2010 04:39:49 GMT</pubDate>
		</item>
		<item>
			<title>Разработка серверных Web-приложений на Delphi</title>
			<description>Практически ежегодно появляется очередная переработанная или серьезно дополненная версия Delphi — в прошлом году была выпущена уже пятая. Количество книг по программированию в среде Delphi, вышедших у нас за последние три-четыре года, свидетельствует о том, что этот продукт наиболее популярен среди аналогичных средств разработки ПО.</description>
			<content:encoded>Практически ежегодно появляется очередная переработанная или серьезно дополненная версия Delphi — в прошлом году была выпущена уже пятая. Количество книг по программированию в среде Delphi, вышедших у нас за последние три-четыре года, свидетельствует о том, что этот продукт наиболее популярен среди аналогичных средств разработки ПО.&lt;br&gt;&lt;br&gt;Его можно использовать для создания различных программ, в том числе и Web-приложений, процесс разработки которых благодаря применению Web-компонентов и Web-классов значительно упростился. &lt;br&gt;&lt;br&gt;Кстати, для тех программистов, которые работают на Си и не хотят переходить на Паскаль, но желали бы пользоваться всеми возможностями и преимуществами Delphi, фирма Inprise выпустила инструментальный аналог этого пакета — C++ Builder. Он обладает всеми достоинствами Delphi и обновляется одновременно с ним. Однако пока пакет не вызывает столь же большого интереса, поскольку выбор соответствующего инструментария при работе на Си шире, чем при использовании Паскаля. &lt;br&gt;&lt;br&gt;Delphi пятой версии существенно отличается от предыдущей. Так, в палитре VCL этого инструментального пакета появилась страница InternetExpress, на которой представлены TWebConnection и TmidasPageProducer. Они подходят для разработки динамических Internet-клиентов с помощью сценариев, написанных на JavaScript, HTML 4 и XML. &lt;br&gt;&lt;br&gt;Delphi 5.0 поставляется в трех вариантах: Standard, Professional и Enterprise, различающихся назначением и составом дополнительных инструментальных средств. В Standard наличествует лишь базовый набор средств разработки, Professional можно дополнительно оснащать Internet-компонентами из специального пакета WebBroker, а Enterprise включает весь доступный Internet-инструментарий и поддерживает новую технологию Microsoft — ASP (Active Server Pages). Для этого в Enterprise также включен специализированный эксперт, с помощью которого можно создавать активные серверные страницы. Такие решения, поддерживаемые Web-сервером MS IIS (Microsoft Internet Information Server), позволяют создавать динамические Web-узлы. Кроме того, для разработки Web-приложений используются элементы, находящиеся на Internet-странице палитры компонентов. Эта страница в Delphi 5.0 существенно отличается от соответствующей в версии 4.0 и внешне (другие значки), и по наполнению. &lt;br&gt;&lt;br&gt;На ней остались лишь те компоненты, которые нужны непосредственно для проектирования Web-приложений. Наряду с пятью невизуальными там имеются ClientSocket и ServerSocket (два первых), а также WebBrowser (последний). &lt;br&gt;&lt;br&gt;Информацию, касающуюся комплектации и обновления Delphi, можно получить на узлах Inprise.ru (соm), interface.ru, demo.ru и др. &lt;br&gt;&lt;br&gt;Web-приложения&lt;br&gt;&lt;br&gt;В качестве клиентских Web-приложений могут быть использованы современные браузеры, среди которых лидируют MS Internet Explorer и Netscape Navigator. Альтернативой является разработка собственной программы с помощью Delphi. Этот путь может показаться более трудоемким и затратным, но в результате зачастую получается такой продукт, который максимально соответствует решаемой задаче. &lt;br&gt;&lt;br&gt;Если в качестве клиентского приложения все же используется универсальный Web-браузер, то при создании интересных динамических Web-страниц на профессиональном уровне уже не обойтись без программирования хотя бы на элементарном уровне. Тогда придется разрабатывать продукты на уровне CGI- или API-приложений, и инструментарий Delphi 5.0 окажется как раз к месту &lt;br&gt;&lt;br&gt;Технология WebBroker&lt;br&gt;&lt;br&gt;Для проектирования серверных Web-приложений в Delphi разработана специальная технология — WebBroker. С ее помощью можно создавать сложные программы, в том числе и работающие с базами данных как локальными, так и хранящимися на наиболее популярных серверах — InterBase, Oracle, Informix, Sybase, MS SQL. В последнем случае связь серверного приложения с источником данных обеспечивается с помощью одного из двух механизмов — BDE (Borland Data Engine) или ODBC. &lt;br&gt;&lt;br&gt;Технология WebBroker реализована на основе Web-компонента — TWebModule. Для обеспечения комфортности работы и ускорения процесса проектирования предусмотрены два мастера — Web Server Application и Database Web Application Wizard. Использование TWebModule позволяет создавать программы, которые будут работать под управлением серверов, поддерживающих интерфейсы расширения — ISAPI (Internet Server API, разработанный корпорацией Microsoft), NSAPI (Netscape API, предложенный компанией Netscape), а также CGI и WinCGI. &lt;br&gt;&lt;br&gt;Особенности каждого из указанных стандартов учитываются в технологии WebBroker. При этом предусматривается выполнение программы непосредственно на сервере. Но Delphi также позволяет создавать приложения типа ActiveX, запускаемых на компьютере клиента. Следует отметить, что каждое Web-приложение может иметь лишь один компонент TWebModule. &lt;br&gt;&lt;br&gt;ISAPI- и NSAPI-приложения — это библиотеки DLL, которые Web-сервер загружает по запросу клиента, поступающему от браузера через Internet по протоколу TCP/IP. Клиентская информация передается из запроса в dll-файл в структурированном виде и обрабатывается компонентом TISAPIApplication. Каждый поток управляется отдельным запросом. Как только dll-файл загрузится, сервер может отвечать на клиентские запросы внутри основного процесса. &lt;br&gt;&lt;br&gt;Поскольку обмен информацией между клиентом и Web-приложением происходит в оперативной памяти сервера, то программы на базе ISAPI/NSAPI работают гораздо быстрее, чем приложения на основе CGI/WinCGI. CGI-приложения являются консольными и не отличаются эффективностью, так как каждый раз при поступлении соответствующего запроса от клиента сначала происходит их запуск, а по окончании работы — полное завершение. Поэтому количество клиентов, подключающихся к Web-серверу с CGI-приложениями, ограничено объемом его оперативной памяти и быстродействием. &lt;br&gt;&lt;br&gt;Однако подобные приложения обладают универсальностью, обусловленной совместимостью с различными платформами, поскольку стандарт CGI был разработан и широко использовался на Unix, а затем был реализован и для других ОС, в том числе для Windows. Данные от клиента, поступающие в командной строке запроса, который организован в этом стандарте, передаются на сервер после обработки компонентом TCGIApplication. &lt;br&gt;&lt;br&gt;WinCGI — модификация стандарта CGI, рассчитанная на работу под управлением ОС Windows. Программы, разработанные на базе этих двух стандартов, будут работать и на Web-серверах — MS IIS 4.0 или Netscape, поддерживающих стандарты ISAPI и NSAPI соответственно. Несомненное достоинство технологии WebBroker — возможность представления конечного программного продукта в любом из указанных стандартов простой перекомпиляцией исходных текстов, что существенно облегчает работу. &lt;br&gt;&lt;br&gt;Для разработки серверных Web-приложений в палитре компонентов Delphi 5 программисту предлагается Internet-страница, на которой расположено пять невизуальных Web-компонентов: TWebDispatcher, TPageProducer, TDataSetPageProducer, TDataSetTableProducer и TQueryTableProducer. Шестой невизуальный компонент — TwebModule — автоматически включается в проект при создании Web-приложения с помощью мастера Web Server Application. Он — основа любого серверного Web-приложения, а также служит репозитaрием (своеобразным «контейнером») для остальных невизуальных компонентов, чем напоминает Data-модуль, применяемый для работы с БД при обычном проектировании клиентских приложений. &lt;br&gt;&lt;br&gt;Чтобы выбрать Web Server Application, следует обратиться к меню File•New•New. После подключения этого мастера открывается подменю, где нужно указать стандарт (ISAPI, NSAPI, CGI или WinCGI), с которым будет работать создаваемое Web-приложение. &lt;br&gt;&lt;br&gt;Это позволит разработать новый проект на основе автоматически определенного Web-модуля. В его единственном окне и будут размещаться Internet-компоненты. Они, как и сам модуль, имеют статус невизуальных, т. е. доступных лишь в режиме проектирования (design-time). Все видимые элементы и компоненты серверного Web-приложения станут отображаться в окне браузера клиента, обращающегося к серверу, а во время разработки, отладки и тестирования Web-программы сам Web-сервер и браузер могут находиться на одном компьютере, выполняющем одновременно функции как клиента, так и сервера &lt;br&gt;&lt;br&gt;Когда разрабатывается ISAPI/ NSAPI-приложение, в заголовок файла проекта добавляется директива library, а в список под директивой uses заносятся необходимые записи. Затем создается сам файл проекта (листинг 1). &lt;br&gt;&lt;br&gt;Листинг 1 &lt;br&gt;&lt;br&gt;Файл проекта ISAPI/NSAPI-приложения &lt;br&gt;library IServer;uses WebBroker, HTTPApp, ISAPIApp, main in ‘main.pas’ {CustomerInfoModule: TDataModule};{$R *.RES}exports GetExtensionVersion, HttpExtensionProc, TerminateExtension;begin Application.Initialize; Application.CreateForm(TCustomerInfoModule, CustomerInfoModule); Application.Run;end.&lt;br&gt;&lt;br&gt;Кстати, в Delphi 5.0 при формировании Web-проекта появился новый модуль WebBroker. Поэтому при переходе на нее в готовом (или разрабатываемом) проекте серверного Web-приложения нужно перед его перекомпилированием приписать в ‘library’ название этого нового модуля в разделе ‘uses’. И наоборот, при возврате к версии 4.0 следует (с помощью комментария) убрать это имя. &lt;br&gt;&lt;br&gt;Классы TWebRequest и TWebResponse &lt;br&gt;&lt;br&gt;TWebModule предоставляет серверному Web-приложению возможность сформировать ответы на клиентские HTTP-запросы. Обмен между серверным и клиентским приложениями происходит в объектной форме. Запросы представляются в виде объектов в соответствии с выбранными условиями в списке свойств action items. &lt;br&gt;&lt;br&gt;В модуле HTTPAPP.pas как абстрактные базовые классы объявлены TWebRequest и TWebResponse. Они инкапсулируют протокол HTTP, по которому происходит обмен информацией между Web-сервером и клиентскими браузерами. Класс TWebRequest предоставляет доступ ко всей информации, поступающей от клиентов на Web-сервер через свои свойства и методы. Класс же TWebResponse, наоборот, с помощью своих свойств и методов позволяет переслать клиенту данные в форме ответа на отправленный ранее запрос по протоколу HTTP. Причем данные от Web-сервера можно переслать любым из возможных для протокола HTTP способов. &lt;br&gt;&lt;br&gt;В действительности взаимодействие между Web-сервером и клиентами обеспечивают классы TISAPIResponse и TISAPIRequest, объявляемые в модуле ISAPIAPP.pas и учитывающие специфику интерфейсов ISAPI и NSAPI. Они являются прямыми потомками абстрактных классов TWebRequest и TWebResponse. Полиморфизм, свойственный Delphi, позволяет организовать их передачу в виде параметров TWebRequest и TWebResponse через обработчик события OnAction в компонент TwebModule (листинг 2). &lt;br&gt;&lt;br&gt;Листинг 2 &lt;br&gt;&lt;br&gt;Обработчик события OnAction &lt;br&gt;procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;Request: TWebRequest; Response: TWebResponse;var Handled: Boolean);begin//обработчик событияend;&lt;br&gt;&lt;br&gt;Свойства класса TISAPIRequest, содержащего информацию запроса от клиентского браузера, позволяют получить разнообразную и достаточно полную информацию о самом клиенте, хотя ряд параметров в передаваемом запросе может быть не определен. Этот класс имеет около 30 ненаследуемых свойств. Так, свойства RemoteHost и RemoteAddr включают Internet-адрес клиентского компьютера. Данные о браузере, установленном на клиентском месте, заключены в свойстве UserAgent. Из свойства Accept можно извлечь список типов графических файлов, с которыми может работать браузер клиента. Свойство Refere содержит URL Web-страницы, где можно получить ссылку на этот Web-сервер, а данные Cookie содержатся только в свойстве Cookie в виде строк. С помощью свойства CookieFields через массивы полей можно сразу же получить доступ к значениям нескольких клиентских рабочих мест. &lt;br&gt;&lt;br&gt;Подробные данные клиентского URL-запроса можно извлечь из свойства Query. Например, если в URL-запросе ‘http://www.TSite.com/art/gallery.dll/ mammals?animal=dog&amp;amp;color=black’ часть ‘/gallery.dll’ представляет собой имя Web-приложения, то свойство Query будет включать animal=dog&amp;amp;color=black. В этом свойстве информация неотделима от URL. Причем Query может включать множественные поля, разделенные знаками логического «И» (&amp;amp;). При передаче параметров через URL они обычно следуют за знаком вопроса (?). Пробелы заменяются плюсом (+), а последний наряду с некоторыми другими передается в кодированном виде: %хх, где хх — шестнадцатеричное представление символа. &lt;br&gt;&lt;br&gt;Чтобы ознакомиться с функциями, свойствами и методами класса TISAPIRequest, целесообразно провести тестирование. Для этого нужно сформировать HTML-страницу в обработчике события OnAction и отобразить на ней значения всех многообразных свойств класса или хотя бы некоторых наиболее важных (листинг 3). &lt;br&gt;&lt;br&gt;Листинг 3 &lt;br&gt;&lt;br&gt;Вывод информации о сервере и клиенте &lt;br&gt; &lt;br&gt;procedure TWebModule1.WebModule1WebActionItem2Action(Sender:TObject; Request: TWebRequest; Response: TWebResponse;var Handled: Boolean);begin Pg:= TstringList.Create; Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&lt;br&gt;&apos;); Pg.Add(&apos;Динамическая страница, созданная в Delphi &lt;br&gt;&lt;br&gt;&apos;); Pg.Add(&apos;как Web-расширение &lt;br&gt;&lt;br&gt;&apos;); Pg.Add(&apos;Method = &apos; + Request.Method + &apos; &lt;br&gt;&apos;); with Pg do begin Add(&apos;ProtocolVersion = &apos; + Request.ProtocolVersion + &apos; &lt;br&gt;&apos;); Add(&apos;URL = &apos; + Request.URL + &apos; &lt;br&gt;&apos;); Add(&apos;Query = &apos; + Request.Query + &apos; &lt;br&gt;&apos;); Add(&apos;PathInfo = &apos; + Request.PathInfo + &apos; &lt;br&gt;&apos;); Add(&apos;PathTranslated = &apos; + Request.PathTranslated + &apos; &lt;br&gt;&apos;); Add(&apos;Authorization = &apos; + Request.Authorization + &apos; &lt;br&gt;&apos;); Add(&apos;CacheControl = &apos; + Request.CacheControl + &apos; &lt;br&gt;&apos;); Add(&apos;Cookie = &apos; + Request.Cookie + &apos; &lt;br&gt;&apos;); Add(&apos;Accept = &apos; + Request.Accept + &apos; &lt;br&gt;&apos;); Add(&apos;From = &apos; + Request.From + &apos; &lt;br&gt;&apos;); Add(&apos;Host = &apos; + Request.Host + &apos; &lt;br&gt;&apos;); Add(&apos;Referer = &apos; + Request.Referer + &apos; &lt;br&gt;&apos;); Add(&apos;UserAgent = &apos; + Request.UserAgent + &apos; &lt;br&gt;&apos;); Add(&apos;ContentEncoding = &apos; + Request.ContentEncoding + &apos; &lt;br&gt;&apos;); Add(&apos;ContentType = &apos; + Request.ContentType + &apos; &lt;br&gt;&apos;); Add(&apos;ContentLength = &apos; + IntToStr(Request.ContentLength) + &apos; &lt;br&gt;&apos;); Add(&apos;ContentVersion = &apos; + Request.ContentVersion + &apos; &lt;br&gt;&apos;); Add(&apos;Content = &apos; + Request.Content + &apos; &lt;br&gt;&apos;); Add(&apos;Connection = &apos; + Request.Connection + &apos; &lt;br&gt;&apos;); Add(&apos;DerivedFrom = &apos; + Request.DerivedFrom + &apos; &lt;br&gt;&apos;); Add(&apos;Title = &apos; + Request.Title + &apos; &lt;br&gt;&apos;); Add(&apos;RemoteAddr = &apos; + Request.RemoteAddr + &apos; &lt;br&gt;&apos;); Add(&apos;RemoteHost = &apos; + Request.RemoteHost + &apos; &lt;br&gt;&apos;); Add(&apos;ScriptName = &apos; + Request.ScriptName + &apos; &lt;br&gt;&apos;); Add(&apos;ServerPort = &apos; + IntToStr(Request.ServerPort) + &apos; &lt;br&gt;&apos;); end; Pg.Add(&apos;&lt;br&gt;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Response.Content := Pg.Text; Pg.Free;end; &lt;br&gt;&lt;br&gt; &lt;br&gt; &lt;br&gt; &lt;br&gt;&lt;br&gt;Эта страница отсылается через Response.Content на клиентский браузер для тестирования системы. &lt;br&gt; &lt;br&gt;&lt;br&gt;Конечно, не нужно отправлять подобную информацию клиенту, пользующемуся услугами Web-сервера, ее целесообразно использовать для подготовки эффективного и даже «интеллектуального» ответа клиенту. В частности, информация о версии и функциональных возможностях браузера позволит выдать клиенту Web-страницу в требующемся виде, например без графических файлов, в том формате, который его браузер не воспринимает. А анализ запросов (например, по свойству Query) позволяет выявить «полезного» и даже «нужного» клиента. Если запомнить его URL-адрес, то при следующем обращении на Web-сервер можно персонально его поприветствовать, сразу открыть ему нужную страницу либо раздел, предоставить доступ к дополнительной информации. Этот же способ помогает регистрировать данные о посетителях на Web-сервере и, если необходимо, избавляться от нежелательных «визитов» и т. п. &lt;br&gt; &lt;br&gt;&lt;br&gt;Данные пересылаются клиенту с Web-сервера в форме ответа через свойство Content класса TISAPIResponse. Этот класс имеет 23 свойства, из них 19 — ненаследуемые. В Content должен содержаться HTML-код, отображаемый клиентским браузером в виде Web-страницы. В другом важном свойстве — Version — указывается версия HTTP-протокола. Значение Version берется из ProtocolVersion свойства HTTPRequest. Для получения дополнительной информации по спецификации HTTP-протокола необходимо ознакомиться с соответствующей документацией, имеющейся, например, по адресу http://www.w3.org/. &lt;br&gt; &lt;br&gt;&lt;br&gt;Большое влияние на работу с классом TISAPIResponse оказывают методы. Например, вызвав после установки свойств объекта HTTP-ответа метод SendResponse, можно послать клиенту сообщение еще до окончания действия обработчика OnAction. Метод SendRedirect поможет перенаправить клиента на другой Web-сервер с соответствующим URL. Метод SendStream обеспечивает передачу данных любого типа. Однако перед его вызовом нужно затребовать SendResponse, который формирует заголовок сообщения HTTP-ответа, базирующийся на свойствах объекта TISAPIResponse. Вместо метода SendResponse перед вызовом SendStream нужно установить свойство ContentStream в значении AStream. &lt;br&gt; &lt;br&gt;&lt;br&gt;Наибольший интерес, пожалуй, представляет использование технологии WebBroker при построении динамических Web-страниц для работы с базами данных. Однако здесь не обойтись без языка HTML, ранее не применявшегося в Delphi. Специальные компоненты TPageProducer, TDataSetPageProducer, TDataSetTableProducer и TQueryTableProducer помогают программисту эффективно решать подобные задачи, которые далеко не всегда тривиальны, что существенно экономит его время и силы. &lt;br&gt; &lt;br&gt;&lt;br&gt;TPageProducer&lt;br&gt; &lt;br&gt;&lt;br&gt;Компонент TPageProducer позволяет создавать динамические Web-страницы и манипулировать ими с помощью шаблонов, т. е. клиенту предоставляется нужная HTML-страница в соответствии с определенными условиями, которые анализируются в обработчике события OnHTMLTag. Само это событие будет инициироваться в момент прочтения специального дескриптора, начинающегося со знака #, который включает имя и параметры с соответствующими значениями, например &lt;#TagName Param1=Value1 Param2=Value2 ...&amp;gt;. Имя должно быть допустимым идентификатором языка Паскаль, а параметры с пробелами заключаются в двойные кавычки. В Delphi имеется семь предопределенных дескрипторов. &lt;br&gt; &lt;br&gt;&lt;br&gt;В TPageProducer предусмотрены свойства — HTMLDoc и HTMLFile. С помощью первого можно определить шаблон, который в дальнейшем будет использоваться для формирования страницы, возвращаемой клиенту при обращении к методу Content (в ответ на запрос). Установив TPageProducer в окне TWebModule и открыв редактор списка строк HTMLDoc, можно построчно набрать там шаблон HTML-страницы. Такой шаблон не будет отличаться от обычной страницы, написанной на стандартном HTML-языке. Метод Content преобразует код, находящийся в свойстве HTMLDoc (где могут присутствовать и ссылки в виде дескрипторов), в окончательную строку в формате HTML. При входе в каждый дескриптор вызывается событие OnHTMLTag, обработчиком которого и выполняется это преобразование (листинг 4). &lt;br&gt; &lt;br&gt;&lt;br&gt;Листинг 4 &lt;br&gt; &lt;br&gt;&lt;br&gt;Замена дескрипторов в обработчике события OnHTMLTag &lt;br&gt;procedure TMyModule.ImageHTMLTag(Sender: TObject; Tag: TTag;const TagString: string; TagParams: TStrings; var ReplaceText: string);var ImageID: integer;begincase Tag of tgImage: begin ImageID := StrToInt(TagParams.Values[‘ImageID’]) if ImageTable.FindKey([ImageID]) then ReplaceText := &apos;else ReplaceText:= &apos;(Изображение отсутствует)&apos; end; tgTable: begin ReplaceText := DataSetTableProducer1.Content; end; end;end;&lt;br&gt; &lt;br&gt;&lt;br&gt;Предопределенный дескриптор tgImage предназначен для описания изображения, а tgTable — для установки HTML-таблицы. Кроме того, в Delphi 5.0 есть предопределенные теги tgCustom, tgLink, tgImageMap, tgObject и tgEmbed. С помощью tgLink описывается гипертекстовая ссылка, tgObject используется для встраивания ActiveX в HTML-страницу, tgImageMap заменяется картой изображения (контекстно-сенсорными зонами), tgEmbed содержит ссылку на DLL-расширение, совместимое с Netscape, tgCustom присваивается свойству Tag тогда, когда в HTML-тексте встречается неопределенный дескриптор, заменяемый любым значением, которое задает пользователь. Например, если в свойстве HTMLDoc HTML-текста имеется также непредопределенный тег &lt;#DATE&amp;gt;, то Tag будет присвоено значение tgCustom. В обработчике OnHTMLTag этот дескриптор может быть заменен командой, выводящей текущую дату на HTML-страницу. &lt;br&gt; &lt;br&gt;&lt;br&gt;Установка HTMLDoc не допускает использования альтернативного HTMLFile, которое предусматривает применение внешнего файла для хранения аналогичного шаблона на языке HTML. А такой способ позволяет еще более расширить функциональные возможности Web-приложения путем замены и манипулирования HTML-страницами в нескольких шаблонах без изменения текста основной программы. &lt;br&gt; &lt;br&gt;&lt;br&gt;TDataSetTableProducer и TQueryTableProducer&lt;br&gt; &lt;br&gt;&lt;br&gt;Компоненты, находящиеся на странице DataControl и предназначенные для управления данными и для их вывода, в том числе и в табличной форме, не могут быть использованы в Web-приложении. Вместо них можно применить TDataSetTableProducer и TQueryTableProducer, информация для которых берется из TTable и TQuery соответственно, включенные в компонент TWebModule. Причем источники данных и компоненты управления непосредственно связаны между собой, потому и не требуется промежуточного компонента типа TDataSource. Компонент TDataSetTableProducer, аналогичный TDBGrid, позволяет переслать на клиентский браузер отчет в табличной форме в формате HTML. Его можно настроить на отображение любых столбцов выбранного набора данных. &lt;br&gt; &lt;br&gt;&lt;br&gt;Свойства Header и Footer позволяют вставить текст на HTML и до таблицы, и после нее. С помощью свойств Columns, RowAttributes и TableAttributes можно форматировать строки, столбцы и отдельные ячейки таблицы. В свойстве Dispatcher должен быть указан компонент-диспетчер, предоставляющий доступ к объектам TWebRequest и TWebResponse для получения запросов и передачи ответов. &lt;br&gt; &lt;br&gt;&lt;br&gt;Аналогично функционирует и TQueryTableProducer, за исключением режима доступа к данным. Этот компонент помогает сформировать HTML-таблицу на основе параметров, указанных в HTTP-запросе. Если последний основан на методе GET, то параметры определяются свойством QueryFields объекта запроса TWebRequest, а если на методе POST — свойством ContentFields того же объекта. В приведенной демонстрационной программе Iserver.dpr представлен пример использования TPageProducer, &lt;br&gt; &lt;br&gt;&lt;br&gt;Отладка серверных Web-приложений&lt;br&gt; &lt;br&gt;&lt;br&gt;Если разработано достаточно сложное Web-приложение в стандарте ISAPI(NSAPI), его необходимо отладить. Этот процесс существенно отличается от общепринятой отладки обычных Windows-приложений в среде Delphi, так как созданное Web-приложение запускается лишь в ответ на запросы, получаемые от браузера клиента через Web-сервер. Запуск даже самого простого Web-приложения непосредственно из среды Delphi 5.0 невозможен, поскольку теряется его связь с Web-сервером. Тогда и приложение не может получать запросы от клиента и, следовательно, реагировать на них. Методы отладки определяются также типом Web-сервера. &lt;br&gt; &lt;br&gt;&lt;br&gt;На платформе NT в качестве Web-сервера наиболее целесообразно с точки зрения доступности использовать MS IIS версий 2—4, а в качестве браузера MS IE —версии не ниже четвертой. Операционная система Windows NT 4.0 поставляется в комплекте с MS IIS 2.0 (дистрибутив — в I386InetSrv). Можно также установить бесплатно распространяемый пакет NTOptPak, в который входит MS IIS 4.0, более распространенная, чем версии 2.0 и 3.0, и лишенная их недостатков. &lt;br&gt; &lt;br&gt;&lt;br&gt;Настройка отладки Web-приложения вместе с MS IIS 4.0 в интегрированной среде Delphi достаточно сложна и трудоемка, главным образом, из-за внесения множества изменений в реестр. Поэтому имеет смысл сначала отладить такое приложение с MS IIS версии 2 или 3. &lt;br&gt; &lt;br&gt;&lt;br&gt;ISAPI- и NSAPI-приложения представляют собой динамические библиотеки DLL с предопределенными адресами входа. Web-сервер запускает Web-приложения передачей запросов на эти адреса. Для обеспечения их связи нужно установить определенные параметры. Причем перед тем, как начнется работа Web-приложения, Web-сервер должен быть остановлен. &lt;br&gt; &lt;br&gt;&lt;br&gt;При отладке Web-приложений с MS IIS в меню Run/Parameters вводится следующее: Host Application: c:winntsystem32inetsrvinetinfo.exe (маршрут к файлу должен соответствовать фактическому) и Run/Parameters: -e w3svc. Это позволит запускать MS IIS 2.0 и 3.0 и производить отладку ISAPI DLL под управлением Web-сервера. &lt;br&gt; &lt;br&gt;&lt;br&gt;Если на сервере установлен MS IIS версии 4.0 или более поздней, то в конфигурацию Windows NT 4.0 придется внести целый ряд изменений. &lt;br&gt; &lt;br&gt;&lt;br&gt;С помощью утилиты-конфигуратора DCOMCnfg нужно изменить учетную запись (user account) в разделе identify сервиса MS IIS Admin Service на имя того пользователя, который будет выполнять отладку. &lt;br&gt; &lt;br&gt;&lt;br&gt;С использованием редактора реестра (REGEDIT) или аналогичной утилиты следует удалить имена LocalService из всех подключей, связанных с аналогичными структурами IISADMIN, которые входят в ветвь реестра HKEY_CLASSES_ROOT/AppID и HKEY_ CLASSES_ROOT/CLSID. Раздел LocalService присутствует в составе следующих подключей: &lt;br&gt; &lt;br&gt; &lt;br&gt;{61738644-F196-11D0-9953-00C04FD919C1} // IIS WAMREG admin Service;&lt;br&gt; &lt;br&gt;{9F0BD3A0-EC01-11D0-A6A0-00A0C922E752} // IIS Admin Crypto Extension;&lt;br&gt; &lt;br&gt;{A9E69610-B80D-11D0-B9B9-00A0C922E750} // IISADMIN Service.&lt;br&gt; &lt;br&gt; &lt;br&gt;&lt;br&gt;Кроме того, из двух первых подключей узлов AppID нужно удалить имя RunAs, а последний дополнить значением Interactive User. &lt;br&gt; &lt;br&gt;&lt;br&gt;Далее с применением REGEDIT необходимо добавить подключи LocalService32 ко всем структурам, связанным с IISADMIN и относящимся к узлу CLSID. Иными словами, каждый подключ узла CLSID, указанный в предыдущем пункте, или любой другой, под которым найдено имя LocalService keyword, следует дополнить подключом LocalService32. После чего нужно установить по умолчанию для этих новых подключей значение: c:winntsystem32inetsrvinetinfo.exe -e w3svc (с учетом фактического расположения файла inetinfo.exe). &lt;br&gt; &lt;br&gt;&lt;br&gt;Следует установить в dword:3 значение Start для подключей: &lt;br&gt; &lt;br&gt; &lt;br&gt;HKEY_LOCAL_MACHINESYSTEM CurrentControlSetServicesIISADMIN, &lt;br&gt; &lt;br&gt;HKEY_LOCAL_MACHINESYSTEM CurrentControlSetServicesMSDTC, &lt;br&gt; &lt;br&gt;HKEY_LOCAL_MACHINESYSTEM CurrentControlSetServicesW3SVC. &lt;br&gt; &lt;br&gt; &lt;br&gt;&lt;br&gt;Чтобы вернуть реестр в исходное положение по окончании процесса отладки, необходимо проделать обратные операции. Они достаточно трудоемки и требуют повышенного внимания. Но можно автоматизировать процесс перенастройки реестра, разработав собственную программу, что поможет быстро определить его состояние без поиска, с помощью стандартных средств просмотра и коррекции, и перейти от отладки к работе ОС в штатном режиме. Такая программа предназначена для многократного использования. В качестве основного класса при разработке можно выбрать Tregistry, а для анализа, чтения и записи значений, а также удаления подключей подойдут многочисленные методы этого компонента: ReadKey, WriteFloat, WriteString, CloseKey, DeleteKey и т. п. &lt;br&gt; &lt;br&gt;&lt;br&gt;Такая программа поможет также контролировать фактическое состояние реестра в нужных подключах. Работа на этом уровне весьма ответственна, поскольку любая ошибка может вызвать недопустимые изменения в важнейшем для ОС механизме и привести к переустановке всей системы. Поэтому целесообразно освоить основные методы чтения фрагментов реестра, а удаление, создание и запись выполнять сначала только на тестовой ветви системы. Если приводимый ниже текст (листинг 5) вставить, например, в подпрограмму, реагирующую на событие открытия формы OnActivate, то в окне Label1 при настройке реестра на режим отладки появится имя подключа LocalServer32, а в окне Edit1 — соответствующее значение по умолчанию: c:winntsystem32inetsrv inetinfo.exe -e w3svc. &lt;br&gt; &lt;br&gt;&lt;br&gt;Используя отлаженную программу, можно быстро и безошибочно изменять, контролировать и восстанавливать необходимые настройки реестра. Для удобства можно заменить числовую информацию пользовательскими терминами и т. п. Предварительно, конечно, придется разработать и отладить программу, вносящую нужные изменения в реестр. &lt;br&gt; &lt;br&gt;&lt;br&gt;При отладке Web-приложений с Personal Web Server под управлением Windows 95/98 в меню Run/Parameters вводятся следующие параметры: Host Application: c:Program Fileswebsvcsysteminetsw95.exe; Run Parameters: -w3svc. Они позволят запускать Personal Web Server и отлаживать ISAPI DLL. Для настройки на отладку Web-приложений с сервером Netscape Server версии 2.0 в соответствии с рекомендациями фирмы Borland требуется дополнительно изменить конфигурацию. Сначала следует скопировать файл ISAPITER.DLL (из каталога Bin) в каталог C:NetscapeServerNsapiExamples (с учетом фактического размещения файлов). Затем необходимо произвести преобразования в серверных конфигурационных файлах, расположенных в каталоге C:NetscapeServerHttpd-Config. &lt;br&gt; &lt;br&gt; &lt;br&gt;В файле OBJ.CONF file после строки Init fn=load-types mime-types=mime.types требуется добавить строку Init funcs=&quot;handle-isapi,check-isapi,log-isapi&quot; fn=&quot;load-modules&quot; shlib=&quot;c:/netscape/server/nsapi/examples/ ISAPIter.dll&quot;. &lt;br&gt; &lt;br&gt;В секции. &lt;br&gt; &lt;br&gt;В конце файла MIME.TYPES следует добавить строку type=magnus-internal/isapi exts=dll. &lt;br&gt; &lt;br&gt; &lt;br&gt;&lt;br&gt;Дополнения в первом и втором действиях вносятся одной непрерывной строкой. Затем для отладки Web-приложений под управлением сервера Netscape Fast Track требуется установить параметры Host Application: c:Netscapeserverbinhttpdhttpd.exe и Run Parameters: c:Netscapeserverhttpd-config. Они позволяют запустить сервер, а также указывают путь к конфигурационным файлам. &lt;br&gt; &lt;br&gt;&lt;br&gt;Создание DLL-приложений для работы под управлением Windows NT также имеет свою специфику. Необходимо расширить права пользователя так, чтобы стало возможным отладить DLL-программы. Делает это администратор Windows NT через программу User Manager, назначив Act As Part Of The Operating System (работа в режиме операционной системы) в меню Policies/User Rights (обязательно указав Show Advanced User Rights) тому пользователю-программисту, который будет осуществлять операцию. Подобная процедура неудобна потому, что по окончании отладки нужно восстановить исходные права пользователя. &lt;br&gt; &lt;br&gt;&lt;br&gt;Перед запуском приложения следует установить в соответствующих местах исходного текста программы точки прерывания таким образом, чтобы при передаче Web-сервером запроса в DLL-приложение прерывалось бы выполнение программы и можно было бы провести отладку. &lt;br&gt; &lt;br&gt;&lt;br&gt;После отладки DLL-приложения в формате ISAPI или NSAPI можно быстро перекомпилировать исходные тексты в exe-файл формата CGI/WinCGI, добавив отлаженный Web-модуль в репозитарий. При этом нужно присвоить название Web-модулю, дать описание, выбрать страницу репозитария (например, Data Modules) и иконку, указать фамилию автора. Созданный Web-модуль сохраняется в качестве шаблона. Затем через меню File/New следует вызвать мастер Web Server Application. В диалоге New Web Server Application выбрать CGI или WinCGI. Стереть автоматически сгенерированный Web-модуль и через меню File/New установить шаблон отлаженного приложения, который был ранее сохранен на соответствующей странице. &lt;br&gt; &lt;br&gt;&lt;br&gt;С помощью Delphi 5.0 можно создавать CGI/WinCGI-приложения, которые в виде exe-файлов должны напрямую запускаться Web-сервером. Однако методика их отладки несколько сложнее, чем DLL-приложений, поскольку нужно моделировать сервер путем создания конфигурационного файла с параметрами, включающими информацию из запроса. Затем нужно запустить WinCGI-приложение, указав полные адреса файла, содержащего информацию от клиента, и файла, в котором должен быть записан ответ. После этого можно, как обычно, отлаживать Web-приложение. &lt;br&gt; &lt;br&gt;&lt;br&gt;Механизм работы CGI/WinCGI-приложений проще, чем у ISAPI/NSAPI-приложений. При каждом обращении они запускаются в отдельном потоке, поэтому пересечения с многопотоковым механизмом не происходит. Кроме того, в CGI/WinCGI-приложениях не возникает проблем, имеющих место при кэшировании Web-модулей ISAPI/NSAPI-приложений. &lt;br&gt; &lt;br&gt;&lt;br&gt;Таким образом, можно облегчить настройку при отладке Web-приложений, используя упрощенную версию MS IIS 2.0. Полученные программы, как правило, могут работать и под управлением MS IIS 4.0. При этом следует учитывать некоторые незначительные на первый взгляд детали, которые могут существенно затруднить процесс отладки серверных приложений, как-то: проблемы с установкой состояния реестра, предварительная настройка доступа к определенным каталогам и файлам и последовательность выполнения операций. &lt;br&gt; &lt;br&gt;&lt;br&gt;Рассмотрим процесс отладки Web-серверного приложения iserver.dll, предлагаемого разработчиками Delphi 5.0. Его исходные тексты (iserver.dpr, main.pas, main.dfm) находятся в каталоге ...Program FilesBorlandDelphi5 DemosWebserv, а файловая база данных — в каталоге ...Program FilesCommon FilesBorland SharedData. На этот же каталог должен указывать и DBDemos, настраиваемый с помощью программы-администратора bdeAdmin.exe, имеющейся в ...Program FilesCommon FilesBorland SharedBDE. &lt;br&gt; &lt;br&gt;&lt;br&gt;Само DLL-приложение должно быть скомпилировано в каталог, из которого Web-сервер может производить запуск exe-программ. Таковым может быть, например, создаваемый по умолчанию (при установке Web-сервера) виртуальный каталог Web-сервера SCRIPTS или аналогичный, созданный заново. После внесения рекомендованных изменений в реестр NT при отладке программы под управлением MS IIS 4.0 Web-сервер может запускаться только из среды Delphi 5.0. А в случае использования MS IIS 2.0 или 3.0 за работой Web-сервера приходится следить программисту, запуская и останавливая соответствующий сервис World Wide Web Publishing Service из окна Services панели управления. &lt;br&gt; &lt;br&gt;&lt;br&gt;Перед отладкой MS IIS должен быть остановлен, а начинать работу он будет запуском Web-приложения (DLL-программы) из среды Delphi 5.0. Сначала разумно проверить, работает ли уже отлаженное приложение, такое как демонстрационный пример Iserver.dll. Для этого нужно поместить исходный файл в раздел SCRIPTS. В окне Services следует проверить, подключен ли сервис Wide Web Publishing Service, если же нет — нужно нажать кнопку Start. Затем в окне браузера требуется набрать имя ПК или IP-адрес &lt;br&gt; &lt;br&gt;&lt;br&gt;Иногда программа полностью не запускается, хотя все вроде бы выполнено правильно, т. е. MS IIS работает и есть доступ к запуску DLL-приложения. В этом случае могут появиться сообщения о «внутренней» ошибке сервера, например о неудачной инициализации BDE, невозможности работать с закрытой таблицей и т. п. Подобная информация свидетельствует об отсутствии права пользователя на доступ к каталогу ...BDE и/или ...DATA, который, если необходимо, открывается или закрывается нажатием правой кнопки мыши на свойствах (properties/Security/permissions) соответствующего компонента (диска, каталога или файла). &lt;br&gt; &lt;br&gt;&lt;br&gt;Перед запуском MS IIS нужно установить протокол TCP/IP и выбрать какой-нибудь (фиктивный) IP-адрес, например 222.10.1.220, поскольку при разработке и отладке серверных приложений ПК следует отключить от Internet. Работу TCP/IP можно протестировать, набрав сначала консольную команду ping 127.0.0.1, а затем ping 222.10.1.220. В случае успешной установки протокола будет получен ответ типа ‘Reply from 127.0.0.1: bytes=32 time&lt;10ms TTL=32’, а при неверной конфигурации — Pinging 222.10.1.220 with 32 bytes of data: Request timed out’. &lt;br&gt; &lt;br&gt;&lt;br&gt;Включившись в работу, завершите функционирование MS IIS из окна Services панели управления. Затем, запустив Delphi 5.0 и открыв указанный проект, расставьте точки останова в тексте модуля main, а после установки параметров загрузите отлаживаемый модуль через меню Run/Add Breakpoint/Module Load Breakpoint. Откройте окно Modules, нажав комбинацию клавиш ++m, и убедитесь, что там есть строка: iserver.dll not loaded. Потом, набрав комбинацию клавиш + (или нажав кнопку Run), запустите Web-сервер. В окне Modules появится список модулей, запущенных под управлением MS IIS, но отлаживаемый модуль еще не будет загружен. &lt;br&gt; &lt;br&gt;&lt;br&gt;Функционирование модуля начнется после запуска браузера и набора строки типа http:// 222.10.1.220/scripts/iserver.dll/. При этом в окне Modules можно увидеть все входные точки и модули, связанные с отлаживаемым приложением. Затем начнется непосредственная отладка, и в iserver.dpr на строке Application.Initialize курсор остановится. Теперь нужно снова запустить приложение, нажав кнопку Run. Следующий останов будет в точке прерывания. Время соединения браузера с сервером ограничено определенными параметрами настройки браузера, а потому не следует медлить, иначе связь клиент—сервер прервется и процесс отладки прекратится. Тогда можно увеличить время соединения и продолжить отладку. &lt;br&gt;&lt;br&gt;&apos;); Pg.Add(&apos;&apos;); Pg.Add(&apos;&apos;); Response.Content := Pg.Text; Pg.Free;end;&lt;br&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/razrabotka_servernykh_web_prilozhenij_na_delphi/2010-12-08-60</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/razrabotka_servernykh_web_prilozhenij_na_delphi/2010-12-08-60</guid>
			<pubDate>Wed, 08 Dec 2010 04:25:29 GMT</pubDate>
		</item>
		<item>
			<title>Работа с директориями (папками) в Дельфи</title>
			<description>&lt;P&gt;В этой статье я постараюсь познакомить Вас с некоторыми стандартными функциями для работы с директориями. И еще приведу несколько пользовательских функций и примеры их использования. Также рассмотрен вопрос вызова диалога выбора директории. &lt;/P&gt;</description>
			<content:encoded>В этой статье я постараюсь познакомить Вас с некоторыми стандартными функциями для работы с директориями. И еще приведу несколько пользовательских функций и примеры их использования. Также рассмотрен вопрос вызова диалога выбора директории. &lt;BR&gt;Для начала начнем с простой функции для создания новой папки. Общий вид функции такой: &lt;BR&gt;function CreateDir(const Dir: string): Boolean; &lt;BR&gt;То есть если папка успешно создана функция возвращает true. Сразу же простой пример ее использования: &lt;BR&gt;procedure TForm1.Button1Click(Sender: TObject); &lt;BR&gt;begin &lt;BR&gt;if createdir(&apos;c:&amp;#92;TestDir&apos;) = true then &lt;BR&gt;showmessage(&apos;Директория успешно создана&apos;) &lt;BR&gt;else &lt;BR&gt;showmessage(&apos;При создании директории произошла ошибка&apos;); &lt;BR&gt;end; &lt;BR&gt;При нажатии на кнопку программа пытается создать папку с именем TestDir на диске C: и если попытка увенчалась успехом, то выводится соответствующее сообщение. Следует отметить, что если вы не указываете имя диска, на котором хотите создавать папку, то функция будет создавать папку в той же директории, где находится сама программа. &lt;BR&gt;Объявления &lt;BR&gt;createdir(edit1.text); &lt;BR&gt;и &lt;BR&gt;createdir(extractfilepath(paramstr(0))+edit1.text); &lt;BR&gt;приведут к одному и тому же результату. &lt;BR&gt;Теперь рассмотрим функцию для удаления папок. Ее объявление выглядит так: &lt;BR&gt;function RemoveDir(const Dir: string): Boolean; &lt;BR&gt;Сразу же хочу предупредить, что данная функция способна удалять только пустые папки, и если там что-нибудь будет, то произойдет ошибка! Но выход есть!!! Здесь нам на помощь придет пользовательская функция с простым названием MyRemoveDir. Вот описание функции: &lt;BR&gt;Function MyRemoveDir(sDir : String) : Boolean; &lt;BR&gt;var &lt;BR&gt;iIndex : Integer; &lt;BR&gt;SearchRec : TSearchRec; &lt;BR&gt;sFileName : String; &lt;BR&gt;begin &lt;BR&gt;Result := False; &lt;BR&gt;sDir := sDir + &apos;&amp;#92;*.*&apos;; &lt;BR&gt;iIndex := FindFirst(sDir, faAnyFile, SearchRec); &lt;BR&gt;while iIndex = 0 do begin &lt;BR&gt;sFileName := ExtractFileDir(sDir)+&apos;&amp;#92;&apos;+SearchRec.Name; &lt;BR&gt;if SearchRec.Attr = faDirectory then begin &lt;BR&gt;if (SearchRec.Name &lt;&amp;gt; &apos;&apos; ) and &lt;BR&gt;(SearchRec.Name &lt;&amp;gt; &apos;.&apos;) and &lt;BR&gt;(SearchRec.Name &lt;&amp;gt; &apos;..&apos;) then &lt;BR&gt;MyRemoveDir(sFileName); &lt;BR&gt;end else begin &lt;BR&gt;if SearchRec.Attr &lt;&amp;gt; faArchive then &lt;BR&gt;FileSetAttr(sFileName, faArchive); &lt;BR&gt;if NOT DeleteFile(sFileName) then &lt;BR&gt;ShowMessage(&apos;Could NOT delete &apos; + sFileName); &lt;BR&gt;end; &lt;BR&gt;iIndex := FindNext(SearchRec); &lt;BR&gt;end; &lt;BR&gt;FindClose(SearchRec); &lt;BR&gt;RemoveDir(ExtractFileDir(sDir)); &lt;BR&gt;Result := True &lt;BR&gt;end; &lt;BR&gt;Копируете это все в Вашу программу, а затем эту функцию можно вызвать например так: &lt;BR&gt;if NOT MyRemoveDir(&apos;C:&amp;#92;TestDir&apos;) then &lt;BR&gt;ShowMessage(&apos;Не могу удалить эту директорию&apos;); &lt;BR&gt;Теперь маленько отстранимся от непосредственной работы с папками и рассмотрим волнующий многих вопрос. Как вызвать диалог выбора папки (как при установке программ)?? ПРОСТО!!! &lt;BR&gt;Подключаем в uses модуль Filectrl.pas (то есть uses FileCtrl;). Теперь ставим на форму еще кнопочку (чтобы не путаться :) и пишем такой код: &lt;BR&gt;procedure TForm1.Button3Click(Sender: TObject); &lt;BR&gt;const &lt;BR&gt;SELDIRHELP = 1000; &lt;BR&gt;var &lt;BR&gt;Dir: string; &lt;BR&gt;begin &lt;BR&gt;Dir := &apos;C:&amp;#92;windows&apos;; &lt;BR&gt;if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],SELDIRHELP) then &lt;BR&gt;Caption := Dir; &lt;BR&gt;end; &lt;BR&gt;При выборе директории в заголовке формы отобразиться ее название! &lt;BR&gt;Теперь рассмотрим следующую процедуру. К примеру Вам надо создать папку Dir1 по адресу: C:&amp;#92;MyDir&amp;#92;Test&amp;#92;Dir1, но при этом папок MyDir и Test на Вашем компьютере не существует. Функция CreateDir здесь не сработает, поэтому воспользуемся процедурой ForceDirectories. Ее общий вид таков: &lt;BR&gt;procedure ForceDirectories(Dir: string); &lt;BR&gt;Пример ее использования (как всегда я поставил на форму новую кнопку, а там написал) &lt;BR&gt;procedure TForm1.Button4Click(Sender: TObject); &lt;BR&gt;var &lt;BR&gt;Dir: string; &lt;BR&gt;begin &lt;BR&gt;Dir := &apos;C:&amp;#92;MyDir&amp;#92;Test&amp;#92;Dir1&apos;; &lt;BR&gt;ForceDirectories(Dir); &lt;BR&gt;end; &lt;BR&gt;Ну и напоследок приведу функцию для проверки: существует ли директория или нет. Ее общий вид такой: &lt;BR&gt;function DirectoryExists(Name: string): Boolean; &lt;BR&gt;Если директория указанная в параметре Name существует - то функция возвратит true. &lt;BR&gt;Надеюсь, что помог Вам описанием данных функций и процедур. Сразу хочется дать совет: почаще заглядывайте в HELP, там много интересной и полезной информации!</content:encoded>
			<link>https://delphi.ucoz.kz/news/rabota_s_direktorijami_papkami_v_delfi/2010-12-02-59</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/rabota_s_direktorijami_papkami_v_delfi/2010-12-02-59</guid>
			<pubDate>Thu, 02 Dec 2010 13:08:13 GMT</pubDate>
		</item>
		<item>
			<title>Сравнительный анализ технологий CORBA и COM</title>
			<description>&lt;P&gt;В последние 2-3 года резко возрос интерес к так называемым распределенным системам. Под распределенными системами обычно понимают программные комплексы, составные части которых функционируют на разных компьютерах в сети. Эти части взаимодействуют друг с другом, используя ту или иную технологию различного уровня - от непосредственного использования сокетов TCP/IP до технологий с высоким уровнем абстракции, таких, как RMI или CORBA.&lt;/P&gt;</description>
			<content:encoded>&lt;P&gt;В последние 2-3 года резко возрос интерес к так называемым распределенным системам. Под распределенными системами обычно понимают программные комплексы, составные части которых функционируют на разных компьютерах в сети. Эти части взаимодействуют друг с другом, используя ту или иную технологию различного уровня - от непосредственного использования сокетов TCP/IP до технологий с высоким уровнем абстракции, таких, как RMI или CORBA. &lt;BR&gt;Рост популярности распределенных систем вызван существенным ужесточением требований, предъявляемых заказчиком к современным программным продуктам. Пожалуй, важнейшими из этих требований являются следующие: Обеспечение масштабируемости систем, т.е. способности эффективно обслуживать как малое, так и очень большое количество клиентов одновременно. Надежность создаваемых приложений. Программный комплекс должен быть устойчив не только к ошибкам пользователей (это определяется главным образом качеством клиентских приложений), но и к сбоям в системе коммуникаций. Надежность подразумевает использование транзакций, т.е. гарантированного перехода системы в процессе функционирования из одного устойчивого и достоверного состояния в другое. Возможность непрерывной работы в течение длительного времени (так называемый режим 24x7, т.е. режим круглосуточной работы в течение недель и месяцев). Высокий уровень безопасности системы, под которой понимается не только контроль доступности тех или иных ресурсов системы и защищенность информации на всех этапах функционирования, но и отслеживание выполняемых действий с высокой степенью достоверности. Высокая скорость разработки приложений и простота их сопровождения и модификации с использованием программистов средней квалификации. Оказалось, что обеспечить соответствие этим требованиям, используя традиционные технологии - а именно, двухзвенные системы &quot;клиент-сервер”, в которых в качестве серверов выступают системы управления базами данных, почти невозможно. &lt;BR&gt;Заметим, что далеко не для всех приложений вышеперечисленные требования являются существенными. Легко представить распределенную систему, которая функционирует на небольшом (до 100) количестве компьютеров, работающих в локальной сети, где нет проблем с перезапуском одного или двух-трех серверов в случае необходимости, а главными задачами, для решения которых используются распределенные технологии, являются задачи использования функциональности нескольких стандартных серверов приложений (например, текстовых процессоров, броузеров и электронных таблиц) в интересах клиентских задач. Необходимо иметь в виду, что термин &quot;распределенные системы” относится к огромному числу задач самого разного класса. &lt;BR&gt;Данный обзор содержит сравнительный анализ двух наиболее популярных и комплексных систем создания распределенных приложений, а именно, CORBA консорциума OMG и COM (DCOM, COM+) фирмы Microsoft. Этот обзор предназначен главным образом для менеджеров проектов, руководителей информационных служб и др., т.е. для тех, кому приходится принимать ответственные, &quot;стратегические” решения. Вследствие этого, в нем будут отсутствовать чисто технические аспекты обоих технологий, которые интересны только для разработчиков. &lt;BR&gt;Кроме того, при написании обзора не ставилась задача сделать окончательный вывод типа &quot;... таким образом, CORBA (COM), бесспорно, лучше, чем COM (CORBA)”. Связано это не с модной в наше время &quot;политкорректностью” или отсутствием у автора своей точки зрения по этому вопросу. Дело даже не в том, что существуют определенные трудности с формализацией такого сравнения - я мог бы представить результаты сравнительных анализов, в которых используются численные оценки (баллы), выставленные экспертами, весовые коэффициенты и прочее, что придает отчету серьезный и весомый вид. Дело в том, что COM и CORBA можно сравнивать только с учетом определенных допущений. Отказ от таких допущений легко позволяет получить какой угодно результат. Вот эти допущения: CORBA, в отличие от COM’а, является концепцией, а не ее реализацией. Когда мы говорим &quot;COM”, то понимаем под этим скорее набор конкретных средств - элементов операционной системы, библиотек, утилит и т.п., являющихся составной частью того, что называется Microsoft Windows. Под термином &quot;CORBA” понимается именно сложная и развитая концепция, сформулированная на уровне специального языка описаний - IDL. Реализации же этой концепции могут сильно отличаться друг от друга по различным критериям, наиболее важным в том или другом случае. Inprise/Corel VisiBroker и Application Server, BEA WebLogic, Iona Orbix, Oracle Application Server и &quot;картриджи” Oracle, IBM BOSS - все эти продукты используют те или иные возможности CORBA. Технология Sun Enterpise JavaBeans создана поверх CORBA и использует такие ее возможности, как удаленный вызов объектов, службу имен, управление транзакциями. Реализация EJB фирмы Inprise связано с CORBA еще более тесным образом. Мы будем сравнивать COM и CORBA именно как концепции создания распределенных систем, а не как ту или иную их реализацию. При работе с реальным проектом необходимо учитывать область применения той или иной технологии. COM (как цельное и комплексное решение) способен функционировать только под Windows NT/Windows2000. Рассуждения о переносе COM на другие операционные системы в настоящий момент носят скорее рекламный характер. Ни компонентная модель COM (т.е. ActiveX), ни монитор транзакций (Microsoft Transaction Server, MTS) не способны работать нигде, кроме Windows, и сама Microsoft не проявляет никакой активности в этом напрвлении (вопросами переноса тех или иных элементов COM на другие платформы занимается консорциум Open Group). CORBA является многоплатформенным решением просто по определению. Помимо чисто технологических аспектов, при принятии решения необходимо оценить затраты на закупку необходимого программного обеспечения, его сопровождения и обучение персонала. COM (в отличие от CORBA) официально является бесплатной технологией. Вы получаете все необходимое, просто приобретя, например, Windows NT Server. (Кстати, сам факт конкуренции дорогостоящей технологии с &quot;аналогичной”, но бесплатной, многое говорит об их технических возможностях). Наличие готовых серверов приложений, пригодных для решения вашей задачи. Если Вы можете решить свои проблемы, используя функциональность Microsoft Office, то ничего лучше COM вы, естественно, не найдете. &lt;BR&gt;Таким образом, главной задачей настоящего обзора является попытка помочь руководителю того или иного уровня принять квалифицированное решение в каждом конкретном случае. Поскольку и CORBA, и COM позиционируются соответственно OMG и Microsoft как универсальные технологии создания распределенных систем, мы будем оценивать и сравнивать их именно с этой точки зрения. Предполагается, что для проекта используется платформа Windows (в противном случае нечего рассматривать COM) и имеется достаточно средств для закупки основных стандартных частей той или иной реализации (иначе обсуждение CORBA теряет смысл). Концептуальный фундамент технологии &lt;BR&gt;COM &lt;BR&gt;Технология создавалась фирмой Microsoft как средство взаимодействия приложений (в том числе составных частей операционной системы) Windows, функционирующих на одном компьютере, с последующим развитием для использования в пределах локальной сети. Главная задача на момент создания - обеспечение технологии Object Linking and Embedding (OLE 1.0). Характерно, что обмен данными между приложениями (Dynamic Data Exchange, DDE) первоначально строился не по COM-технологии, а с использованием механизма сообщений (messages). Развитие технологии идет по мере добавления новых возможностей. Как универсальная технология взаимодействия приложений COM начал использоваться с OLE 2.0 (1991). Концепция технологии неразрывно связана с ее реализацией. Появление новых возможностей - это просто появление новых библиотек, функций API и утилит Windows. &quot;Общий знаменатель технологии” - двоичная структура объекта, хотя в настоящий момент существует язык описания структуры объекта - Interface definition Language (IDL). &lt;BR&gt;CORBA &lt;BR&gt;Технология создавалась консорциумом OMG как универсальная технология создания распределенных систем в гетерогенных средах. OMG представляет собой некоммерческую организацию, являющуюся содружеством разработчиков программного обеспечения и его потребителей, объединивших свои усилия для создания спецификаций этой технологии. В настоящий момент в OMG состоит более 800 членов, включая всех сколько-нибудь серьезных производителей программного обеспечения (и даже c недавнего времени Microsoft). Первая спецификация CORBA появилась в 1991 г. Новые возможности официально считаются добавленными в CORBA в момент утверждения соответствующей спецификации. Как правило, в разработке спецификации участвуют крупнейшие специалисты в данной области. Разработка реализации - задача конкретной фирмы. Обычно от утверждения спецификации до появления высококачественной реализации проходит довольно много времени - иногда несколько лет. &quot;Общий знаменатель” технологии - объявления на языке IDL, который является &quot;сердцем” CORBA с момента ее появления. (Существуют три различных языка описаний с одним и тем же названием - OSF IDL, Microsoft IDL и OMG IDL). &lt;BR&gt;Выводы &lt;BR&gt;Технология CORBA носит существенно более общий и универсальный характер, чем COM, что заложено в ее фундаменте. Опережение разработки спецификаций (по сравнению с реализациями) позволяет добиться более связной, целостной и гармоничной системы. С другой стороны, при разработке реального проекта нужно предварительно убедиться, что высококачественная реализация того или иного сервиса CORBA уже доступна (источниками проблем могут служить, например, Persistence Service и Security Service). Комплексность системы &lt;BR&gt;COM &lt;BR&gt;COM содержит все необходимое, что нужно для построения распределенной системы: технологию удаленного вызова методов (как статических, так и динамических), базы данных серверных объектов (библиотеки типов), которые могут быть импортированы для анализа структуры серверов COM, универсальный протокол обмена между клиентами и серверами, спецификации так называемых &quot;составных документов” (ActiveDoc), объектный монитор транзакций (MTS), компонентную модель (ActiveX) и др. Все составные части прекрасно соответствуют друг другу в рамках модели COM. Уникальной возможностью COM является универсальная технология доступа к базам данных - OLE DB/ADO. &lt;BR&gt;CORBA &lt;BR&gt;В настоящий момент CORBA не имеет своей собственной компонентной модели; работа над ней началась в 1998 г. и еще не завершена. Это главный серьезный недостаток. Правда, он несколько компенсируется наличием основанной на CORBA компонентной моделью Enterprise JavaBeans, так что программисты на Java находятся в привилегированном положении. Все остальное, что присутствует в COM, имеется и в CORBA, и даже более того - за исключением универсальной технологии доступа к БД. Опять-таки, Java-программисты имеют преимущество и здесь - за счет наличия общей для Java технологии доступа к данным JDBC. &lt;BR&gt;Выводы &lt;BR&gt;В настоящий момент COM более законченная система, но на более низком уровне и при существенно большем количестве ограничений, определяемых самой концепцией системы. Используемые языки программирования &lt;BR&gt;COM &lt;BR&gt;Потенциально COM могут поддерживать самые различные языки программирования - все решает фирма Microsoft. Добавление некоторых расширений или экспертов (wizard) в систему разработки позволит использовать для работы с COM любой язык программирования. В настоящий момент наиболее широко используются Visual Basic, C++ и Delphi. Серьезные проблемы возникли при использования языка, на который возлагались особые надежды - с Java. Microsoft добилась прекрасного взаимодействия Java с COM, но достигнуто это было путем отказа от переносимости таких Java-программ на другие виртуальные машины Java. Не случайно продукт фирмы Microsoft - J++ - не содержит в названии &quot;Java”. Вообще, уровень стандартизации для COM достаточно слаб. Это не обязательно нужно рассматривать как недостаток - в конце концов, язык C лет пятнадцать прекрасно обходился без формального стандарта. &lt;BR&gt;CORBA &lt;BR&gt;Под &quot;стандартом” применительно к CORBA понимается то, что официально утверждено консорциумом OMG. Надо сказать, что это очень высокий уровень &quot;легитимности”, так как авторитет OMG в компьютерном мире чрезвычайно высок. В настоящий момент стандартизовано отображение языка IDL на 6 языков программирования - Ada, C, C++, Cobol, Java и Smalltalk. Существуют также отображения на Pascal (точнее, Delphi), Perl, Python и еще десяток языков. &lt;BR&gt;Наиболее используемыми языками в настоящий момент являются Java (вследствие прекрасного взаимодействия Java-технологий, особенно JDBC, RMI, JNDI и EJB, с CORBA), и C++ - как самый эффективный, мощный и распространенный язык компьютерной индустрии. &lt;BR&gt;Выводы &lt;BR&gt;Обе технологии не испытывают особых проблем с точки зрения взаимодействия с языками программирования. Некоторые преимущества имеет CORBA - за счет более строгой стандартизации и более богатого выбора доступных средств разработки. Уровень абстракции &lt;BR&gt;COM &lt;BR&gt;COM реализует высокий уровень абстракции - все вопросы низкого уровня, такие, как взаимодействия с операционной системой или сетевыми средствами, &quot;спрятаны” от прикладного программиста. &lt;BR&gt;CORBA &lt;BR&gt;CORBA обеспечивает даже несколько более высокий уровень за счет базировании технологии исключительно на языке описания IDL с последующим отображением таких спецификаций на конкретный язык программирования, а также некоторых возможностей, например, автоматического (т.е. прозрачного для программиста) распространения контекста транзакций. &lt;BR&gt;Выводы &lt;BR&gt;Обе технологии реализуют примерно одинаковый и достаточно высокий уровень абстракций. Поддержка компонентной модели &lt;BR&gt;COM &lt;BR&gt;Компонентная модель Microsoft, базирующаяся на COM-технологии, в основе имеет двоичную структуру объектов. Это не вызывает никаких проблем при ориентации на одну платформу и операционную систему. Безусловным достоинством такой модели является простота создания компонентов с использованием различных языков программирования. С другой стороны, такая компонентная модель неизбежно связана с определенными ограничениями и недостатками. Одним из самых серьезных недостатков является то, что ее нельзя, строго говоря, назвать объектно-ориентированной. &lt;BR&gt;CORBA &lt;BR&gt;Как уже говорилось, CORBA в настоящее время не имеет своей компонентной модели. Пусть это не имеет практического значения для Java-программистов, но в общем случае эта та область, где OMG (и фирмам-производителям программного обеспечения) еще предстоит серьезно поработать. &lt;BR&gt;Выводы &lt;BR&gt;Это та область, где COM пока имеет существенные преимущества по сравнению с CORBA. C другой стороны, при разработке реальных проектов использование на стороне сервера компонентов Enterprise JavaBeans, построенных поверх инфраструктуры CORBA, предоставляет разработчику значительные преимущества по сравнению с компонентами ActiveX. Универсальный протокол обмена &lt;BR&gt;COM &lt;BR&gt;Передача данных между клиентом и сервером основана на наборе типов, которые называются OLE Automation types. В принципе, схема маршалинга (в том числе типы передаваемых данных) определяется парой стандартных интерфейсов COM. Реализовав по-своему некоторые из методов этих интерфейсов, можно определить свою схему маршалинга. Впрочем, это нетривиальная задача, и обычно разработчики используют уже готовую стандартную реализацию. Упаковка данных и их передача могут быть реализованы поверх различных сетевых протоколов. &lt;BR&gt;CORBA &lt;BR&gt;CORBA значительно более строго и формально подходит к механизмам обмена и передаче данных. Определен протокол CORBA (General Inter-ORB Protocol, GIOP) - и его реализация на базе протокола TCP/IP (Internet Inter-ORB Protocol, IIOP). CORBA способна передавать данные различных типов, включая структуры (struct) и объединения (union), в том числе содержащие рекурсивные определения. Предусмотрена система описания и контроля типов - как на уровне IDL-деклараций, так и динамическая. Для каждого языка используется свое отображение данных IDL. В версии 2.3 появился новый, заимствованный из RMI механизм передачи объектов CORBA - так называемая &quot;передача по значению (objects-by-value)”. В предыдущих версиях CORBA при вызове удаленных методов объекты можно было передавать только по ссылке. &lt;BR&gt;Выводы &lt;BR&gt;CORBA предоставляет значительно больше возможностей, и эти возможности строго формализованы - в противном случае было бы невозможно обеспечить совместную работу различных средств от различных производителей программного обеспечения. Поддержка со стороны различных производителей и открытость &lt;BR&gt;COM &lt;BR&gt;В настоящий момент официальным &quot;хранителем стандарта” технологии COM является консорциум Open Group, хотя &quot;главным игроком на этом поле” является, конечно же, Microsoft. Поддержкой технологии COM занимаются многие небольшие фирмы - некоторые из них создают компоненты ActiveX, некоторые - как Software AG - занимаются переносом фрагментов COM на другие платформы, некоторые - как Borland - создают RAD-инструменты, основанные в том числе и на COM. В любом случае, только Microsoft решает, какая часть технологии и в каком виде попадает из лабораторий Microsoft в открытые спецификации. &lt;BR&gt;CORBA &lt;BR&gt;Ситуация с CORBA совершенно иная. CORBA является результатом совместных усилий огромного числа фирм, среди которых Sun, Oracle, IBM, Netscape/AOL, DEC/Compaq, JavaSoft, Borland/Visigenic (в настоящий момент в связи со слиянием Inprise и Corel принято решение о восстановлении имени Visigenic), BEA, Iona и многие другие. Можно сказать, что все производители программного обеспечения, которое должно функционировать на различных платформах и под управлением различных операционных систем, выбрали CORBA как стандартную инфраструктуру создания программных продуктов. Естественно, все спецификации CORBA являются полностью открытыми. В лагере сторонников CORBA просматривается четкая тенденция к тесному взаимодействию и некоторой унификации используемых технологий (в качестве примера можно привести отказ Sun и ORACLE от создания собственного ORB и лицензирование Visigenic VisiBroker). &lt;BR&gt;Выводы &lt;BR&gt;COM и CORBA имеют совершенно разный уровень открытости и поддержки со стороны ведущих фирм в компьютерной индустрии. &lt;BR&gt;&lt;BR&gt;Развитость сервисной части &lt;BR&gt;COM &lt;BR&gt;COM предоставляет минимальный набор совершенно необходимых средств - кодогенераторы c IDL, утилиты управления доступом (dcomcnfg) и др. Как правило, разработчики пользуются теми или иными инструментами, встроенными в конкретные средства разработки (примером может служит утилита работы с библиотеками типов или эксперт создания ActiveX-объектов в Borland Delphi/C++ Builder). &lt;BR&gt;CORBA &lt;BR&gt;CORBA имеет очень развитую сервисную часть; например, только для поиска серверных объектов по различным критериям можно использовать 4 различных сервиса CORBA. Кроме того, OMG стремится к максимальной стандартизации вспомогательных возможностей CORBA. &lt;BR&gt;Выводы &lt;BR&gt;CORBA предоставляет разработчикам существенно большие возможности, чем COM, в области сервисов и вспомогательных средств. С другой стороны, COM-программисты обычно не испытывают какого-либо дискомфорта из-за их недостатка. Вследствие ограниченности области применения COM объективно нет необходимости в создании таких же развитых и универсальных средств, как это совершенно необходимо для CORBA. &lt;BR&gt;&lt;BR&gt;Самодокументирование системы &lt;BR&gt;COM &lt;BR&gt;COM предусиатривает возможность создания локальной базы данных, хранящей информацию о COM-объектах, их интерфейсах, методах и т.д. для сервера приложений COM. Такая база данных называется библиотекой типов (type library). Использование библиотек типов не является обязательным для OLE, хотя это необходимо в технологии ActiveX. Для получения информации из type library пользователь должен явно импортировать ее, для чего необходимо выбрать соответствующую запись реестра Windows на конкретном компьютере. &lt;BR&gt;CORBA &lt;BR&gt;CORBA имеет аналог библиотеки типов COM - это так называемый Репозитарий Интерфейсов (Interface Repository). Чтобы оценить принципиальную разницу в подходе CORBA по сравнению с COM, достаточно сказать, что Репозитарий Интерфейсов CORBA сам представляет из себя объект CORBA со всеми вытекающими из этого возможностями. Помимо Репозитария Интерфейсов, CORBA использует Репозитарий Реализаций (Implementation Repository), который представляет из себя базу данных, содержащую информацию о серверах приложений CORBA. &lt;BR&gt;Выводы &lt;BR&gt;Средства интроспекции (самодокументрования) CORBA значительно более развиты, мощны, гибки и универсальны, чем аналогичные средства COM. CORBA-программисты получают дополнительные преимущества по сравнению со своими коллегами, работающими с COM, при использовании Java (Java-технологии очень тесно связаны с CORBA). Связано это с тем, что Java предусматривает свой уровень интроспекции, дополнительный по отношению к CORBA. Технология и описание проекта &lt;BR&gt;COM &lt;BR&gt;Обычно объявления на языке IDL при работе с COM не являются существенной частью спецификации проекта, так как IDL-спецификации играют вспомогательную роль в COM-технологии вследствие ее базирования на двоичном стандарте объектов. Кроме того, язык Microsoft IDL не очень развит с точки зрения объявления типов данных, из которых строится программа. &lt;BR&gt;CORBA &lt;BR&gt;Проект с использованием CORBA всегда начинается с написания IDL-спецификаций (особый случай - использование Java, когда в принципе возможно генерировать стандартный код CORBA непосредственно на базе классов Java, хотя вряд ли это разумно для больших проектов.). Эти IDL-спецификации прекрасно отражают суть выполняемых действий с точки зрения функционирования распределенной системы. Синтаксис OMG IDL очень похож на синтаксис С++ (включая те же самые директивы препроцессора). Таким образом, IDL-спецификации могут с успехом использоваться как часть документации проекта. &lt;BR&gt;Выводы &lt;BR&gt;Описания OMG IDL более достоверны и существенно более наглядны, чем описания Microsoft IDL, в роли существенной части спецификации проекта. &lt;BR&gt;&lt;BR&gt;Виды объектов &lt;BR&gt;COM &lt;BR&gt;Объекты COM всегда рассматривались (и продолжают рассматриваться) как серверные объекты, которые просто реализуют тот или иной набор методов. Различные объекты, реализующие один и тот же интерфейс и созданные с помощью обращения к одной и той же фабрике классов, не отличаются друг от друга. Объектная ссылка, которую получает клиент, является указателем на интерфейс и не содержит информации о конкретном объекте. Другими словами, COM оперирует объектами, не имеющими состояния. В общем случае, если клиент, используя одну и ту же объектную ссылку, в цикле вызвал десять раз один и тот же метод, он не может быть уверен, что он обратился к одному, а не к двум, пяти или десяти различным объектам. Естественно, объекты без состояния не имеет смысла хранить дольше, чем существует сервер приложений, в котором они были созданы. Такие объекты применительно к распределенным системам называются временными (transient). COM-объект - это конкретная переменная C++, Visual Basic или Pascal, находящаяся в оперативной памяти и существующая, пока работает создавший ее сервер приложений. Он может быть создана по запросу клиента или заранее (например, с помощью MTS). При работе с COM сопоставить с объектом какое-либо состояние - задача прикладного программиста. Это можно сделать, используя определенный режим создания объектов (выбрав модель управления потоками), хранить состояние объекта на стороне клиента (если это возможно) или использовать так называемые моникеры, которые можно рассматривать как обобщение понятия ключа записи в базе данных. Каждый из этих способов имеет очень существенные ограничения. &lt;BR&gt;CORBA &lt;BR&gt;Понятие &quot;объекта” в CORBA принципиально отличается от своего COM-аналога. Объект CORBA не является переменной языка программирования и в общем случае время его существования не связано со временем работы серверных или клиентских приложений. СORBA-объект не занимает никаких ресурсов компьютера - оперативной памяти, сетевых ресурсов и т.п. Эти ресурсы занимает только так называемый &quot;сервант” (servant), который является &quot;инкарнацией” одного или нескольких CORBA-объектов. Именно сервант является переменной языка программирования. Пока не существует сервант, сопоставленный с конкретным объектом CORBA, этот объект не может обслуживать вызовы клиентов, но, тем не менее, он существует. Результатом создания объекта (при этом совершенно не обязательно при этом создается и сопоставляется с этим объектом соответствующий сервант!) является так называемая &quot;объектная ссылка” CORBA. Объектная ссылка сопоставлена с этим, и только с этим объектом, и это сопоставление остается корректным в течение всего срока существования CORBA-объекта (может быть, в течение нескольких лет). Объектная ссылка CORBA правильно интерпретируется ORB’ами от любого производителя программного обеспечения. После уничтожения CORBA-объекта все объектные ссылки на него навсегда теряют смысл. С помощью объектной ссылки клиент вызывает методы объекта, при этом инкарнациями этого объекта могут быть различные серванты (не более одного одновременно), которые физически могут находиться даже на различных компьютерах. &lt;BR&gt;Выводы &lt;BR&gt;Объект COM может рассматриваться как достаточно примитивный частный случай объекта CORBA - как по своим возможностям, так и с точки зрения его цикла жизни. COM и CORBA предлагают совершенно несопоставимые возможности по созданию и управлению объектами, что жизненно важно для создания надежных и масштабируемых приложений. &lt;BR&gt;&lt;BR&gt;Способы взаимодействия &lt;BR&gt;COM &lt;BR&gt;COM поддерживает как статический, так и динамический способ взимодействия клиента и сервера. Под динамическим способом понимается подход, когда проверка, реализует ли сервер нужный метод, а также все необходимые действия по выполнению удаленного вызова выполняются на этапе работы клиентского приложения, а не этапе его компиляции. При статическом вызове эти действия выполняются именно на этапе компиляции. Разумеется, статический способ предпочтительнее во всех отношениях (когда он возможен вообще). Для его использования сервер COM должен создать и экспортировать библиотеку типов, которая затем импортируется клиентом и используется как часть клиентского процесса. &lt;BR&gt;CORBA &lt;BR&gt;CORBA также поддерживает статический и динамический способ организации удаленных вызовов. &lt;BR&gt;Выводы &lt;BR&gt;Обе технологии предлагают примерно одинаковые возможности в этом плане. CORBA имеет определенные преимущества при использовании динамических вызовов за счет более развитых средств получения информации о серверах (репозитарии интерфейсов). Производительность &lt;BR&gt;COM &lt;BR&gt;COM демонстрирует очень высокую производительность. Читатель, интересующийся этим вопросом, найдет большое количество очень интересной информации в прекрасной книге R. Orfali и D. Harkey &quot;Client/server Programming with Java and CORBA”, second edition, Wiley, 1998. Разумеется, производительность существенно зависит от того, какой способ - статический или динамический - вы используете. &lt;BR&gt;CORBA &lt;BR&gt;Для корректного сравнения CORBA и COM с точки зрения производительности необходимо составить целую систему тестов. Кроме того, необходимо учесть влияние использования того или иного языка программирования. На основе информации, приводимой Orfali и Harkey, а также результатов небольшого сравнительного тестирования, проведенного самим автором обзора (использовался Borland C++ Builder 4.0 и VisiBroker 3.3 для C++), можно сказать, что CORBA демонстрирует даже несколько более высокую производительность. Еще раз повторимся: производительность очень сильно зависит от количества и типов аргументов методов (не забывайте, что их нужно упаковать и передать по сети, а затем распаковать), от выбранной модели управления потоками, от используемых языков программирования (клиент и сервер при этом не обязательно должны быть написаны на одном языке), от конкретной реализации CORBA и многих других факторов. &lt;BR&gt;Выводы &lt;BR&gt;И COM, и CORBA демонстрируют примерно одинаковую (и очень высокую) производительность. Для CORBA говорить о конкретных цифрах можно только для конкретной реализации. В качестве примера приведем следующий факт: Inprise/Visigenic Visibroker прозрачным для разработчика образом работает по-разному в зависимости от того, находятся ли клиентский и серверный объект в одном адресном пространстве, в разных адресных пространствах, но на одном компьютере, или на разных компьютерах. Производительность при этом может отличается на порядок. &lt;BR&gt;&lt;BR&gt;Масштабируемость &lt;BR&gt;COM &lt;BR&gt;Проблемы обеспечения масштабируемости не были заложены в фундамент технологии, если не считать ориентацию на использование только объектов без состояния. Существенным препятствием для создания масштабируемых приложения является очень жесткая связь между клиентом и сервером (объект, т.е. совокупность ресурсов на сервере, не может быть удален, пока клиент явно не укажет, что этот объект больше не нужен). В реальных проектах необходимо управлять состоянием объектов, и это затрудняет создание масштабируемых приложений, так как это обязанность не COM, а программиста. Сильной стороной COM является гибкая модель управления потоками. Основным инструментом, повышающим уровень масштабируемости COM-систем, является MTS. &lt;BR&gt;CORBA &lt;BR&gt;В отличие от COM, CORBA с самого начала рассматривалась как технология создания масштабируемых систем. Разделение собственно объектов CORBA и их сервантов, схемы соответствия между ними, характеристики объектных адаптеров, модели управления потоками и соединениями, схемы активации серверов приложений, универсальные решения по сохранению состояния объектов, автоматическое управление контекстом транзакций и безопасности - все это очень способствует решению данной проблемы. &lt;BR&gt;Выводы &lt;BR&gt;Масштабируемость системы во многом зависит от качества разработки проекта, продуманности принимаемых решений и квалификации менеджеров проекта и разработчиков. При сравнении технологий можно говорить о предпосылках, способствующих (или, наоборот, препятствующих) достижению нужных требований. При прочих равных условиях CORBA имеет громадные преимущества по cравнению с COM. Устойчивость к сбоям &lt;BR&gt;COM &lt;BR&gt;Устойчивость к сбоям COM-систем находится на невысоком уровне, в том числе из-за уже упомянутой излишне жесткой привязки клиентов и серверов. Основным средством обеспечения устойчивости к сбоям (оно же средство управления нагрузкой серверов) является диспетчер, который позволяет перенаправлять вызовы клиента на различные сервера приложений COM. Не слишком содействует отказоустойчивости системы и необходимость выполнения &quot;вручную” большого количества действий по управлению транзакциями. &lt;BR&gt;CORBA &lt;BR&gt;CORBA имеет несколько более высокий уровень устойчивости к сбоям за счет большей изоляции клиентов и серверов, автоматического сохранения состояния объектов, более мощной и продуманной схемы управления транзакциями (включая автоматический откат транзакций по тайм-ауту), а также автоматической привязки объектной ссылки и конкретного объекта CORBA. &lt;BR&gt;Выводы &lt;BR&gt;Проблема обеспечения устойчивости к сбоям, так же как и проблемы обеспечения масштабируемости, не рассматривались как первоочередные при разработке концепции COM. С CORBA ситуация обстоит во многом лучше, но проблемы остаются и здесь. Обе технологии не имеют (или почти не имеют) стандарных средств обеспечения устойчивости к сбоям. Такие компоненты, как VisiBroker Smart Agents, не являются стандартным средством CORBA (хотя они и способны решить многие проблемы при работе с реальными проектами.) Управление транзакциями &lt;BR&gt;COM &lt;BR&gt;Монитором транзакции в COM является MTS. Сервер приложений COM должен быть написан в специальном стиле для того, чтобы иметь возможность взаимодействовать с MTS (такой сервер приложений должен быть реализован в виде DLL). MTS позволяет достаточно гибко управлять режимами выполнения транзакций в системе и поддерживает двухфазное завершение транзакций. Одним из существенных недостатков схемы управления транзакциями COM является необходимость явной передачи контекста транзакции в качестве аргумента при вызове удаленных методов. Такая схема не является ни эффективной, ни гарантирующей от ошибок (особенно при вовлечении в транзакцию большого количества объектов). &lt;BR&gt;CORBA &lt;BR&gt;Управление транзакциями берет на себя так называемый Сервис Управления Транзакциями CORBA (Object Transaction Service, OTS). Он является существенно более гибкой, продуманной и формализованной системой, чем MTS, и содержит все необходимое в рамках CORBA-модели. Сервер приложений CORBA и Сервис транзакций запускаются и работают независимо друг от друга. Важной особенностью CORBA является тесное взаимодействие OTS и ORB, что обеспечивает автоматическое распространение контекста транзакций в многопоточной распределенной среде. Спецификация CORBA предусматривает (необязательную) поддержку вложенных транзакций. &lt;BR&gt;Выводы &lt;BR&gt;На уровне спецификаций Сервис транзакций CORBA имеет определенные преимущества перед MTS. На практике для реализации этих преимуществ нужно предпринять определенные действия. Особенно это касается двухфазного подтверждения транзакций при работе с гетерогенными базами данных. Например, для реализации такой схемы при работе с Java необходимо иметь специальные JDBC-драйвера, которые, насколько мне известно, в настоящий момент не слишком доступны для широкого круга баз данных. В этом плане COM имеет серьезные преимущества за счет взаимодействия MTS со стандартной технологией доступа к базам данных OLE DB/ADO. Обеспечение безопасности &lt;BR&gt;COM &lt;BR&gt;В настоящий момент система безопасности COM базируется на системе безопасности Windows NT/Windows 2000; кроме того, предусмотрена защита данных при их передаче с использованием Socket Security Layer (SSL). Отдельная проблема - обеспечение безопасности при передаче компонентов ActiveX с использованием протокола HTTP. Здесь используется система электронных подписей, лицензий и т.п. - говоря упрощенно, клиент выполняет код компонента, который пришел с &quot;правильного” сервера. &lt;BR&gt;CORBA &lt;BR&gt;С CORBA дела обстоят сложнее - главным образом, в силу того, что ставилась задача создать универсальную систему безопасности, которая могла бы использовать все основные существующие в этой области технологии. Работа над Сервисом Безопасности (Security Service) продолжалась в течение 2 лет, и ее спецификация была принята в 1996 г. Она содержит около 250 страниц. Она позволяет обеспечить уровень безопасности B2 (уровень, близкий к высшему уровню защиты, который используется в государственных учреждениях). Предусмотрена идентификация пользователя, списки прав доступа к ресурсам, система аудита и многое другое. Особенно приятно, что разработчик не должен явно взаимодействовать с этим сервисом - это задача для ORB. Основная нагрузка возложена на системных администраторов. Все это прекрасно, но существует одна небольшая проблема - где взять полномасштабную, высококачественную реализацию этого сервиса? Такие реализации существуют (Gradient, Concept-5), но их использование ограниченно за пределами США. Сервис безопасности от Borland/Visigenic в этом году еще не появится (хотя работа над ним идет). &lt;BR&gt;Выводы &lt;BR&gt;В настоящий момент для реальных проектов для обеих технологий используются сходные решения в области обеспечения безопасности (идентификация на уровне операционной системы и кодирование информации с помощью SSL). Естественно, возможны варианты. Потенциально CORBA предоставляет существенно большие возможности - проблемы здесь организационного, а не концептуального плана. Взаимодействие с Internet &lt;BR&gt;COM &lt;BR&gt;Основой взаимодействия через Internet при работе с COM являются расширения возможностей протокола HTTP, выполненные Microsoft. Броузеры Microsoft (Internet Explorer 3 и выше) позволяют выполнять код ActiveX-компонентов, полученных с Web-серверов. Кроме того, URL доступны при использовании COM - с ними могут работать моникеры. &lt;BR&gt;CORBA &lt;BR&gt;Спецификации CORBA не оговаривают использование Internet в качестве особого случая. Интеграция CORBA и Internet выполняется естественным образом - за счет использования протокола IIOP, построенного поверх TCP/IP. URL-имена могут быть использованы в качестве имен для Службы Именования CORBA. На практике производители программного обеспечения предоставляют расширения CORBA, упрощающие работу с Internet (VisiBroker URL Naming Service) или решающие те или иные проблемы - например, &quot;обход” ограничений, накладываемых на апплеты Java, используемых в качестве CORBA-клиентов (например, Borland/Visigenic GateKeeper). &lt;BR&gt;Выводы &lt;BR&gt;CORBA (особенно при использования Java) без каких-либо проблем может быть интегрирована с Internet. Взаимодействие COM и Internet основано на использовании ActiveX и требует использования только броузеров, поддерживающих тег
&lt;OBJECT&gt;
 Microsoft. Косвенным образом проблемы совместной работы COM и Internet могут возникнуть из-за несовместимости виртуальной машины Java Microsoft с другими виртуальными машинами. 
Скорость разработки систем &lt;br&gt;COM 
&lt;br&gt;Скорость разработки COM-систем может быть очень высокой за счет интенсивного использования компонентной модели ActiveX, а также универсальных подходов, таких, как OLE DB. Не составляет особого труда создание Internet-приложений с броузером Microsoft в качестве клиентского приложения. 
&lt;br&gt;CORBA 
&lt;br&gt;Скорость разработки CORBA-систем сильно зависит от используемой технологии. Наверное, максимально эффективн</content:encoded>
			<link>https://delphi.ucoz.kz/news/sravnitelnyj_analiz_tekhnologij_corba_i_com/2010-12-01-58</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/sravnitelnyj_analiz_tekhnologij_corba_i_com/2010-12-01-58</guid>
			<pubDate>Wed, 01 Dec 2010 14:58:53 GMT</pubDate>
		</item>
		<item>
			<title>Естественные ключи против искуственных ключей</title>
			<description>Данная статья излагает взгляд автора на проблему, регулярно обсуждающуюся в группах новостей, посвящённых разработке приложений с использованием РСУБД.</description>
			<content:encoded>Данная статья излагает взгляд автора на проблему, регулярно обсуждающуюся в группах новостей, посвящённых разработке приложений с использованием РСУБД. О сущности проблемы &lt;BR&gt;&lt;BR&gt;Каждая запись в таблице, входящей в РСУБД, должна иметь первичный ключ (ПК) - набор атрибутов, уникально идентифицирующий её в таблице. Случай, когда таблица не имеет первичного ключа, имеет право на существование, однако в данной статье не рассматривается. &lt;BR&gt;В качестве первичного ключа может использоваться - Естественный Ключ (ЕК) - набор атрибутов описываемой записью сущности, уникально её идентифицирующий (например, номер паспорта для человека); или Суррогатный Ключ (СК) - автоматически сгенерированное поле, никак не связанное с информационным содержанием записи. Обычно в роли СК выступает автоинкрементное поле типа INTEGER. &lt;BR&gt;Есть два мнения: СК должны использоваться, только если ЕК не существует. Если же ЕК существует, то идентификация записи внутри БД осуществляется по имеющемуся ЕК; СК должны добавляться в любую таблицу, на которую существуют ссылки (REFERENCES) из других таблиц, и связи между ними должны организовываться только при помощи СК. Разумеется, поиск записи и представление её пользователю по прежнему производятся на основании ЕК. &lt;BR&gt;Естественно, можно представить себе и некое промежуточное мнение, но сейчас дискуссия ведётся в рамках двух вышеизложенных. Когда появляются СК &lt;BR&gt;&lt;BR&gt;Для понимания места и значения СК рассмотрим этап проектирования, на котором они вводятся в структуру БД, и методику их введения. &lt;BR&gt;Для ясности рассмотрим БД из 2-х отношений - Города (City) и Люди (People) Предполагаем, что город характеризуется Hазванием (Name), все города имеют разные названия, человек характеризуется Фамилией (Family), номером паспорта (Passport) и городом проживания (City). Также полагаем, что каждый человек имеет уникальный номер паспорта. Hа этапе составления инфологической модели БД её структура одинакова и для ЕК и для СК. CREATE TABLE City( Name VARCHAR(30) NOT NULL PRIMARY KEY ); CREATE TABLE People( Passport CHAR(9) NOT NULL PRIMARY KEY, Family VARCHAR(20) NOT NULL, City VARCHAR(30) NOT NULL REFERENCES City(Name) ); &lt;BR&gt;Для ЕК все готово. Для СК делаем еще один этап и преобразуем таблицы следующим образом: CREATE TABLE City( /* В разных диалектах языка SQL автоинкрементное поле будет выражено по-разному - например, через IDENTITY, SEQUENCE или GENERATOR. Здесь мы используем условное обозначение AUTOINCREMENT. */ Id INT NOT NULL AUTOINCREMENT PRIMARY KEY Name VARCHAR(30) NOT NULL UNIQUE ); CREATE TABLE People( Id INT NOT NULL AUTOINCREMENT PRIMARY KEY, Passport CHAR(9) NOT NULL UNIQUE, Family VARCHAR(20) NOT NULL, CityId INT NOT NULL REFERENCES City(Id) ); &lt;BR&gt;Обращаю внимание, что: Все условия, диктуемые предметной областью (уникальность имени города и номера паспорта) продолжают присутствовать в БД, только обеспечиваются не условием PRIMARY KEY, а условием UNIQUE; Ключевого слова AUTOINCREMENT ни в одном из известных мне серверов нет. Это просто обозначение, что поле генерируется автоматически. &lt;BR&gt;В общем случае алгоритм добавления СК выглядит следующим образом: В таблицу добавляется поле INTEGER AUTOINCREMENT; Оно объявляется PRIMARY KEY; Старый PRIMARY KEY (ЕК) заменяется на UNIQUE CONSTRAINT ; Если в таблице есть REFERENCES на другие таблицы, то поля, входящие в REFERENCES, заменяются на одно поле типа INTEGER, составляющее первичный ключ (как People.City заменена на People.CityId). &lt;BR&gt;Это механическая операция, которая никак не нарушает инфологической модели и целостности данных. С точки зрения инфологической модели эти две базы данных эквивалентны. Зачем всё это надо &lt;BR&gt;&lt;BR&gt;Возникает резонный вопрос - а зачем? Действительно, вводить в таблицы какие-то поля, что-то заменять, зачем? Итак, что мы получаем, проделав эту &quot;механическую&quot; операцию. Упрощение сопровождения &lt;BR&gt;&lt;BR&gt;Это область, где СК демонстрируют наибольшие преимущества. Поскольку операции связи между таблицами отделены от логики &quot;внутри таблиц&quot; - и то и другое можно менять независимо и не затрагивая остального. &lt;BR&gt;Hапример - выяснилось, что города имеют дублирующиеся названия. Решено ввести в City еще одно поле - Регион (Region) и сделать ПК (City, Region). В случае ЕК - изменяется таблица City, изменяется таблица People - добавляется поле Region (да, да, для всех записей, про размеры молчу), переписываются все запросы, в том числе на клиентах, в которых участвует City, в них добавляются строка AND XXX.Region = City.Region. &lt;BR&gt;Да, чуть не забыл, большинство серверов сильно не любят ALTER TABLE на поля, входящие в PRIMARY KEY и FOREIGN KEY. &lt;BR&gt;В случае СК - добавляется поле в City, изменяется UNIQUE CONSTRAINT. Всё. &lt;BR&gt;Еще пример - в случае СК изменение списка полей в SELECT никогда не заставляет переписывать JOIN. В случае ЕК - добавилось поле, не входящее в ПК связанной таблицы - переписывайте. &lt;BR&gt;Еще пример - поменялся тип данных поля, входящего в ЕК. И опять переделки кучи таблиц, заново оптимизация индексов... &lt;BR&gt;В условиях меняющегося законодательства это достоинство СК само по себе достаточно для их использования. Уменьшение размера БД &lt;BR&gt;&lt;BR&gt;Предположим в нашем примере, что средняя длина названия города - 10 байт. Тогда на каждого человека в среднем будет приходиться 10 байт для хранения ссылки на город (реально несколько больше за счёт служебной информации на VARCHAR и гораздо больше за счёт индекса по People.City, который придётся построить, чтобы REFERENCES работала эффективно). В случае СК - 4 байта. Экономия - минимум 6 байт на человека, приблизительно 10 Мб для г. Hовосибирска. Очевидно, что в большинстве случаев уменьшение размера БД - не самоцель, но это, очевидно, приведет и к росту быстродействия. &lt;BR&gt;Звучали аргументы, что БД может сама оптимизировать хранение ЕК, подставив вместо него в People некую хэш-функцию (фактически создав СК сама). Hо ни один из реально существующих коммерческих серверов БД так не делает, и есть основания полагать, что и не будет делать. Простейшим обоснованием такого мнения является то, что при подобной подстановке банальные операторы ADD CONSTRAINT … FOREIGN KEY или DROP CONSTRAINT … FOREIGN KEY будут приводить к нешуточной перетряске таблиц, с ощутимым изменением всей БД (надо будет физически добавить или удалить (с заменой на хэш-функцию)) все поля, входящие в CONSTRAINT. Увеличение скорости выборки данных &lt;BR&gt;&lt;BR&gt;Вопрос достаточно спорный, однако, исходя из предположений, что: База данных нормализована; Записей в таблицах много (десятки тысяч и более); Запросы преимущественно возвращают ограниченные наборы данных (максимум единицы процентов от размера таблицы). &lt;BR&gt;быстродействие системы на СК будет ощутимо выше. И вот почему: &lt;BR&gt;ЕК могут потенциально дать более высокое быстродействие, когда: Требуется только информация, входящая в первичные ключи связанных таблиц; нет условий WHERE по полям связанных таблиц. &lt;BR&gt;Т.е., в нашем примере это запрос типа: SELECT Family, City FROM People; &lt;BR&gt;В случае СК этот запрос будет выглядеть как SELECT P.Family, C.Name FROM People P INNER JOIN City C ON P.CityId = C.Id; &lt;BR&gt;Казалось бы, ЕК дает более простой запрос с меньшим количеством таблиц, который выполнится быстрее. Hо и тут не всё так просто: размеры таблиц для ЕК - больше (см. выше) и дисковая активность легко съест преимущество, полученное за счёт отсутствия JOIN`а. Ещё сильнее это скажется, если при выборке данных используется их фильтрование (а при сколько-либо существенном объеме таблиц оно используется обязательно). Дело в том, что поиск, как правило, осуществляется по информативным полям типа CHAR, DATETIME и т.п. Поэтому часто бывает быстрее найти в справочной таблице набор значений, ограничивающий возвращаемый запросом результат, а затем путем JOIN`а по быстрому INTEGER-индексу отобрать подходящие записи из большой таблицы. Например: (ЕК) SELECT Family, City FROM People WHERE City = &apos;Иваново&apos;; &lt;BR&gt;будет выполняться в разы медленнее, чем (CК) SELECT P.Family, C.Name FROM People P INNER JOIN City C ON P.CityId = C.Id WHERE C.Name = &apos;Иваново&apos;; &lt;BR&gt;В случае ЕК - будет INDEX SCAN большой таблицы People по CHARACTER-индексу. В случае СК - INDEX SCAN меньшей CITY и JOIN по эффективному INTEGER индексу. &lt;BR&gt;А вот если заменить = &apos;Иваново&apos; на LIKE &apos;%ваново&apos;, то речь пойдет о торможении ЕК относительно СК на порядок и более. &lt;BR&gt;Аналогично, как только в случае с ЕК понадобится включить в запрос поле из City, не входящее в её первичный ключ - JOIN будет осуществлятся по медленному индексу и быстродействие упадет ощутимо ниже уровня СК. Выводы каждый может делать сам, но пусть он вспомнит, какой процент от общего числа его запросов составляют SELECT * FROM ЕдинственнаяТаблица. У меня - ничтожно малый. &lt;BR&gt;Да, сторонники ЕК любят проводить в качестве достоинства &quot;информативность таблиц&quot;, которая в случае ЕК растет. Ещё раз повторю, что максимальной информативностью обладает таблица, содержащая всю БД в виде flat-file. Любое &quot;повышение информативности таблиц&quot; есть увеличение степени дублирования в них информации, что не есть хорошо. Увеличение скорости обновления данных &lt;BR&gt;INSERT &lt;BR&gt;&lt;BR&gt;Hа первый взгляд ЕК быстрее - не надо при INSERT генерировать лишнего поля и проверять его уникальность. В общем-то так оно и есть, хотя это замедление проявляется только при очень высокой интенсивности транзакций. Впрочем и это неочевидно, т.к. некоторые серверы оптимизируют вставку записей, если по ключевому полю построен монотонно возрастающий CLUSTERED индекс. В случае СК это элементарно, в случае ЕК - увы, обычно недостижимо. Кроме этого, INSERT в таблицу на стороне MANY (который происходит чаще) пойдет быстрее, т.к. REFERENCES будут проверяться по более быстрому индексу. UPDATE &lt;BR&gt;&lt;BR&gt;При обновлении поля, входящего в ЕК, придётся каскадно обновить и все связанные таблицы. Так, переименование Ленинграда в Санкт-Петербург потребует с нашем примере транзакции на несколько миллионов записей. Обновление любого атрибута в системе с СК приведет к обновлению только одной записи. Очевидно, что в случае распределенной системы, наличия архивов и т.п. ситуация только усугубится. Если обновляются поля не входящие в ЕК – быстродействие будет почти одинаковым. Еще о CASCADE UPDATE &lt;BR&gt;&lt;BR&gt;Далеко не все серверы БД поддерживают их на декларативном уровне. Аргументы &quot;это у вас сервер кривой&quot; в этом случае вряд ли корректны. Это вынуждает писать отдельную логику для обновления, что не всегда просто (приводился хороший пример - при отсутствии CASCADE UPDATE обновить поле, на которое есть ссылки, вообще невозможно - надо отключать REFERENCES или создавать копию записи, что не всегда допустимо (другие поля могут быть UNIQUE)). DELETE &lt;BR&gt;&lt;BR&gt;В случае СК будет выполняться быстрее, по той простой причине, что проверка REFERENCES пойдет по быстрому индексу. А есть ли хорошие ЕК? &lt;BR&gt;&lt;BR&gt;Hичто не вечно под Луной. Самый, казалось бы, надежный атрибут вдруг отменяется и перестаёт быть уникальным (далеко ходить не буду - рубль обычный и рубль деноминированный, примерам несть числа). Американцы ругаются на неуникальность номера социального страхования, Microsoft - на китайские серые сетевые платы с дублирующимися MAC-адресами, которые могут привести к дублированию GUID, врачи делают операции по смене пола, а биологи клонируют животных. В этих условиях (и учитывая закон неубывания энтропии) закладывать в систему тезис о неизменности ЕК - закладывать под себя мину. Их надо выделять в отдельный логический слой и по возможности изолировать от остальной информации. Так их изменение переживается куда легче. Да и вообще: однозначно ассоциировать сущность с каким-то из атрибутов этой сущности - ну, странно, что-ли. Hомер паспорта ещё не есть человек. СК же - это некая субстанция, именно и означающая сущность. Именно сущность, а не какой-то из её атрибутов. Типичные аргументы сторонников ЕК &lt;BR&gt;В системе с СК не осуществляется контроль правильности ввода информации &lt;BR&gt;&lt;BR&gt;Это не так. Контроль не осуществлялся бы, если бы на поля, входящие в ЕК не было наложено ограничение уникальности. Очевидно, что если предметная область диктует какие-то ограничения на атрибуты ЕК, то они будут отражены в БД в любом случае. В системе с ЕК меньше JOIN`ов, следовательно, запросы проще и разработка удобнее &lt;BR&gt;&lt;BR&gt;Да, меньше. Hо, в системе с СК тривиально пишется: CREATE VIEW PeopleEK AS SELECT P.Family, P.Passport, C.Name FROM People P INNER JOIN City C ON P.CityId = C.Id &lt;BR&gt;И можно иметь все те же прелести. С более, правда, высоким быстродействием. При этом неплохо упомянуть, что в случае ЕК многим придется программировать каскадные операции, и, не дай Бог в распределённой среде, бороться с проблемами быстродействия. Hа фоне этого &quot;короткие&quot; запросы уже не кажутся столь привлекательными. Введение ЕК нарушает третью нормальную форму &lt;BR&gt;&lt;BR&gt;Вспомним определение: &lt;BR&gt;Таблица находится в третьей нормальной форме (3НФ), если она удовлетворяет определению 2НФ, и ни одно из её неключевых полей не зависит функционально от любого другого неключевого поля. &lt;BR&gt;То есть, речи о ключевых полях там не идёт вообще. Поэтому добавление ещё одного ключа в таблицу ни в коей мере не может нарушить 3НФ. Вообще, для таблицы с несколькими возможными ключами имеет смысл говорить не о 3 НФ, а о Нормальной Форме Бойса-Кодда, которая специально введена для таких таблиц. &lt;BR&gt;Итак: &lt;BR&gt;Таблица находится в нормальной форме Бойса-Кодда (НФБК), если и только если любая функциональная зависимость между его полями сводится к полной функциональной зависимости от возможного ключа. &lt;BR&gt;Таким образом, таблица, имеющая СК, легко может быть нормализована хоть до 5НФ. Точнее будет сказать, что СК к нормализации не имеют никакого отношения. Более того, введение СК уменьшает избыточность данных в БД, что вообще хорошо согласуется с идеологией нормализации. В сущности, нормализация и есть уменьшение информативности отдельных таблиц по определенным правилам. Только СК устраняют аномалии не внутри таблицы, а на межтабличном уровне (типа устранения каскадных обновлений). Так сказать, система с СК - святее Папы Римского :-). В самом деле – ситуация, когда при изменении одного из полей таблицы приходится изменять содержимое этого же поля в других записях ЭТОЙ ЖЕ таблицы, рассматривается как аномалия обновления. Но в системе с ЕК придется проделать то же самое В СВЯЗАННОЙ таблице при изменении ключевого атрибута на стороне 1 отношения 1:N. Очевидно, что эта ситуация с точки зрения физической реализации БД ничем не лучше. В системе с СК таких ситуаций не возникает. Таблицы в системе с ЕК информативнее &lt;BR&gt;&lt;BR&gt;Максимальной информативностью обладает таблица, содержащая всю БД в виде flat-file. Любое &quot;повышение информативности таблиц&quot; есть увеличение степени дублирования в них информации, что не обязательно есть хорошо. Да и вообще термин &quot;Информативность таблицы&quot; сомнителен. Видимо, более важна информативность БД, которая в обоих случаях одинакова. Заключение &lt;BR&gt;&lt;BR&gt;В общем-то, выводы очевидны – введение СК позволяет получить лучше управляемую, более компактную и быстродействующую БД. Разумеется, это не панацея. В некоторых случаях (например, таблица на которую нет REFERENCES и в которую осуществляется интенсивная вставка данных и т.п.) более верно использовать ЕК или не использовать ПК вообще (последнее категорически противопоказано для многих РСУБД и средств разработки клиентских приложений). Но речь шла именно о типовой методике, которую надо рекомендовать к применению в общем случае. Уникальные ситуации могут потребовать уникальных же решений (иногда и нормализацией приходится поступаться). Автор: Тенцер А. Л. &lt;BR&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/estestvennye_kljuchi_protiv_iskustvennykh_kljuchej/2010-12-01-57</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/estestvennye_kljuchi_protiv_iskustvennykh_kljuchej/2010-12-01-57</guid>
			<pubDate>Wed, 01 Dec 2010 14:56:35 GMT</pubDate>
		</item>
		<item>
			<title>Алгоритм шифрования цезарь</title>
			<description>Шифрование алгоритмом цезарь:&lt;br&gt;Описание переменных&lt;br&gt;var i,o,ofset: integer;&lt;br&gt;str:string;&lt;br&gt;x:char;&lt;br&gt;</description>
			<content:encoded>Шифрование алгоритмом цезарь:&lt;br&gt;Описание переменных&lt;br&gt;var i,o,ofset: integer;&lt;br&gt;str:string;&lt;br&gt;x:char;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;Алгоритм шифрования:&lt;br&gt;try&lt;br&gt;final.Caption:=&apos;&apos;;&lt;br&gt;str:=eText.Lines.Text;&lt;br&gt;ofset:=strtoInt(eoffset.Text);&lt;br&gt;for i:=1 to length(str) do&lt;br&gt;begin&lt;br&gt;o:=ord(str[i])+ofset;&lt;br&gt;if o &amp;gt;= 256 then dec(o, 256);&lt;br&gt;&lt;br&gt;x:=chr(o);&lt;br&gt;final.Caption:=final.Caption+x;&lt;br&gt;end;&lt;br&gt;except MessageDlg(&apos;Внимание! Вы не правильно ввели текст или смещение&apos;,mtWarning ,[mbOK ],1);&lt;br&gt;end;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;Дешифрация:&lt;br&gt;Описание переменных:&lt;br&gt;i,o,k:integer;&lt;br&gt;str:string;&lt;br&gt;y:char;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;Алгоритм:&lt;br&gt;try&lt;br&gt;str:=final.Caption;&lt;br&gt;k:=strtoInt(eoffset.Text);&lt;br&gt;final.Caption:=&apos; DeCrypt=&apos;;&lt;br&gt;for i:=1 to length(str) do&lt;br&gt;begin&lt;br&gt;o:=ord(str[i])-k;&lt;br&gt;if o &lt; 0 then Inc(o, 256);&lt;br&gt;y:=chr(o);&lt;br&gt;final.Caption:=final.Caption+y;&lt;br&gt;end;&lt;br&gt;except MessageDlg(&apos;Сначала зашифруйте текст!!!&apos;,mtWarning ,[mbOK ],1);&lt;br&gt;end;&lt;br&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/algoritm_shifrovanija_cezar/2010-12-01-56</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/algoritm_shifrovanija_cezar/2010-12-01-56</guid>
			<pubDate>Wed, 01 Dec 2010 11:27:04 GMT</pubDate>
		</item>
		<item>
			<title>Минимизация занимаемой памяти</title>
			<description>Маленький трюк, который пригодится Вам для создания приложений, работающих в фоновом режиме. Таких, как планировщик задач, служб, серверов и т.п. То есть приложений, которые постоянно сидят себе тихонько в памяти, и чего-то там в фоне делают, не мешая пользователю заниматься своими делами.&lt;br&gt;Для таких приложений важным фактором является размер потребляемой памяти.&lt;br&gt;</description>
			<content:encoded>Маленький трюк, который пригодится Вам для создания приложений, работающих в фоновом режиме. Таких, как планировщик задач, служб, серверов и т.п. То есть приложений, которые постоянно сидят себе тихонько в памяти, и чего-то там в фоне делают, не мешая пользователю заниматься своими делами.&lt;br&gt;Для таких приложений важным фактором является размер потребляемой памяти.&lt;br&gt;Фоновые приложения должны кушать минимум оперативной памяти и не нагружать процессор.&lt;br&gt;В принципе, данный приём можно применять в любых приложениях. Просто для активных интерфейсных приложений в этом нет смысла.&lt;br&gt;Но меньше слов, больше кода: &lt;br&gt;uses Windows, SysUtils;&lt;br&gt; &lt;br&gt;procedure TrimWorkingSet;&lt;br&gt;var&lt;br&gt; MainHandle: THandle;&lt;br&gt;begin&lt;br&gt; if Win32Platform = VER_PLATFORM_WIN32_NT then&lt;br&gt; begin&lt;br&gt; MainHandle := OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessID);&lt;br&gt; SetProcessWorkingSetSize(MainHandle, DWORD(-1), DWORD(-1));&lt;br&gt; CloseHandle(MainHandle);&lt;br&gt; end;&lt;br&gt;end;&lt;br&gt;После вызова этой процедуры, приложение отпустит всю ненужную ему память.&lt;br&gt;Можете попробовать создать пустую форму с кнопкой и посмотреть, как изменится объём занимаемой памяти.&lt;br&gt;P.S. Сработает только на WinNT системах.&lt;br&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/minimizacija_zanimaemoj_pamjati/2010-11-28-55</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/minimizacija_zanimaemoj_pamjati/2010-11-28-55</guid>
			<pubDate>Sun, 28 Nov 2010 06:01:14 GMT</pubDate>
		</item>
		<item>
			<title>Вскрываем ReadOnly property</title>
			<description>При работе со сторонними компонентами и библиотеками, иногда может возникнуть несогласие с автором. В частности рассмотрим такой момент, когда автор класса сторонней библиотеки создал property, которую нельзя изменить, но нам очень хочется.&lt;br&gt;Данный приём имеет ряд ограничений. Поэтому я не буду брать какой-то конкретный класс, а нарисую примитивный для примера.&lt;br&gt;</description>
			<content:encoded>При работе со сторонними компонентами и библиотеками, иногда может возникнуть несогласие с автором. В частности рассмотрим такой момент, когда автор класса сторонней библиотеки создал property, которую нельзя изменить, но нам очень хочется.&lt;br&gt;Данный приём имеет ряд ограничений. Поэтому я не буду брать какой-то конкретный класс, а нарисую примитивный для примера.&lt;br&gt;Допустим, есть такой класс:&lt;br&gt; TStrikeCatsControl = class(TControl)&lt;br&gt; private&lt;br&gt; FCorrectValue: Integer;&lt;br&gt; public&lt;br&gt; constructor Create(AOwner: TComponent); override;&lt;br&gt; published&lt;br&gt; property CorrectValue: Integer read FCorrectValue;&lt;br&gt; end;&lt;br&gt; &lt;br&gt;...&lt;br&gt; &lt;br&gt;constructor TStrikeCatsControl.Create(AOwner: TComponent);&lt;br&gt;begin&lt;br&gt; inherited;&lt;br&gt; FCorrectValue := Screen.DesktopWidth div 2;&lt;br&gt;end;&lt;br&gt;Вобщем какой-то сторонний компонент, у которого есть проперти CorrectValue. Автор контрола считает, что данное проперти не нуждается в записи, а должно вычисляться автоматом.&lt;br&gt;Мы же считаем, что оно должно быть другим. Например Screen.Width div 2;&lt;br&gt;Как быть? Изменить исходники компонента? Логично, но нехорошо. Да их может и не быть. Можно использовать нехитрый трюк.&lt;br&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/vskryvaem_readonly_property/2010-11-28-54</link>
			<category>Советы и трюки</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/vskryvaem_readonly_property/2010-11-28-54</guid>
			<pubDate>Sun, 28 Nov 2010 05:57:49 GMT</pubDate>
		</item>
		<item>
			<title>Программирование на основе Win32 API в Delphi</title>
			<description>Любую современную программу или программную технологию можно представить как совокупность программных &quot;слоев&quot;. Каждый из этих слоев производит свою собственную работу, которая заключается в повышении уровня абстракции производимых операций. Так, самый низший слой (слои) вводит понятия, которые позволяют абстрагироваться от используемого оборудования; следующий слой (слои) позволяет программисту абстрагироваться от сложной последовательности вызовов функций, вводя такое понятие как протокол и т.д. Практически в любом современном программном продукте можно обнаружить и выделить около десятка последовательных слоев абстракции.</description>
			<content:encoded>Программирование на основе Win32 API в Delphi&lt;BR&gt;Источник: www.codenet.ru&lt;BR&gt;1. Введение&lt;BR&gt;&lt;BR&gt;Любую современную программу или программную технологию можно представить как совокупность программных &quot;слоев&quot;. Каждый из этих слоев производит свою собственную работу, которая заключается в повышении уровня абстракции производимых операций. Так, самый низший слой (слои) вводит понятия, которые позволяют абстрагироваться от используемого оборудования; следующий слой (слои) позволяет программисту абстрагироваться от сложной последовательности вызовов функций, вводя такое понятие как протокол и т.д. Практически в любом современном программном продукте можно обнаружить и выделить около десятка последовательных слоев абстракции.&lt;BR&gt;&lt;BR&gt;Абстракция от оборудования и низкоуровневых протоколов вводится в ядра операционных систем в виде библиотек api (application program interface). Однако современные тенденции приводят к необходимости абстрагирования и от самих операционных систем, что позволяет переносить программы с одной операционной системы на другую путем простой перекомпиляции (транслируемые программы, в основном, вообще не требуют никаких действий по переносу).&lt;BR&gt;&lt;BR&gt;Абстракцию, которая доступна программисту в виде библиотек api можно назвать базовой. Это самый низкий уровень абстракции, который доступен для прикладного программирования. На уровне ядра системы доступны и более низкие уровни абстракции, однако для их использования необходимо разрабатывать специализированные программы (драйвера, модули). Базовый уровень абстракции (api) предоставляет максимально широкие возможности для прикладного программирования и является наиболее гибким. Однако, программирование с использованием api является гораздо более трудоемким и приводит к значительно большим объемам исходного кода программы, чем программирование с использованием дополнительных библиотек.&lt;BR&gt;&lt;BR&gt;Дополнительные библиотеки поставляются со многими средствами разработки с целью уменьшения трудоемкости и сроков разработки программ, что в итоге приводит к повышению их конкурентноспособности. Но применение дополнительных библиотек абстракций приводит к резкому увеличению размеров откомпилированных программ, из-за того что в программу включается код используемых библиотек, к тому же это включение зачастую бывает неэффективным - в программу включаются неиспользуемые участки кода. Кроме того, чем больше уровень абстракции библиотеки, тем сложнее ее код, и тем больше трудностей возникает при решении сложных задач. Приходится учитывать множество взаимосвязей и взаимных влияний отдельных элементов и процессов библиотеки друг на друга. Кроме того, структура и функциональность любой библиотеки обычно рассчитывается на удовлетворение всех потенциально возникающих задач, что приводит к ее громоздкости и неэффективности.&lt;BR&gt;&lt;BR&gt;В delphi используется очень мощная и сложная библиотека vcl (visual components library), которая помимо непосредственных абстракций вводит также и множество своих функциональных классов. В этой библиотеке находятся компоненты для визуального отображения информации, работы с базами данных, с системными объектами, компоненты для работы с internet-протоколами, классы для написания своих com-объектов и многое другое. Модули библиотеки подключаются к компиляции по мере необходимости, однако базовый размер простейшего диалогового проекта с одной формой превышает 300кБ (со статически скомпонованной библиотекой). И такой размер во многих случаях может оказаться слишком большим, особенно если программа не требует большой функциональности в интерфейсе.&lt;BR&gt;&lt;BR&gt;Для решения этой проблемы можно отказаться от использования библиотеки vcl, и программировать, используя базовый набор функций win32 api. Однако, если при разработке линейных, недиалоговых, нерезидентных программ не возникает никаких трудностей, то разработка программ, требующих активного взаимодействия с пользователем или системой, становится трудоемкой. Структурное программирование, рекомендуемое в таких случаях, оказывается неэффективным и трудоемким.&lt;BR&gt;&lt;BR&gt;Данная статья посвящена проблеме создания и использования компактной объектно-ориентированной библиотеки, которая бы облегчила построение небольших и эффективных программ на основе win32 api.&lt;BR&gt;&lt;BR&gt;2. Существующие решения&lt;BR&gt;&lt;BR&gt;Автору известны три объектно-ориентированные библиотеки, которые можно рассматривать как альтернативу библиотеке vcl при написании компактных программ. Это библиотеки классов xcl, acl и kol. Все библиотеки бесплатны и поставляются в исходных кодах.&lt;BR&gt;&lt;BR&gt;Библиотека acl (api control library) &lt;BR&gt;Автор: Александр Боковиков, Екатеринбург, Россия &lt;BR&gt;Страничка: http://a-press.ur.ru/pc/bokovikov &lt;BR&gt;e-mail: abb@adx.ru &lt;BR&gt;Классы и модули: tfont, tfonts, tcontrol, twincontrol, tstdcontrol, tlabel, tedit, tlistbox, tbutton, tcheckbox, tcombobox, tgroupbox, tprogressbar, tkeyboard &lt;BR&gt;&lt;BR&gt;Библиотека xcl (extreme class library) &lt;BR&gt;Автор: vladimir kladov (mr.bonanzas) &lt;BR&gt;Страничка: http://xcl.cjb.net &lt;BR&gt;e-mail: bonanzas@xcl.cjb.net &lt;BR&gt;Классы и модули: xform, xapplet, xcanvas, xpen, xbrush, xfont, zddb, zhibmp, zdibitmap, zbitmap, zicon, zgifdecoder, zgif, zjpeg, xlabel, xbutton, xbevel, xpanel, xsplitpanel, xstatus, xgrep, xgroup, xcheckbox, xradiobox, xpaint, xscroller, xscrollbox, xscrollboxex, xedit, xnumedit, xcombo, xgrid, xlistview, xmultilist, xnotebook, xtabs, xtabbednotebook, xcalendar, xgauge, xgaugepercents, xhysto, xhystoex, ximagelist, ximgbutton, xtooltip, xcustomform, xdsgnform, xdsgnnonvisual, clabel, cpaint, cbutton, cedit, cmemo, ccheckbox, cradiobox, clistbox, ccombobox, zlist, zmenu, zpopup, zmainmenu, zpopupmenu, ztimer, zstrings, zstringlist, zinifile, zthread, zqueue, zfilechange, zdirchange, zopensavedialog, zopendirdialog, ztree, zdirlist, zdirlistex, zregistry, zstream, zfilestream, zmemorystream, xstrutils, xdateutils, xfileutils, xwindowutils, xprintutils, xshelllinks, xjustone, xjustonenotify, xpascalunit, xsysicons, xcanvasobjectsmanager, xrotatefonts, xfocuspainter, xformsstdmouseevents, xformsstdkeyevents, xformautosizer, xaligner, xcontrolautoplacer, xmfcantiflicker, xsplitsizer, xresizeantiflicker, xcaretshower, xeditmouseselect, xeditclipboard, xeditundo, xlistmousesel, xlistkeysel, xlistedit, znamedtags, xbtnrepeats, xbuflabels, xbackgrounds, xwnddynhandlers &lt;BR&gt;&lt;BR&gt;Библиотека kol (key object library) &lt;BR&gt;Автор: vladimir kladov (mr.bonanzas) &lt;BR&gt;Страничка: http://xcl.cjb.net &lt;BR&gt;e-mail: bonanzas@xcl.cjb.net &lt;BR&gt;Классы и модули: tobj, tlist, tgraphictool, tcanvas, tcontrol, ttimer, ttrayicon, tstream, tstrlist, tdirlist, tinifile &lt;BR&gt;&lt;BR&gt;Как видно из списка приведенных для каждой библиотеки классов, эти библиотеки предендуют скорее не на помощь при написании программ с использованием win32 api, а пытаются создать более высокий уровень абстракции чем api, по крайней мере в графической части (особенно это относится к xcl). Более того, иерархия и перечень объектов совпадают с соответствующими структурами в библиотеке vcl, что скорее всего связано с желанием авторов обеспечить логическую совместимость с vcl при построении программ на основе этих библиотек.&lt;BR&gt;&lt;BR&gt;Данные библиотеки не обеспечивают минимального размера программы, за счет того что предоставляют более высокий уровень абстракции. Они являются компромисом между программированием с использованием vcl и программированием на чистом api.&lt;BR&gt;&lt;BR&gt;3. Принципы построения api-библиотеки&lt;BR&gt;&lt;BR&gt;тандартным видом api-программирования является структурное программирование. Примеры такого программирования на win32 api есть практически в любой книжке по borland pascal, borland c++, microsoft visual c++ и другим системам разработки. Множество примеров api-программирования на С содержится в поставке microsoft visual c++.&lt;BR&gt;&lt;BR&gt;Структурное программирование с оконными функциями, процедурами обработки команд, не в состоянии обеспечить быструю и эффективную разработку программ. В современной ситуации большинство программистов привыкло к объектно-ориентированному методу, с возможностью инкапсуляции, наследования и переопределения методов объектов. Такое программирование оказывается наиболее эффективным.&lt;BR&gt;&lt;BR&gt;Кроме того, для построения эффективной api-библиотеки прежде всего нужно выяснить, какие задачи при работе с win32 api являются наиболее трудоемкими. Практика показывает, что наиболее неудобным и трудоемким элементом является реализация основного диспетчера логики программы - оконной функции. Реализация этой функции в качестве метода класса, а не простой глобальной функции, позволила бы улучшить структуру кода и облегчить программирование путем инкапсулирования всех переменных внутри оконного класса.&lt;BR&gt;&lt;BR&gt;Программирование может быть еще более облегчено, есть возпользоваться механизмом message-процедур языка object pascal. Вызов этих процедур полностью лежит на компиляторе и корневом объекте tobject и включает в себя методы dispatch, defaulthandler, а также все методы, объявленные с директивой message. Такое решениее позволит полностью отказаться от громоздкого оператора case в оконной функции.&lt;BR&gt;&lt;BR&gt;Учитывая все вышеперечисленное автором была создана компактная библиотека оконных классов winlite. Эта библиотека является минимальной, она не вводит более высоких уровней абстракции чем существуют в win32 api - она только облегчает работу, переводом программирования в объектно-ориентированное русло. Размер библиотеки очень небольшой и вся она помещается в один модуль. Библиотека реализует базовый класс tliteframe и построенные на основе него оконные классы: &lt;BR&gt;&lt;BR&gt;tlitewindow - класс окна, с возможностью subclass&apos;инга; &lt;BR&gt;tlitedialog - класс немодального диалога; &lt;BR&gt;tlitedialogbox - класс модального диалога. &lt;BR&gt;Библиотека может быть использована совместно с vcl. На первый взгляд, это возможность является абсурдной и ненужной, так как об экономии размера в этом случае не может быть и речи. Однако, иногда бывают моменты, когда реализация специфических оконных элементов на основе объектов twincontrol или tcustomcontrol может быть затруднена или неэффективна из-за их сложности и неочевидного поведения. В этом случае, можно реализовать такой элемент на базе класса tlitewindow - он будет вести себя стандартным образом, как и полагается вести себя стандартному оконному элементу win32. &lt;BR&gt;Благодаря своей простой архитектуре библиотека может быть использована в многопоточной программе. Конечно, вы не сможете вызывать методы классов одного потока из другого потока без соответствующей синхронизации. Однако, вы можете беспрепятственно создавать оконные классы в различных потоках без блокировки и синхронизации, а также посылать сообщения оконным классам в другом потоке.&lt;BR&gt;&lt;BR&gt;Практический совет: при api-программировании программист должен сам следить за корректным освобождением многочисленных ресурсов, которые занимает программа во время выполнения. Поэтому, для облегчения этой задачи используйте какую-либо контролирующую утилиту, например memproof или numega boundschecker. Корректное освобождение занятых ресурсов крайне необходимо !&lt;BR&gt;&lt;BR&gt;Для редактирования шаблонов диалогов можно использовать любой редактор ресурсов, например borland resource workshop, правда он несколько неудобен, а окончательный результат все равно приходится корректировать вручную.&lt;BR&gt;&lt;BR&gt;Вся документация необходимая для api-программирования содержится в поставляемых компанией microsoft компакт-дисках с документацией под общим названием msdn (microsoft developer&apos;s network). Существует online-версия документации по адресу http://msdn.microsoft.com. Урезанная версия msdn, содержащая основные файлы помощи, поставляется с delphi.&lt;BR&gt;&lt;BR&gt;Прежде чем вы решите работать над своим проектом в русле win32 api, подумайте, а зачем вам это нужно? В подавляющем числе случаев размер программы не имеет никакого значения. Я не хочу сказать, что api-программирование сложнее чем vcl-программирование. Во многих случаях легче изучить и написать 10 вызовов api с кучей аргументов и понимать, что происходит, чем написать 1 вызов простой, на первый взгляд, vcl-инструкции и потом долго исследовать дебри vcl в поисках ответа. Просто api-программирование - это другая культура, к которой вы, возможно, не привыкли. И первоначальная работа может вызвать у вас сильное разочарование. api-программирование требует дотошности, кропотливости и внимательного изучения документации.&lt;BR&gt;&lt;BR&gt;Те же, кто отважился программировать на api, наряду с библиотекой winlite могут совместно использовать невизуальные классы как из состава vcl (модули sysutils, classes), так и многие сторонние - естественно, что размер вашей программы при этом увеличится. &lt;BR&gt;&lt;BR&gt;Невизуальные классы библиотеки acl - http://a-press.ur.ru/pc/bokovikov &lt;BR&gt;Невизуальные классы библиотеки xcl - http://xcl.cjb.net &lt;BR&gt;jedi code library - http://www.delphi-jedi.com &lt;BR&gt;Системные компоненты на torry - http://www.torry.ru &lt;BR&gt;Заслуживает внимание работа Владимира Кладова по изменению функциональности обязательного модуля system.pas. Со времен первых версий turbo pascal этот модуль по умолчанию компонуется в исполняемый код программы. Код модуля реализует многие принципы и решения заложенные в синтаксис и логику языка object pascal, и изменение этого модуля позволяет модифицировать реализацию этой логики. Такое решение является специфичным для языка object pascal в отличие, например, от c/c++, где компилятор и абсолюдно все модули никак не связаны. Изменение модуля system.pas, а именно его разбиение на блоки и сокращение редко используемых участков кода позволило сократить постоянные (не переменные) издержки примерно на 8 кБ. Конечно, для больших проектов, такое сокращение может быть и незаметным, однако интересен сам принцип. &lt;BR&gt;Модифицированный модуль system.pas - http://xcl.cjb.net &lt;BR&gt;4. Библиотека winlite&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// winlite, библиотека классов и функций для работы с win32 api&lt;BR&gt;// (c) Николай Мазуркин, 1999-2000&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Оконные классы&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;unit winlite;&lt;BR&gt;&lt;BR&gt;interface&lt;BR&gt;&lt;BR&gt;uses windows, messages;&lt;BR&gt;&lt;BR&gt;Инициализационные структуры&lt;BR&gt;Объявление структур, которые используются для формирования параметров вновь создаваемых окон и диалогов соответственно.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Параметры для создания окна&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;twindowparams = record&lt;BR&gt;caption : pchar;&lt;BR&gt;style : dword;&lt;BR&gt;exstyle : dword;&lt;BR&gt;x : integer;&lt;BR&gt;y : integer;&lt;BR&gt;width : integer;&lt;BR&gt;height : integer;&lt;BR&gt;wndparent : thandle;&lt;BR&gt;wndmenu : thandle;&lt;BR&gt;param : pointer;&lt;BR&gt;windowclass : twndclass;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Параметры для создания диалога&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;tdialogparams = record&lt;BR&gt;template : pchar;&lt;BR&gt;wndparent : thandle;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Декларация базового класса tliteframe&lt;BR&gt;Базовый класс для окон и диалогов. Инкапсулирует в себе дескриптор окна и объявляет общую оконную процедуру. Реализует механизм message-процедур.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tliteframe&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Базовый класс для объектов tlitewindow, tlitedialog, tlitedialogbox&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;tliteframe = class(tobject)&lt;BR&gt;private&lt;BR&gt;fwndcallback: pointer;&lt;BR&gt;fwndhandle : thandle;&lt;BR&gt;fwndparent : thandle;&lt;BR&gt;function windowcallback(hwnd: hwnd; msg, wparam, lparam:longint):&lt;BR&gt;longint; stdcall;&lt;BR&gt;protected&lt;BR&gt;procedure windowprocedure(var msg: tmessage); virtual;&lt;BR&gt;public&lt;BR&gt;property wndhandle: thandle read fwndhandle;&lt;BR&gt;property wndcallback: pointer read fwndcallback;&lt;BR&gt;public&lt;BR&gt;constructor create(awndparent: thandle); virtual;&lt;BR&gt;destructor destroy; override;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Декларация оконного класса tlitewindow&lt;BR&gt;Создание уникального класса окна и создание окна. Возможность субклассинга стороннего окна.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitewindow&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Оконный класс&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;tlitewindow = class(tliteframe)&lt;BR&gt;private&lt;BR&gt;fwndparams : twindowparams;&lt;BR&gt;fwndsubclass: pointer;&lt;BR&gt;protected&lt;BR&gt;procedure createwindowparams(var windowparams: twindowparams); virtual;&lt;BR&gt;public&lt;BR&gt;procedure defaulthandler(var msg); override;&lt;BR&gt;constructor create(awndparent: thandle); override;&lt;BR&gt;constructor createsubclassed(awnd: thandle); virtual;&lt;BR&gt;destructor destroy; override;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Декларация диалогового класса tlitedialog&lt;BR&gt;Загрузка шаблона диалога и создание диалога.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitedialog&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Диалоговый класс&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;tlitedialog = class(tliteframe)&lt;BR&gt;private&lt;BR&gt;fdlgparams : tdialogparams;&lt;BR&gt;protected&lt;BR&gt;procedure createdialogparams(var dialogparams: tdialogparams); virtual;&lt;BR&gt;public&lt;BR&gt;procedure defaulthandler(var msg); override;&lt;BR&gt;constructor create(awndparent: thandle); override;&lt;BR&gt;destructor destroy; override;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Декларация модального диалогового класса tlitedialogbox&lt;BR&gt;Загрузка шаблона диалога и создание диалога. Модальный показ диалога.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitedialogbox&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Модальный диалоговый класс&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;type&lt;BR&gt;tlitedialogbox = class(tliteframe)&lt;BR&gt;private&lt;BR&gt;fdlgparams : tdialogparams;&lt;BR&gt;protected&lt;BR&gt;procedure createdialogparams(var dialogparams: tdialogparams); virtual;&lt;BR&gt;public&lt;BR&gt;procedure defaulthandler(var msg); override;&lt;BR&gt;public&lt;BR&gt;function showmodal: integer; &lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Реализация базового класса tliteframe&lt;BR&gt;&lt;BR&gt;implementation&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tliteframe&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Инициализация / финализация&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Конструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;constructor tliteframe.create(awndparent: thandle);&lt;BR&gt;begin&lt;BR&gt;inherited create;&lt;BR&gt;// Запоминаем дескриптор родительского окна&lt;BR&gt;fwndparent := awndparent;&lt;BR&gt;// Создаем место под блок обратного вызова&lt;BR&gt;fwndcallback := virtualalloc(nil,12,mem_reserve or mem_commit,&lt;BR&gt;page_execute_readwrite);&lt;BR&gt;// Формируем блок обратного вызова&lt;BR&gt;asm&lt;BR&gt;mov eax, self&lt;BR&gt;mov ecx, [eax].tliteframe.fwndcallback &lt;BR&gt;mov word ptr [ecx+0], $6858 // pop eax&lt;BR&gt;mov dword ptr [ecx+2], eax // push _self_&lt;BR&gt;mov word ptr [ecx+6], $e950 // push eax&lt;BR&gt;mov eax, offset(tliteframe.windowcallback)&lt;BR&gt;sub eax, ecx&lt;BR&gt;sub eax, 12&lt;BR&gt;mov dword ptr [ecx+8], eax // jmp tliteframe.windowcallback&lt;BR&gt;end;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Деструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;destructor tliteframe.destroy;&lt;BR&gt;begin&lt;BR&gt;// Уничтожаем структуру блока обратного вызова&lt;BR&gt;virtualfree(fwndcallback, 0, mem_release);&lt;BR&gt;// Уничтожение по умолчанию&lt;BR&gt;inherited;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tliteframe&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Функции обработки сообщений&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Функция обратного вызова для получения оконных сообщений&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;function tliteframe.windowcallback(hwnd: hwnd; msg, wparam, lparam: integer):&lt;BR&gt;longint;&lt;BR&gt;var&lt;BR&gt;windowmsg : tmessage;&lt;BR&gt;begin&lt;BR&gt;// Запоминаем дескриптор окна, если это первый вызов оконной процедуры&lt;BR&gt;if fwndhandle = 0 then fwndhandle := hwnd;&lt;BR&gt;// Формируем сообщение&lt;BR&gt;windowmsg.msg := msg;&lt;BR&gt;windowmsg.wparam := wparam;&lt;BR&gt;windowmsg.lparam := lparam;&lt;BR&gt;// Обрабатываем его&lt;BR&gt;windowprocedure(windowmsg);&lt;BR&gt;// Возвращаем результат обратно системе&lt;BR&gt;result := windowmsg.result;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Виртуальная функция для обработки оконных сообщений&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tliteframe.windowprocedure(var msg: tmessage);&lt;BR&gt;begin&lt;BR&gt;// Распределяем сообщения по обработчикам&lt;BR&gt;dispatch(msg);&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Реализация оконного класса tlitewindow&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitewindow&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Инициализация / финализация&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Конструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;constructor tlitewindow.create(awndparent: thandle);&lt;BR&gt;begin&lt;BR&gt;inherited;&lt;BR&gt;// Формируем параметры окна&lt;BR&gt;createwindowparams(fwndparams);&lt;BR&gt;// Регистрируем класс окна&lt;BR&gt;registerclass(fwndparams.windowclass);&lt;BR&gt;// Создаем окно&lt;BR&gt;with fwndparams do&lt;BR&gt;createwindowex(exstyle, windowclass.lpszclassname, caption,&lt;BR&gt;style, x, y, width, height,&lt;BR&gt;wndparent, wndmenu, hinstance, param&lt;BR&gt;);&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Конструктор элемента с субклассингом&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;constructor tlitewindow.createsubclassed(awnd: thandle);&lt;BR&gt;begin&lt;BR&gt;inherited create(getparent(awnd));&lt;BR&gt;// Сохраняем оконную функцию&lt;BR&gt;fwndsubclass := pointer(getwindowlong(awnd, gwl_wndproc));&lt;BR&gt;// Сохраняем дескриптор окна&lt;BR&gt;fwndhandle := awnd;&lt;BR&gt;// Устанавливаем свою оконную функцию&lt;BR&gt;setwindowlong(fwndhandle, gwl_wndproc, dword(wndcallback));&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Деструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;destructor tlitewindow.destroy;&lt;BR&gt;begin&lt;BR&gt;// Наш объект - объект субклассиннга ?&lt;BR&gt;if fwndsubclass = nil then&lt;BR&gt;begin&lt;BR&gt;// Уничтожаем класс окна&lt;BR&gt;unregisterclass(fwndparams.windowclass.lpszclassname, hinstance);&lt;BR&gt;// Уничтожаем окно&lt;BR&gt;if iswindow(fwndhandle) then destroywindow(fwndhandle);&lt;BR&gt;end&lt;BR&gt;else&lt;BR&gt;// Восстанавливаем старую оконную функцию&lt;BR&gt;setwindowlong(fwndhandle, gwl_wndproc, dword(fwndsubclass));&lt;BR&gt;// Уничтожение по умолчанию&lt;BR&gt;inherited;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Формирование параметров окна по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitewindow.createwindowparams(var windowparams: twindowparams);&lt;BR&gt;var&lt;BR&gt;wndclassname : string;&lt;BR&gt;begin&lt;BR&gt;// Формируем имя класса&lt;BR&gt;str(dword(self), wndclassname);&lt;BR&gt;wndclassname := classname+&apos;:&apos;+wndclassname;&lt;BR&gt;// Заполняем информацию о классе окна&lt;BR&gt;with fwndparams.windowclass do&lt;BR&gt;begin&lt;BR&gt;style := cs_dblclks;&lt;BR&gt;lpfnwndproc := wndcallback;&lt;BR&gt;cbclsextra := 0;&lt;BR&gt;cbwndextra := 0;&lt;BR&gt;lpszclassname := pchar(wndclassname);&lt;BR&gt;hinstance := hinstance;&lt;BR&gt;hicon := loadicon(0, idi_application);&lt;BR&gt;hcursor := loadcursor(0, idc_arrow);&lt;BR&gt;hbrbackground := color_btnface + 1;&lt;BR&gt;lpszmenuname := &apos;&apos;;&lt;BR&gt;end;&lt;BR&gt;// Заполняем информацию об окне&lt;BR&gt;with fwndparams do&lt;BR&gt;begin&lt;BR&gt;wndparent := fwndparent;&lt;BR&gt;caption := &apos;lite window&apos;;&lt;BR&gt;style := ws_overlappedwindow or ws_visible;&lt;BR&gt;exstyle := 0;&lt;BR&gt;x := integer(cw_usedefault);&lt;BR&gt;y := integer(cw_usedefault);&lt;BR&gt;width := integer(cw_usedefault);&lt;BR&gt;height := integer(cw_usedefault);&lt;BR&gt;wndmenu := 0;&lt;BR&gt;param := nil;&lt;BR&gt;end;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitewindow&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Функции обработки сообщений&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Обработчик сообщений по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitewindow.defaulthandler(var msg);&lt;BR&gt;begin&lt;BR&gt;// Наш объект - объект субклассиннга ?&lt;BR&gt;if fwndsubclass = nil then&lt;BR&gt;// Вызываем системную функцию обработки сообщений&lt;BR&gt;with tmessage(msg) do &lt;BR&gt;result := defwindowproc(fwndhandle, msg, wparam, lparam)&lt;BR&gt;else&lt;BR&gt;// Вызываем старую оконную функцию обработки сообщений&lt;BR&gt;with tmessage(msg) do &lt;BR&gt;result := callwindowproc(fwndsubclass, fwndhandle, msg, wparam, lparam);&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Реализация диалогового класса tlitedialog&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitedialog&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Инициализация / финализация&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Конструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;constructor tlitedialog.create(awndparent: thandle);&lt;BR&gt;begin&lt;BR&gt;inherited;&lt;BR&gt;// Формируем параметры диалога&lt;BR&gt;createdialogparams(fdlgparams);&lt;BR&gt;// Создаем диалог&lt;BR&gt;with fdlgparams do&lt;BR&gt;createdialogparam(hinstance, template, wndparent, wndcallback, 0);&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Деструктор&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;destructor tlitedialog.destroy;&lt;BR&gt;begin&lt;BR&gt;// Уничтожаем диалог&lt;BR&gt;if iswindow(fwndhandle) then destroywindow(fwndhandle);&lt;BR&gt;// Уничтожение по умолчанию&lt;BR&gt;inherited;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Формирование параметров диалога по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitedialog.createdialogparams(var dialogparams: tdialogparams);&lt;BR&gt;begin&lt;BR&gt;dialogparams.wndparent := fwndparent;&lt;BR&gt;dialogparams.template := &apos;&apos;;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Обработка сообщений по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitedialog.defaulthandler(var msg);&lt;BR&gt;begin&lt;BR&gt;// Возвращаемые значения по умолчанию&lt;BR&gt;with tmessage(msg) do&lt;BR&gt;if msg = wm_initdialog then result := 1&lt;BR&gt;else result := 0;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;Реализация модального диалогового класса tlitedialogbox&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// tlitedialogbox&lt;BR&gt;// _____________________________________________________________________________&lt;BR&gt;// Инициализация / финализация&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Формирование параметров диалога по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitedialogbox.createdialogparams(var dialogparams: tdialogparams);&lt;BR&gt;begin&lt;BR&gt;dialogparams.wndparent := fwndparent;&lt;BR&gt;dialogparams.template := &apos;&apos;;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Активизация модального диалога&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;function tlitedialogbox.showmodal: integer;&lt;BR&gt;begin&lt;BR&gt;// Формируем параметры диалога&lt;BR&gt;createdialogparams(fdlgparams);&lt;BR&gt;// Показываем диалог&lt;BR&gt;with fdlgparams do&lt;BR&gt;result := dialogboxparam(hinstance, template, wndparent, wndcallback, 0);&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;// Обработка сообщений по умолчанию&lt;BR&gt;////////////////////////////////////////////////////////////////////////////////&lt;BR&gt;procedure tlitedialogbox.defaulthandler(var msg);&lt;BR&gt;begin&lt;BR&gt;// Возвращаемые значения по умолчанию&lt;BR&gt;with tmessage(msg) do&lt;BR&gt;if msg = wm_initdialog then result := 1&lt;BR&gt;else result := 0;&lt;BR&gt;end;&lt;BR&gt;&lt;BR&gt;end.&lt;BR&gt;&lt;BR&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/2009-08-19-53</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/2009-08-19-53</guid>
			<pubDate>Wed, 19 Aug 2009 04:54:18 GMT</pubDate>
		</item>
		<item>
			<title>Работа с текстовыми файлами</title>
			<description>В этой лекции вы познакомитесь с методами чтения текста из файла, и записи текста в файл. Научитесь пользоваться объектом TStringList, освоите файловый тип TFileStream.</description>
			<content:encoded>TStringList&lt;BR&gt;Практически любая программа взаимодействует с какими-либо типами файлов. Delphi позволяет нам работать с файлами различных типов. Текстовый файл – одна из этих разновидностей. В этих файлах информация расположена не сплошным блоком данных, а в виде строк, которые заканчиваются символом конца строки и перевода каретки. Можно работать с текстовыми файлами общим способом, то есть, побайтно считывать и записывать данные. Однако это не всегда удобно. Рассмотрим пример:&lt;BR&gt;&lt;BR&gt;Привет!&lt;BR&gt;Как жизнь?&lt;BR&gt;Если мы считаем эти 2 строки сплошным блоком, то получим строку:&lt;BR&gt;&lt;BR&gt;&apos;Привет!&apos; + #13 + #10 + &apos;Как жизнь?&apos;&lt;BR&gt;Это очень неудобно, так как для обработки строк нам каждый раз придется искать эти два символа конца строки. А если строк много, например 100? И если нужно получить доступ к 75-й строке?&lt;BR&gt;&lt;BR&gt;Тут на помощь приходит объект TStrings, который мы использовали при обработке Memo, и который является простым контейнером для хранения строк. Однако использовать объект TStrings напрямую нельзя, так как этот объект является шаблоном для других объектов, работающих со строками. Вспомните, в компоненте Memo и ListBox мы тоже не использовали этот объект напрямую, мы использовали его &quot;потомков&quot; - Lines и Items. Поэтому лучше использовать более продвинутый вариант этого объекта – TStringList. Этот вариант наследует все возможности объекта TStrings и добавляет еще новые. Это, пожалуй, самый простой способ работы с текстовыми файлами.&lt;BR&gt;&lt;BR&gt;Чтобы воспользоваться этим объектом, требуется вначале объявить переменную этого типа, затем проинициализировать ее, а в конце закрыть. В простейшем варианте это будет выглядеть так:&lt;BR&gt;&lt;BR&gt;var&lt;BR&gt;  f : TStringList; //объявили переменную - объект&lt;BR&gt;begin&lt;BR&gt;  f := TStringList.Create(); //проинициализировали&lt;BR&gt;  f.Free; //освободили (уничтожили)&lt;BR&gt;end;&lt;BR&gt;Здесь мы создаем объект и тут же его уничтожаем, не работая с ним. Когда мы объявили переменную типа объект TStringList, мы указали компилятору, сколько оперативной памяти потребуется выделить в дальнейшем для этой переменной. Когда мы проинициализировали объект методом Create, мы выделили под него оперативную память. В дальнейшем, с этим объектом можно работать, записывать в него текст, считывать текст, пользоваться свойствами, методами и событиями этого объекта. Метод Free разрушает объект, уничтожает его в оперативной памяти. После этого к переменной f типа TStringList обращаться уже нельзя. Все, что должен был делать этот объект, должно быть описано до метода Free.&lt;BR&gt;&lt;BR&gt;Чтение и запись с таким объектом происходит знакомым нам способом. Допустим, нам нужно прочитать текстовый файл и изменить в нем 10-ю строку:&lt;BR&gt;&lt;BR&gt;  var&lt;BR&gt;  f : TStringList;&lt;BR&gt;begin&lt;BR&gt;  f := TStringList.Create();&lt;BR&gt;  //читаем текст из файла:&lt;BR&gt;  f.LoadFromFile(&apos;c:&amp;#92;myfile.txt&apos;);&lt;BR&gt;  //меняем текст 10-й строки (строки начинаются с 0):&lt;BR&gt;  f[9] := &apos;Новая строка&apos;;&lt;BR&gt;  //сохраняем измененный текст обратно в файл:&lt;BR&gt;  f.SaveToFile(&apos;c:&amp;#92;myfile.txt&apos;);&lt;BR&gt;  f.Free;&lt;BR&gt;end;&lt;BR&gt;Обратите внимание, что мы обратились к 9-му индексу, так как нумерация индексов начинается с нуля, и f[9] содержит 10-ю строку.&lt;BR&gt;&lt;BR&gt;Свойство Count этого объекта возвращает общее количество строк, начиная с первой. Давайте напишем пример, в котором мы будем среди всех строк искать строку &quot;Привет, Москва!&quot;. Если такая строка будет найдена, то программа выведет номер искомой строки, иначе выведет сообщение, что такой строки нет.&lt;BR&gt;&lt;BR&gt;Вначале воспользуйтесь собственным редактором текстов и создайте текстовый файл, куда запишите 10-15 строк. Одну из строк сделайте &quot;Привет, Москва!&quot;.&lt;BR&gt;&lt;BR&gt;Затем делаем новое приложение, устанавливаем кнопку &quot;Выполнить&quot; и диалог OpenDialog. Затем создаем обработчик событий для кнопки, куда записываем следующий код:&lt;BR&gt;&lt;BR&gt;procedure TForm1.Button1Click(Sender: TObject);&lt;BR&gt;var&lt;BR&gt;  f : TStringList;&lt;BR&gt;  i : Integer;&lt;BR&gt;begin&lt;BR&gt;  //если ничего не открыли, выходим из процедуры:&lt;BR&gt;  if not OpenDialog1.Execute then Exit;&lt;BR&gt;&lt;BR&gt;  //читаем из файла:&lt;BR&gt;  f := TStringList.Create();&lt;BR&gt;  f.LoadFromFile(OpenDialog1.FileName);&lt;BR&gt;&lt;BR&gt;  //ищем строку:&lt;BR&gt;  for i := 0 to f.Count-1 do begin&lt;BR&gt;  if f[i] = &apos;Привет, Москва!&apos; then begin&lt;BR&gt;  ShowMessage(&apos;Строка найдена под № &apos; + IntToStr(i+1));&lt;BR&gt;  Break;&lt;BR&gt;  end; //if&lt;BR&gt;  end; //for&lt;BR&gt;&lt;BR&gt;  //закрываем файл:&lt;BR&gt;  f.Free;&lt;BR&gt;end;&lt;BR&gt;Здесь код достаточно прозрачен, однако еще раз обращаю ваше внимание на то, что индексы строк начинаются с нуля, а свойство Count возвращает общее количество строк. То есть, если в тексте лишь 2 строки и Count вернет цифру 2, то индексы этих строк будут 0 и 1, поэтому в цикле мы использовали диапазон от 0 до Count-1, иначе бы произошла ошибка переполнения цикла.&lt;BR&gt;&lt;BR&gt;Итак, кроме того, что мы уже рассмотрели, этот объект имеет и другие, известные вам по Memo методы:&lt;BR&gt;&lt;BR&gt;•Add – добавить новую строку в конец: &lt;BR&gt;f.Add(&apos;Новая строка&apos;);&lt;BR&gt;•Clear – очистить объект (не будет текста): &lt;BR&gt;f.Clear;&lt;BR&gt;•Insert – вставить строку. Есть 2 параметра – индекс вставляемой строки, и сама строка: &lt;BR&gt;f.Insert(3, &apos;Новая 4-я строка, следующие строки сдвинутся вниз&apos;);&lt;BR&gt;•Delete – удалить строку. Есть параметр – индекс удаляемой строки. &lt;BR&gt;f.Delete(f.Count-1); //удалили последнюю строку&lt;BR&gt;&lt;BR&gt;Общие принципы работы с файлами&lt;BR&gt;В предыдущих примерах мы сохраняли текст в файл и считывали текст из файла при помощи свойств:&lt;BR&gt;&lt;BR&gt;Memo1.Lines.SaveToFile()&lt;BR&gt;Memo1.Lines.LoadFromFile()&lt;BR&gt;Этот метод удобен и хорош, однако он не позволяет нам контролировать весь процесс записи в файл и чтения из файла. То есть, эти функции весь процесс чтения и записи выполняют скрыто от нас.&lt;BR&gt;&lt;BR&gt;Однако бывает, когда программист испытывает необходимость контроля этих процессов, кроме того, не для всех типов эти функции доступны. Например, у нас есть текст в строковой переменной. Мы уже говорили, что строковая переменная может хранить почти неограниченное количество символов, то есть в переменную мы можем записать весь текстовый файл, включая и символы перехода на другую строку и возврата каретки (#13 #10). С функциями SaveToFile() и LoadFromFile() могут работать данные, которые имеют тип TStrings, а простые строки не могут их вызывать. Поэтому приходится делать записи в файл напрямую, и также напрямую их считывать.&lt;BR&gt;&lt;BR&gt;Для работы с файлами многие программисты предпочитают использовать функции WinAPI. Несмотря на грозное звучание, ничего особо сложного в этих функциях нет, тем не менее, такие функции имеют один крупный недостаток. Корпорация MicroSoft постоянно вносит какие-то изменения в свои операционные системы. Так, в первых версиях Windows, для чтения файлов использовалась функция WinAPI _lread. Потом появилась функция ReadFile и Microsoft стала рекомендовать использовать в программировании именно ее. А затем появилась функция ReadFileEx, которая позволяет работать с файлами больших размеров. После каждого изменения этих функций очень часто приходится переделывать всю программу, чтобы она могла работать с новой операционной системой. А это отнимает много времени и создает дополнительные неудобства и для программистов, и для пользователей.&lt;BR&gt;&lt;BR&gt;Поэтому в Delphi рекомендуется использовать встроенный специализированный объект TFileStream. Если Microsoft введет какие-то новшества, Borland учтет их в объекте, и нам останется лишь перекомпилировать нашу программу, не меняя ее кода. Кроме того, использование TFileStream намного проще, чем функции WinAPI. TFileStream - это объект, и как каждый объект, его нужно вначале объявить, а затем проинициализировать.&lt;BR&gt;&lt;BR&gt;Первым делом необходимо создать переменную типа TFileStream:&lt;BR&gt;&lt;BR&gt;var&lt;BR&gt;  f : TFileStream;&lt;BR&gt;Таким образом, мы объявили переменную типа объект TFileStream, и в дальнейшем можем работать с этой переменной, как с объектом. То есть, указывать имя этой переменной, а после точки выбирать свойства, методы и события этого объекта. Однако объявить переменную мало, требуется еще проинициализировать ее.&lt;BR&gt;&lt;BR&gt;f := TFileStream.Create(параметры);&lt;BR&gt;У метода Create объекта TFileStream может быть три параметра, причем третий параметр необязателен, его можно не указывать. Разберемся с этими параметрами.&lt;BR&gt;&lt;BR&gt;Имя файла – этот параметр – простая строка, которая может содержать только имя файла, или полное имя файла, включая и адрес.&lt;BR&gt;&lt;BR&gt;Режим открытия. Здесь можно указать один из следующих параметров:&lt;BR&gt;&lt;BR&gt;•fmCreate – Создать файл с указанным в первом параметре именем. Если файл уже существует, он откроется в режиме для записи.&lt;BR&gt;•fmOpenRead – Открыть файл только для чтения. Если файл не существует, произойдет ошибка, поэтому прежде требуется выполнить проверку на существование файла. Запись в файл в этом режиме невозможна.&lt;BR&gt;•fmOpenWrite – Открыть файл для записи. При этом текущее содержимое файла уничтожается, и файл перезаписывается.&lt;BR&gt;•fmOpenReadWrite – Открыть файл для редактирования, то есть, и чтения, и записи.&lt;BR&gt;Права, с которыми будет открыт файл. Этот параметр необязателен, его можно не указывать. Он имеет следующие возможные значения:&lt;BR&gt;&lt;BR&gt;•fmShareCompat – Другие приложения тоже имеют право работать с открытым файлом.&lt;BR&gt;•fmShareExclusive – Другие приложения не смогут открыть файл.&lt;BR&gt;•fmShareDenyWrite – Другие приложения смогут открыть файл только для чтения, записать в него данные они не смогут.&lt;BR&gt;•fmShareDenyRead – Другие приложения смогут открыть файл только для записи, для чтения они не смогут его открыть.&lt;BR&gt;•fmShareDenyNone – не мешать другим приложениям работать с файлом.&lt;BR&gt;Пример:&lt;BR&gt;&lt;BR&gt;f := TFileStream.Create(&apos;C:&amp;#92;MyFile.txt&apos;, fmOpenReadWrite, fmShareExclusive);&lt;BR&gt;Для чего нужны права доступа к файлу? Например, текстовый файл может быть открыт стандартной программой &quot;Блокнот&quot;, этот же файл мы можем открыть из нашего собственного текстового редактора. Редактор менеджера файлов FAR также может открыть этот текстовый файл. И программа MS Word тоже может его открыть! Теперь предположим, что наша программа делает запись в файл. В это же самое время какая-то другая программа также сохраняет изменения в этом файле. Наша программа сделала изменения и закрыла файл, а другая программа даже не подозревает об этих изменениях, и просто перезаписывает файл со своими изменениями. Таким образом, наши изменения просто теряются!&lt;BR&gt;&lt;BR&gt;Тоже самое может произойти, если ваша программа выполнена в сетевом варианте. Например, есть какой-то специальный файл, в который сотрудники отдела записывают свои изменения. Этот файл может находиться на каком-то сетевом диске, и доступ к этому файлу имеет каждый сотрудник. И у каждого сотрудника установлена ваша программа. Таким образом, если одновременно двое сотрудников будут производить изменения в файле, то данные одного из них потеряются, так как программа другого перезапишет файл без учета этих изменений. Если вы пишете однопользовательскую программу, и доступ к файлу будет иметь только она, то про третий параметр можете вовсе забыть.&lt;BR&gt;&lt;BR&gt;После того, как Вы создали объект, проинициализировали его и поработали с ним, файл нужно закрыть и освободить память, занимаемую этим объектом. Для этого достаточно вызвать метод:&lt;BR&gt;&lt;BR&gt;f.Free;&lt;BR&gt;Теперь осталось разобраться со структурой файла, и методами чтения из него, и записи в него. Начнем со структуры.&lt;BR&gt;&lt;BR&gt;Когда вы только открыли файл, позиция курсора устанавливается на начало, и любая попытка чтения или записи будет применена к этой позиции курсора. Чтобы прочитать (записать) в другую позицию, требуется передвинуть курсор. Для этого используют метод Seek, который имеет два параметра:&lt;BR&gt;&lt;BR&gt;•Число, указывающее количество байт (символов), на которые требуется передвинуть курсор.&lt;BR&gt;•Откуда нужно двигаться. Тут может быть три варианта: &lt;BR&gt;◦SoFromBeginning – двигаться на указанное количество байт от начала файла.&lt;BR&gt;◦SoFromCurrent – двигаться от текущей позиции курсора.&lt;BR&gt;◦SoFromEnd – двигаться на указанное количество байт от конца файла к его началу.&lt;BR&gt;Итак, чтобы передвинуть курсор от начала файла на 10 байт, нужно выполнить команду:&lt;BR&gt;&lt;BR&gt;f.Seek(10, soFromBeginning);&lt;BR&gt;Метод Seek – это функция, она всегда возвращает количество байт смещения от начала файла. Этим свойством можно воспользоваться, чтобы узнать общее количество байт в файле:&lt;BR&gt;&lt;BR&gt;Размер_Файла := f.Seek(0, soFromEnd);&lt;BR&gt;Правда, если нам требуется просто посмотреть размер файла, то этот трюк не совсем подходящий: нам придется открыть файл, переместиться в его конец, и затем закрыть его. Как узнать размер файла более подходящим способом, узнаем позже.&lt;BR&gt;&lt;BR&gt;Для чтения из файла нужно использовать метод Read, у которого тоже есть два параметра:&lt;BR&gt;&lt;BR&gt;•Переменная, в которую будет записан прочитанный текст.&lt;BR&gt;•Количество байт, которые следует прочитать.&lt;BR&gt;Разберем пример чтения из файла 10 символов, начиная с 15-й позиции:&lt;BR&gt;&lt;BR&gt;var&lt;BR&gt;  f : TFileStream; //объявляем переменную&lt;BR&gt;  buf : array [0..10] of Char; //буфер для хранения прочитанных данных&lt;BR&gt;begin&lt;BR&gt;  //открываем файл filename.txt для чтения и записи:&lt;BR&gt;  f := TFileStream.Create(&apos;c:&amp;#92;filename.txt&apos;, fmOpenReadWrite);&lt;BR&gt;  //перемещаемся на 15 символов вперед:&lt;BR&gt;  f.Seek(15, soFromBeginning);&lt;BR&gt;  //читаем в буфер 10 символов из установленной позиции:&lt;BR&gt;  f.Read(buf, 10);&lt;BR&gt;  Memo1.Lines.Add(buf); //скопировали эти 10 символов в Memo&lt;BR&gt;  //уничтожаем объект и тем самым закрываем файл:&lt;BR&gt;  f.Free;&lt;BR&gt;end;&lt;BR&gt;Метод Read возвращает количество реально прочитанных байт. Оно должно быть равно тому количеству байт, которые мы указали при вызове этого метода. Есть две причины, по которым это количество может быть не равно указанному:&lt;BR&gt;&lt;BR&gt;1.При чтении был достигнут конец файла, и функция прочитала меньше байт, чем планировалось.&lt;BR&gt;2.Ошибка на диске или любая другая проблема.&lt;BR&gt;Для записи в файл используется метод Write. Есть два параметра и у него:&lt;BR&gt;&lt;BR&gt;1.Переменная, содержимое которой нужно записать.&lt;BR&gt;2.Число байт для записи.&lt;BR&gt;Пользоваться методом записи можно точно также, как и методом чтения.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;</content:encoded>
			<link>https://delphi.ucoz.kz/news/2009-08-14-52</link>
			<category>Статьи участников клуба</category>
			<dc:creator>delphi</dc:creator>
			<guid>https://delphi.ucoz.kz/news/2009-08-14-52</guid>
			<pubDate>Fri, 14 Aug 2009 10:05:47 GMT</pubDate>
		</item>
	</channel>
</rss>