Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Plugin


Автор: <Spawn> 28.6.2003, 10:25
Хочется сделать что то типа плагинов к своим прогам, но вот не поиму как, например, добавить из ДЛЛ еще один TTabSheet в TPageControl своей проги? Например, использование подобного кода приводит к ошибке.

Код
Library TestDLL;
uses
 SysUtils,
 Classes,
 ShareMem,
 ComCtrls;

{$R *.res}

function GetPluginControl:TTabSheet;export;stdcall;
begin
with Result.Create(nil) do
Caption:='TestTabSheet';
end;

exports
GetPluginControl;

Автор: &-ray 28.6.2003, 13:18
Скорее всего ошибка здесь:

Цитата
Result.Create(nil)


Почему nil confused.gif
Здесь по-моему должен быть владелец твоего ttabsheet типа tpagecontrol

А вообще в help'е в Делфях сказано так

Цитата
When creating tab sheets at runtime, use the PageControl property to insert them into a page control object.
, т.е. мути непосредственно все через pagecontrol.


Автор: <Spawn> 28.6.2003, 13:33
Ну к примеру, если я передам PageControl по ссылке то вылетает Access Vialetion
Код
procedure GetPluginControl(var PageCtrl:TPageControl);export;stdcall;
var
TabSheet:TTabSheet;
begin
with TabSheet.Create(PageCtrl) do
Caption:='TestTabSheet';
end;

exports
GetPlugin;

Автор: <Spawn> 28.6.2003, 13:39
Если же передавать не по ссылке PageControl, то возникает ошибка EStackOverflow.

Автор: dm9 28.6.2003, 14:15
ИМХО, так и не должно работать.

Кто ж вызывает так метод Create?

Надо, насколько я знаю, так:

Код
Library TestDLL;

uses
SysUtils,
Classes,
ShareMem,
ComCtrls;

{$R *.res}

function GetPluginControl:TTabSheet;export;stdcall;
begin
  Result := TTabSheet.Create(nil) do
  Result.Caption := 'TestTabSheet';
end;

exports
  GetPluginControl;


Только:
1) Не забывай освобождать память. nil дело плохое. Лучше передавай в процедуру того, кто будет владельцем - потом проблем меньше будет.
2) Не уверен, что строка Result.Caption := 'TestTabSheet'; будет работать. Хотя, если откомпилирует, то всё ОК. Просто я не уверен, то можно так обращаться к переменное Result. Хотя хз. Делфей нет, проверить не могу.
3) Если передашь в процедуру того, кто будет Parent'ом, проблем будет меньше: он может быть Owner'ом и сразу скажешь, что он Parent. (Хотя нужен ли TabSheet'у Parent? Не помню confused.gif )
smile.gif

Автор: <Spawn> 28.6.2003, 14:24
Дак записи типа
Result:=TTabSheet.Create(nil)
и
with Result.Create(nil) do

это одно и то же smile.gif

Автор: dm9 28.6.2003, 14:26
Тьфу ты, сорри. smile.gif Крыша едет. Конечно, у тебя же там TTabSheet как результат ф-ции выдаётся.

Автор: dm9 28.6.2003, 16:32
Я тут поразмышлял немного и понял, что был прав. Не одно это и то же. Ты пишешь код, эквивалентный этому:

Код
function GetPluginControl:TTabSheet;export;stdcall;
begin
  GetPluginControl.Create(nil);
  GetPluginControl.Caption:='TestTabSheet';
end;


Такое не работает по определению.

Тогда уж так делай:

Код
function GetPluginControl:TTabSheet;export;stdcall;
begin
  Result := TTabSheet.Create (nil);
  Result.Caption := 'TestTabSheet';
end;


У тебя ошибка возникает при вызове ф-ции dll.
В моём коде такой ошибки нет.
Другое дело, что потом, уже в теле основной программы, я не могу ничего сделать с полученным указателем

TabSheet := Proc; - работает
TabSheet.PageControl := PageControl1; - возникает ошибка (cannot assign TFont to TFont)

В чём дело - не пойму. Может, ещё какие директивы надо указывать? Я с dll очень мало работал...

Автор: &-ray 28.6.2003, 22:28
2<Spawn>
А вот так не пробовал confused.gif:

Цитата
procedure GetPluginControl(var PageCtrl:TPageControl);export;stdcall;
var
TabSheet:TTabSheet;
begin
TabSheet:=PageCtrl.Pages.Create(nil);
TabSheet.Caption:='TestTabSheet';
end;

exports
GetPlugin;


2dm9
Цитата
TabSheet.PageControl := PageControl1;

Лично я не понял, что ты этим хотел сказать confused.gif

Автор: Fantasist 30.6.2003, 17:18
Цитата
Result:=TTabSheet.Create(nil)
и
with Result.Create(nil) do

это одно и то же 


Естесственно, это совсем НЕ одно и то же. Например, равносильны ли следующие строчки кода:

Код

var
 b:TButton;
begin
   b:=TButton.Create(nil);
end;


и

Код

var
  b:TButton;
begin
    b.Create(nil);
end;



Цитата
TabSheet := Proc; - работает
TabSheet.PageControl := PageControl1; - возникает ошибка (cannot assign TFont to TFont)


Бросте эту ерунду. Дело в том, что для с классами, которые возвращает dll не работает RTTI. То есть, так как дллка компилируется отдельно от ехе-шника, то в каждом из них создается своя таблица с информацией о классах. Эти таблицы сравниваются примитивно, по равности указателя на них. Так что даже если эти таблицы абсолютно идентичны, то они будут считаться как принадлежащие разным классам. VCL довольно плотно использует RTTI, например в процедуре Assign:

Код

procedure TFont.Assign(Source: TPersistent);
begin
 if Source is TFont then
    .....
end;


Так как процедура Assign скомпилированна в ехе, а Source в dll, то эта проверка обламывает присвоение на корню. Так что передавать туда-сюда ссылки (dll->exe и наоборот) на VCL-вские компоненты и пытаться их использовать гиблое дело.

Плагины лучше писать при помощи пакетов.

Автор: Vyacheslav 8.7.2003, 08:22
Цитата(Fantasist @ 30.6.2003, 17:18)

  Бросте эту ерунду. Дело в том, что для с классами, которые возвращает dll не работает RTTI. То есть, так как дллка компилируется отдельно от ехе-шника, то в каждом из них создается своя таблица с информацией о классах. Эти таблицы сравниваются примитивно, по равности указателя на них. Так что даже если эти таблицы абсолютно идентичны, то они будут считаться как принадлежащие разным классам. VCL довольно плотно использует RTTI, например в процедуре Assign:

Код

procedure TFont.Assign(Source: TPersistent);
begin
 if Source is TFont then
    .....
end;


  Так как процедура Assign скомпилированна в ехе, а Source в dll, то эта проверка обламывает присвоение на корню. Так что передавать туда-сюда ссылки (dll->exe и наоборот) на VCL-вские компоненты и пытаться их использовать гиблое дело.

 

Эти вопросы легко снимаются, если для основного приложения и плагинов включить опцию "Build with runtime package". Во всяком случае это справедливо для Builder'а. В этом случае виртуальные таблицы классов (или как там они в Delphi называются) будут присутствовать для одинаковых классов в одном экземпляре

Автор: Fantasist 8.7.2003, 23:17
Цитата
Эти вопросы легко снимаются, если для основного приложения и плагинов включить опцию "Build with runtime package".


Да, я помниться, рекомендовал то же самое, однако, коли плагин пишиться для Delphi/Builder, то и оформить его логично в виде package'а, а не dll.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)