Q&A

  • MDIchild를 DLL로 구성하고 ODAC 이용하는데 문제발생
버전     : Delphi6
DBMS     : Oracle
컴포넌트 : ODAC

MDIChild방식으로 데이타모듈을 이용하여 ODAC 컴포넌트의 OraSession컴포넌트를 올려놓고 사용했습니다. 실행파일의 메인메뉴에서 메뉴를 클릭하여 Child폼(폼속성은 MDIChild로 지정)을 호출하는데 호출은 정상적으로 됩니다 그런데 자료를 조회하는 버튼을 여속적으로 10번을 클릭을 하면
Access Violation 에러가 발생합니다. 소스를 보시고 문제가 되는부분을 해결 부탁합니다.

- 메인소스 -
unit Nis_Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ExtCtrls, DB, DBAccess, Ora, StdCtrls, psapi;

type
  TNis_MainW = class(TForm)
    MainMenu1: TMainMenu;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure N2Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TCreateChildForm = procedure (MainApp : TApplication; exe_scr : Tscreen; GP_OraSession: TComponent; GPs_Dat : Array of PChar); stdcall;

var
  Nis_MainW: TNis_MainW;

implementation

Uses
  Nis_Dm;

{$R *.dfm}

procedure TNis_MainW.FormClose(Sender: TObject; var Action: TCloseAction);
var
  i : integer ;
begin
  for i:=0 to Screen.FormCount - 1 do
  begin
    if Screen.Forms[i].Name <> 'Nis_MainW' then
      Screen.Forms[i].close ;
  end;

  Nis_DmW.OraSession1.Disconnect;
  Action := caFree;
end;

procedure TNis_MainW.N2Click(Sender: TObject);
var
  DllHandle        : THandle;
  ProcAddr         : Pointer;
  CreateChildForm : TCreateChildForm;
  i : Integer;
  Form: TForm;
  AControl: TControl;
begin
  for i:=0 to Screen.FormCount - 1 do
  begin
    if Screen.Forms[i].Name = 'wf_Lv1w' then
    begin
      Screen.Forms[i].BringToFront;
      exit;
    end;
  end;

  DllHandle := LoadLibrary(PChar('Lv1.dll'));
  if DllHandle > 32 then
  begin
    ProcAddr := GetProcAddress(DllHandle, 'CreateMDIChildForm');

    if ProcAddr <> nil then
    begin
      CreateChildForm := ProcAddr;
      CreateChildForm(Application, Screen, Nis_DmW.OraSession1, ['11','12']);
    end;
  end;
end;

procedure TNis_MainW.FormShow(Sender: TObject);
begin
  Nis_DmW.OraSession1.Connect;
end;

end.

- DLL 소스 -
library Lv1;

uses
  SysUtils,
  Classes,
  Forms,
  Ora,
  wf_Lv1 in 'wf_Lv1.pas' {wf_Lv1w},
  Init in 'Init.pas';

procedure CreateMDIChildForm(MainApp : TApplication; exe_scr : Tscreen; GP_OraSession: TComponent; GPs_Dat : Array of PChar); stdcall;
begin
  Application    := MainApp;
  Screen         := Exe_scr;
  
  if wf_Lv1w = nil then
  begin
    wf_Lv1w := Twf_Lv1w.Create(nil);
    wf_Lv1w.Edit1.Text := GPs_Dat[0];
    wf_Lv1w.Edit2.Text := GPs_Dat[1];
    wf_Lv1w.OraQuery1.Session := TOraSession(GP_OraSession);
    wf_Lv1w.Show;
  end;
end;

exports
  CreateMDIChildForm;

begin

end.

- DLL에 포함된 폼(wf_Lv1.pas) 소스 -
unit wf_Lv1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, dxCntner, dxTL, dxDBCtrl, dxDBGrid, DB, MemDS, DBAccess, Ora,
  StdCtrls, dxDBTLCl, dxGrClms;
  
type
  Twf_Lv1w = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Button2: TButton;
    Edit3: TEdit;
    Label1: TLabel;
    OraDataSource1: TOraDataSource;
    OraQuery1: TOraQuery;
    dxDBGrid1: TdxDBGrid;
    dxDBGrid1Column1: TdxDBGridColumn;
    OraQuery1LVY_KEY: TStringField;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure dxDBGrid1DblClick(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  wf_Lv1w: Twf_Lv1w;

implementation

procedure ShowChildForm_Lv2(MainApp : TApplication; exe_scr : Tscreen; GP_OraSession: TComponent; GPs_Dat : Array of PChar); stdcall; external 'Lv2.dll'


{$R *.dfm}

procedure Twf_Lv1w.Button1Click(Sender: TObject);
begin
  Label1.Caption := '';
  Label1.Refresh;

  with OraQuery1 do
  try
    Close;
    Sql.Clear;
    Sql.Text := 'SELECT LVY_KEY FROM RISTNLVBOOK';

    Label1.Caption := OraQuery1.Session.Username+','+OraQuery1.Session.Password+','+OraQuery1.Session.Server;

    Open;

    Edit3.Text := IntToStr(OraQuery1.RecordCount);
  except
    on E : Exception do
    begin
      Edit3.Text := '0';
      Application.MessageBox(Pchar(E.Message+#13#10+OraQuery1.Session.Username+','+OraQuery1.Session.Password+','+OraQuery1.Session.Server),
                             '확인',MB_OK);
    end;
  end;
end;

procedure Twf_Lv1w.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure Twf_Lv1w.FormShow(Sender: TObject);
begin
  Left := 0;
  Top  := 0;
end;

procedure Twf_Lv1w.dxDBGrid1DblClick(Sender: TObject);
begin
  ShowChildForm_Lv2(Application, Screen, OraQuery1, [PChar(OraQuery1.FieldByName('LVY_KEY').AsString)]);
end;

procedure Twf_Lv1w.Button2Click(Sender: TObject);
begin
  if OraQuery1.Session.Connected then
    ShowMessage(OraQuery1.Session.Username+','+OraQuery1.Session.Password+','+OraQuery1.Session.Server)
  else
    ShowMessage('해제');
end;

procedure Twf_Lv1w.FormDestroy(Sender: TObject);
begin
  wf_Lv1w := nil;
end;

end.

- DLL에 포함된 Init.pas 소스-
unit Init;

interface

Uses
  Forms;

var
  DllApplication : TApplication;
  DllScreen      : TScreen;

implementation

initialization
  DllApplication := Application;
  DllScreen      := Screen;

finalization
  Application := DllApplication;
  Screen      := DllScreen;
end.
1  COMMENTS
  • Profile
    채팅 2006.10.01 05:11
    exe와 dll간에는 객체를 공유할 수 없습니다.

    exe와 dll프로젝트를 모두 bpl를 사용하는 방식으로 컴파일을 해야 가능합니다.

    물론 배포상의 불편은 감수해야 합니다.