delphi来写你的第一个dll文件,非常简单!

Delphi7 开发 DLL 及调用 按里说函数的实现部分应该放在单元里。这果偷懒就没建单元了。打开新建对话框,新建一个 DLL 项目。新建一个窗体项目,拖两个按钮出来。 阅读详情

一、开使你的第一个DLL专案
1.File->Close all->File->New﹝DLL﹞

代码:

//自动产生Code如下
library Project2;

//
这有段废话。
uses
  SysUtils,
  Classes;

{$R *.RES}

begin
end.



2.加个Func进来:

代码:

library Project2;
uses
  SysUtils,
  Classes; 

    
    Function MyMax ( X , Y : integer ) : integer ; stdcall ;
        begin
        if X > Y then
            Result := X
        else
            Result := Y ;
        end ;
    //
切记:Library 的名字大小写没关系,可是DLL-Func的大小写就有关系了。
    //   
在 DLL-Func-Name写成MyMax与myMAX是不同的。如果写错了,立即
    //   
的结果是你叫用到此DLL的AP根本开不起来。
    //
参数的大小写就没关系了。甚至不必同名。如原型中是 (X,Y:integer)但引
    //    用时写成(A,B:integer),那是没关系的。
    //切记:要再加个stdcall。书上讲,如果你是用Delphi写DLL,且希望不仅给
    //     Delphi-AP也希望BCB/VC-AP等使用的话,那你最好加个Stdcall ; 的指示
    //参数型态:Delphi有很多种它自己的变量型态,这些当然不是DLL所喜欢的
    //    ,Windows/DLL的母语应该是C。所以如果要传进传出DLL的参数,我们
    //   
尽可能照规矩来用。这两者写起来,后者会麻烦不少。如果你对C不熟
    //   
的话,那也没关系。我们以后再讲。
{$R *.RES}

begin
end.



3.将这些可共享的Func送出DLL,让外界﹝就是你的Delphi-AP啦﹞使用:光如
此,你的AP还不能用到这些,你还要加个Exports才行。

代码:

{$R *.RES}
exports
    MyMax ;
begin
end.



4.好了,可以按 Ctrl-F9编译了。此时可不要按F9。DLL不是EXE┌不可单独执行的,如果你按F9,会有ErrorMsg的。这时如果DLL有Error,请修正之。再按Ctrl-F9。此时可能有Warning,不要紧,研究一下,看看就好。再按Ctrl-F9,此时就『Done , Compiled 』。同目录就会有个 *.dll 。恭喜,大功告成了。

二、进行测试:开个新application:
1.加个TButton

代码:

ShowMessage ( IntToStr(MyMax(30,50)) ) ;


2.告知Exe到那里抓个Func

代码:

//在Form,interface,var后加
Function MyMax ( X , Y : integer ) : integer ; stdcall ; external 'MyTestDLL.dll' ;
// MyTestDLL.dll
为你前时写的DLL项目名字
// DLL
名字大小写没关系。不过记得要加 extension的 .DLL。在Win95或NT,
//     
是不必加 extension,但这两种OS,可能越来越少了吧。要加extension欧。



可以了,简单吧。


上面的例子是不是很简单?熟悉Delphi的朋友可以看出以上代码和一般的Delphi程序的编写基本是相同的,只是在TestDll函数后多了一个stdcall参数并且用exports语句声明了TestDll函数。只要编译上面的代码,就可以得到一个名为Delphi.dll的动态链接库。现在,让我们来看看有哪些需要注意的地方。 一、在DLL中编写的函数或过程都必须加上stdcall调用参数。在Delphi 1或Delphi 2环境下该调用参数是far。从Delphi 3以后将这个参数变为了stdcall,目的是为了使用标准的Win32参数传递技术来代替优化的register参数。忘记使用stdcall参数是常见的错误,这个错误不会影响DLL的编译和生成,但当调用这个DLL时会发生很严重的错误,导致操作系统的死锁。原因是register参数是Delphi的默认参数。

 

