Форум: "Основная";
Текущий архив: 2005.02.27;
Скачать: [xml.tar.bz2];
ВнизInterface + TDataSet. Проблемы совместимости. Найти похожие ветки
← →
Джинн (2005-02-09 16:42) [0]Есть некий интерфейс, возвращающий экземпляр класса TDataSet
TMyInterface = interface(IUnknown)
function GetDataSet: TDataSet; stdcall;
end;
В случае реализации данной конструкции внутри одного исполняемого модуля- проблем нет никаких.
Однако, если этот интерфес используется в плагине (dll), могут возникнуть проблемы с возвращаемым объектом, так как VMT у возвращаемого объекта TDataSet и VMT для объектов класса TDataSet в основной программе могут быть разными. Так ли это?
Или в данном случае обработка виртуальных методов производится как-то по-иному, например, используется VMT из подключаемого модуля?
Если это так, то какие могут быть пути для обхода такой ситуации?
Возможно, необходимо создать какой-либо дополнительный класс (TDataSetEx = class(TDataSet)), откомпилировав его в отдельный DCU, а затем использовать этот модуль для основной программы и подключаемых модулей, чтобы VMT были одинаковыми?
Или я в чем-то ошибаюсь?
← →
Digitman © (2005-02-09 17:12) [1]
> так как VMT у возвращаемого объекта TDataSet и VMT для объектов
> класса TDataSet в основной программе могут быть разными.
> Так ли это?
так.
> Если это так, то какие могут быть пути для обхода такой
> ситуации?
пересмотреть концепцию использования интерфейсов
← →
Джинн (2005-02-09 17:31) [2]> так как VMT у возвращаемого объекта TDataSet и VMT для объектов
> класса TDataSet в основной программе могут быть разными.
> Так ли это?
так.
Хорошо. В этом мнении мы сошлись.
Кстати, как тогда относится к предложению (на www.delphikingdom.ru) использовать следующую конструкцию в плагинах:
library SomePlugin;
var
OldApp: TApplication;
procedure InitPlugin(App: TApplication);
begin
OldApp := Application;
Application := App;
end;
finalization
Application := OldApp;
end;
Ведь в критическом случае получится так, что в программе при подключении такого плагина возникнут серьезные ошибки, так как VMT для TApplication в основной программе и в подключаемом модуле могут быть различными.
Это баг?
А насчет пересмотра концепции.
Если подключаемый плагин передает в основную программу набор данных, то как оформить механизм передачи?
Можно использовать TDataSet, но это чревато последствиями.
Использовать для этого простые типы данных можно, конечно, но тогда процесс передачи может затянуться на продолжительное время.
Использовать потоки? Но тогда процесс загрузки данных будет тоже длительным:
В плагине: Загрузка данных с сервера - Сохранение в поток
В основной программе: Загрузка данных из потока - Использование
И еще. Размещение указателей на методы в VMT зависят от порядка следования этих методов в объявлении класса? То-есть, если поменять местами два метода в объявлении класса, то изменится VMT?
← →
Ihor Osov'yak © (2005-02-09 17:32) [3]> пересмотреть концепцию использования интерфейсов
имхо концепцию используемых интерфейсов, а не использования.
Ps. Не использовать как параметры и возвращаемые значения классовые ссылки. Подумать об использовании интерфейсных ссылок.
← →
Джинн (2005-02-09 18:17) [4]Нашел решение. Может, кому-то подойдет.
Можно использовать TCustomClientDataSet вместо TDataSet.
Дело в том, что TCustomClientDataSet использует в качестве хранилища данных некий COM-объект, на который ссылается через
protected property DSBase: IDSBase;
Это свойство можно сделать public, а можно реализовать пару дополнительных методов, чтобы не нарушать инкапсуляцию (все же, разработчики TCustomClientDataSet не зря сделали это property protected). Тогда можно просто передавать этот интерфес для обмена данными.
И еще, возвращаясь к плагинам и Application. Как избежать проблем с ссылками на экземпляры разных TApplication? Можно использовать Application.Handle - это решает большинство проблем, в частности, исключает появление еще одной кнопки на панели задач, но при этом внутри основного приложения и внутри подключаемого модуля существуют разные объекты Application. Не будет ли тут каких-либо "подводных камней"?
← →
Ihor Osov'yak © (2005-02-09 18:35) [5]> TCustomClientDataSet вместо TDataSet.
не возвращайте с ДЛЛ экземпляров классов - рано или позно будут грабли.
> использует в качестве хранилища данных некий COM-объект
а вот ком - ради бога, если к нему достучитесь...
> Как избежать проблем с ссылками на экземпляры разных TApplication?
не использовать в длл кода, работающего с экземпляром TApplication. Особенно Application.ProcessMessages :-).
Вообще-то помещать vcl-евскую визуальность в длл - немного чревато, грабли всю дорогу раставлены.
← →
Юрий Зотов © (2005-02-09 20:47) [6]> Джинн (09.02.05 17:31) [2]
> Ведь в критическом случае получится так, что в программе при
> подключении такого плагина возникнут серьезные ошибки
Не возникнут (см. ниже).
> так как VMT для TApplication в основной программе и в
> подключаемом модуле могут быть различными.
В данном случае это неважно. Мы подменили экземпляр объекта. Его первые 4 байта указывают на VMT, поэтому вместе с объектом мы подменили и VMT - но подменили на точно такую же (в смысле, для точно такого же класса). Кроме того, новая VMT и все ссылки из нее в данном случае находятся в том же АП, что и старая VMT - то есть, с доступом проблем не будет.
Поэтому код просто начинает работать с новой VMT, игнорируя старую. И вся наука.
Остается только добавить, что использование объектов VCL в DLL без включения компиляции с run-time пакетами - это все же плохой стиль. Хотя бы из-за дублирования кода.
← →
Джинн (2005-02-10 09:39) [7]В данном случае это неважно. Мы подменили экземпляр объекта. Его первые 4 байта указывают на VMT, поэтому вместе с объектом мы подменили и VMT - но подменили на точно такую же (в смысле, для точно такого же класса)
Так ли? Я не в курсе, но мне кажется, что для разных версий Delphi (а в частном случае, когда вносятся изменения в код VCL или в качестве Application используется объект класса, порожденного от TApplication - и для одной и той же версии Delphi) класс TApplication может иметь различия в реализации, то-есть, мы на самом деле работаем все же с разными классами, хоть и именоваными одинаково: TApplication.
Насколько я понимаю, ссылки на методы размещаются в VMT по некоторому, вполне определенному, смещению, определяемому на этапе компиляции. И для разных исполняемых модулей (exe и dll) эти ссылки могут (и, скорее всего, будут) размещаться по другому смещению. Таким образом, при вызове из модуля метода объекта Application, подставленного из основной программы, попадаем на совершенно другой метод.
Поэтому еще один вопрос: используют ли объекты VCL (формы, прочие компоненты) глобальный объект Application? То-есть, если я не буду явно использовать глобальный объект Application в подключаемом модуле, возникнут ли какие-либо проблемы? И если возникнут, то какого плана?
И еще. Если вместо dll использовать пакеты, проблем с Application быть не должно? Как и про изготовление плагинов в разных версиях Delphi?
← →
Verg © (2005-02-10 09:55) [8]
> Насколько я понимаю, ссылки на методы размещаются в VMT
> по некоторому, вполне определенному, смещению, определяемому
> на этапе компиляции. И для разных исполняемых модулей (exe
> и dll) эти ссылки могут (и, скорее всего, будут) размещаться
> по другому смещению.
Конечно.
Это касается и невиртуадьных методов и не только методов.
Если DLL и приложение скомпилированы с одинаковыми библиотеками (по-сути в одной сборке), то можно расчитывать на полную идентичность структур объектов и VMT для одинаковых классов.
Только это все до поры до времени.
Какой смысл в DLL, если обязательным условием их корректного взаимодействия является одновременность сборки?
← →
Ihor Osov'yak © (2005-02-10 11:27) [9]2 [6] Юрий Зотов © (09.02.05 20:47)
> Поэтому код просто начинает работать с новой VMT, игнорируя старую. И вся наука.
А если приложение и "плагин" будут собраны с оспользованием различных версий библиотек, что не исключает возникновение различий в VMT?
← →
Юрий Зотов © (2005-02-10 15:19) [10]Да, версионность не учел. Факт.
> Джинн (10.02.05 09:39) [7]
Формы (а также фреймы и некоторые функции из модуля Forms) точно используют Application и Screen.
Вообще, что касается разных версий, то лучше всего все делать на интерфейсах. Получили ссылку - вызвали метод, а уж как он там реализован - это внутреннее дело модуля.
← →
Джинн (2005-02-10 16:38) [11]>>Вообще, что касается разных версий, то лучше всего все делать на интерфейсах
Я понимаю, что если задействовать только интерфейсы, проблем быть не должно.
Но у меня есть сомнения насчет нормального поведения форм и прочих объектов VCL, размещенных в плагинах.
Предположим, я буду использовать внутри подключаемых модулей свои объекты Application, а внутри основной программы - свой.
Не будет ли при этом каких-то побочных эффектов?
Вот один из вариантов. Предположим, у меня в плагине есть некоторая панель, которую я размещаю на форме в основной программе, используя Windows.SetParent(PanelHandle, MainFormHandle). При этом я обеспечу своевременное удаление этой панели до удаления основной формы. Тут могут быть проблемы?
← →
Юрий Зотов © (2005-02-10 23:04) [12]> Джинн (10.02.05 16:38) [11]
> Тут могут быть проблемы?
ИМХО, могут. Хотя бы из-за той же разницы версий. Проблем не будет, если вся DLL написана на чистом API, либо если dpиспользуются только интерфейсы.
Схема может быть, например, такой. Программа грузит DLL (плагин), запрашивает у нее некий предопределенный интерфейс и получает ссылку на него. Далее программа вызывает методы этого интерфейса, по полученной через них информации САМА конструирует панель с лежащими на ней контролами и размещает ее, где нужно.
Таким образом, VCL работает только внутри самой программы, а DLL лишь снабжает ее информацией о том, как надо построить панель и что на ней разместить.
← →
Набережных С. © (2005-02-11 07:23) [13]Я бы предпочел плагины в виде Active Forms. Хост создает контейнер и грузит в него объект из длл. Преимуществ масса, а недостатков практически нет.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.02.27;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.04 c