DLL编写与调用全解

DDR3 DDR4的DLL LPDDR4中的OSC 对读写DQSDQ之间的延迟的影响 (1)DDR中对于读操作,利用DLL实现读DQS外部时钟的对齐。这样读的DQSPHY上的时钟相位是对齐的,这样可以降低PHY的设计复杂度。(2)对于LPDDR4,为了节省功耗,所以不采用DLL。但这样读DQS是PHY上的时钟是异步的,所以需要PHY这边用异步FIFO完成传输。(3)对于写操作,DDR内部DQSDQ的传输延迟是比较小的,所以对于写DQS2DQ的延迟无需太多关注。但对于LPDDR4,为了减少功耗,所以对于写,DQ先采到,DQS后面采到;所以中间的延迟会比较大。 阅读详情

DLL编写与调用全解

DELPHI学习    2008-12-23 22:52   阅读8   评论0  
字号:    

第一章 为什么要使用动态链接库(DLL) top
提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维护升级的重要保证。(举个例子,笔者的Win95 System目录下尽有500多个DLL文件。)其实,DLL是一种特殊的可执行文件。说它特殊主要是因为一般它都不能直接运行,需要宿主程序比如*.EXE程序或其他DLL的动态调用才能够使用。简单的说,在通常情况下DLL是经过编译的函数和过程的集合。
使用DLL技术主要有以下几个原因:

一、减小可执行文件大小。
DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。

二、实现资源共享。
这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。早期的程序员经常碰到这样的事情,在不同的编程任务中编写同样的代码。这种方法显然浪费了很多时间,为了解决这个问题人们编写了各种各样的库。但由于编程语言和环境的不同这些库一般都不能通用,而且用户在运行程序时还需要这些库才行,极不方便。DLL的出现就像制定了一个标准一样,使这些库有了统一的规范。这样一来,用不同编程语言的程序员可以方便的使用用别的编程语言编写的DLL。另外,DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。

三、便于维护和升级。
细心的朋友可能发现有一些DLL文件是有版本说明的。(查看DLL文件的属性可以看到,但不是每一个DLL文件都有)这是为了便于维护和升级。举个例子吧,早期的Win95中有一个BUG那就是在闰年不能正确显示2月29日这一天。后来,Microsoft发布了一个补丁程序纠正了这个BUG。值得一提的是,我们并没有重装Win95,而是用新版本的DLL代替了旧版本的DLL。(具体是哪一个DLL文件笔者一时想不起来了。)另一个常见的例子是驱动程序的升级。例如,著名的DirectX就多次升级,现在已经发展到了6.0版了。更妙的是,当我们试图安装较低版本的DLL时,系统会给我们提示,避免人为的操作错误。例如我们升级某硬件的驱动程序时,经常碰到Windows提示我们当前安装的驱动程序比原来的驱动程序旧。

四、比较安全。
这里说的安全也包括很多方面。比如,DLL文件遭受病毒的侵害机率要比普通的EXE文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

第二章 在Delphi中编写DLL top

注意:在这里笔者假定读者使用的是Delphi 3或Delphi 4开场白说了那么多,总该言归正传了。编写DLL其实也不是一件十分困难的事,只是要注意一些事项就够了。为便于说明,我们先举一个例子。

library Delphi;

uses
SysUtils,
Classes;

function TestDll(i:integer):integer;stdcall;
begin
Result:=i;
end;

exports
TestDll;

begin
end.

上面的例子是不是很简单?熟悉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(以及静态和动态方式调用) 阅读详情

相关推荐

Java调用C++动态链接库dll,有详细过程。VS2015+Eclipse以及失败解决方案

背景 由于之前一直没有接触过用Java调用C++,目前正在考虑用C++写主要的算法,然后用Java来调用。通过查找资料,发现要嘛用通信的方式,要嘛就使用JNI,也就是Java Native Interface的简称,中文是“Java本地调用”。通常在Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写函数。 Native程序中的函数可以调用Java层的函数

倒着走的码农 9002

