DLL问题 ( 积分: 100 )

  • 主题发起人 主题发起人 gmsft
  • 开始时间 开始时间
G

gmsft

Unregistered / Unconfirmed
GUEST, unregistred user!
下面的程序执行正常:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ADODB, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
function UserLogin(UserName, UserPSWD: string): boolean;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}


function TForm1.UserLogin(UserName, UserPSWD: string): boolean;
var
DBQry: TADOQuery;
begin
DBQry := TADOQuery.Create(nil);
DBQry.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;'+
'Data Source=D:/Projects/IDEMO/Database.mdb;'+
'Persist Security Info=False';
DBQry.Close;
DBQry.SQL.Clear;
DBQry.SQL.Add('SELECT Name FROM employees');
DBQry.SQL.Add(' WHERE ID = :ID and PSWD = :PSWD');
DBQry.Parameters.ParamByName('ID').Value := UserName;
DBQry.Parameters.ParamByName('PSWD').Value := UserPSWD;
DBQry.Open;
result := not (DBQry.RecordCount = 0);
DBQry.Close;
DBQry.Free;
DBQry := nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if UserLogin(Edit1.Text, Edit2.Text) then
ShowMessage('登录成功!')
else
ShowMessage('登录失败!');
end;


end.

写进 DLL 后,不能执行, 提示:
"exception EOleSySError in module Project1.dll at 00026FE9."


library Project1;

{ 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
ShareMem,
SysUtils,
ADODB,
Classes;

{$R *.res}

function UserLogin(UserName, UserPSWD: string): boolean;
var
DBQry: TADOQuery;
begin
DBQry := TADOQuery.Create(nil);
DBQry.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;'+
'Data Source=D:/Projects/IDEMO/Database.mdb;'+
'Persist Security Info=False';
DBQry.Close;
DBQry.SQL.Clear;
DBQry.SQL.Add('SELECT Name FROM employees');
DBQry.SQL.Add(' WHERE ID = :ID and PSWD = :PSWD');
DBQry.Parameters.ParamByName('ID').Value := UserName;
DBQry.Parameters.ParamByName('PSWD').Value := UserPSWD;
DBQry.Open;
result := not (DBQry.RecordCount = 0);
DBQry.Close;
DBQry.Free;
DBQry := nil;
end;

exports
UserLogin;

begin
end.
 
下面的程序执行正常:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ADODB, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
function UserLogin(UserName, UserPSWD: string): boolean;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}


function TForm1.UserLogin(UserName, UserPSWD: string): boolean;
var
DBQry: TADOQuery;
begin
DBQry := TADOQuery.Create(nil);
DBQry.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;'+
'Data Source=D:/Projects/IDEMO/Database.mdb;'+
'Persist Security Info=False';
DBQry.Close;
DBQry.SQL.Clear;
DBQry.SQL.Add('SELECT Name FROM employees');
DBQry.SQL.Add(' WHERE ID = :ID and PSWD = :PSWD');
DBQry.Parameters.ParamByName('ID').Value := UserName;
DBQry.Parameters.ParamByName('PSWD').Value := UserPSWD;
DBQry.Open;
result := not (DBQry.RecordCount = 0);
DBQry.Close;
DBQry.Free;
DBQry := nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if UserLogin(Edit1.Text, Edit2.Text) then
ShowMessage('登录成功!')
else
ShowMessage('登录失败!');
end;


end.

写进 DLL 后,不能执行, 提示:
"exception EOleSySError in module Project1.dll at 00026FE9."


library Project1;

