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.
|