文档库 最新最全的文档下载
当前位置:文档库 › Delphi下写DLL大全

Delphi下写DLL大全

Delphi下写DLL大全
Delphi下写DLL大全

Delphi下写DLL的文章

Delphi制作DLL

一Dll的制作一般步骤

二参数传递

三DLL的初始化和退出清理[如果需要初始化和退出清理]

四全局变量的使用

五调用静态载入

六调用动态载入

七在DLL建立一个TForM

八在DLL中建立一个TMDIChildForM

九示例:

十Delphi制作的Dll与其他语言的混合编程中常遇问题:

十一相关资料

一Dll的制作一般分为以下几步:

1 在一个DLL工程里写一个过程或函数

2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。

二参数传递

1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。

2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].

一句话,与windows c++兼容。

3 用stdcall声明后缀。

4 最好大小写敏感。

5 无须用far调用后缀,那只是为了与windows 16位程序兼容。

三DLL的初始化和退出清理[如果需要初始化和退出清理]

1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:

procedure DllEnterPoint(dwReason: DWORD);far;stdcall;

dwReason参数有四种类型:

DLL_PROCESS_ATTACH:进程进入时

DLL_THREAD_ATTACH :线程进入时

DLL_THREAD_DETACH :线程退出时

在初始化部分写:

DLLProc := @DLLEnterPoint;

DllEnterPoint(DLL_PROCESS_ATTACH);

2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil);

3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。

四全局变量的使用

在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。

五调用静态载入

1 客户端函数声名:

1)大小写敏感。

2)与DLL中的声明一样。

如:showform(form:Tform);Far;external'yproject_dll.dll';

3)调用时传过去的参数类型最好也与windows c++一样。

4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径;

windows;widows\system;windows\ssystem32;

六调用动态载入

1 建立一种过程类型(或者是一个Function)[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如:

type

mypointer=procedure(form:Tform);Far;external;

//mypointer=function(form:Tform);Far;external;

var

Hinst:Thandle;

showform:mypointer;

begin

Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。

showform:=getprocaddress(Hinst,'showform');//按函数名找,大小写敏感。如果你知道自动化对象的本质就清楚了。

showform(application.mainform);//找到函数入口指针就调用。

Freelibrary(Hinst);

end;

七在DLL建立一个TForM

1 把你的Form Uses到Dll中,你的Form用到的关联的单元也要Uses进来[这是最麻烦的一点,因为你的Form 或许Uses了许多特殊的单元或函数]

2 传递一个Application参数,用它建立Form.

八在DLL中建立一个TMDIChildForM

1 Dll中的MDIForm.FormStyle不用为fmMDIChild.

2 在CreateForm后写以下两句:

function ShowForm(mainForm:TForm):integer;stdcall

var

Form1: TForm1;

ptr:PLongInt;

begin

ptr:=@(Application.MainForm);//先把dll的MainForm句柄保存起来,也无须释放,只不过是替换一下

ptr^:=LongInt(mainForm);//用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源.

//为什么不直接Application.MainForm := mainForm,因为Application.MainForm是只读属性

Form1:=TForm1.Create(mainForm);//用参数建立

end;

备注:参数是主调程序的Application.MainForm

九示例:

DLL源代码:

library Project2;

uses

Classes,

Dialogs,

Forms,

Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}

var

ccc: Pchar;

procedure OpenForm(mainForm:TForm);stdcall; var

Form1: TForm1;

ptr:PLongInt;

begin

ptr:=@(Application.MainForm);

ptr^:=LongInt(mainForm);

Form1:=TForm1.Create(mainForm);

end;

procedure InputCCC(Text: Pchar);stdcall; begin

ccc := Text;

end;

procedure ShowCCC;stdcall;

begin

ShowMessage(String(ccc));

end;

exports

OpenForm;

InputCCC,

begin

end.

调用方源代码:

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Button1: TButton;

Button2: TButton;

Edit1: TEdit;

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure OpenForm(mainForm:TForm);stdcall;External'project2.dll';

procedure InputCCC(Text: Pchar);stdcall;External'project2.dll';

procedure TForm1.Button1Click(Sender: TObject);

var

Text: Pchar;

begin

Text := Pchar(Edit1.Text);

// OpenForm(Application.MainForm);//为了调MDICHILD

InputCCC(Text);//为了实验DLL中的全局变量是否在各个应用程序间共享

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

ShowCCC;//这里表明WINDOWS 32位应用程序DLL中的全局变量也是在应用程序地址空间中,16位应用程序或许不同,没有做实验。

end;

十Delphi制作的Dll与其他语言的混合编程中常遇问题:

1 与PowerBuilder混合编程

在定义不定长动态数组方面在函数退出清理堆栈时老出现不可重现的地址错,原因未明,大概与PB的编译器原理有关,即使PB编译成二进制代码也如此。

在DELPHI中编写DLL时,如果DLL有创建ADO对象要被调用函数开始处写:CoInitialize(nil);

结束时写:CoUninitialize;