{ 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
ShareMem,
SysUtils,
ADODB,
Classes;

{$R *.res}

function UserLogin(UserName, UserPSWD: string): boolean;
var
DBQry: TADOQuery;
begin
DBQry := TADOQuery.Create(nil);
DBQry.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;'+
'Data Source=D:/Projects/IDEMO/Database.mdb;'+
'Persist Security Info=False';
DBQry.Close;
DBQry.SQL.Clear;
DBQry.SQL.Add('SELECT Name FROM employees');
DBQry.SQL.Add(' WHERE ID = :ID and PSWD = :PSWD');
DBQry.Parameters.ParamByName('ID').Value := UserName;
DBQry.Parameters.ParamByName('PSWD').Value := UserPSWD;
DBQry.Open;
result := not (DBQry.RecordCount = 0);
DBQry.Close;
DBQry.Free;
DBQry := nil;
end;

exports
UserLogin;

begin
end.
 
uses
ActiveX;

initialization
CoInitialize(Nil);

finalization
CoUnInitialize;
 
http://www.cnblogs.com/dksoft/articles/109862.html
 
创建DLL动态连接库
Windows 的执行文件可以划分为两种形式程序和动态连接库(DLLs)。一般程序运行是用.EXE文件,但应用程序有时也可以调用存储在DLL 中的函数。
当我们调用Windows 中的API 函数的时候,实际上就是调用存储在DLL 中的函数。
在如下几种情况下,调用DLL 是合理的:
1) 不同的程序使用相同的DLL ,这样只需要将DLL 在内存中装载一次,节省了内存的开销。
2) 当某些内容需要升级的时候,如果使用DLL 只需要改变DLL 就可以了,而不需要把整个程序都进行变动。
3) 由于DLL 是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的时候,使用DLL 便于程序系统的交流,当然,Delphi开发的DLL 也可以在诸如Visual BASIC,C++ 等系
统中使用。
下面通过几个例子,说明Delphi开发动态连接库的方法和规范。

第一节 动态连接库的构建和调用方法
一、动态连接库构建

File---New---Other---DLL Wizard

这就创建了一个动态连接库的基本模块

library Project2;

uses
SysUtils,
Classes;

{$R *.res}

begin

end.

把工程名改为Mydll,并写入必要的函数

library mydll;

uses
SysUtils,Classes,Dialogs,windows;

function Triple(N:Integer):integer;stdcall;
begin
result:=N+3;
end;

function Double(N:Integer):integer;stdcall;
begin
result:=N+2;
end;

function Triple1(N:Integer):integer;stdcall;
begin
showmessage('计算N+3');
result:=N+3;
end;

function Double1(N:Integer):integer;stdcall;
begin
messagebox(0,'计算N+2','计算N+2',mb_ok);
result:=N+2;
end;

exports
Triple name 'Tr',
Double name 'Do',
Triple1 name 'TrM',
Double1 name 'DoM';

Triple,Double,Triple1,Double1;

{$R *.RES}

begin

end.

其中函数:Triple:把传入值加三
Double:把传入值加二
Triple1:把传入值加三并显示提示
Double1:把传入值加二并显示提示

从这个例子中可以看出DLL 程序的几个规则:

1) 在DLL 程序中,输出函数必须被声明为stdcall,以使用标准的Win32 参数传递技术来代替优化的Register。

(说明:在Delphi中Register方式是缺省的调用约定,这个约定尽量采用寄存器来传递参数,传递次序从左到右,最多可用到3个CPU 的寄存器,如果参数多于3 个,剩下的就通过栈来传送,使用寄存器传送可保证参数传递的速度最快。
而stdcall 方式是通过Windows 的标准调用来传递参数,传递秩序从左到右,这种方式适合调用Windows 的API ,在DLL 中,当然要使用这种方式)。

2)所有的输出函数都必须列在exports子句下面,这使的子例程在DLL外部就可以看到。

exports

Triple name 'Tr',
Double name 'Do',
Triple1 name 'TrM',
Double1 name 'DoM';

列出了用户使用这个函数的接口名字。虽然别名不是必须的,但最好给个别名,以便用户程序更容易找到这个函数,同时还要指出,Delphi 6.0取消了Delphi 5.0中允许使用的index ,如果还用Index来指明接口名字,Delphi 6.0中将提示错误。
实例中给出了两种提示方法,主要想说明一个问题:
showmessage(''),是VCL 提供的函数,由于多次编译VCL,做出的程序会比较大。
而messagebox(0,'','',mb_ok) 是Windows提供的API 函数,做出的程序会比较小。
这就是说,编写DLL 程序的时候,要尽量避免多次编译VCL 。作为一个实例,这里把两种方法都列出来了。

