Delphi的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;
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Delphi是一种编程语言,而DLL(Dynamic-Link Library)是一种模块化的文件格式,用于存储代码和数据,可以被多个应用程序共享。DLL注入是一种技术,它允许将DLL文件加载到正在运行的进程中,并使得该进程能够调用DLL中的函数和使用其中的数据。 在Delphi中实现DLL注入的方法有很多种。一种常见的方法是使用Windows API函数LoadLibrary和GetProcAddress。通过调用LoadLibrary函数,将DLL文件加载到进程的虚拟地址空间中。然后使用GetProcAddress函数获取DLL中导出函数的地址,并将其传递给需要调用的函数。通过这种方式,可以在运行时将DLL注入到目标进程中,并且通过调用DLL中的函数来扩展进程的功能。 DLL注入在实际应用中有多种用途。例如,可以使用DLL注入来为某个程序添加额外的功能或修改程序的行为。DLL注入还可以用于实现一些调试和监控的功能。通过注入DLL,可以截获程序的输入和输出,或者在程序执行某些指定的操作时进行额外的处理。 在Delphi中实现DLL注入需要一定的编程知识和技巧。需要考虑目标进程的架构和权限限制,以及如何管理注入的DLL的生命周期和资源管理。同时,还需要处理一些安全性和稳定性方面的问题,以确保注入过程不会对目标进程造成损害或崩溃。 总之,Delphi可以通过调用Windows API函数来实现DLL注入,从而扩展和修改进程的功能。但在实际应用中,需要考虑各种方面的问题,并且遵守相关的法律和规定,以确保注入操作的安全性和合法性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值