Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Помогите разобраться с DLL


Автор: AlexLogos 20.9.2010, 09:57
Привет народ. Хочу разобраться с DLL. Уже который раз начинаю да все никак не закончу.
Есть у меня df.dll со следующим кодом

Код

library df;

uses
  ShareMem, SysUtils,
  Classes, SameRec in 'SameRec.pas', Forms;

{$R *.res}

procedure ShowSame1(num:Integer); stdcall;
var Same:TSameRecord;
begin
 Same:=TSameRecord.Create(Application);
 With Same do
  begin
   PnCaption.Caption:='найдено '+IntToStr(num)+' записей';
   ShowModal;
   FreeAndNil(Same);
  end;
end;

exports ShowSame1;
begin
end.


В программне я описываю ее
Код

var
  procedure ShowSame1(num:Integer); stdcall; external 'df.dll';


Вызываю по нажатию кнопки
Код

ShowSame1(5);


Появляеться окошко вызванной формы, но "надено 4776177 записей", по закрытии этой формы - AV и плюс ко всему когда закрываю основную прогу - форма исчезает, но процесс остается в памяти. Где я ошибся?

Автор: aleksh 22.9.2010, 17:12
а что будет если этот код использовать не в длл а в основном проекте? работает нормально?

покажи реализацию TSameRecord

Автор: AlexLogos 22.9.2010, 17:28
Кода много, кое-где он однообразен, поэтому укорочу

Код

unit SameRec;

interface

uses
  ShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, ExtCtrls;

