Delphi的DLL技巧汇集
作者:滒娶伱 | 来源:互联网 | 2023-07-20 03:14
Delphi的DLL技巧汇集调用一个DLL比写一个DLL要容易一些。首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。同样的,我们先举一个静态调用的例子。
Delphi的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;
推荐阅读
-
本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ...
[详细]
蜡笔小新 2023-12-12 15:48:10
-
本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ...
[详细]
蜡笔小新 2023-12-13 04:59:58
-
-
本文目录一览:1、什么是Java?2、java ...
[详细]
蜡笔小新 2023-12-09 09:28:18
-
本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ...
[详细]
蜡笔小新 2023-12-14 18:18:21
-
本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ...
[详细]
蜡笔小新 2023-12-14 10:34:15
-
先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ...
[详细]
蜡笔小新 2023-12-12 13:36:56
-
本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ...
[详细]
蜡笔小新 2023-12-11 16:50:17
-
第一步:PyQt4Designer设计程序界面该部分设计类同VisvalStudio内的设计,改下各部件的objectName!设计 ...
[详细]
蜡笔小新 2023-10-17 17:26:41
-
AtonepointIhadlookedatimplementingaclasstemplateinC++thatwouldsupportanEnumthatwo ...
[详细]
蜡笔小新 2023-10-15 15:41:16
-
vb如何去掉最后的换行符?这是VB在读多行文件时出现的问题,最后行多了换行字符。可以用Left函数来取去除最后换行字符的文本。Left函数返回Variant(String),其中包 ...
[详细]
蜡笔小新 2023-10-15 06:16:00
-
本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ...
[详细]
蜡笔小新 2023-12-14 18:07:46
-
本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ...
[详细]
蜡笔小新 2023-12-14 17:46:55
-
本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ...
[详细]
蜡笔小新 2023-12-14 16:00:02
-
场景Winform中连接Mysql8并查询表中数据进行显示:https:blog.csdn.netBADAO_LIUMANG_QIZHIarticledetails12039598 ...
[详细]
蜡笔小新 2023-10-15 19:45:10
-
今天来法分析AlertDialogcancel()销毁窗口流程。前面文章说了其实activity和dialog都是通过window对象来管理视图的。所以我们可以从AlertDialog销毁过程来了 ...
[详细]
蜡笔小新 2023-10-14 17:03:40
-