在Delphi中静态调用DLL 引用外部Dll External Dll 导入Dll

来源:互联网 发布:漫画版网络小胖表情包 编辑:程序博客网 时间:2024/05/17 22:22

======================================================
注:本文源代码点此下载
======================================================

在delphi中静态调用dll 引用外部dll external dll 导入dll

调用一个dll比写一个dll要容易一些。首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。同样的,我们先举一个静态调用的例子。

unit unit1;

interface

uses

windows, messages, sysutils, classes, graphics,

controls, forms, dialogs, stdctrls;

type

tform1 = class(tform)

edit1: tedit;

button1: tbutton;

procedure button1click(sender: tobject);

private

{ private declarations }

public

{ public declarations }

end;

var

form1: tform1;

implementation

{$r *.dfm}

//本行以下代码为我们真正动手写的代码

function testdll(i:integer):integer;stdcall;

external ’delphi.dll’;

procedure tform1.button1click(sender: tobject);

begin

edit1.text:=inttostr(testdll(1));

end;

end.

上面的例子中我们在窗体上放置了一个编辑框(edit)和一个按钮(button),并且书写了很少的代码来测试我们刚刚编写的delphi.dll。大家可以看到我们唯一做的工作是将testdll函数的说明部分放在了implementation中,并且用external语句指定了delphi.dll的位置。(本例中调用程序和delphi.dll在同一个目录中。)让人兴奋的是,我们自己编写的testdll函数很快被delphi认出来了。您可做这样一个实验:输入“testdll(”,很快delphi就会用fly-by提示条提示您应该输入的参数是什么,就像我们使用delphi中定义的其他函数一样简单。

注意事项有以下一些:

一、调用参数用stdcall。

和前面提到的一样,当引用dll中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。

二、用external语句指定被调用的dll文件的路径和名称。

正如大家看到的,我们在external语句中指定了所要调用的dll文件的名称。没有写路径是因为该dll文件和调用它的主程序在同一目录下。如果该dll文件在c:\,则我们可将上面的引用语句写为external ’c:\delphi.dll’。注意文件的后缀.dll必须写上。

三、不能从dll中调用全局变量。

如果我们在dll中声明了某种全局变量,如:var s:byte 。这样在dll中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。不过在调用程序中声明的变量可以作为参数传递给dll。

四、被调用的dll必须存在。

这一点很重要,使用静态调用方法时要求所调用的dll文件以及要调用的函数或过程等等必须存在。如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。

编写技巧

1 、为了保证dll的正确性,可先编写成普通的应用程序的一部分,调试无误后再从主程序中分离出来,编译成dll。

2 、为了保证dll的通用性,应该在自己编写的dll中杜绝出现可视化控件的名称,如:edit1.text中的edit1名称;或者自定义非windows定义的类型,如某种记录。

3 、为便于调试,每个函数和过程应该尽可能短小精悍,并配合具体详细的注释。

4 、应多利用try-finally来处理可能出现的错误和异常,注意这时要引用sysutils单元。

5 、尽可能少引用单元以减小dll的大小,特别是不要引用可视化单元,如dialogs单元。例如一般情况下,我们可以不引用classes单元,这样可使编译后的dll减小大约16kb。

调用技巧

1 、在用静态方法时,可以给被调用的函数或过程更名。在前面提到的c++编写的dll例子中,如果去掉extern ”c”语句,c++会编译出一些奇怪的函数名,原来的testc函数会被命名为@testc$s等等可笑的怪名字,这是由于c++采用了c++ name mangling技术。这个函数名在delphi中是非法的,我们可以这样解决这个问题:

改写引用函数为

function testc(i:integer):integer;stdcall;

external ’cpp.dll’;name ’@testc$s’;

其中name的作用就是重命名。

2 、可把我们编写的dll放到windows目录下或者windows\system目录下。这样做可以在external语句中或loadlibrary语句中不写路径而只写dll的名称。但这样做有些不妥,这两个目录下有大量重要的系统dll,如果您编的dll与它们重名的话其后果简直不堪设想,况且您的编程技术还不至于达到将自己编写的dll放到系统目录中的地步吧!

调试技巧

1 、我们知道dll在编写时是不能运行和单步调试的。有一个办法可以,那就是在run|parameters菜单中设置一个宿主程序。在local页的host application栏中添上宿主程序的名字就可进行单步调试、断点观察和运行了。

2 、添加dll的版本信息。开场白中提到了版本信息对于dll是很重要的,如果包含了版本信息,dll的大小会增加2kb。增加这么一点空间是值得的。很不幸我们如果直接使用project|options菜单中version选项是不行的,这一点delphi的帮助文件中没有提到,经笔者研究发现,只要加一行代码就可以了。如下例:

library delphi;

uses

sysutils,

classes;

{$r *.res}

//注意,上面这行代码必须加在这个位置

function testdll(i:integer):integer;stdcall;

begin

result:=i;

end;

exports

testdll;

begin

end.

3 、为了避免与别的dll重名,在给自己编写的dll起名字的时候最好采用字符数字和下划线混合的方式。如:jl_try16.dll。

4 、如果您原来在delphi 1或delphi 2中已经编译了某些dll的话,您原来编译的dll是16位的。只要将源代码在新的delphi 3或delphi 4环境下重新编译,就可以得到32位的dll了

参考文章:在delphi与c++之间实现函数与对象共享 http://www.zahui.com/html/2/4202.htm

1.c++共享delphi对象

要实现从c++调用delphi对象,首先要在delphi单元的接口部分以及c++的头文件中说明需要共享的对象的接口,在对象接口中定义该对象包含哪些属性与方法,并说明可供共享的部分。对象的共享,关键在于方法的共享。在delphi语言中,要使一个对象可以被共享,可以把它说明为两个接口部分,暂称为"共享接口"与"实现接口"。其中共享接口指明对象中哪些方法可被另一种语言所共享;实现接口则继承共享接口,并且在单元实现部分针对实现接口中的方法定义具体的实现。要定义一个可供c++共享的delphi对象,共享接口的说明应注意:

在delphi程序里,要共享的方法必须被说明为抽象(abstract),而且虚拟(virtual );

在c++程序里,必须用关键字"virtual"及"=0"后缀,把从delphi共享的方法说明成"pure virtual";

共享的对象方法必须在两种语言里都被说明成相同的调用方式,通常使用标准系统调用方式(stdcall)。

下面,举例说明这些规则,假设有这样的一个delphi对象:

ttestobject=class

procedure proc1(x:integer);

function func1(x:integer):pchar;

procedure proc2;

function func2:integer;

end;

如果c++程序需要共享其中的方法proc1、func1,可把上述说明修改成以下形式:

stestobject=class

procedure proc1(x:integer); virtual; abstract; stdcall;

function func1(x:integer); virtual; abstract; stdcall;

end;

ttestobject=class(stestobject)

procedure proc1(x:integer);

fuction func1(x:integer):pchar;

procedure proc2;

fuction func2:integer;

end;

在c++程序中做如下对象原型说明:

class stestobject {

virtual void proc1(int x)=0;

virtual char *func1(int x)=0;

};

为了能在c++中成功地访问delphi定义的类, delphi接口说明时必须包含一个可共享的"制造函数(factory function)"createtestobject,该制造函数可被定义在动态链接库或目标文件(.obj)中,例如:

library testlib;

exports createtestobject;

function createtestobject:stestobject; stdcall;

begin

result:=ttestobject.create;

end;

end.

经过这样的处理,现在可在c++程序中使用这个由delphi定义的对象,调用方式如下:

extern "c" stestobject stdcall *createtestobject();

void usetestobject(void) {

stestobject *thetestobject=createtestobject();

thetestobject->proc1(10);

char *str=thetestobject->func1(0);

}

当调用制造函数createtestobject时,实际上已经在delphi一侧占用了一个对象实例的空间,c++程序在针对该对象的所有处理完成后必须考虑释放这一空间,具体的实现可在delphi中定义一个类,如上述proc1的共享方法free,以此来完成这一任务:

stestobject=class

procedure proc1(x:integer); virtual; abstract; stdcall;

function func1(x:integer); virtual; abstract; stdcall;

procedure free; virtual; abstract; stdcall;

end;

implementation

procedure ttestobject.free;

begin

end;

end.

2.delphi共享c++对象

通常,程序员会考虑使用delphi来编制用户界面,所以delphi代码调用c++代码似乎显得更加实际些。其实,delphi共享c++对象的实现方法与上述c++共享delphi对象非常相似。用同样的共享接口与实现接口说明方法来定义c++的类:

class stestobjedt {

virtual void proc1(int x)=0;

virtual char *func1(int x)=0;

};

class ttestobjedt :public stestobject {

void proc1(int x);

char *func1(int x);

void proc2();

int func2();

void free();

};

然后实现这些方法。同样地,c++对象需要一个与之对应的制造函数,这里以dll为例

stestobject stdcall export *createtestobject() {

return (stestobject *) new ttestobject.create;

}

delphi代码可以通过调用制造函数createtestobject,很容易地在c++中创建实例,获得指向该实例的指针值,并以这个指针值来调用对象中的共享方法。当然,在进行完该对象的相关处理后,千万不要忘了调用free释放占用的空间。

张维

摘要:delphi以其独特的面向控件的开发方式、强大的数据库功能以及快速的编译技术,使得它自发布起即格外引人注意。随着delphi 5提供丰富的internet应用,delphi日益成为最重要的软件开发工具之一,它吸引了许多原visual basic、foxpro、dbase甚至c++的程序员,而这些程序员使用delphi时需要解决的一个重要问题就是怎样利用他们原有的代码。本文将介绍delphi与c++程序集成的方法,包括:

delphi与c++之间函数的共享;

代码的静态链接和动态链接;

对象的共享。

函数的共享

在delphi中调用c++函数与c++调用delphi函数相当直接,需要注意的是,delphi 1默认的函数调用方式是pascal方式,delphi 4、delphi 5的默认方式则是优化的cdecl调用方式,即register方式。要在c++与delphi程序之间实现函数共享,除非有充分的原因,否则应该使用标准系统调用方式,即stdcall方式。为了使c++编译器不将函数标记为"mang led",使delphi编译器误认为函数是采用cdecl调用方式,应该在c++代码中,以extern "c "说明被共享的函数,如下例所示:

原型说明:

在c++中:

extern "c" int _stdcall testfunc();

在delphi中:

function testfunc:integer; stdcall;

调用语法:

在c++中:

int i=testfunc();

在delphi中:

var i:integer;

begin

i:=testfunc;

end;

共享函数的参数必须是两种语言都支持的变量类

参考文章:delphi 中动态链接库的使用 http://blog.csdn.net/feifei1018/admin/editposts.aspx

在delphi中,有两种方法可用于调用一个储存在dll(动态链接库)中的过程。

一、 调用方法

1、 静态调用或显式装载使用一个外部声明子句,使dll在应用程序开始执行前即被装入。例如:

function instring (sourcestr: pchar ;

check: char): integer; far; external ‘ demostr’

这种方式要在单元的interface 部分用external 指示字列出要从dll中调用的例程。far 指令表明可以被其他段,例如其他单元调用的子例程。所有在单元接口中声明的子例程在缺省情况下都是far类型的,其相反的指令是near。

如果external 后什么也不跟,必须用 {$ l } 编译指令预先指定一个dll名字,如:

{ $ l mydlls.dll }

procedure setstring(var str: string) ;

stdcall ; external

但是使用静态调用方法时,程序无法在运行时间里决定dll的调用。在delphi中使用dll时,例程的标识符必须与dll中相应输出例程的标识符完全一致(尽管delphi本身大小写不敏感)。

2、 动态调用或隐式装入

使用windows api 函数 loadlibrary 和getprocaddress可以实现在运行时间里的动态装载dll,并调用其中的过程。

例如:

type tmyproc=procedure (param:pchar ) ;stdcall;

var myproc: tmyproc;

myhandle:thandle;

myhandle:=loadlibrary (‘mydll’) ;

if myhandle关注我收藏该文与我联系


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
原创粉丝点击