如要返回字符串要用PChar,最好用PChar用out或var方式返回,PChar的内存分配和释放在调用函数处理:GetMem(p, Size);FreeMem(p);

procedure CommonDLL(AHnd: THandle; //AApp: TApplication;

ADllFileName: PChar;

AConnStr: PChar; AUserID: integer; ABillTypeID: integer);

var

LPtr:PLongint;

strDllFileName: string;

begin

CoInitialize(nil);

strCon := StrPas(AConnstr);

strDllFileName := StrPas(ADllFileName);

try

Application.Handle := AHnd;

Screen := AScr;

LPtr := @Application.MainForm;

LPtr^ := Longint(AApp.MainForm);

finally

end;

CoUninitialize;

end;

在加载DLL时要保存原来的句柄,退出DLL时还原句柄:var

OldHnd: THandle;

// OldApp: TApplication;

OldScr: TScreen;

procedure InitDll(dWseason: DWORD);

begin

case dWseason of

DLL_PROCESS_ATTACH:

begin

OldHnd := Application.Handle;

// OldApp := Application;

OldScr := Screen;

end;

begin

Application.Handle := OldHnd;

// OldApp := GApplication;

OldScr := GScreen;

end;

end;

end;

begin

DllProc := @InitDll;

InitDll(DLL_PROCESS_ATTACH);

end.

在DLL被用函数中有创建窗体对象,一定要记得传Application或者Application.Handle。

DLL中的窗体一般要用FormClass.Create(application)来创建比较好。

我见过有DLL会传Screen对象到DLL,这个我不没具体了解为什么,也希望有知道朋友告诉我有一下传Screen对象有什么作用,有什么优缺点。

传Screen是为了使主程序主窗体的MDIChildCount正常增加,

否则,不管打开多少DLL中的MDIChild窗体,MDIChildCount都不会增加。

第一章为什么要使用动态链接库(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

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

library Delphi;

uses

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

调用一个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 }

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必须写上。

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

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

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

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

第四章在Delphi中动态调用DLL

动态调用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;

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,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。动态方法较好地解决了静态方法中存在的不足,可以方便地访问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选项是不行的,

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编程都有很多益处。

2007-9-14 16:22:41

Delphi中如何调用DLL

马上想得到的使用说明有以下几点:

1. 所需动态连结的DLL 须置放在与执行档同一目录或Windows System 目录

2. 确认DLL export 出来的函式的原型, 以目前的情况而言, 通常只拿得到C语言的函数原型,这时要注意 C 与object Pascal 相对应的型别, 如果需要, 在interface 一节定义所需的资料类别

3. 在implementation 节中宣告欲使用的函式, 语法大致如下:

p rocedure ProcName(Argu...); far; external ’DLL档名’;

index n;

function FuncName(Argr...): DataType; far;

external ’DLL档名’; index n;

宣告时, index n 如果不写, 便是参考资料中所谓import by name 的方式, 此时, 由於需要从DLL 的name table 中找出这个函式, 因此, 连结执行速度比import by ordinal稍慢一些, 此外, 还有一种by new name, 由於我没用过, 您可以查一参考资料, 大意是可以import 後改用另一个程式命名呼叫这个函式

4. 然後, 呼叫与使用就与一般的Delphi 没有两样

5. 上述是直接写到呼叫DLL函式的程式单元中, 此外,也可以将DLL的呼叫宣告集中到一个程式单元(Import unit), Delphi 内附的WinTypes, WinProcs是一个例子,

您可以参考一下,同时观察一下 C 与Pascal 互相对应的资料型态6. 除了上述的static import 的方式, 另外有一种dynamic import 的写法,先宣告一个程序类型(procedural-type),程式执行时, 以LoadLibrary() API Load进来後, 再以GetProcAddress() API 取得函式的位址的方式来连结呼叫, 在ObjectPascal Language Guide P.132-133 有一个例子, 您可以参考看看

如果要举个例子, 以下是从我以前的程式节录出来的片断:

(* for CWindows 3.1 *)

unit Ime31;

interface

uses

type

(* 必要的资料型态宣告*)

tDateNTime = record

wYear, wMonth, wDay: word;

wHour, wMin, wSec: word;

end;

TImePro = record

hWndIme: HWnd; { IME handle }

dtInstDate: tDateNTime; { Date and time of installation } wVersion: word; { the version of IME }

szDescription: array[0..49] of byte; { Description of IME module} szName: array[0..79] of byte; { Module name of the IME } szOptions: array[0..29] of byte; { options of IME at startup} fEnable: boolean; { IME status; True=activated,False=deactivated } end;

pTImePro = ^TImePro;

function SetIme(const sImeFileName: string): boolean; far;

implementation

(* begin 呼叫winnls.dll export 函数的宣告*)

function ImpSetIme(hWndIme: HWND; lpImePro: pTImePro): boolea n;far; external ’winnls.dll’; (* end 呼叫winnls.dll export 函数的宣告*)

(* -------------------------------------------------- *)

