Написание плагинов на Delphi 2009

Автор SeUp, 20.08.09, 10:33:16

« назад - далее »

0 Пользователи и 2 гостей просматривают эту тему.

SeUp

Кто-нибудь пытался под ЛОЦМАН, хотя бы, 9.0 SP1, писать плагины на Delphi 2009 из CodeGear студии. Тот же проект компилируется без ошибок, встраивается в меню, но не работает. Поделитесь опытом, если он имеется в этом деле. Заранее благодарен.

teplinskiy

По вопросу перевода старых проектов на Delphi 2009 поссмотри следующую статью:
http://www.interface.ru/home.asp?artId=20265

и для более полного ознакомления с теорией:
http://www.interface.ru/home.asp?artId=20240
http://www.interface.ru/home.asp?artId=20263

SeUp

Цитата: teplinskiy от 20.08.09, 12:17:15
По вопросу перевода старых проектов на Delphi 2009 поссмотри следующую статью:
http://www.interface.ru/home.asp?artId=20265

и для более полного ознакомления с теорией:
http://www.interface.ru/home.asp?artId=20240
http://www.interface.ru/home.asp?artId=20263

Спасибо большое, попробую.

teplinskiy

Уж лучше не пробовать...)))

перевод серьезного проекта занимает не одну неделю...
(как говорят... ;))

YorikER

Если честно, я остановился на Delphi2007... Слишком много времени пришлось тратить на вылавливание многих несостыковок при переходе на 2009...

Chaa

Вообще есть два интерфейса плагинов - один для плагинов Delphi в виде PIClasses.pas, другой для плагинов на других языках в виде COM-интерфейсов.
Если использовать COM-интерфейсы, то можно писать смело.
А вот с написанием плагинов с использованием PIClasses.pas сразу не получится.
Есть несколько проблем:
1. В Delphi 2009 тип String использует юникод. Это правится переписыванием PIClasses.pas и заголовков экспортируемых функций.
2. В Delphi 2009 есть новые подтипы Variant, такие как vtUnicodeString, которые RunMethod Лоцмана не поймет.
3. В Delphi 2009 для TClientDataSet для метаданных используется кодировка UTF-8, и будут проблемы с именами столбцов с русскими буквами.
4. Может что-то еще.
Если очень хочется писать на Delphi 2009, то нужно будет серьезно подумать.

Chaa

5. Исключения в Delphi 2009 несовместимы с Лоцманом, поэтому плагины не должны генерировать исключения, и исключения из RunMethod-а Лоцмана тоже не должны попадать в код плагина.

YorikER

Цитата: Chaa от 09.09.09, 14:44:28
3. В Delphi 2009 для TClientDataSet для метаданных используется кодировка UTF-8, и будут проблемы с именами столбцов с русскими буквами.

Переходить на новые версии Delphi придется... Сегодня все переходят на кодировку UTF8... Линукс тоже... Действительно в TClientDataSet в Delphi 2010 (2009) есть проблемы с кодировкой... Методы сервера приложений GetTree и GetLinkedObjectsEx возвращают наборы данных в формате UTF16 с пользовательскими атрибутами, наименования которых могут быть русскоязычными... При передаче в TClientDataSet Delphi 2010 (2009) ругается "Missing Field Name". Проблема решается двумя путями:
1. Все атрибуты должны быть англоязычными либо начинаться с англоязычных символов (достаточно вставить "_" в начало русского наименования атрибута и все будет ОК);
2. Передача информации в XML формате и программное заполнение TCLientDatSet с переименованием русскоязычных колонок.

Вопросы всем и АСКОНУ.
1. Кто-нибудь сталкивался с этой проблемой и как ее решал?
2. Будет ли АСКОН в новых версиях переходить с UTF16 на UTF8, и как специалисты АСКОНа собираются решать проблемы совместимости с существующими рабочими базами данных в ЛОЦМАНЕ?

Chaa