type
  TSameRecord = class(TForm)
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    PnCaption: TPanel;
    SpeedButton4: TSpeedButton;
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton4Click(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  SameRecord: TSameRecord;

implementation

uses AddressFrame, AMTFrame, DocFrame, FilesFrame, ObjektFrame,
  OsobaFrame, RichFrame, SpezpovFrame, TelFrame;
var
  OsobaFr:TFrOsoba;
  DocFr:TFrDoc;
  NoteFr:TFrSpezpov;
  AmtFr:TFrAmt;
  FileFr:TFrFile;
  RichFr:TFrRich;
  ObjFr:TFrObject;
  TelFr:TFrTel;
  AdrFr:TFrAddress;
{$R *.dfm}

procedure TSameRecord.SpeedButton1Click(Sender: TObject);
begin
//ShowMessage(Self.Owner.ClassName);
 ModalF:=TForm.Create(Self);
 with ModalF do
  begin
   Height:=Round(Screen.Height*0.85);
   Width:=Round(Screen.Width*0.85);
   Top:=Round(Screen.Height*0.04);
   Left:=Round(Screen.Width*0.08);
   Caption:=Self.Owner.ClassName;
   Position:=poDesktopCenter;
  end;
if Self.Owner.ClassName='TFrOsoba' then
 begin
  OsobaFr:=TFrOsoba.Create(ModalF);
  with OsobaFr do
   begin
    Name:='FrOsoba';
    Parent:=ModalF;
    Visible:=True;
    Connect;//(TFrOsoba(Self.Owner).OSOsoba.Username,TFrOsoba(Self.Owner).OSOsoba.Password);
    ConTable:='Osoba';
    //TFrOsoba(Self.Owner).OQResult.SQL;
    OQResult.Active:=false;
    OQResult.SQL:=TFrOsoba(Self.Owner).OQResult.SQL;
    OQResult.ExecSQL;
    TFrOsoba(Self.Owner).OQResult.Active:=False;
    OQResult.Active:=True;
    ShowMain;
//    Tyda;
    RadioGroup1.Visible:=False;
    BBClear.Enabled:=False;
    BBSearch.Visible:=False;
    //BBBack.Visible:=False;
    ConType.Visible:=False;
    AddLink.Visible:=False;
    Memo1.Lines.Add(ConTable+' '+inttostr(ConId)+' '+ConnectionString);

    DBNav.Visible:=True;
    BBAddRec.Enabled:=False;
   end;
 end;
///.................................... 
ModalF.ShowModal;
Self.Close;
end;

procedure TSameRecord.SpeedButton2Click(Sender: TObject);
begin
Self.Close;
end;

procedure TSameRecord.SpeedButton3Click(Sender: TObject);
begin
if Self.Owner.ClassName='TFrOsoba' then  TFrOsoba(Self.Owner).SaveRecord;
if Self.Owner.ClassName='TFrFile' then  TFrFile(Self.Owner).SaveRecord;
Self.Close;
end;

procedure TSameRecord.SpeedButton4Click(Sender: TObject);
begin
if Self.Owner.ClassName='TFrOsoba' then
 with TFrOsoba(Self.Owner) do
  begin
   //Tyda;
   ShowMain;
   BBAddRec.Enabled:=False;
   //BBBack.Enabled:=True;
   DBNav.Visible:=True;
   ConnectConnections;
  { TFrKrumhk1.ShowMain;
   TFrPrukm1.ShowMain; }
  end;
////.......................................
Self.Close;
end;

end.



Может дело в том что TSameRecord ссылается на другие юниты?

Автор: aleksh 22.9.2010, 18:01
странно, может форма, которая вызывает процедуру в длл перед этим уничтожается...

а почему freeandnil сразу после появления формы, может прописать его в деструкторе?

и еще - попробуй описать эту процедуру там же, откуда вызываешь и проверь как работает

Автор: AlexLogos 23.9.2010, 09:44
Процедура которая описана в ДЛЛ взята из юнита форми, там она работает нормально. Я хотел несколько уменьшить код юнита и решил перенести несколько процедур в ДЛЛ. Начал из самой простой. 
Форма которая вызывает не уничтожается.
Я будрал FreeAndNil(Same); из ДЛЛ, и изменил тип передаваемых параметров так как ДЛЛ плохо работает со String.
Код

procedure ShowSame1(RecCou:integer;Parent:TComponent); stdcall;
var Same:TSameRecord;
begin
 Same:=TSameRecord.Create(Parent);
 With Same do
  begin
   PnCaption.Caption:='Найдено '+Inttostr(RecCou)+' записи(ей)';
   ShowModal;
  end;
end;

Теперь количество "Найдено ... записей" отображается праивльно, но по надатию на кнопки формы - получаю AV, да и после закрытия всех форм и программы - процес и дальше торчит в памяти... Какие особенности работы с ДЛЛ не учел я в работе?

Автор: cat512 23.9.2010, 09:57
Если нет жёстких требований по использованию именно DLL в качестве контейнера кода, то лучше использовать BPL Об этом неоднократно писалось на этом форуме. Если же всё таки неюбходимо использование именно DLL то надо правильно (в DLL должны использоваться гл. объекты основного приложения) связывать объекты приложения с глобальными объектами VCL (Application, Session и т. д.), потому как в dll дублируется код VCL, уже существующий висполняемом модуле приложения (ехе). Ты понимаешь какой owner будет у твоего объекта при выполнении следующего кода???
Код

Same:=TSameRecord.Create(Application);

Если вызов TSameRecord  находится в dll то соответсвенно Application - ,будет тот который находится в DLL. Bpl лишены этого недостатка. Поэтому если используешь DLL то соответсвенно надо в функцию DLL передовать Application из основного приложения, либо использовать GetModuleHandle + GetProcAddress либо GetModuleHandle + FindHinstance (FindClassHinstance). Если используешь строки, дин. массивы, НЕ ЗАБУДЬ подключить SHAREMEM первым в файлы проектов основного приложения и DLL
И ещё один важный момент: операторы is, as опять же будут работать не коррекно по вышеописанной причине(дубль кода) Т.е. если передаёшь объектную ссылку из основного приложения
 а выполняешь сравнение по типу объекта в dll то оп. is вернёт ложный результат, так как сравнивает
в контексте RTTI DLL, а не основного приложения. Поэтому тут надо осторожно подходить к использованию объектов в DLL. Однако мне в одно время тоже приходилось использовать dll в качестве контейнера кода. Но у меня всё работало, потому как был вооружён. smile

Автор: AlexLogos 25.9.2010, 10:23
Да действительно, я не в курсе был что в ДЛЛ свой Application. Темой ДЛЛ занялся недавно, да и в умной книге по Делфе таких тонкостей не было. По свободе опробую все что ты сказал.

Автор: bems 26.9.2010, 08:41
Цитата(AlexLogos @  20.9.2010,  09:57 Найти цитируемый пост)
procedure ShowSame1(num:Integer); stdcall;
var Same:TSameRecord;
begin
 Same:=TSameRecord.Create(Application);
 With Same do
  begin
   PnCaption.Caption:='найдено '+IntToStr(num)+' записей';
   ShowModal;
   FreeAndNil(Same);
  end;
end;
если это и все что делается с формой, то Application вообще не нужен. Делай так
Код

with TSameRecord.Create(nil) do
  try
    PnCaption.Caption:='найдено '+IntToStr(num)+' записей';
    ShowModal;
  finally
    Free
  end;


Добавлено через 1 минуту и 18 секунд
Или еще лучше: убрать Free, и в OnClose формы делай Action := caFree

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