【DRAM存储器十五】DDR介绍-关键技术之DLL和prefetch

详述DDR DLL和预取原理以及几个DDR相对初代SDRAM新增的时序参数

highman110的博客 4248

Java webservice 调用自定义dll(有其他依赖)方法全解,无需设置环境变量

终于搞定java中调用dll很久没有上来写博客了,今天终于搞定了如何调用使用java调用dll,网上千篇一律的全是将dll放置到JDK底下,通过环境变量来加载,使用System.loadlibrary()。考虑到可能设计项目的迁移,其他机子可能缺少一些dll文件,以及还需要配置环境变量,着实不方便。博主这里给出通过使用类似于加载文件的方式,来加载dll。其实加载dll和加载文件是一样的。我们再使用d

倒着走的码农 4660

DDR 延迟锁定回路(DLL

DDR 延迟锁定回路(DLL) 转载自http://www.cnblogs.com/shengansong/archive/2012/09/01/2666213.html DDR SDRAM对时钟的精确性有着很高的要求,而DDR SDRAM有两个时钟,一个是外部的总线时钟,一个是内部的工作时钟,在理论上DDR SDRAM这两个时钟应该是同步的,但由于种种原因,如温度、电压波动而

嵌入式技术在路上 8616

Delphi环境中编写调用DLL的方法和技巧

第一章 为什么要使用动态链接库(DLL) top 提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维护升级的重要保证。(举个例子,笔者的Win95 System目录下尽有500多个DLL文件。)其实,DLL是一种特殊的可执行文件。说它特殊主要是因为一般它都不能直接运行,需要宿主程序比如*.EXE程序或其他DLL的动态调用才能够使用。简单

yfzhu的专栏 2215

Windows DLL问题全解:当aef.dll不见时,你该怎么做

aef.dll(Adobe Extension Framework)是Adobe公司开发的一款动态链接库文件,主要用于支持Adobe Creative Suite系列软件的功能扩展。这个DLL文件包含了Adobe应用程序执行所需的一些基础代码和数据,确保软件能够正常启动和运行。

Xixix777的博客 958

无需 KMS 也不用补丁:ohook 教你用一枚 DLL 实现 Office 永久激活(原理实操全解

深夜加班,Word 顶部又亮起那条刺眼的红字:"许可证即将到期"。你试过 180 天就得重新激活的 KMS,试过一更新就失效的破解补丁,也试过服务一关就作废的在线激活器。而 ohook 这个开源 Office 激活钩子工具,提供了一条截然不同的路:它不碰任何系统文件,只靠替换一枚 `sppc.dll`,就能让订阅版 Microsoft 365 长期维持"已授权"状态。读完这篇 ohook 使用教程

gitblog_00722的博客 149

SharpZipLib避坑指南:Unity2019-2022各版本DLL引用问题全解(含NuGet正确姿势)

本文详细解析了在Unity 2019至2022版本中集成SharpZipLib库时常见的DLL引用平台兼容性问题。针对移动端打包报错、NuGet引用失败等核心痛点,提供了手动配置DLL、正确处理I18N依赖、设置平台导入规则以及编写跨平台健壮压缩解压工具类的完整解决方案,确保在Android、iOS等全平台稳定运行。

hh234的博客 591

《幽灵行动》dbdata.dll问题全解:从根源入手,彻底修复

在玩《幽灵行动》系列游戏时,部分玩家可能会遇到“dbdata.dll丢失”或“dbdata.dll找不到”等问题,导致游戏无法正常启动或运行。这些问题通常会让玩家感到困惑,但通过一些简单的方法往往可以解决。本文将详细探讨这一问题的原因,并提供几种有效的解决方案。

Xixix777的博客 1263

无法启动程序 libexpatw.dll 文件丢失问题全解:快速修复找不到 libexpatw.dll 的方法

在尝试运行某些应用程序或游戏时,您可能会遇到错误提示:“由于找不到,无法继续执行代码。” 这个问题表明系统缺少必要的动态链接库文件,导致程序无法正常启动。是一个重要的 DLL 文件,用于处理 XML 数据。本文将详细探讨该问题的原因以及如何解决这一问题。

Xixix777的博客 1934

《命令征服:变节者》游戏启动问题全解:应对libcurl.dll文件丢失的实用策略

在享受《命令征服:变节者》这款经典即时战略游戏的过程中,不少玩家可能会遇到一个让人头疼的问题:游戏启动时提示“找不到libcurl.dll”或“libcurl.dll文件丢失”,这无疑会打断游戏体验。本文将详细介绍libcurl.dll文件的作用、丢失的原因以及如何解决这一问题,帮助你快速回到游戏战场。

Xixix777的博客 1134

多玩模拟器msvcp140.dll文件丢失问题全解:原因、症状对策

在使用多玩模拟器时,遇到“加载msvcp140.dll文件丢失”的提示可能会阻碍模拟器的正常运行。这个错误通常意味着模拟器在启动时未能找到必要的动态链接库文件,这可能是由于文件丢失、损坏或版本不匹配等原因造成的。本文将详细探讨这个问题的原因以及如何解决此类问题。

Xixix777的博客 966

DDR的概念解读-三大关键技术

但是,DDR SDRAM对时钟的精确性有着很高的要求,而DDR SDRAM有两个时钟,一个是外部的总线时钟,一个是内部的工作时钟,在理论上DDR SDRAM这两个时钟应该是同步的,但由于种种原因,比如温度、电压波动而产生延迟使两者很难同步,更何况时钟频率本身也有不稳定的情况。由于数据是在时钟的上下沿触发,造成传输周期缩短了一半,因此必须要保证传输周期的稳定以确保数据的正确传输,这就对CK的上下沿间距有了精确的控制的要求。DLL主要的目的就是生成一个延迟量给内部时钟,来补充正负不同步造成的正负延迟。

启芯硬件的博客 7007

DDR中的DLL

在DDR4内存系统中,DLL(Delay Locked Loop,延迟锁相环)是一个非常重要的组件,用于确保数据信号(DQS)和时钟信号(CK)之间的同步。- 时序变化:在DLL-off模式下,tDQSCK(读数据时钟到DQS的时序关系)会受到影响,其值会比DLL-on模式下的大很多。- 时序校准:当DLL启用时,它会持续工作,确保DQS信号CK信号之间的相位对齐。- 提高数据传输可靠性:通过确保DQS信号CK信号的同步,DLL可以减少数据传输中的时序偏差,从而提高数据采样的准确性和可靠性。

意大利炮修理师的博客 1317

DDR存储接口中的DLL系统分析介绍

DDR3 SDRAM即第三代双倍数据传输速率的同步动态随机存取存储器,遵循联合电子器件工程委员会开发的新一代内存技术JEDEC79-3A标准。为了满足频率提升的需要,DDR3 SDRAM现有DDR1 SDRAM和DDR2 SDRAM所采用的总线型设计有了很大不同,这将会使主板芯片组的内存控制器设计产生巨大的变化。DDR3SDRAM控制器中采用了阻抗自调整以保证DDR3 SDRAM的所有DQ端输出...

鹰飞天下 1234

learning ddr DLL-off mode

转载于:https://www.cnblogs.com/lianghong881018/p/10619203.html

weixin_30814329的博客 1363

Delphi制作DLL小结

Dll的制作一般分为以下几步:1 在一个DLL工程里写一个过程或函数2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。二 参数传递1 参数类型最好window C++的参数类型一致。不要用DELPHI的数据类型。2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,windows c++兼容。3 用

bjskyhorse的专栏 1208

DRAM的DLL为啥一直只存在在DDR系列里面呢?下次不要再迷茫了

【代码】DRAM的DLL为啥一直只存在在DDR系列里面呢?下次不要再迷茫了。

一个DRAM从业者的告白 894
上一篇: 转自genispan的专栏 - delphi 调用dll窗体
下一篇: 键盘按键代码
hack_wg
博客等级 码龄17年 11粉丝 7原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值