二、所写的函数和过程应该用exports语句声明为外部函数。
  正如大家看到的,TestDll函数被声明为一个外部函数。这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(Quick View)”功能查看该DLL文件。(如果没有“快速查看”选项可以从Windows CD上安装。)TestDll函数会出现在Export Table栏中。另一个很充分的理由是,如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。

三、当使用了长字符串类型的参数、变量时要引用ShareMem。
  Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但Delphi中string类型在默认情况下长度可以达到2G。(对,您没有看错,确实是两兆。)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用ShareMem单元,而且必须是第一个引用的。既在uses语句后是第一个引用的单元。如下例:
uses
ShareMem,
SysUtils,
Classes;
  还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。不这样做的话,您很有可能付出死机的代价。避免使用string类型的方法是将string类型的参数、变量等声明为Pchar或ShortString(如:s:string[10])类型。同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。

第三章 在Delphi中静态调用DLL top

  调用一个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文件”等运行错误。

                  第四章 在Delphi中动态调用DLL top

  动态调用DLL相对复杂很多,但非常灵活。为了全面的说明该问题,这次我们举一个调用由C++编写的DLL的例子。首先在C++中编译下面的DLL源程序。

#include

extern ”C” _declspec(dllexport)
int WINAPI TestC(int i)
{
return i;
}

  编译后生成一个DLL文件,在这里我们称该文件为Cpp.dll,该DLL中只有一个返回整数类型的函数TestC。为了方便说明,我们仍然引用上面的调用程序,只是将原来的Button1Click过程中的语句用下面的代码替换掉了。

procedure TForm1.Button1Click(Sender: TObject);
type
TIntFunc=function(i:integer):integer;stdcall;
var
Th:Thandle;
Tf:TIntFunc;
Tp:TFarProc;
begin
Th:=LoadLibrary(’Cpp.dll’); {装载DLL}
if Th>0 then
try
Tp:=GetProcAddress(Th,PChar(’TestC’));
if Tp<>nil
then begin
Tf:=TIntFunc(Tp);
Edit1.Text:=IntToStr(Tf(1)); {调用TestC函数}
end
else
ShowMessage(’TestC函数没有找到’);
finally
FreeLibrary(Th); {释放DLL}
end
else
ShowMessage(’Cpp.dll没有找到’);
end;

  大家已经看到了,这种动态调用技术很复杂,但只要修改参数,如修改LoadLibrary(’Cpp.dll’)中的DLL名称为’Delphi.dll’就可动态更改所调用的DLL。

一、定义所要调用的函数或过程的类型。
  在上面的代码中我们定义了一个TIntFunc类型,这是对应我们将要调用的函数TestC的。在其他调用情况下也要做同样的定义工作。并且也要加上stdcall调用参数。

二、释放所调用的DLL。
  我们用LoadLibrary动态的调用了一个DLL,但要记住必须在使用完后手动地用FreeLibrary将该DLL释放掉,否则该DLL将一直占用内存直到您退出Windows或关机为止。

  现在我们来评价一下两种调用DLL的方法的优缺点。静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些;但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程;但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,笔者建议您使用静态方法,待熟练后再使用动态调用方法。

                    第五章 使用DLL的实用技巧 top

一、编写技巧。
  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了。

[后记]:除了上面介绍的DLL最常用的使用方法外,DLL还可以用于做资源的载体。例如,在Windows中更改图标就是使用的DLL中的资源。另外,熟练掌握了DLL的设计技术,对使用更为高级的OLE、COM以及ActiveX编程都有很多益处。

Delphi编写DLL(以及静态和动态方式调用) 阅读详情

相关推荐

delphi调用vc写的dll的方法

