Midas и COM. Советы и ПриемыDelphi , Технологии , MIDASMidas и COM. Советы и Приемы
Автор: Bill Todd Статья показывает, как писать приложения, использующие несколько модулей, которые связываются через COM и совместно используют Midas сервер. Освещаются вопросы перемещения файлов, массивов и других структур данных c использованием COM. Вы можете не нуждаться в распределенных приложениях, но вы нуждаетесь в Midas Borland разрабатывал Midas как инструмент для создания многоуровневых распределенных приложений. Но Midas - лучший способ построить любое приложение баз данных, особенно большое приложение, даже, когда Вы не нуждаетесь в распределенной базе данных. Транзакции в настольных базах данных Если Вы работаете с Paradox или Dbase таблицами, и нуждаетесь в поддержке транзакций, Вы ограничены, потому что единственный уровень изоляции транзакции read uncommited (также грязное чтение). Вдобавок ко всему, невозможно произвести откат при возникновении аварийной ситуации , т.е аварийный отказ может оставлять вашу базу данных в несогласованном состоянии. Однако, если Вы используете ClientDataSet, Вы действительно получаете транзакции и автоматический откат в аварийных ситуациях. ClientDataSets имеет копию данных в памяти и Вы фактически работаете с локальной копией базы. Вы не будете видеть вставки, удаления или модификаций, сделанных другими пользователями или другими наборами данных в том же самом приложении. Это дает Вам обеспечение изоляции транзакции. Независимо от того сколько раз Вы просматриваете ваши данные, Вы будете всегда видеть снимок данных, с которым Вы начали работать. ClientDataSet содержит все изменения в памяти в свойстве Delta, пока Вы не вызывете ApplyUpdates. Это означает, что при аварии произойдет откат транзакции, потому что все изменения в Delta будут потеряны. Единственый недостаток в использовании ClientDataSet, то, что аварийный отказ, во время выполнения ApplyUpdates, может все еще оставлять вашу базу данных в несогласованном состоянии. Однако, Если Вы вызываете ApplyUpdates достаточно часто достаточно, чтобы гарантировать, что только несколько записей модифицируются, модификация происходит в течении долей секунды. Это - намного меньшее окно уязвимости, чем использование локальных транзакций, где база данных может находится в несогласованном состоянии с момента первого изменения до проведения или отката транзакции. Для пользователя, вручную вносящего изменения, это время может быть несколько минут. Улучшение параллельности работы баз данных Одна из проблема транзакциями в любой базе данных состоит в том, что транзакции, которые являются активными в течение длительного времени, уменьшают способность другого пользователя модифицировать базу данных. Это случается, потому что каждый раз измененная запись должна быть блокирована, и блокировка должна быть задержана, пока транзакция не завершится, чтобы гарантировать, что никакой другой пользователь не может изменять запись. Эта проблема особенно актуальна, если база данных использует блокировку страницы, это делает невозможным для других пользователей изменение строк на блокированной странице. Кэшируемые изменения были первоначально добавлены к Delphi, чтобы преодолеть эту проблему, и ClientDataSet является развитием этой идеи. Если Вы используете ClientDataSets, чтобы редактировать ваши данные, изменения сохранятся в локальной копии данных - в кэше ClientDataSet. База данных не содержит сделанных изменений, пока Вы не вызываете ApplyUpdates. Так как транзакция активна на сервере только, во время обращения к ApplyUpdates т.е обычно на доли секунды, блокировки не задерживается в течение длительного времени, и параллелизм улучшается. Обеспечение нескольких платформ серверов баз данных Предположим, что Вы пишете приложение для рынка. Вы знаете, что некоторые из ваших потенциальных заказчиков уже выбрали платформу сервера базы данных, так что Вы должны создать версии вашего приложения, для выполнения на Oracle, Microsoft SQL и Interbase. Компоненты, используемые, для работы с базами данных различны. Для Interbase самый лучший выбор Interbase Express, для MS SQL , самый лучший выбор - ADO Express и для Oracle, Вы можете использовать или BDE или ADO Express. Midas делает создание таких приложений намного проще. Для каждой базы данных разрабатывают Midas приложение - сервер, которое содержит только специфический код для одного типа базы данных. Вся логика приложения находится в клиентском приложении. Это позволяет Вам, реализовать большую часть кода, общего для всех типов баз данных в Midas клиенте, а Midas сервер, будет обеспечивать только соединение с конкретным типом базы данных. Вы будете иметь общего Midas клиента и Midas сервер, который соответствует базе данных, которую использует клиент. Другая проблема, которую это решает, имеет место, если Вы настроили приложение для специфического клиента, и клиент затем решает заменить платформу базы данных. С Midas все, что Вы должны сделать - устанить Midas сервер, который работает с новой платформой. Никакие изменения для настроенного клиента не требуются. Создание модульных приложений Объединение Midas с COM позволяет, создавать большие сложные приложения из множества COM серверов, которые совместно используют общее соединение базы данных. Использование Midas и COM вместе:
Следующие разделы этой статьи посвящены разработке простого приложения, которое показывает совместное использование Midas и COM. Также рассмотрены обратные вызовы от COM сервера к клиенту. Мы разработаем модульное приложение. Создадим очень простой пример, который состоит из Midas сервера и двух Midas клиентов. Первый Midas клиент будет главной формой приложения, отображающей данные из таблиц Customer и Order. Это приложение - EXE. Второй Midas клиент отобразит данные из таблицы Order и выполнен как внутренний сервер автоматизации. Midas сервер также выполнен как DLL внутреннего сервера автоматизации. Роли трех модулей могут немного смутить Вас. Чтобы разъяснить кто, что делает следующая таблица показывает каждое приложение и его назначение
Разработка Midas сервера Midas сервер имеет только одну необычную возможность. Он выполнен как DLL, так что не будет отображать форму или показывать иконку в панели задач. В то время как наличие отображаемой формы сервера может быть допустимым для распределенной системы, где никто обычно не видит экран машины - Midas сервера, это - плохая идея для приложения, где сервер и клиент выполнится на одном PC, потому что пользователь может быть введен в заблуждение дополнительной иконкой и может пробовать закрывать сервер. Решение состоит в том, чтобы выполнить Midas сервер как DLL, так чтобы он не имел никакого интерфейса пользователя. При выполнении Midas сервера в виде DLL также улучшается производительность. Для создания Midas сервера как DLL, выберем меню File | New из меню и затем закладку ActiveX репозитария объектов. Двойным щелчком левой кнопки мыши на иконке ActiveX Library создаст новый проект ActiveX библиотеки. С тех пор как Midas использует COM, чтобы обработать связь между Midas клиентом и Midas сервером, ActiveX библиотека используется, чтобы обеспечить требуемую поддержку COM. После этого процесс создания сервера в виде DLL ничем не отличается от разработки EXE. Выберите File | New, перейдите к странице Multitier, и добавьте Remote Data Module (удаленный модуль данных ) к проекту. Рисунок 1 показывает удаленный модуль данных для типового приложения.
Рис.1. Удаленный модуль данных Это приложение написано в типичном стиле клиента / сервера. Когда пользователь открывает приложение, никакие данные не отображаются. Взамен пользователь должен ввести некоторые критерии выбора(выделения), которые выберут приемлемое число записей. Чтобы реализовать этот подход, предложение SQL для CustomerQry компонента: select * from Customer where CustNo = -1 Это позволяет открывать Customer ClientDataSet в приложении DemoClient немедленно без отображения любых данных, т.к нет никаких записей в таблице Customer, чей номер заказчика является отрицательным. И DataSetProvider (CustomerProv) и DataSource (CustomerSrc) соединены с CustomerQry, устанавкой их свойств DataSet в CustomerQry. В свойстве Options DataSetProvider poAllowCommandText установлен в True, так что клиентское приложение может изменять свойство SQL CustomerQry, чтобы выбрать различные записи из таблицы Customer. OrdersQry обеспечивает выборку записей текущего заказчика. Свойство SQL установлено в: select * from Orders where (CustNo =:CustNo) Свойство DataSource установлено в CustomerSrc, таким образом значение параметра :CustNo будет обеспечено в соответствии с текущей записью в CustomerQry. Это приводит к сохранению в наборе данных Customer данных о заказах, в виде вложенного набора данных. Приложение DemoOrders позволяет пользователю искать записи в таблице Order по номеру заказа или всем заказы по номеру заказчика. Чтобы обеспечивать доступ к всем заказам необходим второй компонент TQuery - OrdersAllQry, который не связан с CustomerQry. Свойство SQL установлено, чтобы не выбирать никаких записей, т.е номер заказа - минус один. DataSetProvider для OrdersAllQry также имеет poAllowCommandText равный True. Так как этот Midas сервер - DLL, Вы не можете зарегистрировать его, запустив на выполнение. Вместо этого, выберите Run | Register ActiveX Server из меню Delphi, чтобы cкомпилировать и затем зарегистрировать Midas сервер. Midas сервер в типичных трех уровнех распределенных приложениях не, только обеспечивает соединение с базой данных, но может также обеспечивать бизнес логику или другие сервисы. Однако, в этой статье мы обсуждаем приложение, состоящее из нескольких модулей. Все модули будут Midas клиентами, использующими один Midas сервер и и клиент, и сервер работают на той же самой машине. Предположим, что Вы пишете приложение, используя эту архитектуру. Если Вы должны поддерживать несколько видов серверов баз данных, Вы можете захотеть ограничить код Midas сервера только, тем кодом, который является специфическими для специфической базы данных, типа Oracle или Microsoft SQL Server, и хранить весь общий для баз данных код клиентских модулях. Это позволит Вам, поддерживать несколько Midas серверов для различных баз данных без дублирования кода. Разработка COM Клиента Рисунок 2 показывает главную форму приложения. Она состоит из двух DBGRID и двух DBNAVIGATOR. Верхний DBGRID и DBNAVIGATOR отображают информацию о заказчике и нижний DBGRID и DBNAVIGATOR - таблицу заказов. Рисунок 3 показывает модуль данных для этого приложения.
Рис.2. Главная форма
Рис.3 Модуль данных Модуль данных содержит компонент DCOMCONNECTION, два ClientDataSet и два DataSources. Имя DCOMCONNECTION компонента - DemoConn, и св-во ServerName установлено в DemoDllSrvr.DllDemoServer. Свойство RemoteServer CustomerCds установлено в DemoConn, и ProviderName установлено равным CustomerProv. Свойство DataSetField компонента OrdersCds установлено в CustomerCdsOrdersQry, чтобы получить данные из вложенного набора данных. Меню Edit содержит диалог поиска, который отображает диалог, показанный на рисунке 4. Диалог дает возможность выбирать заказчика по номеру или выбирать все записи с определенным состоянием, используя метод FindCustomer в модуле данных CustomerDm. Реализацию данного метода Вы можете посмотреть в коде приложения.
Рис. 4. Диалог поиска заказчика Меню File на основной форме содержит пункт вызова формы выбора заказов, форма позволяет искать любой заказ по номеру заказчика или номеру заказа. Сетка заказов соединена со всплывающим меню, которое имеет два пункта. Первый, отобразить текущий заказ, открывает форму заказов и показывают текущую запись заказа. Второй, все заказы данного заказчика. Создание COM сервера Теперь начинается самое интересное. Следующий наш шаг - создание формы заказов и методов, которые форма просмотра заказчиков будет использовать, чтобы открыть форму заказов, искать заказы заказчика иискать заказ по его номеру. Однако, форма заказов будет расположена в отдельном приложении, которое является сервером Автоматизации, и форма заказчиков вызовает методы формы заказов через интерфейс автоматизации. Чтобы создать приложение Orders, выберите закладку ActiveX репозитарии и двойным щелчком мыши пункт ActiveX Library. Добавьте форму и модуль данных к приложению. Законченная форма изображена на рисунке 5 и модуль данных на рисунке 6.
Рис.5 Форма заказов
Рис. 6 Модуль данных заказов Компонент DCOMCONNECTION на рисунке 6, OrdersConn, соединяется с Midas сервером, DemoDllSrvr.DllDemoServer, так же как компонент DCOMCONNECTION модуле данных заказчиков. Свойство RemoteServer OrdersCds установлено в OrdersConn, и ProviderName установлено в OrdersAllProv. Следующий шаг превратит этоту DLL в сервер автоматизации. Вернитесь к закладке ActiveX репозитария, двойной щелчок на мастере построения объекта автоматизации (ActiveX Object), и введите значение OrdersServer для имени CoClass. Также проверьте установку переключателя Generate Event Support Code. В редакторе библиотеки типов (Type Library Editor) добавьте методы к интерфейсу IORDERSERVER (таблица) и затем нажмите кнопку Refresh.
Код для первых трех методов расположен в модуле OrdersAuto и показан здесь на рисунке 7.
рис.7. Методы FindByOrderNo, FindByCustNo, OpenOrdersForm
Рис. 8. Методы модуля данных OrdersDM
Первые два метода, FindByOrderNo и FindByCustNo вызывают методы с тем же самым именем в модуле данных заказов. Реализация модуля данных заказов приведена на рисунке 8. Оба метода закрывают ClientDataSet заказов, устанавливают новое SQL предложение в тексте команды и затем вновь открывают ClientDataSet. При открытии ClientDataSet значение в CommandText передается к Midas серверу и затем в свойство SQL компонента OrdersAllQry прежде, чем запрос будет открыт. Программа работы с заказчиками вызывает эти методы для поиска по номеру заказа или для вывода всех заказов, сделанных заказчиком. Третий метод, OpenOrdersForm, создает модуль данных, OrderDm, и отображает форму заказов OrdersForm. Программа работы с заказчиками вызывает этот метод для отображения формы заказов. FindOrder метод модуля данных заказов вызывается из меню Edit формы заказов. При этом отображается диалоговое окно FindOrdersForm, которое позволяет пользователю найти один или большее количество заказов по номеру или по номеру заказчика. Обратный вызов COM клиенту Используя вышеописанные методы наше приложение, может вызывать методы на COM сервере, чтобы сформировать заказ и найти заказы по номеру или по принадлежности к заказчику. Однако, COM сервер должен быть способным передавать данные клиенту по двум причинам. Первая, когда пользователь просматривает заказ, он должен иметь возможность отобразить запись заказчика для этого заказа. Другими словами, форма заказов должна уметь сообщить форме заказчика о необходимости найти нужного заказчика и отобразить себя. Вторая проблема состоит в том, что COM сервер показывает форму заказов в режиме modeless. Это означает, что COM клиент не может знать о закрытии COM сервер. Единственое решение состоит в том, что COM сервер должен сообщить COM клиенту, когда пользователь закрывает форму заказов. Имеются три способа для связи сервера с клиентом.
Рис.9 Генерация событий Код обработчиков событий приведен на рисунке 9. CloseOrders и FindCustomer - методы, которые были добавлены к IORDERSERVER ранее. CloseOrders вызывается из обработчика события OnDestroy формы заказов. FindCustomer вызывается из обработчика события OnClick пункта меню View | Customer. Чтобы вызывать эти методы, Вы должны иметь ссылку на объект OrderServer. Чтобы получать эту ссылку, сделаны два изменения, показанные на рисунках 10 и 11, в модуле OrdersAuto. Глобальная переменная OrderServer добавлена к разделу интерфейса модуля. Добавлена строка в методе Initialize объекта TORDERSERVER, устанавливающая глобальную переменню OrderServer в Self. Переменная OrderServer теперь обеспечивает ссылку на объект автоматизации OrderServer, который может использоваться, чтобы вызвать методы из формы Заказов в обработчике OnDestroy и обработчиком OnClick пункта меню или в любом месте приложения DemoOrders. Обратите внимание, что, если Вы только хотите возбуждать событие из метода в интерфейсе IORDERSERVER, Вы можете опускать эти два изменения. Мы нуждались в ссылке к объекту Automation только, потому что мы нуждались в генерации событий из в любом месте приложения.
Рис. 10 Объявление переменной ссылки на объект автоматизации
Рис.11 Инициализация ссылки на OrderServer Последний шаг реализация события в COM клиенте. В проекте DemoClient, открытом в IDE, выберите Project | Import Type Library из меню, чтобы отобразить диалог импорта, показанный на рисунке 12. Выберите библиотеку DemoOrders в окне списка, и удостоверьтесь, что флажок Generate Component Wrapper установлен. Это создаст компонент, типа TORDERSERVER, и добавит его к вашей палитре компонентов. Когда Вы нажмете кнопку Install, Вас будут спрашивать, хотите ли Вы устанавливать этот компонент в новый пакет или существующий пакет. Вы возможно найдете это более удобным поместить все компоненты сервера для проекта, над которым Вы работаете в их собственном пакете. Чтобы вы не делали, не устанавливайте этот компонент в существующие пакеты компонентов Delphi. Выбрав щелкните пакета ОК, затем Yes в диалоге, сообщающем Вам, что пакет будет сформирован и затем установлен. Компонент, который создан - оболочка вокруг COM сервера и может использоваться, чтобы соединиться с сервером и вызывать методы. Компонент OrderServer также имеет событие для каждого события, которое Вы добавили к интерфейсу IORDERSERVEREVENTS в COM сервере.
Рис.12 Диалог импорта библиотеки типов Киньте TORDERSERVER компонент на форму заказчика, и назовите его OrderServer. Установите свойство AutoConnect в False, так что соединение с COM сервером не будет открыто автоматически, когда программа стартует. Переключитесь на закладку Events инспектора объектов, и создайте обработчики событий OnCloseOrders и OnFindCustomer . Код для обоих обработчиков события показывается на рисунке 13.
Рис. 13 Обработчики событий Осталось реализовать обработчик события OnClick для меню File | Orders и всплывающее меню сетки Orders. Код для этих обработчиков события показывается на рисунке 14.
Рис. 14 Обработчик пункта меню Перемещение Данных Между Сервером и Клиентом Что Вы делаете, когда хотите переместить данные, который не сохранены в таблице базы данных между COM сервером и COM клиентом? Заполните Variant, и передайте это как параметр. Обратите внимание, что я не говорю Midas сервера и клиента, а любого COM сервера и клиента. В то время как некоторые из методов в этом разделе будут демонстрироваться с Midas сервером, и клиент, будет использовать интерфейс IAPPSERVER они будут работать в равной степени хорошо работать между любым COM сервером и клиентом, использующим любой интерфейс. Передача Табличных Данных Если Вам необходимо передать табличные данные, самый простой способ - это использовать ClientDataSet и передать данные как показано в приложении PassData. Это приложение состоит из COM сервера и COM клиента. Основная форма клиента, показанная на рисунке 15, содержит Database, Query, DataSetProvider, ClientDataSet и DataSource, соединенный с DBGRID для отображения данных таблицы заказчика из DBDEMOS. Обработчик события OnClick кнопки Send Data показан на рисунке 16.
Рис. 15 Главная форма COM клиента
Рис. 16 Обработчик события нажатия кнопки Send Data Клиентское приложение использует модуль интерфейса библиотеки типов сервера, так что можно соединяться с сервером, вызывая coclass's сервера, использовать метод Create и получить ссылку интерфейс. PassDataServer объявлена как закрытая переменная формы типа - IPASSDATA. IPASSDATA - интерфейс, реализованный COM сервером. Вторая строка вызывает метод PassData интерфейса IPASSDATA и передает свойство Data ClientDataSet как параметр. Рисунок 17 показывает метод PassData сервера. Этот метод получает параметр типа OleVariant, который используется, чтобы передать свойство Data ClientDataSet от клиента к серверу. Форма главного приложения сервера содержит ClientDataSet, DataSource и DBGRID. Код на рисунке 17 присваивает значение параметра CdsData свойству Data ClientDataSet и открывает ClientDataSet.
Рис 17 Метод PassData Если необходимо передать изменения, которые были сделаны пользователем в ClientDataSet, содержащиеся в свойстве Delta ClientDataSet, добавьте другой параметр OleVariant, и присвойте дельту этому параметру. К сожалению, свойство Delta - доступно только для чтения, так что Вы не можете назначать параметр Delta свойству Delta ClientDataSet. Обратите внимание, что ClientDataSet не соединен с удаленным сервером или провайдером в этом примере, хотя это и возможно. Передача данных Flat файла Одна из интересных особенностей Midas - то, что данные, которые Midas сервер посылает клиенту, могут храниться где угодно. То есть не обязательно в таблице базы данных. Один из методов в приложении выборки PassOther обеспечивает данные Midas клиенту из CSV файла ASCII. Самый простой способ делать это состоит в том, чтобы разместить ClientDataSet и DataSetProvider в удаленном модуле данных сервера. Используйте инспектор объектов, чтобы редактировать свойство FieldDefs ClientDataSet и добавить определения полей. Затем написать обработчик события BeforeGetRecords для DataSetProvider, который получает данные, в этом случае из файла ASCII, и загрузит их в ClientDataSet. DataSetProvider затем получает данные из ClientDataSet и посылает их клиентскому приложению нормальным способом. Рисунок 18 показывает обработчик события BeforeGetRecords.
В начале обработчика BeforeGetRecords создается StringList FieldVals, который используется для просмотра записей из разделенного запятой файла ASCII (csv). Затем это проверяет открытие ClientDataSet, и если он открыт очищает его. Если не открыт вызывает CreateDataSet который, и создает набор данных в памяти, используя FieldDefs, определенный во временя разработки и открывает ClientDataSet. AssignFile и Reset открывают файл ASCII. Обратите внимание, что имя файла в обращении к AssignFile - параметр OwnerData, переданный обработчику события. OwnerData позволяет клиенту передавать любую информацию серверу, устанавливая значение параметра OwnerData в событии BeforeGetRecords ClientDataSet клиентского приложения. OwnerData - Variant, Вы можете передавать любомой типу данных, включая массив вариантов. Это дает Вам возможность передать любое количество значений любого типа. Цикл while читает запись из текстового файла в строковую переменную Rec, очищает StringList, и устанавливает значение свойства CommaText StringList в Rec. Когда Вы назначаете строку CommaText анализируется наличие любых запятых или пробелов, которые не включены в кавычки, и каждая подстрока записывается в элемент StringList. Затем, новая запись вставляется в ClientDataset, и значения из StringList присваиваются полям. Новая запись закрепляется. По достижении конца текстового файла CloseFile закрывает файл ASCII. Затем, обращение к First перемещает курсор ClientDataSet к первой записи. Это важно, потому что DataSetProvider начнет с текущей записи, когда будет формировать пакет данных, чтобы послать клиенту. Если Вы оставляете ClientDataSet, позиционированный в последнюю запись, последняя запись единственная, которая будет послана Midas клиенту. В заключение, обращение к методу Free StringList освобождает память. На клиентских местах все гораздо проще. Когда Вы открываете ClientDataSet в клиентском приложении генерируется событие BeforeGetRecords. Рисунок 19 показывает код для события клиента BeforeGetRecords.
Рис. 19 Обработчик события BeforeGetRecords Единственая вещь, которая выполняется здесь - то, что имя текстового файла записывается в параметр OwnerData. OwnerData автоматически отправляется Midas серверу, где, появляется как параметр для BeforeGetRecords события DataSetProvider. Отсылка файла, который не требуется отображать пользователю Использование ClientDataSet удобно для данных, которые Вы хотите отображать на форме. Но предположим, что Вы должны передать файл, который не надо отображать в ClientDataSet от COM сервера к клиенту. Это совершенно, просто, даже если Вы должны послать файл который является слишком большим, чтобы размещаться в память. Закладка File типового приложения содержит кнопку Copy File и компонент Memo. Рисунок 20 - код из обработчика события OnClick этой кнопки. Процедура начинается с объявления константы ArraySize, которая содержит размер массива, используемого для передачи файлов от COM сервера к клиенту. Эта типовая программа отображает блоки чтения данных из сервера в компоненте Memo на форме. В приложении, где Вы передаете большое количество данных и сохраняете их в памяти или пишете в файлу, Вы могли бы использовать намного больший размер массива, например 4КБ или 16КБ, чтобы передать большее количество данных за одно обращения к серверу. Так как мы хотим помещать данные в компонент Memo, строка байтов, возвращенных из сервера должна быть интерпретирована как строковая переменная, в этом случае S. Обращение к SetLength устанавливает размер S равным размеру массива. Затем компонент DCOMCONNECTION открывается, чтобы установить соединение с сервером, и Memo очищается. Пересылка файла выполнена тремя пользовательскими методами, добавленными к интерфейсу приложения IAPPSERVER сервера, используя Редактор Библиотеки типов. Первый, OpenFile, берет один параметр - имя файла, который будет перемещен. Цикл while вызывает второй метод IAPPSERVER, GetFileData. GetFileData передает вариант, VDATA, как возвращаемый параметр и размер массива и возвращает число байт фактически прочитанных из файла. Это будет размер массива для каждого блока за исключением последнего, который может содержать меньшее количество байтов, если размер файла - не четный множитель блочного размера. Если число байтов, возвращенных обращением к GetFileData - нуль, конец файла был достигнут, и цикл с условием продолжения покидается. Следующий шаг должен поместить байты, возвращенные в массиве в строковую переменную, S, и добавлять строку к компоненту Memo. Чтобы обращаться к данным в вариантном массиве, быстрее массив блокирован обращением к VarArrayLock (VDATA), который возвращает указатель на фактический массив данных в варианте. Указатель сохраняется в переменной PDATA, которая объявлена с типом PBYTEARRAY. PBYTEARRAY объявлен в модуле System как указатель на массив типа "байт". Данные перемещаются от массива в строковую переменную вызывом Move(PDATA ^, S [1], ByteCount). Процедура Move копирует определенное число байтов из одного участка в памяти в другой. Первый параметр - исходное расположение, второй параметр - адресат, и третий параметр - число копируемых байтов. Обратите внимание, что Move не выполняет никакую проверку ошибок любого вида, так будьте внимательным, чтобы использовать правильные параметры, потому что странные вещи случатся во времени выполнения, если Вы записываете в неправильную область памяти. Кроме того, Move не выполняет никакой контроль соответствия типов. Вы можете перемещать любую комбинацию разрядов в строку или любой другой вид переменной. Если только данные переместились от массива в строку, массив разблокируется, и строка добавляется в Memo.После копирования происходит обращение к третьему методу IAPPSERVER - CloseFile для закрытия файл на сервере.
На стороне сервера методы OpenFile, GetFileData и CloseFile были добавлены к интерфейсу IAPPSERVER, используя редактор библиотеки типа. Рисунок 21 показывает код из удаленного модуля данных для OpenFile метода. OpenFile содержит одиночную строку программы, которая создает объект FileStream для файла, переданного как параметр метода. Файл открыт в режиме чтения и разделен для чтения, но никакая запись не допускается. FileStream назначен к переменной Fs, которая является закрытой переменной удаленного модуля данных.
Рис. 21 Метод OpenFile Рисунок 22 показывает метод GetFileData. Этот метод имеет выходной параметр, который является вариантом и возвращает массив байтов, содержащих данные файла. После создания вариантного массива GetFileData блокирует его для быстрого доступа и получает указатель, возвращенный VarArrayLock в локальную переменную PDATA. Затем вызывается метод чтения FileStream, передавая адрес PDATA, указывающий на массив, чтобы сохранить данные и передающий VarArrayHighBound (Данные, 1) + 1, поскольку число байтов всегда равно размеру массива. Число байтов прочитанных фактически возвращается функцией. В заключение, обращение к VarArrayUnlock разблокирует вариантный массив.
Рис. 22 Метод GetFileData Рисунок 23 показывает метод CloseFile, который освобождает объект FileStream и устанавливает переменную Fs к nil. Обработчик события OnDestroy для удаленного модуля данных также освобождает FileStream, если Fs - не nil, на случай если клиентская программа не вызывает CloseFile.
Рис. 23 Метод CloseFile Пересылка массивов или других структур, находящихся в памяти Вы можете также переслать массив или любую другую структуру данных, которая существует в памяти, заполняя в вариантный массив байтов. Рисунок 24 показывает метод выборки GetArray Midas сервера. Этот метод объявляет массив Integer размером 10 элементов. Вариант, VDATA, передан по ссылке клиентским приложением. GetArray вызывает VarArrayCreate, чтобы создать вариантный массив байтов, чей размер равнен размеру целочисленного массива, который будет возвращен. Затем вариантный массив блокируется, целочисленный массив перемещается в него, и вариантный массив разблокируется.
Рис. 24 Метод GetArray
Рис.25 Обработчик OnClick Рисунок 25 показывает OnClick обработчик события для кнопки Copy Array в приложении PassOther. Этот метод соединяется с Midas сервером, вызывая метод Open компонента DcomConnection. Затем вызывает GetArray метод сервера, передавая вариант как параметр. Затем вариант который теперь содержит массив блокируется и данные перемещаются из вариантного массива байтов в целочисленный массив IntArray. В заключение вариантный массив разблокируется, и целые числа отображаются в компоненте Memo на форме. Заключение Midas обеспечивает мощный гибкий способ работs с и локальными базами и c удаленными серверами. Это оказывается настолько полезным, чтобы стать краеугольным камнем нового Borland DB Express. От переводчика: К сожалению из-за большого объема данной статьи невозможно до конца выправить стилистику и т.д. Если Вы обнаружили какие-либо ошибки, имеете вопросы и предложения, я с радостью приму их по адресу mgoblin@mail.ru. It seems like you've provided a lengthy article about Midas and its capabilities for working with local and remote databases. Here's a summary of the main points: 1. Midas is a powerful tool that allows developers to work with local and remote databases, Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |