用dll封装mdi子窗体,子窗体里做数据库操作。所需要的adoconnection 从主窗体获取,主窗体调用dll以参数或者以adoconnection 指针方式传过去。子窗可以正常取得adoconnection 连接,并做相关数据库操作,但在关闭子窗体后再关主窗体(先关那个不重要,在打开子窗体的时候直接关主窗体也是一样)就会报错,Runtime error 216 at 0029336
找不到原因。分不多,全给了,下面跟出代码 ,各位帮我看看。是不是那里重复释放了资源。先来DLL的。
library Project2;{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }uses
SysUtils,
Classes,
Forms,
Windows,
Messages,
ADODB,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
type
adoPI = ^TADOConnection;{$R *.res}
var DLLApp: TApplication;
//adopi1 : adoPI;
function ShowForm(var App: TApplication;ParentForm: TForm): Boolean;export; stdcall;
begin
try
{获取调用窗体的Application,显而易见的功能是 能使你的窗体融合到调用程序中。通过它还能进行很多操作}
Application:= App;//将DLL的Application转为App
Form1:= TForm1.Create(ParentForm);//创建子窗体,子窗体随着ParentForm存在、释放。
Form1.FormStyle:= fsMDIChild;//设置窗体模式
Form1.Show;
Result:=True;
finally
//FreeMem(nil);//有问题
end;
end;function ShowForm_2(var App: TApplication; ParentForm: TForm; adopi1: adoPI): Boolean;export; stdcall;
begin
{获取调用窗体的Application,显而易见的功能是 能使你的窗体融合到调用程序中。通过它还能进行很多操作}
Application:= App;//将DLL的Application转为App
Form2:= TForm2.Create(ParentForm);//创建子窗体,子窗体随着ParentForm存在、释放。
Form2.FormStyle:= fsMDIChild;//设置窗体模式
Form2.Show;
form2.ADOTable1.Connection:=adopi1^;
end;
{重写Dll入口函数,否则程序会出错}
procedure DLLUnloadProc(Reason: Integer); register;
begin
{DLL取消调用时,发送DLL_PROCESS_DETACH消息,此时将DLL的Application返回为本身}
if Reason = DLL_PROCESS_DETACH then Application:=DLLApp;
end;exports
ShowForm,
ShowForm_2;begin
{在DLL入口预先储存DLL的Application}
DLLApp:=Application;
{DllProc:DLL入口函数指针。Delphi定义为 DllProc: TDLLProc;}
{在此指向我们自己定义的函数}
DLLProc := @DLLUnloadProc;end.下面是DLL里的封装的一个窗体,其中一个unit Unit2;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB;type
TForm2 = class(TForm)
ADOTable1: TADOTable;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form2: TForm2;
procedure SynAPP(App:THandle);stdcall;
procedure ShowForm;stdcall;
implementation{$R *.dfm}
procedure SynAPP(App:THandle );stdcall;
begin
Application.Handle := App;
end;procedure ShowForm;stdcall;
begin
try
Form2 := TForm2.Create (Application);
try
if Form2.ShowModal = idOk then
begin
try
Form2 := TForm2.Create(Application);
Form2.ShowModal;
finally
FreeAndnil(Form2);
end;
end;
finally
FreeAndNil(Form2);
end;
except
on E: Exception do
MessageDlg ('Error in DLLForm: ' +
E.Message, mtError, [mbOK], 0);
end;
end;procedure TForm2.Button1Click(Sender: TObject);
begin
ADOTable1.Open;
Label1.Caption:=ADOTable1.ConnectionString;
ShowMessage(ADOTable1.ConnectionString);
end;procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//ADOTable1.Free;
Action:=caFree;
end;end.再下面是主窗体的,
interfaceuses Windows, SysUtils, Classes, Graphics, Forms, Controls, Menus,
StdCtrls, Dialogs, Buttons, Messages, ExtCtrls, ComCtrls, StdActns,
ActnList, ToolWin, ImgList,XPMan,DataMod,ADODB;type
TMainForm = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
FileNewItem: TMenuItem;
FileOpenItem: TMenuItem;
FileCloseItem: TMenuItem;
Window1: TMenuItem;
Help1: TMenuItem;
N1: TMenuItem;
FileExitItem: TMenuItem;
WindowCascadeItem: TMenuItem;
WindowTileItem: TMenuItem;
WindowArrangeItem: TMenuItem;
HelpAboutItem: TMenuItem;
OpenDialog: TOpenDialog;
FileSaveItem: TMenuItem;
FileSaveAsItem: TMenuItem;
Edit1: TMenuItem;
CutItem: TMenuItem;
CopyItem: TMenuItem;
PasteItem: TMenuItem;
WindowMinimizeItem: TMenuItem;
StatusBar: TStatusBar;
ActionList1: TActionList;
EditCut1: TEditCut;
EditCopy1: TEditCopy;
EditPaste1: TEditPaste;
FileNew1: TAction;
FileSave1: TAction;
FileExit1: TAction;
FileOpen1: TAction;
FileSaveAs1: TAction;
WindowCascade1: TWindowCascade;
WindowTileHorizontal1: TWindowTileHorizontal;
WindowArrangeAll1: TWindowArrange;
WindowMinimizeAll1: TWindowMinimizeAll;
HelpAbout1: TAction;
FileClose1: TWindowClose;
WindowTileVertical1: TWindowTileVertical;
WindowTileItem2: TMenuItem;
ToolBar2: TToolBar;
ToolButton1: TToolButton;
ToolButton2: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
ToolButton6: TToolButton;
ToolButton9: TToolButton;
ToolButton7: TToolButton;
ToolButton8: TToolButton;
ToolButton10: TToolButton;
ToolButton11: TToolButton;
ImageList1: TImageList;
DLL1: TMenuItem;
DLL2: TMenuItem;
procedure FileNew1Execute(Sender: TObject);
procedure FileOpen1Execute(Sender: TObject);
procedure HelpAbout1Execute(Sender: TObject);
procedure FileExit1Execute(Sender: TObject);
procedure DLL1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure DLL2Click(Sender: TObject); private
{ Private declarations }
procedure CreateMDIChild(const Name: string);
public
{ Public declarations }
end; adoPI = ^TADOConnection;var
MainForm: TMainForm;
function ShowForm(var App: TApplication; ParentForm: TForm): Boolean;stdcall; external 'Project2.dll';
function ShowForm_2(var App: TApplication; ParentForm: TForm; adopi1: adoPI): Boolean; stdcall; external 'Project2.dll';implementation{$R *.dfm}uses CHILDWIN, about;procedure TMainForm.CreateMDIChild(const Name: string);
var
Child: TMDIChild;
begin
{ create a new MDI child window }
Child := TMDIChild.Create(Application);
Child.Caption := Name;
if FileExists(Name) then Child.Memo1.Lines.LoadFromFile(Name);
//ADOpI := @DataModule1.ADOConnection1
end;procedure TMainForm.FileNew1Execute(Sender: TObject);
begin
CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1));
end;procedure TMainForm.FileOpen1Execute(Sender: TObject);
begin
if OpenDialog.Execute then
CreateMDIChild(OpenDialog.FileName);
end;procedure TMainForm.HelpAbout1Execute(Sender: TObject);
begin
AboutBox.ShowModal;
end;procedure TMainForm.FileExit1Execute(Sender: TObject);
begin
Close;
end;procedure TMainForm.DLL1Click(Sender: TObject);
begin
ShowForm(Application, Self);
end;procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin //Close;
//FreeAndNil(Self);
Exit;
end;procedure TMainForm.DLL2Click(Sender: TObject);
begin ShowForm_2(Application, Self, @DataModule1.ADOConnection1);
end;end.上面就是完整的代码。只要主窗体不调用DLL。关闭主窗体时就不会出错,只要一调DLL。就会出错,还有两个情况,一个是这个程序我拿在win2k AND win7 关闭主窗体后就不会报错,只有在XP上会,还有一个情况是,只要我DLL里不装ADO控件,只是一个窗体上面放点基本控件,也就不会报错,网上找了些资料,说是可能有资源也经释放了,后面又释放,就会这样,不过我也找不到那里有问题,
找不到原因。分不多,全给了,下面跟出代码 ,各位帮我看看。是不是那里重复释放了资源。先来DLL的。
library Project2;{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }uses
SysUtils,
Classes,
Forms,
Windows,
Messages,
ADODB,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
type
adoPI = ^TADOConnection;{$R *.res}
var DLLApp: TApplication;
//adopi1 : adoPI;
function ShowForm(var App: TApplication;ParentForm: TForm): Boolean;export; stdcall;
begin
try
{获取调用窗体的Application,显而易见的功能是 能使你的窗体融合到调用程序中。通过它还能进行很多操作}
Application:= App;//将DLL的Application转为App
Form1:= TForm1.Create(ParentForm);//创建子窗体,子窗体随着ParentForm存在、释放。
Form1.FormStyle:= fsMDIChild;//设置窗体模式
Form1.Show;
Result:=True;
finally
//FreeMem(nil);//有问题
end;
end;function ShowForm_2(var App: TApplication; ParentForm: TForm; adopi1: adoPI): Boolean;export; stdcall;
begin
{获取调用窗体的Application,显而易见的功能是 能使你的窗体融合到调用程序中。通过它还能进行很多操作}
Application:= App;//将DLL的Application转为App
Form2:= TForm2.Create(ParentForm);//创建子窗体,子窗体随着ParentForm存在、释放。
Form2.FormStyle:= fsMDIChild;//设置窗体模式
Form2.Show;
form2.ADOTable1.Connection:=adopi1^;
end;
{重写Dll入口函数,否则程序会出错}
procedure DLLUnloadProc(Reason: Integer); register;
begin
{DLL取消调用时,发送DLL_PROCESS_DETACH消息,此时将DLL的Application返回为本身}
if Reason = DLL_PROCESS_DETACH then Application:=DLLApp;
end;exports
ShowForm,
ShowForm_2;begin
{在DLL入口预先储存DLL的Application}
DLLApp:=Application;
{DllProc:DLL入口函数指针。Delphi定义为 DllProc: TDLLProc;}
{在此指向我们自己定义的函数}
DLLProc := @DLLUnloadProc;end.下面是DLL里的封装的一个窗体,其中一个unit Unit2;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB;type
TForm2 = class(TForm)
ADOTable1: TADOTable;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form2: TForm2;
procedure SynAPP(App:THandle);stdcall;
procedure ShowForm;stdcall;
implementation{$R *.dfm}
procedure SynAPP(App:THandle );stdcall;
begin
Application.Handle := App;
end;procedure ShowForm;stdcall;
begin
try
Form2 := TForm2.Create (Application);
try
if Form2.ShowModal = idOk then
begin
try
Form2 := TForm2.Create(Application);
Form2.ShowModal;
finally
FreeAndnil(Form2);
end;
end;
finally
FreeAndNil(Form2);
end;
except
on E: Exception do
MessageDlg ('Error in DLLForm: ' +
E.Message, mtError, [mbOK], 0);
end;
end;procedure TForm2.Button1Click(Sender: TObject);
begin
ADOTable1.Open;
Label1.Caption:=ADOTable1.ConnectionString;
ShowMessage(ADOTable1.ConnectionString);
end;procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//ADOTable1.Free;
Action:=caFree;
end;end.再下面是主窗体的,
interfaceuses Windows, SysUtils, Classes, Graphics, Forms, Controls, Menus,
StdCtrls, Dialogs, Buttons, Messages, ExtCtrls, ComCtrls, StdActns,
ActnList, ToolWin, ImgList,XPMan,DataMod,ADODB;type
TMainForm = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
FileNewItem: TMenuItem;
FileOpenItem: TMenuItem;
FileCloseItem: TMenuItem;
Window1: TMenuItem;
Help1: TMenuItem;
N1: TMenuItem;
FileExitItem: TMenuItem;
WindowCascadeItem: TMenuItem;
WindowTileItem: TMenuItem;
WindowArrangeItem: TMenuItem;
HelpAboutItem: TMenuItem;
OpenDialog: TOpenDialog;
FileSaveItem: TMenuItem;
FileSaveAsItem: TMenuItem;
Edit1: TMenuItem;
CutItem: TMenuItem;
CopyItem: TMenuItem;
PasteItem: TMenuItem;
WindowMinimizeItem: TMenuItem;
StatusBar: TStatusBar;
ActionList1: TActionList;
EditCut1: TEditCut;
EditCopy1: TEditCopy;
EditPaste1: TEditPaste;
FileNew1: TAction;
FileSave1: TAction;
FileExit1: TAction;
FileOpen1: TAction;
FileSaveAs1: TAction;
WindowCascade1: TWindowCascade;
WindowTileHorizontal1: TWindowTileHorizontal;
WindowArrangeAll1: TWindowArrange;
WindowMinimizeAll1: TWindowMinimizeAll;
HelpAbout1: TAction;
FileClose1: TWindowClose;
WindowTileVertical1: TWindowTileVertical;
WindowTileItem2: TMenuItem;
ToolBar2: TToolBar;
ToolButton1: TToolButton;
ToolButton2: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
ToolButton6: TToolButton;
ToolButton9: TToolButton;
ToolButton7: TToolButton;
ToolButton8: TToolButton;
ToolButton10: TToolButton;
ToolButton11: TToolButton;
ImageList1: TImageList;
DLL1: TMenuItem;
DLL2: TMenuItem;
procedure FileNew1Execute(Sender: TObject);
procedure FileOpen1Execute(Sender: TObject);
procedure HelpAbout1Execute(Sender: TObject);
procedure FileExit1Execute(Sender: TObject);
procedure DLL1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure DLL2Click(Sender: TObject); private
{ Private declarations }
procedure CreateMDIChild(const Name: string);
public
{ Public declarations }
end; adoPI = ^TADOConnection;var
MainForm: TMainForm;
function ShowForm(var App: TApplication; ParentForm: TForm): Boolean;stdcall; external 'Project2.dll';
function ShowForm_2(var App: TApplication; ParentForm: TForm; adopi1: adoPI): Boolean; stdcall; external 'Project2.dll';implementation{$R *.dfm}uses CHILDWIN, about;procedure TMainForm.CreateMDIChild(const Name: string);
var
Child: TMDIChild;
begin
{ create a new MDI child window }
Child := TMDIChild.Create(Application);
Child.Caption := Name;
if FileExists(Name) then Child.Memo1.Lines.LoadFromFile(Name);
//ADOpI := @DataModule1.ADOConnection1
end;procedure TMainForm.FileNew1Execute(Sender: TObject);
begin
CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1));
end;procedure TMainForm.FileOpen1Execute(Sender: TObject);
begin
if OpenDialog.Execute then
CreateMDIChild(OpenDialog.FileName);
end;procedure TMainForm.HelpAbout1Execute(Sender: TObject);
begin
AboutBox.ShowModal;
end;procedure TMainForm.FileExit1Execute(Sender: TObject);
begin
Close;
end;procedure TMainForm.DLL1Click(Sender: TObject);
begin
ShowForm(Application, Self);
end;procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin //Close;
//FreeAndNil(Self);
Exit;
end;procedure TMainForm.DLL2Click(Sender: TObject);
begin ShowForm_2(Application, Self, @DataModule1.ADOConnection1);
end;end.上面就是完整的代码。只要主窗体不调用DLL。关闭主窗体时就不会出错,只要一调DLL。就会出错,还有两个情况,一个是这个程序我拿在win2k AND win7 关闭主窗体后就不会报错,只有在XP上会,还有一个情况是,只要我DLL里不装ADO控件,只是一个窗体上面放点基本控件,也就不会报错,网上找了些资料,说是可能有资源也经释放了,后面又释放,就会这样,不过我也找不到那里有问题,
CoInitialize(nil);
finalization
CoUninitialize;试试!
对了,其中还必须uses ActiveX
CoInitialize(nil);
finalization
CoUninitialize;
begin
Application.Handle := App;
end;procedure ShowForm;stdcall;
begin
try
Form2 := TForm2.Create (Application);
try
if Form2.ShowModal = idOk then
begin
try
Form2 := TForm2.Create(Application);
Form2.ShowModal;
finally
FreeAndnil(Form2);
end;
end;
finally
FreeAndNil(Form2);
end;
except
on E: Exception do
MessageDlg ('Error in DLLForm: ' +
E.Message, mtError, [mbOK], 0);
end;
end;
你是怎么解决的呀,不要上面的一部分是不要哪部分?