1. 在VC中新建一个 DLL 工程。写如代码,如:extern "C"{  _declspec(dllexport) int getPPLength();  _declspec(dllexport) int npn(int m, int n);}int getPPLength(){  return 5* 12;}int npn(int m, int n) {    int sum; 

boqing的专栏 4457

DELPHI调用VC写的DLL经验

由于项目的需要,必须使用DELPHI调用VC编写的DLL,而我是编写DLL的。 这里总结几个出现过的问题,以后再遇到就会用了。 一、需要在每一个输出的函数开始添加上AFX_MANAGE_STATE(AfxGetStaticModuleState());  AFX_MANAGE_STATE(AfxGetStaticModuleState())这是用来实现DLL资源的切换!

独爱糕 3489

PowerBuilder调用Delphi写的Dll时发生的奇怪问题。

  因项目需要,我用Delphi写了一个连接数据库把数据导出到Sql文件的dll,其中使用了TADOQuery组件。其中只有一个导出方法:function DataExport(path,ini_path:PChar):integer;   写完之后,用delphi写了一个test.exe进行测试,发现可以正常使用。之后便把这个dll交给了同事,让他在PowerBuilder中调用。同事拿过去之后

党宇航 的专栏 3955

Delphi 调用 rust 编写的 DLL 文件

Delphi 是一种基于对象的、可视化的、事件驱动的编程语言,它可以用来开发各种 Windows 应用,如桌面软件、数据库系统、网络服务等。delphi 支持调用外部的 DLL 文件,以实现与其他语言或库的互操作。rust 是一种现代的、高性能的、安全的编程语言,它可以用来开发各种应用,如操作系统、网络服务、游戏、嵌入式系统等。rust 也支持编写和导出 DLL 文件,以提供给其他语言或程序调用。这样,你就完成了在 Delphi 中调用 rust 编写的 DLL 文件的过程。

codemethod的博客 1119

node.js调用Delphi写的Dll

一、调用代码 Delphi版本Delphi 10 Seattle Delphi代码 unit Unit1; interface function testint(i: Integer): Integer; stdcall; function testpchar(value: PAnsiChar): PAnsiChar; stdcall; implementation functio...

小祝的专栏 1135

Delphi调用C# DLL方法

C#端 新建类库: 想要COM组件能够让Delphi调用必须使用接口形式 使用vs工具生成GUID删除多余的花括号 代码如下: namespace TestDll { public interface ITestClass1 { void YourFunction1(); void YourFunction2(string str); } [ClassInterface(ClassInterfaceType.None)] [Gui

m0_37876197的博客 3645

C#中如何调用Delphi写的Dll

在以前用Delphi开发的项目中,会经常用到TChart这个画图控件,它本身很强大,支持各类图,如点线图,柏拉图,柱状图等等,加上可以输出成BMP,JPEG,JPG,SVG,GIF等各种格式图片,很好用,当时也封装成比较独立的DLL文件。这次开发.NET程序正好派上用场。  几个关键技术点:  1 C#要以非托管方式调用DLL  2 C#把整理好的画图数据生成事先定义好格式的XML文件,...

banshu2416的博客 258

Delphi中调用及释放DLL的实践案例

本文还有配套的精品资源,点击获取 简介:Delphi,基于Object Pascal语言的IDE,广泛用于开发桌面应用。DLL作为Windows核心组件,使得程序间能共享功能,节省内存,提高效率。本例展示在Delphi中如何正确调用和释放DLL资源。介绍了DLL的导出函数定义、加载、获取函数指针、调用函数以及最终释放DLL的步骤。提供了一个完整的Delphi程序示例,帮助初...

weixin_35671843的博客 1520

Delphi 中如何调试 DLL

网上看到很多人问delphi中如何调试 DLL 的,众大侠回答也基本一致,但是,我使用时却时灵时不灵,今天发现了原因。完整的调试 DLL方法如下:1)新建一个 DLL 工程,名字就叫 MyDll 吧,编译后生成 MyDll.dll,我们要调试的就是它了。2)新建一个用来调试 MyDll 的 Application 工程,名字就叫 MyDllTest 吧,编译后生成的可执行性文件为 My

