在DELPHI中静态调用DLL
- 格式:pdf
- 大小:136.83 KB
- 文档页数:16
delphi如何调用C#的dlldelphi如何调用C#的dll发表于2010-03-11 16:37:13 1delphi如何调用C#的dll?在你的环境变量Path中加入C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin;C:\WINNT\\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 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();}/// <summary>/// 显示窗口/// </summary>public void ShchildFrm(){Form1 frm = new Form1();frm.Show();}/// <summary>/// 按钮事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>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, connectionString);SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);DataTable table = new DataTable();table.Locale = System.Globalization.CultureInfo.InvariantCulture;dataAdapter.Fill(table);bindingSource1.DataSource = table;dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);}catch (SqlException){MessageBox.Show("To run this example, replace the value of the " +"connectionString variable with a connection string that is " +"valid for your system.");}}}}右击项目名在属性对话框中更改输出类型为”类库” 在界面点击程序集信息按钮如下图:使程序集com可见必须选中完成dll文件生成二.DotNet 类库打包成COM类型库(在vs命令行执行如下操作)Tlbexp.exe SFrm.dll /out: SFrm.tlb三.注册COM类型库Regasm.exe SFrm.dll四.Delphi导入类型库Delpi 中,Project -> Import Type Library ,选中类型库:dotnet2com.tlb,生成 DotNet2Com_TLB 单元文件。
Delphi如何调用C++写的DLLBOOL WINAPI funname(char *pFileName,char *pID);这是C++写的一个DLL里面的函数我现在想用delphi调用这个函数静态:function funname(var pFileName:pchar;var pID:pchar):integer;stdcall;external 'DLLNAME.dll' name 'funname';动态:OneHandle := LoadLibrary(DLLNAME.dll'); //动态载入DLL,并返回其句柄tryif oneHandle<>0 then@funname:= GetProcAddress(OneHandle,'funname');if not( @funname = nil ) then.....finallyFreeLibrary(OneHandle);现在调试数据不成功是不是传参问题呢还是函数在delphi里调用不对调用应该是成功的哪位高手帮帮忙--------------------------------------------------------------------------------试过了不行滴说--------------------------------------------------------------------------------typeTFun = function(FileName: PChar; ID: PChar): BOOL; stdcall;varFunc: TFunc;beginHandle := LoadLibrary(DLLNAME.dll'); //动态载入DLL,并返回其句柄tryif Handle > 0 thenFunc := GetProcAddress(Handle, 'funname');if Assigned(Func) thenFunc('MyFileName', 'MyID');finallyFreeLibrary(Handle);end--------------------------------------------------------------------------------function funname(pFileName:pchar; pID:pchar):integer; stdcall; external 'DLLNAME.dll' name 'funname';这样试下,一般char *对应的是PChar,而不是var A: PChar--------------------------------------------------------------------------------dll可能不是按照标准顺序调用参数的--------------------------------------------------------------------------------先用vc++做个dll,记得声明函数的时候要_stdcall做前缀,例如:_stdcall int TestC(int i);_stdcall char* add1(char *s);然后将此dll放在delphi程序的目录里,在delphi动态引用此dll 的某函数的时候,要用cdecl做后缀;例如:M:function(i:integer):integer;cdecl;M1:function(i:pChar):pChar;cdecl;--------------------------------------------------------------------------------function funname(pFileName:pchar; pID:pchar):integer; stdcall; external 'DLLNAME.dll' name 'funname';也可以这样试试function funname(pFileName:pchar;var pID:char):integer; stdcall; external 'DLLNAME.dll' name 'funname';--------------------------------------------------------------------------------delphi中的char *是pansichar--------------------------------------------------------------------------------ansean基本把这个问题说清楚了。
[转]Delphi中资源文件的使用在Delphi中,生成一个Appliction工程时,会默认生成一个与工程同名的资源文件,即使删除也会再度创建,但是这个资源文件中只有一个图标和一个版本信息。
通常情况下,我们还需要更多的多种多样的资源,虽然可以在IDE中载入并编译到EXE文件中去,但是有时我们需要将资源与EXE分开,以便生成多语言程序或将程序改为其它语言(如汉化)。
Delphi附带的ImageEdit可以编辑资源文件,但只能编辑位图、图标和光标,无法加入字符串资源,而且只持256色的图像。
为了将更多种类的资源,只有编写资源脚本或者使用其它资源编辑器,如Vis ual Stadio 6。
不过,Visual Stadio 6编辑的资源文件中包含了C++头文件定义,并且支持的具体资源类型较多,在Delphi中是无法识别的。
只好选择编写资源脚本了,资源脚本文件扩展名为.RC,可以用纯文本编辑器编写。
如下面是两个图标与两个字符串的脚本:COMPUTER RCDATA"computer.ico" /* Delphi中只支持RCDATA类型*/WINDOWSXP RCDATA"XP.ico"STRINGTABLEBEGIN1 "computer(电脑)"2 "Windows XP"END将其保存为MyRes.rc,需要注意的是,这里包含了两个图标,注意文件名及路径(这里是与文件同一目录)。
在命令提示符窗口中将目录切换到MyRes.rc所在的路径,运行brcc32 MyRes.rc,其中brcc 32.exe是Delphi附带的资源编译工具。
如果想将资源文件生成其中扩展名的文件(如.DLL),可以增加-fo参数,如:brcc32 MyRes.rc –of MyRes.dll。
接下来是对资源的引用,引用方法有静态与动态两种,静态引用就是将资源文件包含到源码中编译到EXE中去;动态引用则是把资源文件当成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,并且数据集已关闭。
标题:Delphi中使用DLL调用及结构参数传递的方法一、引言在Delphi中,我们经常需要使用动态信息库(DLL)来实现对外部功能的调用。
而在调用DLL时,有时需要传递结构参数,本文将介绍在Delphi中使用DLL进行结构参数传递的方法。
二、调用DLL1. 静态信息和动态信息在Delphi中,我们可以通过静态信息和动态信息两种方式调用DLL。
静态信息是将DLL文件直接嵌入到可执行文件中,而动态信息则是在程序运行时加载DLL文件。
一般来说,动态信息是更为常用的方式。
2. 使用动态信息调用DLL在Delphi中使用动态信息调用DLL,一般需要使用`LoadLibrary`函数加载DLL文件,然后使用`GetProcAddress`函数获取DLL中的函数位置区域,最后通过指针调用DLL函数。
示例代码如下:```delphivarhDLL: THandle; // DLL句柄addFunc: function(a, b: Integer): Integer; stdcall; // DLL函数指针beginhDLL := LoadLibrary('MyDll.dll'); // 加载DLLif hDLL <> 0 thenbegin@addFunc := GetProcAddress(hDLL, 'Add'); // 获取DLL中的Add函数位置区域if Assigned(addFunc) thenbegin// 调用DLL函数Result := addFunc(1, 2);end;FreeLibrary(hDLL); // 释放DLLend;end;```三、结构参数传递在DLL调用中,有时我们需要传递结构参数,即将自定义的结构体作为函数参数传递给DLL中的函数。
下面将介绍在Delphi中如何实现结构参数的传递。
1. 定义结构体我们需要在Delphi中定义需要传递的结构体。
Delphi动态与静态调用DLL(最好的资料)摘要:本文阐述了 Windows 环境下动态链接库的概念和特点,对静态调用和动态调用两种调用方式作出了比较,并给出了 Delphi 中应用动态链接库的实例。
一、动态链接库的概念动态链接库( Dynamic Link Library ,缩写为 DLL )是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。
动态链接库文件的扩展名一般是 dll ,也有可能是 drv 、 sys 和 fon ,它和可执行文件( exe )非常类似,区别在于 DLL 中虽然包含了可执行代码却不能单独执行,而应由 Windows 应用程序直接或间接调用。
动态链接是相对于静态链接而言的。
所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。
换句话说,函数和过程的代码就在程序的 exe 文件中,该文件包含了运行时所需的全部代码。
当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。
而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。
仅当应用程序被装入内存开始运行时,在 Windows 的管理下,才在应用程序与相应的 DLL 之间建立链接关系。
当要执行所调用 DLL 中的函数时,根据链接产生的重定位信息, Windows 才转去执行 DLL 中相应的函数代码。
一般情况下,如果一个应用程序使用了动态链接库, Win32 系统保证内存中只有 DLL 的一份复制品,这是通过内存映射文件实现的。
DLL 首先被调入 Win32 系统的全局堆栈,然后映射到调用这个 DLL 的进程地址空间。
在 Win32 系统中,每个进程拥有自己的 32 位线性地址空间,如果一个 DLL 被多个进程调用,每个进程都会收到该 DLL 的一份映像。
动态链接库是一个能够被应用程序和其它的DLL调用的过程和函数的集合体,它里面包含的是公共代码或资源。
由于DLL代码使用了内存共享技术,在某些地方windows也给了DLL一些更高的权限,因而DLL中可以实现一些一般程序所不能实现的功能,如实现windows的HOOK、ISAPI等。
同时,DLL还为不同语言间代码共享提供了一条方便的途径。
因而DLL在编程时应用较为广泛,本文将介绍如何在 Delphi 中建立和使用DLL。
一.DLL 库内存共享机制从使用效果看,DLL和unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。
如果一个程序模块中用uses语句引用了某个unit,编译程序在编译该模块时,便会连同unit一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用unit中过程和函数的原因。
当同一个unit被多个工程所引用时,则每个工程中都含有该unit 的可执行代码,当含有该unit的多个工程同时执行时,unit的可执行代码会随不同工程而多次被调入内存,造成内存资源的浪费。
DLL则不同,它即使被某个工程调用,编译后仍是独立的,也就是说编译后,一个DLL库形成一个单独的可执行文件,而不与任何其它的可执行文件连接在一起,因而DLL库并不从属于某个特定的工程,当多个工程调用同一个DLL库时只有第一个工程把DLL库调入内存,其余工程并不重复调入同一个DLL库到内存,而是到同一个共享内存区读取。
并且,DLL的执行代码是在程序运行期间动态调入的,而不是如unit在程序运行时就与整个工程一起调入内存。
这样便可消除unit带来的相同代码多处占用内存的弊病。
二 Delphi中DLL库的建立在Delphi环境中,编写一个DLL同编写一个一般的应用程序并没有太大的区别。
事实上作为DLL主体的DLL函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。
Delphi中高级DLL的编写和调用2001年06月14日10:54:38 赛迪网苏涌根据Delphi提供的有关DLL编写和调用的帮助信息,你可以很快完成一般的DLL编写和调用的应用程序。
本文介绍的主题是如何编写和调用能够传递各种参数(包括对象实例)的DLL。
例如,主叫程序传递给DLL一个ADOConnection 对象示例作为参数,DLL中的函数和过程调用通过该对象实例访问数据库。
需要明确一些基本概念。
对于DLL,需要在主程序中包含exports子句,用于向外界提供调用接口,子句中就是一系列函数或过程的名字。
对于主叫方(调用DLL的应用程序或其它的DLL),则需要在调用之前进行外部声明,即external保留字指示的声明。
这些是编写DLL和调用DLL 必须具备的要素。
另外需要了解Object Pascal 中有关调用协议的内容。
在Object Pascal 中,对于过程和函数有以下五种调用协议:指示字参数传递顺序参数清除者参数是否使用寄存器register 自左向右被调例程是pascal 自左向右被调例程否cdecl 自右向左调用者否stdcall 自右向左被调例程否safecall 自右向左被调例程否这里的指示字就是在声明函数或过程时附加在例程标题之后的保留字,默认为register,即是唯一使用CPU寄存器的参数传递方式,也是传递速度最快的方式;pascal: 调用协议仅用于向后兼容,即向旧的版本兼容;cdecl: 多用于C和C++语言编写的例程,也用于需要由调用者清除参数的例程;stdcall: 和safecall主要用于调用W indows API 函数;其中safecall还用于双重接口。
在本例中,将使用调用协议cdecl ,因为被调用的DLL中,使用的数据库连接是由主叫方传递得到的,并且需要由主叫方处理连接的关闭和销毁。
下面是DLL完整源程序和主叫程序完整源程序。
包括以下四个文件:Project1.DPR {主叫程序}Unit1.PAS {主叫程序单元}Project2.DPR {DLL}Unit2.PAS {DLL单元}{---------- DLL 主程序Project2.DPR ----------}library Project2;usesSysUtils,Classes,Unit2 in 'Unit2.pas' {Form1};{$R *.RES}{ 下面的语句用于向调用该DLL的程序提供调用接口}exportsDoTest; { 过程来自单元Unit2 }beginend.{---------- DLL中的单元Unit2.PAS ----------}unit Unit2;interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Db, ADODB, StdCtrls, Menus;typeTForm1 = class(TForm)ADOConnection1: TA DOConnection;{ 本地数据库连接}Memo1: TMemo; { 用于显示信息}privatepublicend;{ 该过程向外提供}procedure DoTest(H: THandle; { 获得调用者的句柄}A Conn: TADOConnection;{ 获得调用者的数据库连接}S: string; { 获得一些文本信息}N: Integer); { 获得一些数值信息}cdecl; { 指定调用协议}implementation{$R *.DFM}procedure DoTest(H: THandle; AConn: TA DOConnection; S: string; N: Integer); beginApplication.Handle := H; { 将过程的句柄赋值为调用者的句柄}{ 上面语句的作用在于,DLL的句柄和调用者的句柄相同,在任务栏中就不会} { 各自出现一个任务标题了。
Delphi7 调用C 的DLL的问题DLL的接口函数是这样定义的int ykt_readopencardinfo_local (char *pRegion, char *pDeptid,char *pDeptKey, char *pIssuedept id,char *pIssuedate, char *pCardtype,char *pCardno,char *pIdtype,char *pId,char *pName, char *pSex,char *pBirthDate,char *pCompany,char *pAddress,char *pTelephone, char *pWarnmsg,ch ar *pErrmsg)。
Delphi程序:声明:function ykt_readopencardinfo_local(pRegion: string; pDeptid: string; pDeptKey: string; var pIssu edeptid: PChar; var pIssuedate: PChar; var pCardtype: PChar; var pCardno: PChar;var pIdtype: PChar; var pId: PChar; var pName: PChar; var pSex: PChar; var pBirthDate: PChar; v ar pCompany: PChar; var pAddress: PChar; var pTelephone: PChar; var pWarnmsg: PChar; var pErr msg: PChar): Integer; stdcall; external 'fzyktclient.dll';调用:pstr8:=StrAlloc(49);pstr9:=StrAlloc(17);pstr10:=StrAlloc(11);pstr11:=StrAlloc(41);pstr12:=StrAlloc(11);pstr13:=StrAlloc(49);pstr14:=StrAlloc(25);pstr15:=StrAlloc(11);pstr16:=StrAlloc(17);pstr17:=StrAlloc(121);pstr18:=StrAlloc(49);pstr19:=StrAlloc(49);pstr20:=StrAlloc(1051);pstr21:=StrAlloc(1051);retCode:=ykt_readopencardinfo_local(ls_Region, ls_DeptID, ls_DeptKey,pstr8, pstr9, pstr10, pstr11, pstr12, pstr13, pstr14, pstr15, pstr16, pstr17,pstr18, pstr19,pstr20, pstr21);Showmessage(strpas(pstr13)); //出错strCopy(@buf_pId, @pstr13); //其中 var buf_pId: array[0..48] of Char;Edit4.Text := buf_pId; //字符错位,比如返回结果应该是 pstr8='12345' pstr9='abcde',但返回的结果是 pstr9='12345 abcde' pstr8='5 abcde'比pstr9少前面四个字符。
一、开始你的第一个DLL专案1.File->Close all->File->New﹝DLL﹞代码://自动产生Code如下library Project2;//这有段废话usesSysUtils,Classes;{$R*.RES}beginend.2.加个Function进来:代码:library Project2;usesSysUtils,Classes;Function MyMax(X,Y:integer):integer;stdcall; beginif X>Y thenResult:=XelseResult:=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}beginend.3.将这些可共享的Func送出DLL,让外界﹝就是你的Delphi-AP啦﹞使用:光如此,你的AP还不能用到这些,你还要加个Exports才行。
代码:{$R*.RES}exportsMyMax;beginend.二、进行测试:开个新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的动态链接库。
现在,让我们来看看有哪些需要注意的地方:1.在DLL中编写的函数或过程都必须加上stdcall调用参数。
在Delphi1或Delphi2环境下该调用参数是far。
从Delphi3以后将这个参数变为了stdcall,目的是为了使用标准的Win32参数传递技术来代替优化的register参数。
忘记使用stdcall参数是常见的错误,这个错误不会影响DLL的编译和生成,但当调用这个DLL时会发生很严重的错误,导致操作系统的死锁。
原因是register参数是Delphi的默认参数。
2.所写的函数和过程应该用exports语句声明为外部函数。
正如大家看到的,TestDll函数被声明为一个外部函数。
这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(Quick View)”功能查看该DLL文件。
(如果没有“快速查看”选项可以从Windows CD上安装。
)TestDll 函数会出现在Export Table栏中。
另一个很充分的理由是,如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。
3.当使用了长字符串类型的参数、变量时要引用ShareMem。
Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但Delphi中string类型在默认情况下长度可以达到2G。
(对,您没有看错,确实是两兆。
)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用ShareMem单元,而且必须是第一个引用的。
既在uses语句后是第一个引用的单元。
如下例:usesShareMem,SysUtils,Classes;还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。
不这样做的话,您很有可能付出死机的代价。
避免使用string类型的方法是将string类型的参数、变量等声明为Pchar或ShortString(如:s:string[10])类型。
同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。
在Delphi中静态调用DLL调用一个DLL比写一个DLL要容易一些。
首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。
同样的,我们先举一个静态调用的例子。
unit Unit1;interfaceusesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls;typeTForm1=class(TForm)Edit1:TEdit;Button1:TButton;procedure Button1Click(Sender:TObject);private{Private declarations}public{Public declarations}end;varForm1:TForm1;implementation{$R*.DFM}//本行以下代码为我们真正动手写的代码function TestDll(i:integer):integer;stdcall;external’Delphi.dll’;procedure TForm1.Button1Click(Sender:TObject);beginEdit1.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不能被调用程序使用,既不能作为全局变量传递给调用程序。
不过在调用程序中声明的变量可以作为参数传递给DLL。
四、被调用的DLL必须存在这一点很重要,使用静态调用方法时要求所调用的DLL文件以及要调用的函数或过程等等必须存在。
如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。
在Delphi中动态调用DLL top动态调用DLL相对复杂很多,但非常灵活。
为了全面的说明该问题,这次我们举一个调用由C++编写的DLL的例子。
首先在C++中编译下面的DLL源程序。
#includeextern”C”_declspec(dllexport)int WINAPI TestC(int i){return i;}编译后生成一个DLL文件,在这里我们称该文件为Cpp.dll,该DLL中只有一个返回整数类型的函数TestC。
为了方便说明,我们仍然引用上面的调用程序,只是将原来的Button1Click过程中的语句用下面的代码替换掉了。
procedure TForm1.Button1Click(Sender:TObject);typeTIntFunc=function(i:integer):integer;stdcall;varTh:Thandle;Tf:TIntFunc;Tp:TFarProc;beginTh:=LoadLibrary(’Cpp.dll’);{装载DLL}if Th>0thentryTp:=GetProcAddress(Th,PChar(’TestC’));if Tp<>nilthen beginTf:=TIntFunc(Tp);Edit1.Text:=IntToStr(Tf(1));{调用TestC函数}endelseShowMessage(‘TestC函数没有找到’);finallyFreeLibrary(Th);{释放DLL}endelseShowMessage(‘Cpp.dll没有找到’);end;大家已经看到了,这种动态调用技术很复杂,但只要修改参数,如修改LoadLibrary(‘Cpp.dll’)中的DLL名称为’Delphi.dll’就可动态更改所调用的DLL。
一、定义所要调用的函数或过程的类型在上面的代码中我们定义了一个TIntFunc类型,这是对应我们将要调用的函数TestC的。
在其他调用情况下也要做同样的定义工作。
并且也要加上stdcall 调用参数。
二、释放所调用的DLL我们用LoadLibrary动态的调用了一个DLL,但要记住必须在使用完后手动地用FreeLibrary将该DLL释放掉,否则该DLL将一直占用内存直到您退出Windows或关机为止。