保存

编译:Projrct---Build Mydll

这就完成了一个简单的动态连接库的编写。

二、动态连接库的调用
首先在implementation下做调用声明

const
gdi32='mydll.dll';

function triple(n:integer):integer;stdcall;external gdi32 name 'Tr';
function Double(N:Integer):integer;stdcall;external gdi32 name 'Do';
function triple1(n:integer):integer;stdcall;external gdi32 name 'TrM';
function Double1(N:Integer):integer;stdcall;external gdi32 name 'DoM';

以后程序中就可以作为普通的函数使用了,例如:

procedure TForm1.Button1Click(Sender: TObject);
var N:integer;
begin
N:=updown1.position;
edit1.text:=inttostr(triple(N));
end;

第二节 DLL 中的Delphi窗体
一、在DLL 中放置窗的的方法
在DLL 中,除了放置标准的函数和过程以外,也可以放置已经做好的的delphi窗体,也可以把做好的窗体供其它程序使用,方法是:

1)首先按普通方法制作窗体,不过在interface区域,对接口函数做如下声明

function Createform(capt:string):string;stdcall;

2)在implementation下加入接口函数

function Createform(capt:string):string;stdcall;
var Form1: TForm1;
begin
form1:=Tform1.Create(application);
form1.show;
form1.caption:=capt;
end;


3)制作DLL 动态连接库,但要声明:

uses
unit1 in 'unit1.pas';

exports

{写入接口标示符}
Createform name 'Myform';

4)调用窗体的程序按普通方法制作,但是 在implementation下首先声明要调用的DLL函数

const
gdi32='myFormdll.dll';
function Createform(capt:string):string;stdcall;external gdi32 name 'Myform';


procedure TForm3.Button1Click(Sender: TObject);
var n,m:string;
begin
m:='我的窗体';
Createform(m);
end;

二、DLL 中的调用窗体时的数据传递
在窗体调用时,可以用普通的函数方法传递数据,下面举个例子。

1)建立窗体
做一个改变颜色窗体,放在DLL 中,可以用普通的方法来做,但要作如下声明:

function mycolor(col:longint):longint;stdcall;
function Getcolor:longint;stdcall;

其中,mycolor为构造窗体;Getcolor为传递颜色数据。
在implementation区声明一个窗体内全局的变量

var color1:longint;

下面写出相应的程序

function mycolor(col:longint):longint;stdcall;
var Form1: TForm1;
begin
form1:=Tform1.Create(application);
form1.show;
form1.panel1.Color:=col;
form1.edit1.Text:=inttostr(form1.panel1.Color);
result:=color1;
end;


function Getcolor:longint;stdcall;
begin
result:=color1;
end;


procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
panel2.Color:=RGB(ScrollBar1.Position,ScrollBar2.Position,ScrollBar3.Position);
edit2.Text:=inttostr(panel2.Color);
color1:=panel2.Color;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Free
//析构Form1
end;

2)建立动态连接库
运行成功后,再建立动态连接库:

library FormDLL;

{从文件调入}
uses
unit1 in 'unit1.pas';

exports

{写入接口标示符}
Mycolor name 'My',
Getcolor name 'Get';

begin
end.

3)建立调用的程序
首先声明要调用的DLL函数

const
gdi32='formDll.dll';
function Mycolor(col:longint):longint;stdcall;external gdi32 name 'My';
function Getcolor:longint;stdcall;external gdi32 name 'Get';

然后写出相应的程序

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

procedure TForm1.Button2Click(Sender: TObject);
begin
color:=getcolor;
end;

我们可以看到,在改变颜色的窗体中做了颜色变化后,当前窗体的颜色将发生变化。

三、在Visual Basic应用程序中调用Delphi DLL(略。以后补全)

转篇!
 

xianguo 的方案,能解决问题,请解释一下好吗?

 
http://www.ccw.com.cn/htm/app/aprog/01_4_25_4.asp
(ADO本身就是COM对象)
 
感谢 xianguo !

请看:http://www.delphibbs.com/delphibbs/dispq.asp?lid=2711772
 
接受答案了。
 
后退
顶部