一个EXE文件中FORM太多怎么办,TDATABASE可以作为参数传递到DLL中吗?(270分)

  • 主题发起人 六窍通
  • 开始时间

六窍通

Unregistered / Unconfirmed
GUEST, unregistred user!
本人在开发一个应用系统,ORACLE + DELPHI。
应用中FORM非常多(40~50个,无法精简和分成多个EXE)。
如何处理?用DLL还是PACKAGE?
如果使用DLL,PACKAGE数据库连接如何处理,每激活一个
FORM就输入USERID/PASSWORD显然是无法接受的。
DLL,PACKAGE中的FORM如何使用DATAMODAL中的构件?
 
您的问题可以有不通种解决方案。
1。Form太多的解决办法:我编程时就不喜欢很多的forms,解决方法是建立一个
通用的form,比如在一个form中放一个(或几个)TDBGrid,然后根据不同的需要
更换TDBGrid的DataSource。这样就能用一个form现实多个数据表。
2。dll还是package:package的实质是dll格式,只不过Borland在resource记录
里面作了一些手脚,使它能够存放classes。我认为使用package比较好,最打的好
处是编程方便,不必去一个个地编译调试dll文件。对于您的问题,我看无需自定义
自己的package,只要说明使用runtime package就行了,因为你并没有自定义任何
components。
3。password问题:我没有试过ORACLE,但是在使用PARADOX表时,是可以通过程序
来给USERID/PASSWORD赋值使得PASSWORD DIALOG不再出现,具体实现可以看一看
DATABASE/TTABLE的SESSION说明。记得在此论坛中有关于PASSWORD的主题。
 
补充huizhang先生的第一点,
您可以尝试一下Form的继承。我试过,感觉不错。
 
各位好,对各位的解答,在此表示感谢。
需要补充的是:
之所以提出上述问题,主要是基于效率上的考虑。
HUIZHANG先生的方法一,本人在另一个应用中使用过,感觉在维护
时付出太多,也不利于模块划分及工作组的任务分派,如果FORM之间
相似之处很少,会有很大的困难。
就HUIZHANG先生的第二点:如果FORM在DLL或PACKAGE中,又不能使用
主FORM中的数据库连接,势必要新建连接,即便隐含使用USERID/PASSWORD
每次打开FORM时的数据库连接时间也让人无法忍受。
如果使用RUNTIME PACKAGE,DELPHI是否会替我完成这些工作?
 
动态创建Form不行吗?用的时候创建,不用时就Free掉。
 
使用runtime package并不能减少你的form数量,只能缩小你的程序的大小,加快
调入时间,编程上与不用runtime package一样,什么都不用改动。使用动态创建form也不能缩短程序装载时间,因为虽然form没有被create但是所有的代码必须都
装载到内存程序才能运行。

这里还需强调一下什么是package,package是delphi version dll,它是用来存
放所有的delphi的注册了的classes,components...如果你硬要将你的forms封装
成一个package,这样并没有多大意义。

隐藏login dialog是不难实现的,看来你面临的问题还是怎样减少forms。另外一
个办法是使用pages,或者是改变可见性。
 
问题一的方法是创建动态FORM
1。在DELPHI主菜单的OPTION选项之FORMS页中,
把要动态创建的FORM由auto-create-forms中移到Available中
2。在程序中加上
with Tform1{要创建的Form类型}.create(nil) do
try
showmodal;
finally
free;
end;
至于隐藏登录画面
1。将数据集控件都连接到数据库控件
2。将数据库控件的loginprompt设为False
3。在数据库的params中写入如下两行
user name=你的用户名
password=你的密码
4。将数据库的connected设成true即可
 
可以让从FORM中TDATABASE构件等于主FORM的。
 
我想你也不会把四五十个Form都各自编译为一个DLL(Package, 下同)吧,
只不过想把它大卸八块而已,你可以使用这种方法:
分成几个DLL,各个DLL都有一个Database元件,使用方法参照方栩的大作,
在调用DLL时把所需要的参数传下来;另外,为了避免Database的别名相同,
在把Connected设成True之前记得确保别名唯一,否则会提示出错,使用
TSession.GetAliasNames可以取得所有的别名。
 
