当前位置:文档之家› VC与Delphi之间动态链接库互相调用

VC与Delphi之间动态链接库互相调用

VC与Delphi之间动态链接库互相调用


Delphi 调用VC的DLL


VC中DLL声名格式:

Extern “C” void __declspec(dllexport) __stdcall ShowMess(HWND hwnd, char* mess);

输出格式为:_ShowMess@8,“8”为函数参数字节数

为了避免名称分裂,可采用以下方法解决:

1.声明中不加__stdcall,采用VC默认格式__cdecl,但在Delphi中要注明调用格式为cdecl。

2.在VC工程中添加def文件,如:

LIBRARY

EXPORTS

ShowMess @1

则DLL中输出函数名称不分裂。


Delphi中调用格式:

Procedure ShowMess (h:HWND; mess:PChar); Stdcall;{Cdecl;} external LibName;

如无Stdcall或Cdecl声名,Delphi默认Register(FastCall)调用格式。


注意Delphi与VC的对齐格式不同,在VC中定义结构时要用以下格式:

#pragma pack(4)

//结构定义

#pragma pack()


常用工具:

TDump.exe-Delphi 4 和 C++ Builder 3 提供

Impdef.exe 和 Implib.exe - C++ Builder 3提供

DumpBin.exe-VC5.0提供

Lib.exe-VC5.0提供


VC调用Delphi的DLL



Delphi中的声名格式:

Function ShowDialog( hMainWnd:THandle; Msg:PChar ):integer; stdcall;

输出到Dll文件中时,名称不分裂。


VC中的调用格式:

extern "C" __declspec(dllimport) int __stdcall ShowDialog( HWND hwnd,char* Msg );

.如带有__stdcall,则要求Lib文件中对应函数名称分裂,可有以下步骤生成Lib文件:

.用Impdef.exe生成def文件,格式为:Impdef def文件名 dll文件名

.手工调制def文件参数,如ShowDialog改为ShowDialog@8

.用Lib.exe生成lib文件,格式为:Lib /def:def文件名

.如声名中无__stdcall,默认调用格式仍为stdcall,但不要求名称分裂,用以下批处理文件MkLib.bat可生成Lib文件:

@echo off

if %1.==. goto error

impdef %1.def %1.dll

lib /def:%1.def

goto end

:error

echo Usage: MkLib DllName

echo Note: Don't add extension ".dll" to parameter "DllName"

:end


delphi创建DLL动态链接库2008-03-24 16:31Windows 的执行文件可以划分为两种形式程序和动态连接库
(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);var n,m:string;
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.ScrollBar1C

hange(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;

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



相关主题
文本预览
相关文档 最新文档