Данные действительно передаются в UTF-16, и с ними проблем нет (внутри Delphi 2009 везде UTF-16), но я писал про метаданные - как например названия столбцов. Они используют кодировку ANSI в Delphi 7 и UTF-8 в Delphi 2009. Поэтому и получается исключение "поле не найдено". Если интересно, посмотрите в исходниках VCL код TCustomClientDataSet.CreateDSBase.
Выхода как обычно два:
1) Свой класс TClientDataSet вместо стандартного.
2) Создать на Delphi 7 библиотеку DLL, в которой все методы работы с TClientDataSet собраны в одном месте. Я сделал свой компонент с интерфейсом IDataSet из Loodsman.tlb. Было бы хорошо, если бы Аскон сделал такое сам.
Вообще, если интересно, могу позже написать подробно.

YorikER

Насчет своего TClientDataSet - спасибо попробую, мысль интересная...
Насчет интерфейса IDataSet если можно поподробнее...

YorikER

С написанием своего TClientDataSet не все так просто... Скорее всего придется перекомпилировать стандартный пакет компонентов dclmid140.bpl, а вот где найти исходник его, это вопрос... Создать новый компонент на основе TDataSet  и повторить методы TCustomClientDataSet, переписав метод CreateDSBase тоже не так просто, исходник методов использует защищенные свойства других компонентов, описанных в теле DBClient... В лоб пройти этот путь не получилось, хотя мысль интересная... Создать dll в Delphi7 тоже вряд ли пройдет - слишком далеко разошлись версии midas...
А вот насчет компонента с интерфейсом IDataSet все-таки поподробнее... Очень интересно...

Chaa

В клиенте Лоцман есть возможность писать плагины на языках, отличных от  Delphi. Для этого клиент Лоцман вызывает функции InitUserDLLCom и PgiCheckMenuItemCom и передает в них интерфейс IPluginCall. Один из его методов возвращает интерфейс IDataSet для доступа к TClientDataSet из плагина на любом языке, понимающим COM. Методы интерфейсов объявлены как safecall, т.е. не генерируют исключений, а возвращают код ошибки COM.
Я сделал свою реализацию IDataSet в DLL, собранной в Delphi 7, чтобы при необходимости иметь возможность вызывать вышеописанные плагины из своих приложений, т.е. ради совместимости с клиентом Лоцмана. К тому же, как оказалось, с интерфейсом удобней работать за счет поддержки компилятором Delphi автоматического подсчета ссылок на него и его освобождения. Теперь не надо писать try/finally вокруг каждого создания TClientDataSet.
IPluginCall = interface(IDispatch)
    function RunMethod(const stMetod: WideString; vaParams: OleVariant): OleVariant; safecall;
    function GetDataSet(const stMetod: WideString; vaParams: OleVariant): IDataSet; safecall;
    property DBName: WideString;
    property CheckOut: Integer;
    property AppHandle: OLE_HANDLE;
    property ClientHandle: OLE_HANDLE;
    property IdVersion: Integer;
    property stType: WideString;
    property stProduct: WideString;
    property stVersion: WideString;
    property IdParent: Integer;
    property stParentType: WideString;
    property stParentProduct: WideString;
    property stParentVersion: WideString;
    property IdLink: Integer;
    property SelectedParent: WordBool;
end;

IDataSet = interface(IDispatch)
    procedure First; safecall;
    procedure Last; safecall;
    procedure Next; safecall;
    procedure Prior; safecall;
    procedure Append; safecall;
    procedure Delete; safecall;
    procedure Edit; safecall;
    procedure Post; safecall;
    procedure Cancel; safecall;
    procedure Insert; safecall;
    function MoveBy(Distance: Integer): Integer; safecall;
    function IsEmpty: WordBool; safecall;
    function Locate(const KeyFields: WideString; KeyValues: OleVariant; CaseSensitive: WordBool; PartialKey: WordBool): WordBool; safecall;
    property CurrentRecord: Integer;
    property RecordCount: Integer;
    property FieldValue[const Name: WideString]: OleVariant;
    property FieldCount: Integer;
    property FieldName[Index: Integer]: WideString;
    property Filter: WideString;
    property Filtered: WordBool;
    property DATA: OleVariant;
    property Eof: WordBool;
    property Bof: WordBool;
    property IndexFieldNames: WideString;
end;

Chaa

DLL библиотека LUStub.dll, содержит:
1) Компонент, реализующий интерфейс IDataSet. Также там используется уже мой, а не Асконовский, интерфейс IDataSetEx, он может создавать датасет.
2) Обертка для RunMethod, передаваемого из клиента Лоцман. Используется плагинами, написанными на Delphi 2009.

