MDI调用了一个DLL,该DLL有一个FORM,并且窗体里定义了ADOConntion对象。
当MDI试图Call这个DLL显示窗体时就立即报错:
>>>>
Project MDI.exe raised exception class EOleSysError with message '标记没有引用存储'.Process stopped.Use Step or Run to continue.
>>>>
如果在SDI中一点问题都没有,或者换成BDE而不是ADO也是一点问题都没有。dll文件:library mdidll;uses
Windows,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
mdi_Unit in 'mdi_Unit.pas' {Form2};var
Form2: TForm2;
procedure LoadChild(ParentApplication: TApplication; ParentForm: TForm); export; stdcall;
var DllProc: Pointer;begin
Application:=ParentApplication;
Form2:=TForm2.Create(ParentForm);
Form2.MyParentForm:=ParentForm;
Form2.MyParentApplication:=ParentApplication;
Form2.Show;
end;procedure CloseChild(); export; stdcall;
begin
Form2.Free;
end;
procedure DLLUnloadProc(Reason: Integer); register;
begin
if Reason = DLL_PROCESS_DETACH then Application:=DllApplication;
end;{$R *.res}
exports
LoadChild,CloseChild;
begin
DllApplication:=Application;
DLLProc := @DLLUnloadProc;
end.
dll中的窗体unit:unit mdi_Unit;
interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids, Mask, DBCtrls, ExtCtrls,
DBTables,ActiveX;type
TForm2 = class(TForm)
Label1: TLabel;
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
DBGrid1: TDBGrid;
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
MyParentForm: TForm;
MyParentApplication: TApplication;
end;var
DllApplication: TApplication;
implementation{$R *.dfm}procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;end.在MDI主窗口调用方法(动态调用):
T_ProvaChild = procedure (ParentApplication: TApplication; ParentForm: TForm); stdcall;procedure TForm1.N1Click(Sender: TObject);
var
DllHandle: THandle;
ProcAddr: FarProc;
ProvaChild: T_ProvaChild;
begin
DllHandle := LoadLibrary('mdidll');
ProcAddr := GetProcAddress(DllHandle, 'LoadChild');
if ProcAddr <> nil then
begin
ProvaChild := ProcAddr;
ProvaChild(Application,Self);
end
else
showMessage('ProcAddr is Nil');
end;
当MDI试图Call这个DLL显示窗体时就立即报错:
>>>>
Project MDI.exe raised exception class EOleSysError with message '标记没有引用存储'.Process stopped.Use Step or Run to continue.
>>>>
如果在SDI中一点问题都没有,或者换成BDE而不是ADO也是一点问题都没有。dll文件:library mdidll;uses
Windows,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
mdi_Unit in 'mdi_Unit.pas' {Form2};var
Form2: TForm2;
procedure LoadChild(ParentApplication: TApplication; ParentForm: TForm); export; stdcall;
var DllProc: Pointer;begin
Application:=ParentApplication;
Form2:=TForm2.Create(ParentForm);
Form2.MyParentForm:=ParentForm;
Form2.MyParentApplication:=ParentApplication;
Form2.Show;
end;procedure CloseChild(); export; stdcall;
begin
Form2.Free;
end;
procedure DLLUnloadProc(Reason: Integer); register;
begin
if Reason = DLL_PROCESS_DETACH then Application:=DllApplication;
end;{$R *.res}
exports
LoadChild,CloseChild;
begin
DllApplication:=Application;
DLLProc := @DLLUnloadProc;
end.
dll中的窗体unit:unit mdi_Unit;
interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids, Mask, DBCtrls, ExtCtrls,
DBTables,ActiveX;type
TForm2 = class(TForm)
Label1: TLabel;
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
DBGrid1: TDBGrid;
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
MyParentForm: TForm;
MyParentApplication: TApplication;
end;var
DllApplication: TApplication;
implementation{$R *.dfm}procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;end.在MDI主窗口调用方法(动态调用):
T_ProvaChild = procedure (ParentApplication: TApplication; ParentForm: TForm); stdcall;procedure TForm1.N1Click(Sender: TObject);
var
DllHandle: THandle;
ProcAddr: FarProc;
ProvaChild: T_ProvaChild;
begin
DllHandle := LoadLibrary('mdidll');
ProcAddr := GetProcAddress(DllHandle, 'LoadChild');
if ProcAddr <> nil then
begin
ProvaChild := ProcAddr;
ProvaChild(Application,Self);
end
else
showMessage('ProcAddr is Nil');
end;
Unit1.PAS {主叫程序单元}
Project2.DPR {DLL}
Unit2.PAS {DLL单元}
{---------- DLL 主程序 Project2.DPR ----------}library Project2;uses
SysUtils,
Classes,
Unit2 in 'Unit2.pas' {Form1};{$R *.RES}{ 下面的语句用于向调用该 DLL的程序提供调用接口 }
exports
DoTest; { 过程来自单元Unit2 }begin
end.
{---------- DLL中的单元 Unit2.PAS ----------}unit Unit2;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, ADODB, StdCtrls, Menus;type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;{ 本地数据库连接 }
Memo1: TMemo; { 用于显示信息 }
private
public
end;{ 该过程向外提供 }
procedure DoTest(H: THandle; { 获得调用者的句柄 }
AConn: TADOConnection;{ 获得调用者的数据库连接 }
S: string; { 获得一些文本信息 }
N: Integer); { 获得一些数值信息 }
cdecl; { 指定调用协议 } implementation{$R *.DFM}procedure DoTest(H: THandle; AConn: TADOConnection; S: string; N: Integer);
begin
Application.Handle := H; { 将过程的句柄赋值为调用者的句柄 }
{ 上面语句的作用在于, DLL的句柄和调用者的句柄相同,在任务栏中就不会 }
{ 各自出现一个任务标题了。 }
with TForm1.Create(Application) do try{ 创建窗体 }
Memo1.Lines.Append('成功调用'); { 显示一行信息 }
ADOConnection1 := AConn; { 获得数据库连接的实例 }
Memo1.Lines.Append(
ADOConnection1.ConnectionString +
' - ' + S + ' - ' + IntToStr(N)); { 根据得到的参数显示另一行信息 }
ShowModal; { 模式化显示窗体 }
finally
Free; { 调用结束时销毁窗口 }
end;
end;end.
{---------- 调用者 Project1.DPR,很普通的工程文件 ----------}program Project1;uses
Forms,
Unit1 in 'Unit1.pas' {Form1};{$R *.RES}begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
{---------- 调用者单元Unit1.PAS ----------}unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Db, ADODB;type
TForm1 = class(TForm)
Button1: TButton; { 按此按钮进行调用 }
ADOConnection1: TADOConnection; { 本地数据库连接,将传递给 DLL }
procedure Button1Click(Sender: TObject);{ 调用 DLL}
private
public
end;var
Form1: TForm1;implementation{$R *.DFM}{ 外部声明必须和 DLL中的参数列表一致,否则会运行时错误 }
procedure DoTest(H: THandle; { 传递句柄 }
AConn: TADOConnection; { 传递数据库连接 }
S: string; { 传递文本信息 }
N: Integer); { 传递数值信息 }
cdecl; { 指定调用协议 }
external 'Project2.dll';{ 指定过程来源 }{ 调用过程 }
procedure TForm1.Button1Click(Sender: TObject);
begin
DoTest(Application.Handle,
ADOConnection1,
'Call OK',
256);
end;end.
[email protected]
MSN : [email protected]
如何加?我也认为是初始化问题,但不知道如何初始化。
然后在调用DLL加如下代码:
1.OnClose:
action:=caFree;
2.OnDestroy:
form1 := nil;
即可解决你的问题!
Application.MainForm.如果是Mdi程序调用时应该传送这个参数。
========================================
以前遇到一种情况,在dll中使用了db\adodb,在调用的单元也必需要有db\adodb
不然会报错!
XXSingle(三笑留情〓★▲◆) 和 nxfbccu() 说的是对的
感谢所有的参于者
给分了!