老牛(niniu)的专栏 1万+

DELPHI DLL注入技术详解与源码实践

DLL注入技术是计算机程序设计中的一项高级技术,它允许开发者将动态链接库(Dynamic Link Library,简称DLL)注入到另一个运行中的进程空间内。这种技术在软件开发、性能监控、安全研究等多个领域有着广泛的应用。本章节将为大家提供一个关于DLL注入技术的概览,包括它的工作原理、使用场景以及技术要点,为深入理解后续章节内容打下基础。DLL注入的原理是利用操作系统的API(应用程序编程接口)函数,将一个DLL文件映射到目标进程的地址空间内,并执行其导出函数,从而实现功能的动态扩展或修改。

weixin_35826166的博客 1111

Delphi 几种常见的Dll调用方法l

Delphi7 调用DLL几种常见的方法源码。

Delphi调用DLL文件里的窗体

Delphi调用DLL文件里的窗体 在我们写程序时候,有些窗体要重复使用,最好就是把这些窗体写到一个DLL文件里去,这样就比较方便调用,下面的演示如何调用DLL文件里的窗体。 DLL文件 {*******************************************************} {

haiou327’blog 2581

【LPDDR4 - 学习二】LPDDR4 介绍 ——LPDDR4 芯片引脚说明解析

本文系统解析了LPDDR4内存芯片的引脚定义与特性,重点介绍了272球POPFBGA封装的双通道架构。内容涵盖电源管理(三级供电架构与上电时序)、控制信号(差分时钟与复用命令总线)、数据接口(16位双向数据总线与选通信号)以及校准复位等核心模块。通过表格详细列明了各引脚电压范围、功能定义及工程注意事项,并附有典型封装球位分布图。全文基于JEDEC标准,为移动设备内存设计提供全面的硬件参考,特别强调电源时序控制、信号完整性及抗干扰设计等关键点。

zap15622077817的博客 2639

delphi 编写dll

开使你的第一个DLL专案 1.File->Close all->File->New﹝DLL﹞ 代码: //自动产生Code如下: ibrary Project2; //这有段废话。 uses SysUtils, Classes; {$R *.RES} begin end. 2.加个Func进来: 代码: library Project...

weixin_30521649的博客 1415

拜耳阵列(Bayer Pattern)和解马赛克简介

拜尔阵列由柯达的布莱斯·拜尔发明,拜尔阵列将更多的像素用于绿色,而不是红色和蓝色,因为人眼对绿色更敏感。但这张照片,每个像素只有rgb中的一种颜色,每个像素还缺少其它两个颜色分量,效果如下图3所示。典型的图像传感器(例如我们在数码相机中使用的图像传感器,主要有CCD, CMOS)由许多单独的光电传感器组成,所有这些传感器都会捕获光线。如果想要获得不同颜色的光,最直接的做法是加入不同颜色的滤镜,从而滤出 RGB 三个通道的颜色。这个覆盖层可以理解为一个过滤层,每种类型的过滤器通常只允许一种颜色的光线的通过。

qq_34999565的博客 5982

FPGA工程师必看:JESD204B同步机制实战指南(含SYSREF信号调试技巧)

本文为FPGA工程师提供了一份JESD204B同步机制的实战指南,重点聚焦于SYSREF信号的调试技巧。文章从同步的核心逻辑出发,深入剖析了时钟、SYSREF与对齐序列这“三驾马车”的协作,并详细阐述了硬件PCB布局、FPGA IP核配置、状态机监控以及使用示波器进行波形分析等关键实战步骤,旨在帮助工程师解决多通道高速系统中的同步难题,确保链路的稳定与确定性延迟。

weixin_29239661的博客 331
上一篇: D7下FastMM的使用
下一篇: 写dll应该注意的问题
Devillyd
博客等级 码龄23年 58粉丝 101原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值