YorikER

Т.е. (если я все правильно понял) само тело TClientDataSet с метаданными в ANSI формате находится в теле клиента ЛОЦМАНа, а вы к нему прописали интерфейс IDataSet, чтобы доступиться из плагина... Дело в том, что от плагинов я отказался уже давно, и вообще не использую ЛОЦМАН-Клиент... Речь идет о написании своего собственного клиента, который использует методы сервера приложений (см. http://www.infnt.ru/VL/VL.html)... При переходе на Delphi2009 (2010) начались проблемы с методами, которые я написал выше...

Chaa

Нет, тело TClientDataSet находится в LUStub.dll, написанной на Delphi 7, а интерфейс IDataSet используется для совместимости с плагинами под Лоцман.
Т.е. из вашего клиента на Delphi 2009 вы будете использовать функции LUStub.dll для работы с датасетом. В принципе вы можете написать свой интерфейс для этого, если вам не нужна совместимость с плагинами Лоцмана.
Чтобы было понятнее вот примерно код:
var
DataSet: IDataSet;
Product: String;

DataSet := StubCreateDataSet;
DataSet.Data := AppServer.RunMethod('...', [...]);
while not DataSet.Eof do
begin
    Product := DataSet.FieldValue['_PRODUCT'];
    DataSet.Next;
end;

У меня, кстати, тоже есть свой клиент Лоцмана. Но он не заменяет стандартный, а дополняет его связкой с Workflow (у нас Лоцман 8.5). И поэтому мой клиент поддерживает плагины Лоцмана, так как их у нас используется много.

YorikER

Спасибо понял, но все равно это как-то исскуственно... Проблема в двух методах всего... Переключайся на XML формат и раздраконивай его в своем клиенте хоть вдоль, хоть поперек... Остальные методы возвращают англоязычный формат метаданных... На мой взгляд это проще, хотя идея своего T...ClientDataSet тоже пока еще не умерла...

YorikER

А что скажут специалисты АСКОНа?

Chaa

#17
В моем случае это удобно, так как IDataSet мне все равно нужен для поддержки плагинов.

Свой TClientDataSet я бы попробовал сделать следующим образом:
1) Скопировал DBClient.pas из исходников Delphi 2009 в свой проект, переименовав его.
2) Удалил оттуда все, кроме класса TCustomClientDataSet.
3) Переименовал класс TCustomClientDataSet в свой класс.
4) Внес в свой класс необходимые исправления. Насколько я помню, нужно изменить только CreateDSBase. Подробнее можно узнать, сравнив DBClient.pas от D7 и D2009 с помощью, например, WinMerge.

P.S.
Для работы с сервером приложений у меня используется набор классов, реализующих интерфейс IRemoteConnection. Вся логика приложений пользуется этим интерфейсом. При этом он может создаваться на основе переданного в плагин RunMethod-а, может создаваться из переданного в плагин интерфейса IPluginCall, а может создаваться и самостоятельно, получая параметры подключения из реестра, так, как это делает клиент Лоцмана. При этом поддерживается и соединение через DCOM, и через сокет-сервер, и веб-соединение. Этот же интерфейс используется для подключения к СП Workflow. Внутри интерфейса проверяются ошибки при вызове методов сервера приложений и генерируются исключения при возникновении ошибки, так же, как в RunMethod-е клиента Лоцмана.
Все делается как в клиенте Лоцмана, все с ним совместимо.

YorikER

с TCustomClientDataSet я так и делал, ничего не получилось, правда это было в Delphi2010, там метод CreateDSBase отличается от Delphi2009. В лоб быстро не проходит, нужно подумать... Не хочется городить огород из разных версий...

YorikER

Прикол заключается в том, что программным путем через TClientDataSet.FieldDefs и CreateDataSet можно создать таблицу с русскоязычными колонками, программно ее заполнить и достучаться до полей с русскоязычными названиями... А вот получить пакет от СП Лоцмана через свойство Data, не получается... Интересно, нельзя ли полученный пакет OleVatiant загрузить куда-то в буфер, а затем программным путем загнать в TClientDataSet (не через Data:=...)?