(* SetIme(const sImeFileName: string): boolean;

(* ======

(* 切换到某一特定的输入法

(*

(* 传入引数:

(* sImeFileName: 输入法IME 档名, 例: phon.ime;

(* 空字串: 英数输入法

(*

(* 传回值:

(* True: 切换成功

(* -------------------------------------------------- *) function SetIme(const sImeFileName: string): boolean; var

pImePro: pTImePro;

begin

Result := False;

if MaxAvail < SizeOf(TImePro) then

begin

MessageDlg(’记忆体不足’, mtWarning, [mbOk], 0); Exit;

end

else

begin

New(pImePro);

try

if sImeFileName = ’’ then (* 空字串, 还原到英数输入法*)

在VB中调用DLL的方法

1制作好DLL之后,就可以用VB调用它,实现VB调用C程序。VB程序要使用DLL中的函数,首先必须要有特殊的声明,用Declare声明语句在窗体级或模块级或全局模块的代码声明段进行声明,将动态链接库中的函数声明到VB中,供VB程序调用。 语句格式为:Declare Sub过程名Lib[Alias"别名]([ByVal参数AS类型]),或为Declare Function函数名Lib[Alias"别名]([ByVal参数AS类型])AS类型在声明中首先用Declare 关键字表示声明DLL中的函数。在C语言中有的函数类型为VOID,它表示不具有返回值,则必须用关键字Sub将其声明成过程。有的函数具有返回值,则必须用关键字Function将其声明成函数,并且在声明语句的最后要用AS关键字指明函数返回值的类型。 例如上面的ADD.DLL在VB中就可以声明为: Declare Function ADD Lib“c:\ADD.dll”(ByVal X AS Integer,ByVal Y AS Integer,ByVal filein asstring)AS Integer 通过此声明语句将函数ADD声明到VB中,便可直接调用。 2、dll文件中的函数好像是C语言写的, //函数名:int__stdcall GetMacNo(int*MacNo) //功能:获取卡机的卡机号(单机时) //参数:MacNo[0]-被读出的卡机号 //返回值:0-成功, //2-PC接收超时, //3-应答错误 dll的文件名是COMM232.dll 函数的形参int*MacNo是指针吗? 在VB中应该怎么声明和调用该函数? VB里也可以定义指针吗? 问题补充:vb调用dll文件中的函数我是会的,但这儿的形参有一个星号才不知是怎么一回事, 我是这样声明的对吗? Public Declare Function GetMacNo Lib"COMM232.dll"(ByVal MacNo As Integer)As Integer 又应该怎么调用呢?要先定义一个指针的变量再传给*MacNo还是要怎么做? 都说了MacNo是被读出的卡机号,那么就是传址的了。 dim l as integer dim m as integer l=GetMacNo(m) if l=0then label1.caption="卡机号:"&m elseif l=2then msgbox"PC接收超时" elseif l=3then msgbox"应答错误" end if

DELPHI中如何调用API,可举例说明

DELPHI中如何调用API,可举例说明 第一部分Delphi知识1. 如果一个元件希望放到IDE的元件面板上,它必须从________类派生,如果一个元件能作为其它元件的容器,它必须从_____________类派生,如果一个元件在运行时可见,它必须从___________________类派生(A)TGraphicControl (B)TWinContr 1、rtl70.bpl是什么?有什么用? 2、delphi的Package相对dll有什么优点? 3、以下的记录(结构)变量在内存占多少字节?type a = packed record v1: Byte; v2: Word; v3: string[16]; v4: Double; v5: string; v6: TForm; end; 4、以下的写法是否正确?type a 1.您为什么选择软件开发这个行业?(30字左右简写); 2.如果有您解决不了的软件问题您会采取什么样的解决措施; 3.a.请您写出Object Pascal所支持的数据类型;b.请您写出Shl、Shr、Xor、Not 的数学表示法; 4.请您写出VCL结构层次(以TObject开始,最少五层);5 二.是非题(共20道)1.从主菜单上选择Project|Syntax Check 菜单选项,Delphi将编译从上次编译后有改动的任何单元,并报出遇到的错误。()2.Delphi的VCL对象有些是指针,从堆栈中分配空间,有些则不是。()3.粘贴时,如果作为容器的组件已被选择,

剪贴 一.选择题(共40道)1.用户开发程序时需要经常在窗体和编辑器窗口之间来回切换,可使用快捷键()。A、F12和F11 B、F12和F13 C、F12和Ctrl+F12 D、F12和Alt+F12 E、F12和Shift+F12 2.某函数如下:Function check(n,k:Integer):Integer; Var m:Integer; Beg 编程语言:delphi7.0或Vc++6.0 时间:4小时内环境:可参考帮助文档,但不能上网查资料1、编程查找指定目录下所有EXE 文件,并将其全路径存入Result.txt中,要求用递归。2、采用SOCKET(可用SOCKET API或delphi Socket控件)实现点对点传输大文件,要求不能掉

delphi之调用外部dll中的函数

分早绑定和晚绑定两种。 早绑定的代码如下: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; //MB 函数的声明: function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; implementation {$R *.dfm} {调用外部 DLL 中的函数,譬如调用系统 user32.dll 中的 MessageBoxA} //function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; // stdcall; external user32 name 'MessageBoxA'; {其中 user32 是 Delphi 定义的常量 'user32.dll',可以直接写成:} //function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; // stdcall; external 'user32.dll' name 'MessageBoxA'; {name 后面说明函数的真实名字} {external 子句说明单元载入时就加载函数,也就是早绑定;如果晚绑定需要用LoadLibrary} {stdcall 指令表示参数传递是从右到左(Pascal则反之),不通过CPU寄存器

易语言中调用DLL使用说明

易语言中调用DLL使用说明 基本说明 本文所描述的部分功能需易语言4.01或以上版本支持。 “在易语言中调用DLL”包含两方面的内容:调用Windows系统API函数;调用普通DLL函数。 下文用到的“调用API”或“调用DLL”等字眼,除非特别注明,一般都是指以上两方面之一或之和,视上下文而定。绝大多数情况下,无需明确区分调用的是系统API还是普通DLL。 目前易语言只支持以stdcall方式调用DLL中的导出函数。 Windows系统API一般都是以stdcall调用方式导出的,故在易语言中调用它们时通常不必考虑函数调用方式的问题。而普通DLL有可能导出“非stdcall调用方式”(比如cdecl)的函数,调用时需要特别注意。一般而言,考虑到通用性,DLL开发者都会选择导出以sdtcall方式调用的函数。(支持生成DLL的编程语言通常都支持导出stdcall调用方式的函数,具体实现请参考各编程语言手册。) 易语言编译生成的DLL,其导出函数全部为stdcall调用方式,所以在易语言中调用易语言生成的DLL不存在问题。 目前在易语言中调用DLL时只支持1字节对齐的结构(自定义数据类型) 如果DLL命令的某个参数或参数的某个成员是结构类型(自定义数据类型),则其对齐方式必须是1字节对齐。Windows系统API中所用到的结构都是1字节对齐的,故在调用API时不受此限制。但如果想用其它编程语言生成DLL供易语言调用且数据类型中包含了1或2字节数据长度的成员(如字符型或短整数),就需要考虑结构的1字节对齐。

在Delphi中,可以这样定义1字节对齐的结构(结构在Delphi中称为record): 在其它编程语言或编译器中的定义方式请参考各自的编程手册。 目前易语言支持调用任意复杂的DLL命令 只要满足了前面的两个条件——调用方式为stdcall,参数结构为1字节对齐——易语言支持调用任意复杂的DLL命令:参数除了可以是基本数据类型或普通结构类型外,还可以是基本类型地址或基本类型数组,也可以是结构类型地址或结构类型数组,结构类型的成员中还可以包含任意数量和任意层次的其它结构、结构地址、结构数组,等等。 DLL命令调用表 要在易语言中调用Windows API或普通DLL中的导出函数,必须首先在易语言中对该函数进行声明,声明的方式就是颇具易语言特色的“填写‘DLL命令调用表’”。“DLL命令调用表”正确填写完毕之后,就可以象调用普通易语言子程序一样调用DLL命令了。 下面重点说明“DLL命令调用表”的填写。 在易语言中,选择菜单“插入→DLL命令”即可插入一个空白的“DLL命令调用表”。当然还有其它操作方式,请参考易语言相关操作手册。

如何用delphi制作DLL动态库方法

用Delphi制作DLL的方法 一Dll的制作一般步骤 二参数传递 三DLL的初始化和退出清理[如果需要初始化和退出清理] 四全局变量的使用 五调用静态载入 六调用动态载入 七在DLL建立一个TForM 八在DLL中建立一个TMDIChildForM 九示例: 十Delphi制作的Dll与其他语言的混合编程中常遇问题: 十一相关资料 一Dll的制作一般分为以下几步: 1 在一个DLL工程里写一个过程或函数 2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。 二参数传递 1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。 2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容。 3 用stdcall声明后缀。 4 最好大小写敏感。 5 无须用far调用后缀,那只是为了与windows 16位程序兼容。 三DLL的初始化和退出清理[如果需要初始化和退出清理] 1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下: procedure DllEnterPoint(dwReason: DWORD);far;stdcall; dwReason参数有四种类型: DLL_PROCESS_ATTACH:进程进入时 DLL_PROCESS_DETACH进程退出时 DLL_THREAD_A TTACH 线程进入时 DLL_THREAD_DETACH 线程退出时 在初始化部分写: DLLProc := @DLLEnterPoint; DllEnterPoint(DLL_PROCESS_ATTACH); 2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil); 3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。 四全局变量的使用 在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用

delphi中dll综合运用的例子

delphi中dll综合运用的例子(动态加载插件) 2008年01月15日星期二 10:59 1,新建dll客户端模块 ---------------dll工程文件PlugIns.dll------------------------------- library PlugIns; { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. } uses SysUtils, Classes, PlugInFrm in 'PlugInFrm.pas' {FrmPlugIns}; {$R *.res} //输出接口函数 exports ShowDLLForm,GetCaption; begin end. -------------新建模块PlugInFrm.pas的窗体文件--------------- unit PlugInFrm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TFrmPlugIns = class(TForm) Label1: TLabel; private { Private declarations }

delphi如何调用C#的dll

delphi如何调用C#的dll delphi如何调用C#的dll 发表于2010-03-11 16:37:13 Idelphi如何调用C#的dll ?在你的环境变量Path中加入 C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin; C:\WINNT\https://www.wendangku.net/doc/f06005041.html,\Framework\v1.1.4322 随便建立一个ClassLibrary 编译成DLL 文件切换到MS-DOS 命令行下面,运行:C:\>regasm out ClassLibrary1.DLL /regfile:ClassLibrary1.reg 上面的命令行是注册我们的.NET 组件,并且产生了一个备用的注册表文件。对应Windows 的注册COM 文件命令:regsvr32 c:\test.dll . 在.NET下面,注册.NET组件就需要上面的regasm命令了然后在MS-DOS 命令行下面,运行: C:\>tlbExp ClassLibrary1.dll /out:ClassLibrary1.tlb 上面的命令行表示将会产生一个.NET 组件的类型库 有了TLB 文件也就和正常的COM 组件一样了,运行Delphi 导入类型库文件TLB ........... 和正常的COM 调用一样发表于2010-03-11 17:32:21 2 以前用delphi 写的CS 程序今天客户要加几个模块上去,刚

好会点C# ,这后面模块就用C#写的编译成dll文件,在用delphi 调用C#写的dll文件时折腾好阵子就有了这些经 历写下来。一、打开vs2005 新建windows 应用程序项目命名为SFrm,删除应用程序自动生成的Program.cs (因为我们 是要生成dll 文件)在窗体类新建一接口(interface SHFRM) 让窗体类实现接口代码如下:using System;using System.Collections.Generic;using https://www.wendangku.net/doc/f06005041.html,ponentModel;using System.Data;using System.Data.SqlClient;using System.Drawing;using System.Text;using System.Windows.Forms;namespace SFrm{public interface SHFRM // 此接口用在delphi 下调用必须用到{void ShchildFrm();}public partial class Form1 : Form,SHFRM{private BindingSource bindingSource1 = new BindingSource();private SqlDataAdapter dataAdapter = new SqlDataAdapter();public Form1(){InitializeComponent();}/// /// 显示窗口/// public void ShchildFrm(){Form1 frm = new Form1();frm.Show();}/// /// 按钮事件/// /// /// private void button1_Click(object sender, EventArgs e){dataGridView1.DataSource = bindingSource1;GetData("select * from Customers");}private void GetData(string selectCommand){try{String connectionString = "Data Source=.;initial catalog=Northwind;user id =sa;pwd=";dataAdapter = new SqlDataAdapter(selectCommand,

在DELPHI中静态调用DLL

一、开始你的第一个DLL专案 1.File->Close all->File->New﹝DLL﹞ 代码: //自动产生Code如下 library Project2; //这有段废话 uses SysUtils, Classes; {$R*.RES} begin end. 2.加个Function进来: 代码: 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. 二、进行测试:开个新application: 1.加个TButton 代码: ShowMessage(IntToStr(MyMax(30,50)));

在Delphi编程中使用C语言代码 - 调用C语言编写的DLL文件

1、使用Visual C++ 6.0编写和链接DLL 打开Visual C++ 6.0集成开发环境,新建一个Win32 Dynamic-Link Library类型的工程CDLL,在工程中新建一个C语言源文件cdll.c。源文件中的内容如下: __declspec(dllexport) int max(int x,int y) /* 比较两个整型变量大小的函数max */ { if (x>y) return x; else return y; } 输入完毕后按下F7键来编译和链接CDLL.dll,之后可以在存放该工程的文件夹的Debug子文件夹中找到一个名为CDLL的DLL文件,该文件即以上的C语言源程序生成的DLL。 2、使用Delphi 7编写调用该DLL的应用程序 打开Delphi 7集成开发环境,在默认生成的窗体Form1上拖放3个Edit 控件Edit1、Edit2、Edit3和1个Button控件Button1,并在Object Inspector中将3个Edit控件的Text属性都清空。然后在默认生成的Unit1.pas文件的implementation后输入: function max(x,y: Integer): Integer; stdcall external 'CDLL.DLL';

返回Form1,双击Button1控件,在生成的事件处理程序中输入: Edit3.Text:=IntToStr(max(StrToInt(Edit1.Text), StrToInt(Edit2.Text))); 输入完毕后,保存这个Project。最后,将CDLL.dll文件copy到保存该Project的文件夹中。 3、测试 在Delphi集成开发环境下,按下F9来运行刚刚编写的Project。在Edit1中输入2,Edit2中输入4,然后单击Button1,可以看到Edit3中会出现4,测试成功。 4、基础知识 4.1、回调函数 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。其中回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础。 回调函数与普通函数的申明并无区别,但如果是不同的开发语言之间通过回调函数来传递与处理数据,则一定要注意在不同语言对回调函数的申明与实现时其函数调用约定必须保持一致。 4.2、函数调用约定 声明过程或函数时,可以指定调用约定(calling convention),尤其在以接口形式提供给其它语言工具使用时,则必须指定过程或函数的调用方式。 Delphi指定调用约定可以使用的指示字包括register、pascal、cdecl、stdcall 以及safecall。C/C++调用约定有stdcall、cdecl、fastcall、thiscall、naked call 等。 决定了传递给例程的参数的顺序,还影响参数从栈中的解除、参数传递时对寄存器的使用以及处理错误和异常等。缺省的调用约定是register。 下表是调用约定的简要概括:

Delphi 中的dll 封装和调用对象方法

Delphi 中的dll 封装和调用对象方法 2011-01-28 22:18 动态链接库是一种特殊格式的二进制数据文件,后缀名为.dll。它可以在程序运行时调用,并不需要进行重新编译,又由于它是完全独立的一个功能模块,使得其重用性非常好。将dll载入内存后,dll中的功能接口可以被系统中任何正在运行的应用程序所使用。具有节省空间,升级容易和高重用性等优点。 很多delphi的教材资料上讲到dll,大多都是将用dll来封装一些函数或者过程。但有时我们想把某个问题当成一个对象来处理,使程序模块化、组件化,方便团队开发、维护和更新。这时我们就需要用到dll封装和调用对象的技术,然而delphi在封装对象方面有一定的技术难度,资料也比较少,使得很多程序员认为delphi的dll不支持对象封装。下面简单分享一下我学习dll对象封装和调用的一些心得,希望能对这方面有需求的程序员一些帮助。 首先让我们认识一点,调用dll的程序只能使用与dll中对象动态绑定的方法,理解这一点是实现Dll封装和使用对象的关键。理解了这一点,我们就会想怎样才能实现与dll中对象的动态绑定呢?Delphi的接口技术为我们提供了一个好的选择,我们可以通过接口类去动态的获取dll中的对象。下面我用一个简单的demo来说明如何实现。 我建立了这样一个工程组,如下图 按如下几步进行: 1、先定义一个接口单元IDemo,代码如下: unit IDemo;

interface type IMax = interface (IInterface) function Max(num1, num2 : Integer) : Integer; end; implementation end. 建立我们需要封装的对象单元UnitMax.pas,注意看TMax继承自哪些父类,代码如下: unit UnitMax; interface uses IDemo; type TMax = class(TInterfacedObject, IMax) function Max( num1, num2 : Integer ) : Integer; end; implementation function TMax.Max(num1: Integer; num2: Integer) : Integer; begin Result := 0; if num1 > num2 then Result := num1 else Result := num2; end; end. 3、再在dll单元,输入如下代码:

C#中如何调用Delphi写的Dll

C#中如何调用Delphi写的Dll C#中如何调用Delphi写的Dll 在以前用Delphi开发的项目中,会经常用到TChart这个画图控件,它本身很强大,支持各类图,如点线图,柏拉图,柱状图等等,加上可以输出成BMP,JPEG,JPG,SVG,GIF等各种格式图片,很好用,当时也封装成比较独立的DLL 文件。这次开发.net程序正好派上用场。 几个关键技术点: 1 C#要以非托管方式调用DLL 2 C#把整理好的画图数据生成事先定义好格式的XML 文件,传给DLL 3 DLL解析XML文件,根据相应格式,要求,画图 4 DLL输出GIF文件(经过比较GIF图像失真率小,且文件大小最小) 5 C#装载GIF文件,传到前台展示 关键代码: C# 以下是引用片段: #region 定义调用Delphi写的画图DLL /// /// 定义调用Delphi写的画图DLL

/// private class DrawChartFromDll { //定义DLL文件名,此文件路径要加到系统Path中 private const string _fileDll = @"Chart.dll"; //调用非托管Dll,GetChartFromXMLByNet是ChartAccess.dll公开的函数名称 [DllImport(_fileDll, EntryPoint = "GetChartFromXMLByNet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] //C#中的申明 public static extern int GetChartFromXMLByNet(int piChartType, string psXMLFileName, string psPriChartFileName, string psSecChartFileName, string psPriHotFileName, string psSecHotFileName); } #endregion public ChartResultData GetCharts(ChartData _ChartData, Hashtable _HotPriAdditionSeqNo, Hashtable _HotSecAdditionSeqNo) { //根据数据生成XML文件

如何用delphi制作DLL动态库方法

用DeIPhi制作DLL的方法 一Dll的制作一般步骤 二参数传递 三DLL的初始化和退出清理[如果需要初始化和退出清理] 四全局变量的使用 五调用静态载入 六调用动态载入 七在DLL建立一个TForM 八在DLL中建立一个TMDIChiIdForM 九示例: 十DeIPhi制作的Dll与其他语言的混合编程中常遇问题:十一相关资料一Dll的制作一般分为以下几步: 1在一个DLL工程里写一个过程或函数 2写一个EXPOrtS关键字,在其下写过程的名称。不用写参数和调用后缀。 二参数传递 1参数类型最好与Window C++的参数类型一致。不要用DELPHI的数据类型。 2最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败]?一句话,与Windows c++兼容。 3用Stdcall声明后缀。 4最好大小写敏感。 5无须用far调用后缀,那只是为了与Windows 16位程序兼容。 三DLL的初始化和退出清理[如果需要初始化和退出清理] 1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入 口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下: PrOCedUre DllE nterPoi nt(dwReaso n: DWoRD);far;StdCaII; dwReason参数有四种类型: DLL_PROCESS_ATTACH:进程进入时 DLL_PROCESS_DETACH 进程退出时 DLL_THREAD_A TTACH 线程进入时 DLL_THREAD_DETACH 线程退出时 在初始化部分写: DLLPrOC := @DLLE nterPoi nt; DIIE nterPoi nt(DLL_PROCESS_ATTACH); 2 女口Form 上有TdCOmCOnnectiOn 组件,就USeS Activex,在初始化时写一句CoInitialize (nil); 3在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。 四全局变量的使用 在Widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中 是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用 程序间的数据传递,除非你用内存映像文件。

delphi编写调用有窗体有返回值的dll的实现方x页

delphi编写调用有窗体有返回值的dll的实现方法 本人使用的delphi是版,用delphi编写dll工程很简单,在新建。。中就有创建Dll的选项。在编写DLL工程时,需要注意的包括,工程单元有很大差异,一个关键字是program ,一个关键字是library。dll工程单元中还包括exports 子句,那些需要提供给其他主叫程序调用的过程,都需要包括在exports中(只是列出函数的名字,不需要参数表)。对于主叫方(调用dll的应用程序或者其他dll),则需要在调用之前进行外部声明,即external保留字指示的声明。 另外需要了解object pascal中有关调用协议的内容,在object pascal中对于过程或函数有以下五种调用协议: 指示字参数传递顺序参数清除者参数是否使用寄存器 register 自左向右被调例程是 pascal 自左向右被调例程否 cdecl 自右向左调用者否 stdcall 自右向左被调用例程否 safecall 自右向左被调用例程否 这里的指示字就是在声明函数或过程时附加在例程标题之后的保留字,默认为register,即是唯一使用CPU寄存器的参数传递方式,也是传递速度最快的方式; pascal: 调用协议仅用于向后兼容,即向旧的版本兼容; cdecl: 多用于C和C++语言编写的例程,也用于需要由调用者清除参数的例程; stdcall: 和safecall主要用于调用Windows API 函数;其中safecall还用于双重接口。 现在以一个实例来说明一个用delphi编写的程序如何调用包含form窗体dll的程序。 Dll工程: library Project2; { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the shared memory manager, which must be deployed along with your DLL. To avoid using , pass string information using PChar or ShortString parameters. } uses SysUtils, Classes, Unit1 in '' {Form1}; {$R *.RES} exports Execute name 'Execute';{过程来自于Unit1} begin end. —————————————————————————————————————— unit Unit1; interface

delphi中调用dll知识

Delphi环境中编写调用DLL的方法和技巧 提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维护升级的重要保证。(举个例子,笔者的Win95 System目录下尽有500多个DLL文件。)其实,DLL是一种特殊的可执行文件。说它特殊主要是因为一般它都不能直接运行,需要宿主程序比如*.EXE程序或其他DLL的动态调用才能够使用。简单的说,在通常情况下DLL是经过编译的函数和过程的集合。 使用DLL技术主要有以下几个原因: 一、减小可执行文件大小。 DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。 二、实现资源共享。 这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。早期的程序员经常碰到这样的事情,在不同的编程任务中编写同样的代码。这种方法显然浪费了很多时间,为了解决这个问题人们编写了各种各样的库。但由于编程语言和环境的不同这些库一般都不能通用,而且用户在运行程序时还需要这些库才行,极不方便。DLL的出现就像制定了一个标准一样,使这些库有了统一的规范。这样一来,用不同编程语言的程序员可以方便的使用用别的编程语言编写的DLL。另外,DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。 三、便于维护和升级。

Delphi 类库(DLL)动态调用与静态调用示例讲解

Delphi 类库(DLL)动态调用与静态调用示例讲解 在Delphi或者其它程序中我们经常需要调用别人写好的DLL类库,下面直接上示例代码演示如何进行动态和静态的调用方法 { **********************************************************} { } { DLL动态调用与静态调用的例子} { 编译环境Delphi XE } { 转载或编译请不要修改此文件} { ******************************************************* ***} { ******************************************************* ***} { Designed by Jason 2013-08-30 } { ******************************************************* ***} program LoadDll; {$APPTYPE CONSOLE} uses SysUtils, windows; type TGetCPUID = function(CPUID: PAnsiChar): integer; stdcall; //注1 function GetCPUID(CPUID: PAnsiChar): integer; stdcall;external 'CPUID_Util.dll'; var dllHandle: THandle; GetId: TGetCPUID; Id: Array [0 .. 255] of Ansichar; //注2:DELPHI XE中使用Unicode编码字符串这里使用ansichar begin try //注3:静态调用 WriteLn('先尝试静态调用'); GetCPUID(Id); WriteLn(Id); if (Trim(Id) <> '') then WriteLn('静态调用成功,回车尝试动态调用') else

Delphi深入DLL编程

Delphi深入DLL编程 引言 相信有些计算机知识的朋友都应该听说过“DLL”。尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心,没有驱动损坏,没有病毒侵扰,仍然在使用(安装)了一段时间软件后,发现windows系统越来越庞大,操作越来越慢,还不时的出现曾经能使用的软件无法使用的情况,导致最终不得不重装系统。这种情况常常是由于dll文件的大量安装和冲突造成的。这一方面说明DLL的不足,另一方面也说明DLL的重要地位,以至我们无法杜绝它的使用。 DLL(动态链接库,Dynamic Link Library)简单来说是一种可通过调用执行的已编译的代码模块。DLL是windows系统的早期产物。当时的主要目的是为了减少应用程序对内存的使用。只有当某个函数或过程需要被使用时,才从硬盘调用它进入内存,一旦没有程序再调用该DLL了,才将其从内存中清除。光说整个windows系统,就包括了成百上千个dll 文件,有些dll文件的功能是比较专业(比如网络、数据库驱动)甚至可以不安装的。假如这些功能全部要包括在一个应用程序(Application program)里,windows将是一个数百M 大小的exe文件。这个简单的例子很容易解释DLL的作用,而调用DLL带来的性能损失则变得可被忽略不计。 多个应用程序调用同一个DLL,在内存里只有一个代码副本。而不会象静态编译的程序那样每一个都必须全部的被装入。装载DLL时,它将被映射到进程的地址空间,同时使用DLL的动态链接并非将库代码拷贝,而仅仅记录函数的入口点和接口。 同时DLL还能带来的共享的好处。一家公司开发的不同软件可能需要一些公用的函数过程,这些函数过程可能是直接的使用一些内部开发的DLL;一些常用的功能则可以直接使用windows的标准DLL,我们常说的windows API就是包含在windows几个公用DLL文件里的函数过程;理论上(如果不牵涉作者的版权),知道一个DLL的声明及作用(函数定义的输入参数及返回值),我们完全可以在不清楚其实现(算法或编译方式)的情况下直接使用它。 假如一个DLL中函数过程的算法得到了更新,BUG得到了修正,整个dll文件会得到升级。一般来说为了保证向下兼容,调用声明与返回结果应该保持不变。但实际上,即使是同一家开发的DLL,随着功能的改善,也很难保证某个调用执行完全不变。在使用其他人开发的DLL时这种糟糕情况更加的严重。比如我在一个绘图程序里使用了某著名图形软件商旧版本的DLL包,我所有的调用都是根据他发布的旧版的声明来执行的。假设用户安装了该软件商的一个新软件,导致其中部分DLL被更新升级,假如这些DLL已经有过改动,直接后果将是我的软件不再稳定甚至无法运行!不要轻视这种情况,事实上它是很普遍的,比如windows在修正BUG和升级过程中,就不断改动它包含的那些DLL。往往新版DLL 不是简单的增加新的函数过程,而是更换甚至取消了原有的声明,这时候我们再也无法保证所有程序都运行正常。

Delphi下写DLL大全

Delphi下写DLL的文章 Delphi制作DLL 一Dll的制作一般步骤 二参数传递 三DLL的初始化和退出清理[如果需要初始化和退出清理] 四全局变量的使用 五调用静态载入 六调用动态载入 七在DLL建立一个TForM 八在DLL中建立一个TMDIChildForM 九示例: 十Delphi制作的Dll与其他语言的混合编程中常遇问题: 十一相关资料 一Dll的制作一般分为以下几步: 1 在一个DLL工程里写一个过程或函数 2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。 二参数传递 1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。 2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败]. 一句话,与windows c++兼容。 3 用stdcall声明后缀。 4 最好大小写敏感。 5 无须用far调用后缀,那只是为了与windows 16位程序兼容。 三DLL的初始化和退出清理[如果需要初始化和退出清理] 1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下: procedure DllEnterPoint(dwReason: DWORD);far;stdcall; dwReason参数有四种类型: DLL_PROCESS_ATTACH:进程进入时

DLL_THREAD_ATTACH :线程进入时 DLL_THREAD_DETACH :线程退出时 在初始化部分写: DLLProc := @DLLEnterPoint; DllEnterPoint(DLL_PROCESS_ATTACH); 2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil); 3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。 四全局变量的使用 在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。 五调用静态载入 1 客户端函数声名: 1)大小写敏感。 2)与DLL中的声明一样。 如:showform(form:Tform);Far;external'yproject_dll.dll'; 3)调用时传过去的参数类型最好也与windows c++一样。 4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径; windows;widows\system;windows\ssystem32; 六调用动态载入 1 建立一种过程类型(或者是一个Function)[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如: type mypointer=procedure(form:Tform);Far;external; //mypointer=function(form:Tform);Far;external; var Hinst:Thandle; showform:mypointer; begin Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。

相关文档
相关文档 最新文档