实际上,将一个庞大的EXE划分为DLL至少有以下这些好处:
1. 降低了模块之间的相关性,对于开发维护的工作量都会
减少不少
2. Windows程序一般资源在EXE文件本身,如果应用已经在
运行当中,需要修改其中的功能模块需要所有用户全部
退出,这有时很难做到,而DLL功能模块所牵连的用户就
少的多
3. 对于软件的个性化及权限控制也有不小的好处。如果你买
我的商品化软件,你甚至可以只买那些功能模块,我不给
你DLL,你是没有办法破解的。
此外还有其它一些好处。

我目前所开发的一个系统完全采用的是主控程序+DLL的策略,
目前感觉还不错。

可惜我目前采用的还是Paradox,对于Paradox只要程序编译
成使用Runtime Package就可以在DLL中直接使用主程序中
定义的Database.

如果有兴趣,我们可以Email详谈。

delphi@263.net
 
Delphi,
请您简单介绍一下“在DLL中直接使用主程序中定义的Database”之方法,好吗?
 
在主执行文件中放一个TDatabase,
设置DatabaseName以及其他各个属性,并连接到DBMS
各个DLL中的TTable或者TQuery的DatabaseName直接为TDatabase的DatabaseName
就可以了。

如:主程序中有一个TDatabase, dbSystem
DatabaseName: System

DLL中的Table Database Name属性直接添: System
 
Delphi 的方法不行,依然出现密码录入窗。我采用的方法是:

在DLL中:

unit ...

procture CallDllFun(App: TApplication; AppSessions: TSessions);
begin
Application := App;
if Sessions <> AppSessions then
begin
Session.Free;
Sessions.Free;
Sessions := AppSessions;
Session := Sessions.FindSession('Default');
//如果使用其它的Session请修改上面一行
end;
...Do Something...
end;

initialization

finalization
Application := nil;
Sessions := nil;
end.

在调用DLL时:
Database1.Connected := True;
CallDllFun(Application, Sessions);

说明:
Session及Sessions是DBTables单元中的全局变量,该单元initialization
时创建;
方法绝对可靠,应该是我得到这200分!
 
忘记说明一句:DLL中的DataSet数据库别名应该为调用者中Database1(或其它)
指定的别名。
 
怎么会不行呢?只要在主程序的Database连接中设置TDatabase
的Params保证不出PasswordDialog就可以了,在DLL
中只是使用主程序中已经定义的Database。
前提是主程序和DLL必须全部编译成为使用Runtime Package.
我目前开发的应用就是使用这个方法,绝对没错的。 :)
 
在Oracle+Delphi时,如果以TDataBase作为Dll接口函数的参数,
不管Params怎么设,都要出现Login对话框,我也白忙过一个上午...

我用过两种方法:1.用TSessions作为参数,但是有时显得效率不高;
2.在主程序中将TTable和TQuery绑到你的Database上,然后以TTable
和TQuery作为参数传递,但是这个方法不够灵活。

 
为什么非要传递参数到DLL中?
在我的方法中,根本就不要把Database做为参数传递嘛,
在主EXE中已经定义了Database,DLL可以象使用别名
一样使用这个Database.
只需要在DLL中使用TDatabase的名字。
下面是一个使用Interbase的例子,我想Oracle也应该可以的,
该程序在Delphi 4及Interbase下完全通过调试。
Intebase数据库: c:/temp.gdb
Table: AAA

