답변감사합니다
bpl로 함 해봐야 겠네요...
박지훈.임프 님이 쓰신 글 :
: ODAC를 써본 적이 없어서 확실하게 답변을 드리기는 어렵지만.. 좀 의심이 가는 부분만 말씀드리지요.
: 폼들을 dll로 만들어 올렸을 경우, ODAC처럼 폼들에서 참조되는 라이브러리들은 어떻게 처리하셨나요?
: ODAC를 패키지(bpl)로 런타임 패키지로 불러들였든 혹은 정적으로 링크시켰든 문제의 소지가 있습니다.
:
: 기본적으로 dll로 만든 폼들 사이에서는 각각 VCL의 주소공간이 별도로 생성되므로, dll마다 별도의 ODAC 구현이 포함되어 있을 것입니다. 설사 ODAC bpl을 불러들이도록 했다고 해도 각 폼 dll들이 불러들인 ODAC 구현은 별도로 여러번 로딩될 것입니다.
:
: 여기까지는 ODAC 뿐만 아니라 어떤 라이브러리를 써도 마찬가지입니다. 문제는 이 다음부터입니다. 만약 ODAC라는 라이브러리가, 한 프로그램에서는 하나의 인스턴스만 실행되어야 한다는 것을 전제로 만들어졌다면 이런 상황에서는 문제가 생깁니다. 복잡한 컴포넌트 라이브러리라면 얼마든지 있을 수 있는 상황입니다.
:
: 문제가 발생한 원인이 이것 때문인지 아닌지 확실히 하실 필요가 있을테니, 문제가 생긴 폼을 dll이 아닌 별도의 exe로 만들어서 같은 방법으로 테스트해보시길 권해드립니다. 새 빈 프로젝트를 만들어서 거기에 해당 폼을 포함시키면 간단히 테스트할 수 있겠지요.
:
: 만약 문제가 이것 때문이라고 판단이 된다면, 해결책은 dll 폼을 쓰지 않는 것 뿐입니다. 그렇다고 반드시 전체를 하나의 exe로 뭉뚱그려 만들 필요는 없습니다. 더 권하고 싶은 방법은, 폼을 dll이 아닌 bpl로 나누는 것입니다. bpl로 만들어진 폼은 그 자신도 메인 exe의 VCL 주소 공간에 포함되고, 당연히 폼에서 사용한 다른 서드파티 컴포넌트도 마찬가지이므로 그런 문제는 발생하지 않습니다.
:
: 그럼...
:
:
: 도랑치기 님이 쓰신 글 :
: : 버전 : 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.
|