Project1.Dpr
------------------------
program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Form1.DFM
-----------
object Form1: TForm1
Left = 186
Top = 107
Width = 435
Height = 300
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object DBGrid1: TDBGrid
Left = 88
Top = 72
Width = 273
Height = 169
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
end
object Button1: TButton
Left = 200
Top = 16
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
object Database1: TDatabase
Connected = True
DatabaseName = 'TestDB'
DriverName = 'INTRBASE'
LoginPrompt = False
Params.Strings = (
'SERVER NAME=c:/temp.gdb'
'USER NAME=sysdba'
'OPEN MODE=READ/WRITE'
'SCHEMA CACHE SIZE=8'
'LANGDRIVER='
'SQLQRYMODE='
'SQLPASSTHRU MODE=SHARED AUTOCOMMIT'
'SCHEMA CACHE TIME=-1'
'MAX ROWS=-1'
'BATCH COUNT=200'
'ENABLE SCHEMA CACHE=FALSE'
'SCHEMA CACHE DIR='
'ENABLE BCD=FALSE'
'BLOBS TO CACHE=64'
'BLOB SIZE=32'
'PASSWORD=masterkey')
SessionName = 'Default'
Left = 104
Top = 24
end
object Table1: TTable
Active = True
DatabaseName = 'TestDB'
TableName = 'AAA'
Left = 24
Top = 72
end
object DataSource1: TDataSource
DataSet = Table1
Left = 56
Top = 72
end
end

Unit1.Pas
------------
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, DBGrids, Db, DBTables;

type
TForm1 = class(TForm)
Database1: TDatabase;
Table1: TTable;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
procedure Test; external 'project2';

procedure TForm1.Button1Click(Sender: TObject);
begin
Test;
end;

end.



Project2.DPR
--------------
library Project2;

uses
SysUtils,
Classes,
Unit1DLL in 'Unit1DLL.pas' {Form1};

procedure Test;
begin
form1 := tform1.create(nil);
form1.show;
end;

exports Test;
begin
end.


Unit1DLL.DFM
-------------
object Form1: TForm1
Left = 186
Top = 103
Width = 417
Height = 221
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object DBGrid1: TDBGrid
Left = 48
Top = 32
Width = 320
Height = 120
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
end
object Button1: TButton
Left = 256
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
object Table1: TTable
DatabaseName = 'TestDB'
TableName = 'AAA'
Left = 144
Top = 16
end
object DataSource1: TDataSource
DataSet = Table1
Left = 96
Top = 16
end
end

Unit1DLL.PAS
-----------
unit Unit1DLL;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Db, DBTables, Grids, DBGrids;

type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
Table1: TTable;
DataSource1: TDataSource;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
table1.open;
end;

end.
 
Hello, delphi.
“我想Oracle也应该可以的”?
No,no,no.
 
Ranolph:
delphi的方法应该可以的,我用Delphi+Sybase
也是用得这种方法.
 
先把问题抠去一半,我不讨论DataBase,因为这段时间我不写数据库,主要精力
放在VCL组件编程和系统级API编程上。
关于减少form的方法,我想是极有价值讨论的。因为写数据库常常会写成这样。

解决方案:
1. 采用动态创建组件的方法,在单一Form中动态维护具有较多相同性的Form。
总而言之,动态创建组件比动态创建一个Form要快。尤其是类似当前窗口有一个
TLabel,你又要动态创建TLabel的这种情况。如果在多个Form中,你需要维护一相同的数据表,使用动态创建组件来维护Form,不但省了Form.create的时间,
也省了DataBase的Connect时间。是极为理想的。
作为一种思路,你可以用一个数组来定义创建组件的初始数据(位置和大小),用
一个TList来动态维护这些组件。两个Form的切换就成了一个TList中组件的
Visible属性赋值的For循环了!本讨论板的已答问题区中有一个我回答过的关于
TList操作一序列动态创建组件的实例,可供参考。
2. 采用动态创建Form的方法,将不常用的Form放在程序运行中建立。
有一个奇怪现象。如果你Create了一个Form,即使你Free或Destroy了它,你再
创建都会比直接创建来得快。这是我在写一个复杂的图形界面程序中的Setup
Form时发现的。
由于Application.Initialize的实质只是初始化所有单元的初始化部分,其后是
一大堆的CreateForm(),所以,导致系统调入变慢的主要因素是Form的创建和这
些Form中的数据表的连接。如果使用动态创建Form的方法,则速度可以得以提高。
3. 使用DLL或Packer的技术并不能解决问题,它和动态创建Form的实质是一样的
。因为Form的速度主要牺牲在Create上,而不是牺牲在Load上。而DataBase Connect并不会在DLL内部完成,Connect的代码执行还是在运行期,也还是同样
牺牲速度。
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
965
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
顶部