dll传递string实现方法
delphi中dll传递string的实现方法:
dll项目uses第一个引用sharemem单元;
调用的项目uses第一个引用sharemem单元;
调用的单元uses第一个引用sharemem单元;
**************************************************************
delphi中dll传递string的实现方法:
dll项目uses第一个引用sharemem单元;
调用的项目uses第一个引用sharemem单元;
调用的单元uses第一个引用sharemem单元;
**************************************************************
最好是不要使用 string作Dll参数或返回值,用Pchar更好兼容非Delphi语言编程
Delphi写DLL要注意的问题
a. 参数和返回值为string、动态数组类型时,DLL和EXE都要把ShareMem作为.dpr工程的第一个单元引用。当然最好是不要使用 string、动态数组类型,可以改用PChar、数组指针类型,如果是混合语言编程使用的话,就一定不能用string、动态数组类型。这样做的原因是 DLL和EXE的内存管理器(MemoryManager)不是一个,而string、动态数组类型是通过引用计数由Delphi自动进行内存管理的,它 何时分配何时释放,我们不能显式的知道的,DLL分配而EXE释放的话,这样就出问题了。用ShareMem就是为了让它们统一使用一个内存管理器进行内 存分配释放。 关于DLL和EXE内存管理器不同这一点,非常重要! b.DLL和EXE的VCL类体系不是一个,它们各自有一套,因此,从EXE传递过去的对象,要在DLL中用is判断类型和as作类型转换,那都不能得到期望的结果。 如果是bpl,就不会有这个问题 c.DLL中应用ADO、窗体(模态、非模态、MDI子窗体)、线程等的一些相关问题与今天的主题关系不大,就不作多讲了。参考DLL的详细论述请参考《Windows核心编程》第19、20章。
对使用Delphi制作DLL复用文件的建议在公司里有一些需要制作DLL的场合,因为熟悉、方便和简易,大多数使用Delphi来制作。现在就这个主题提出一些个人建议。
尽 量使用标准DLL接口。指的是传递的参数类型及函数返回类型不能是Delphi特有的,比如string(AnsiString),以及动态数组和含有这 些类型成员的复合类型(如记录),也不能是包含有这些类型成员数据成员的对象类型,以避免可能的错误。如果使用了string类型或动态数组类型,且调用 方不是Delphi程序,则基本上会报错。如果调用方是Delphi但调用方或被调用方没有在工程文件的第一包含单元不是ShareMem,也可能会出 错。
如果调用方是Delphi应用程序,则可能可以使用不包含禁止类型(string, 动态数组)数据成员的对象作为参数或返回值,但也应尽量避免。
如果调用方与被调用方都是Delphi程序,而且要使用string或动态数组作参数,则双方工程文件的第一包含单元必须是ShareMem。(C++Builder程序的情况可能与此相同,不过没有测试过。)
如果调用方不是Delphi程序,则string、动态数组、包含string或动态数组的复合数据类型及类实例,都不能作为参数及返回值。
因此,为了提高DLL的复用范围,避免可能存在的错误,应当使用标准WIN32 API标准参数类型,以前使用string的变量,可以使用PChar(s)转换。动态数组则转换为指针类型(@array[0]),并加上数组的长度。
如果因为调用方与被调用方都是Delphi程序,为了编写方便,不想进行上述转换,则推荐使用运行时包的形式。运行时包可以保证动态分配数据的正确释放。这样因为其扩展名(.bpl),显出该文件仅限于Delphi/C++Builder使用(不象DLL)。
其 次,尽量避免使用overload的函数/过程作输出,如果同一操作有多个方式,则可以让函数/过程名有少许差别,类似于Delphi中的 FormatXXXX、CreateXXXX等函数及方法,如CreateByDefaultFile, CreateDefault。
最 后,作为DLL的提供者,应当提供直接编程的接口文件,如Delphi中的.pas或.dcu(最好是.pas,因为可以有注释)、C及C++中的.h 和.lib。而不是让使用者们自己创建。如果非要有overload的函数/过程,这一点显得特别重要。另外,作为Delphi应用,提供的.pas文件 可以是提前连接的(使用external指定DLL中的输出函数),也可以是后期连接的(使用LoadLibrary、 GetProcAddress),DLL提供者提供编程接口文件,既显得正式(或HiQoS),又有保障。
delphi DLL中如何传递string参数
Function IntToBin(N:Int64;L:Byte):Pchar;stdcall; var i: Int64 ; j: Byte ; str1:string; begin Result:=‘‘;str1:=‘‘; i:= N ; for j:=1 to L do begin str1:=str1+Chr(i mod 256 ); i:=i div 256 ; end ; result:=Pchar(str1);//在应用程序中调用时返回值出错 end;
原函数是
Function IntToBin(N:Int64;L:Byte):String; var i: Int64 ; j: Byte ; str1:string; begin Result:=‘‘;str1:=‘‘; i:= N ; for j:=1 to L do begin str1:=str1+Chr(i mod 256 ); i:=i div 256 ; end ; result:=str1; end;
1.不用引用ShareMem
2.全部用shortstring类型
3.如果能够,尽量不要用string回传参数,可以用integer代替(事先协议)
PChar可以,你就
var MyProc=procedure(str: pchar);stdCall; //这样就行了
Delphi DLL 字符串传递例子
library EN; uses SysUtils, Classes, UnitFormEN in ‘UnitFormEN.pas‘ {FormEN}; {$R *.res} function GetJobType(p: PChar): Boolean; stdcall; var str: string; begin str := ‘我们是中国人,我们爱自己的祖国.‘; StrCopy(p, PChar(str)); Result := Length(p) > Length(str); end; function GetRates(p: PChar): Boolean; stdcall; var str: string; begin str := ‘我爱北京*.‘; StrCopy(p, PChar(str)); Result := Length(p) > Length(str); end; exports GetJobType, GetRates, ShowFormEN; begin end.
Dll中传送Pchar类型
procedure GetMsg(ret:Integer;Msg:PChar);stdcall; begin StrPCopy(Msg,‘OK‘); end; var P:Pchar; begin P:=stralloc(1024); GetMsg(100,P); showmessage(P); strdispose(P); end;
dll传进传出字符串
需要别人的封装的dll,我想把封装的函数做一个dll在pb中调用,写的dll函数中需要传入传出字符串,我是用的pchar
函数如下:
function p_string(var s:pchar):pchar;stdcall; begin s := ‘123‘; Result := s; end; exports p_string;
做好dll后,在delphi中调用没有问题,返回的值也是正确的,delphi调用如下
unit csstring; 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; function p_string(var s:pchar):pchar;stdcall;external ‘hljms.dll‘; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var a,b:pchar; begin b := p_string(a); showmessage(b+‘,‘+a);//返回b=‘123‘,a=‘123‘ end; end.
我在pb中声明
function string p_string(ref string s) library ‘hljms.dll‘
调用如下
string s,ls_return
s = space(10)
ls_return = p_string(s)
messagebox(‘‘,s+‘,‘+ls_return)
返回是:ls_return = ‘123‘,s = ‘?? ‘
我该如何处理,传入的问题已经解决,由于pb中没有指针,pchar代表指针类型,传入字符串,使用指针取值即可!可传出的怎么处理?
这个问题实际还是 dll 中的导出函数在使用指针做参数的时候,谁来分配空间的问题。
通常的做法是,在exe中分配空间,然后将指针传递给dll导出的函数,在函数里使用空间,然后返回。
dll:
function func1(buff: PChar; var bufflen: Cardinal): Cardinal; stdcall; begin strncpy(buff, ‘this is a test!‘, bufflen); bufflen := strlen(buff); Result := bufflen; end; exe: var pbuff : PChar; len, ret : Cardinal; begin len := 1024; pbuff := AllocMem(len); ret := func1(pbuff, len); ShowMessage(pubff); FreeMem(pbuff); end;
我不熟悉 pb,不知道 string 是怎样定义的数据类型。如果 pb 支持字符数组的话,可以用字符数组试试。
dll用Pchar返回数据的问题
因为有可能被其它语言调用,所以想用Pchar来返回一些值,现在dll函数定义如下: function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall; 然后我用delphi写了个小程序调用, Retcode : PChar; iPort : integer; sn,ID,No,PCode:Pchar; begin iCommPort := cmbComm1.ItemIndex +1; Retcode := ReadInfo_HF(iPort,SN,ID,No,PCode); 这样调用取出来的Pchar的值不对,经常改变,这个dll应该如何定义呢,程序又改如何调用呢
Retcode : String; // 必须改 PChar; tmpchar:pchar; iPort : integer; sn,ID,No,PCode:Pchar; begin iCommPort := cmbComm1.ItemIndex +1; setlength(Retcode,1024);// 尽量大 tmpchar:=@Retcode[1]; tmpchar := ReadCardInfo_HF(iPort,SN,ID,No,PCode); setlength(Retcode,pos(#0,Retcode));
PChar 实际是是一个指针,最好是加个返回长度,返回长度是不定的,只有dll里面才能确定,应该怎么加呢?
其实你按照 wql 的方法就可以做了的. var Retcode : String; iPort : integer; sn,ID,No,PCode,tmpchar:Pchar; begin iCommPort := cmbComm1.ItemIndex +1; GetMem(TmpChar,1024); // 设定好 sn,id,no,pcode 的值 TmpChar:= ReadCardInfo_HF(iPort,SN,ID,No,PCode); Retcode:=StrPas(TmpChar); freemem(TmpChar,1024); end;
Delphi例子: function Test_GetXML( const XML : PChar; const XMLLen : Integer ):Integer;stdcall; var s : string; l : integer; begin s := ‘..........................‘;//获取值 Result := Length(s); //值长度 l := Result; if xmllen < l then l := xmllen; //处理分配长度不够的情况 ZeroMemory(XML, XMLLen); CopyMemory(XML, @s[1], l); //写入调用者分配的内存 end; C#调用声明: public class Dll_Test { private const string Dll_FileName = @"D:\Test.dll"; [DllImport(Dll_FileName)] public static extern int Test_GetXML( StringBuilder XML, //输出参数,XML文档内容,请分配足够的空间 int XMLLen //上面分配空间大小 ); //返回XML文档大小 } C#调用: StringBuilder s = new StringBuilder(5000); Dll_Test.Test_GetXML( s, s.Capacity ); textbox.Text = s.ToString(); 内存管理原则:谁分配的空间谁释放 你返回PChar的话,是DLL分配的内存,应该DLL释放,而调用者不知道DLL什么时候会释放,容易出错,特别在跨语言调用的情况下 所以参考WINAPI的约定写代码就行了
//DLL function ReadInfo(iPort:Integer;SN,ID,No,PCode:Pchar):integer;stdcall; begin StrCopy (SN,PChar(‘1‘)); StrCopy(ID,PChar(‘2‘)); StrCopy(No,PChar(‘3‘)); end; //调用 var //使用静态分配内存的方式 vSN,vID,vNo:array[0..255] of char;//视具体情况分配内存 begin FillChar(vSN,255,#0); FillChar(vID,255,#0); FillChar(vNo,255,#0); ReadInfo(1,vSN,vID,vNo);//vSN,vID,vNo就可以得到返回值了 end; 或者 用动态分配内存的方式 var vSN,vID,vNo:PChar; begin GetMem(vSN,255); GetMem(vID,255); GetMem(vNo,255); ReadInfo(1,vSN,vID,vNo);//vSN,vID,vNo就可以得到返回值了 FreeMem(vSN); FreeMem(vID); FreeMem(vNo); end;
function ReadInfo(iPort:Integer; SN,ID,No,PCode:Pchar):Pchar;stdcall; 或者可以使用 function ReadInfo(iPort:Integer;SN,ID,No,PCode:WideString):WideString;stdcall; 由于返回值都是指针类型的数据。 只要传入的数据指针不为空,而且大小符合,就没有问题。 建议使用WideString,因为PChar在别的语言里调用有时候会有问题,而WideString是Windows的标准数据类型。
要分两种情况,主要是看谁分配内存。 第一种情况,DLL分配内存。这是针对 zhhg975 同学的。 函数定义不用改变,下面这样就可以,要改变的是它的实现 function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall; begin //1 分别分配内存 //2 将分配的内存分别赋给SN,ID,No,PCode //如 sn := pchar(AllocMem(Size)); //返回值也一样 result := pchar(AllocMem(Size)); //当然对SN[x]的赋值是必须的,否则总变化 end; 第二种情况,调用程序分配内存,这时DLL中直接使用就可以了,不用再分配了。 注意,最好把关键字var去掉。当然返回值还是要分配内存的 function ReadInfo(iPort:Integer;SN,ID,No,PCode:Pchar):Pchar;stdcall; begin //sn[x] := ....; //result := pchar(AllocMem(Size)); //... end; 按照个人的用途可选用不同的内存分配函数。
Delphi调用Dll动态链接库,参数问题
我有个C++写的动态链接库,导出方式用extern "C" CString _declspec(dllexport)funname
在Delphi中调用时,当我像函数传入参数时就会报错,后来发现Dll中函数参数类型为CString的
请问:在Delphi中对应VC++的CString的是什么?PChar我也试过了,不行
但Dll中有些函数的返回值也是用CString的,我直接可以用showmessage弹出信息,不会报错,
以上,请帮忙解决
d中没有对应cstring的类,pchar不行,pchar是d的基本类型,c++在dll中使用cstring作为参数或返回值并不合适,需要做特殊的处理,可以考虑使用char*或lpstr替代
DELPHI代码一般都用pchar交互,并且用stdcall作参数传递约定
C++的DLL要用char*作参数
如果C++的dll你能修改,那就改成Char*吧,如果你改不了,那么,因为CString是VC特有的数据类型,所以Delphi无法与之交互。
就像如果Delphi导出一个返回值是TStringList的函数,C++没法接收一样。
例如:
SendRcv2: function(cBegin: Pchar; SendMess: Pchar; ReturnMess: Pchar): PChar; stdcall; RMess := Sendrcv2(‘12345678‘, Pchar(Value), pchar(sReturnStr)); 。。。。。。 constructor TShy.Create(Value, sfdm: string); var h: Integer; begin inherited create; h := LoadLibrary(‘SendRcv2.dll‘); if h <> 0 then begin @SendRcv2 := GetProcAddress(h, ‘SendRcv2‘); if @SendRcv2 = nil then begin // error end; end else begin // error end; end;
修改了下C++ 用char*代替了
delphi 将Dll等生成资源文件
资源文件一般为扩展名为res的文件,其自带的资源编译工具BRCC32.EXE(位于/Delphi/BIN目录下)
1.编写rc脚本文本
用记事本或其它文本编辑器编写一个扩展名为rc的文件,格式分别为在资源文件中的名称->类型->实际文件名称。
例如:要将文件名 demo.Dll的文件打包成一个资源文件,首先 新建一个文本文档,输入内容
mydemoDll RCDATA demo.DLL
mydemoDll 和 RCDATA 你可以随便写,这个是为了在使用资源时定义的名称和类型你也可以写成:a b demo.DLL
将文本保存,保存后将文本的后缀(.txt)改成(.rc)
2.将rc文件编译成res资源文件
将脚本文件和实际文件拷到Brcc32.EXE所在目录,执行DOS命令。格式为:Brcc32 脚本文件(回车),
例如:
将上面的Mydll.rc和demo.Dll拷到Brcc32.EXE所在目录,执行 Brcc32 Mydll.rc(回车)即可。如果编译成功,则会生成一个Mydll.res的文件,这个文件就是我们需要的资源文件。
3.在Delphi单元中加入资源文件
将生成的res资源文件拷贝到你所编程序的路径下,在单元文件{$R *DFM}后加上一句{$R Mydll.res},则将res文件加入去,编译后资 源文件即已包含在可执行文件中了。若你有多个资源文件,也按上法依次加入。/
4.在Delphi程序中调用资源文件(也可以在EXE中运行资源文件,如在EXE中直接运行另外一个EXE,或者调用DLL等,篇幅原因就不写了)
//D7下编辑
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; implementation {$R *.dfm} {$R mydll.RES} //释放资源文件到指定文件夹,参数1:资源名称 参数2 资源类型,参数3:存放目录 function ExtractRes(ResName,ResType, ResNewName: string): boolean; var Res: TResourceStream; begin try Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); try Res.SavetoFile(ResNewName); Result := true; finally Res.Free; end; except Result := false; end; end; procedure TForm1.Button1Click(Sender: TObject); begin ExtractRes(‘mydemoDll‘,‘RCDATA‘,‘d:/aaa.dll‘); end;
调用dll窗体
1.首先用delphi建一个dll工程:
library Project2; uses SysUtils, Classes, Unit1 in ‘Unit1.pas‘ {Form1}; //dll中的窗体为Form1 procedure ShowTest();stdcall; //dll函数 用于显示窗体 var f:TForm1; begin f:=TForm1.Create(nil); try f.ShowModal; finally f.Free; end; end; {$R *.res} exports ShowTest; //外部调用函数 begin end.
2.新建Form1窗体,窗体为空窗体--》Unit1.pas。
unit Unit1; interface uses Windows, SysUtils, Controls, Forms; type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} end.
3. CTRL+F9编译dll。 编译成功,并生成Project2.dll
4.新建工程,Project1. 采用动态调用dll方式:
unit Unit_main; interface uses Windows, SysUtils, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); type mypointer=Procedure();stdcall; var Handle:THandle; frm_p:mypointer; begin Handle:=loadlibrary(‘Project2.dll‘); if Handle>32 then begin frm_p:=GetProcAddress(Handle,‘ShowTest‘); if @frm_p<>nil then frm_p; end; Freelibrary(Handle); end; end.
5. 修改Project1.dpr文件,加上Sharemem:
Sharemem已经说的很清楚了,如果的导出函数中参数或返回值有string类型,那么就需要引用ShareMem
至于你dll内部使用string类型跟引不引用ShareMem没关系,ShareMem只是解决dll中直接与外界
发生交互的string变量内存管理问题,比如何时释放啊该不该释放
uses Sharemem ,Forms, Unit_main in ‘Unit_main.pas‘ {Form1};
6. 运行Project1,点击Button1,实现调用出dll窗体。
Delphi中DLL的其他应用
1.DLL的入口函数和出口函数
在编写DLL时可以在DLL项目文件的begin..end之间加入DLL的进入口函数和出口函数,全局变量DLLProc是一个过程指针,指定入口/出口函数,初始值为nil,只需将自己的出入口函数赋值给它即可,自己的出入口函数必须传入一个DWord类型的参数。一下是出入口函数事件对应的用途。 DLL_PROCESS_ATTACH 在进程启动或调用LoadLibrary( )时,DLL映射到当前进程的地址空间。在这个事件期间,D L L初始化实例数据 DLL_PROCESS_DETACH DLL正从进程的地址空间分离出来,这也许是进程本身退出或调用了FreeLibrary( )。在该事件里,D L L也许没有初始化任何实例。 DLL_THREAD_ATTACH 进程创建了一个新线程。这时,系统会调用所有和这个进程相关联的DLL入口函数。这个调用在新线程的环境中进行,用于分配线程特定的数据 DLL_THREAD_DETACH 一个线程正在退出。在该事件里,DLL将释放线程特定的初始化数据 警告 调用TerminateThread()非正常终止线程时,没有调用DLL_THREAD_DETACH。
2.DLL中使用回调函数
回调函数一般被Win32DLL或其他DLL调用,而不是由应用程序调用。当调用回调函数时传递函数的地址。在DLL可以定义一种回调函数类型,然后将其做为导出函数的参数,实际应用程序调用DLL时需自己实现该回调函数类型,并传递实际类型参数。
案例一。
打开delphi新建一个dll,源码如下:
library DLLEntry; uses SysUtils, Windows, Dialogs, Classes; {$R *.res} procedure DLLEntryPoint(dwReason:DWord); //入出口函数 begin case dwReason of DLL_Process_Attach:showmessage(‘Attaching to process‘); DLL_PROCESS_DETACH:Showmessage(‘Detaching from process‘); DLL_THREAD_ATTACH:MessageBeep(0); DLL_THREAD_DETACH:MessageBeep(0); end; end; begin DllProc:=@DLLEntryPoint; //赋值给全局变量 DLLEntryPoint(DLL_PROCESS_ATTACH); //传DWord类型值 end.
调用dll,新建一个Delphi应用程序,在窗体上放置一个label和4个button控件。源码如下:
unit mainFrm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TTestThread=class(TThread) //定义线程 procedure Execute;override; procedure SetCaptionData; end; TmainForm = class(TForm) btnLoadLib: TButton; btnFreeLib: TButton; btnCreateThread: TButton; btnFreeThread: TButton; lblCount: TLabel; procedure btnLoadLibClick(Sender: TObject); procedure btnFreeLibClick(Sender: TObject); procedure btnCreateThreadClick(Sender: TObject); procedure btnFreeThreadClick(Sender: TObject); procedure FormCreate(Sender: TObject); private LibHandle:THandle; TestThread:TTestThread; Counter:Integer; GoThread:Boolean; public { Public declarations } end; var mainForm: TmainForm; implementation {$R *.dfm} procedure TTestThread.Execute(); //重写线程的Execute方法 begin while mainForm.GoThread do begin Synchronize(SetCaptionData); Inc(mainForm.Counter); end; end; procedure TTestThread.SetCaptionData; //线程的异步方法修改label控件的caption begin mainForm.lblCount.Caption:=IntToStr(mainForm.Counter); end; procedure TmainForm.btnLoadLibClick(Sender: TObject); //载入dll begin if LibHandle=0 then begin LibHandle:=LoadLibrary(‘DLLEntry.dll‘); if LibHandle=0 then raise Exception.Create(‘Unable to Load DLL‘); end else MessageDlg(‘Library already loaded‘,mtWarning,[mbOK],0); end; procedure TmainForm.btnFreeLibClick(Sender: TObject); //释放dll begin if not (LibHandle=0) then begin FreeLibrary(LibHandle); LibHandle:=0; end; end; procedure TmainForm.btnCreateThreadClick(Sender: TObject); //开启线程 begin if TestThread=nil then begin GoThread:=True; TestThread:=TTestThread.Create(False); end; end; procedure TmainForm.btnFreeThreadClick(Sender: TObject); //释放线程 begin if Assigned(TestThread) then begin GoThread:=False; TestThread.Free; TestThread:=nil; Counter:=0; end; end; procedure TmainForm.FormCreate(Sender: TObject); //初始化操作 begin LibHandle:=0; TestThread:=nil; end; end.
新建一个dll,源码如下:
library StrSrchLib; uses SysUtils, Windows; {$R *.res} type TFoundStrProc=procedure (StrPos:PChar);stdcall; //定义过程类型 function SearchStr(ASrcStr,ASearchStr:PChar;AProc:TFarProc):Integer;stdcall; //字符串查找功能 var FindStr:PChar; begin FindStr:=ASrcStr; FindStr:=StrPos(FindStr,ASearchStr); //查找ASearchStr在FindStr中出现位置 while FindStr<>nil do begin if AProc<>nil then TFoundStrProc(AProc)(FindStr); //强制类型转换,将FindStr作为参数 FindStr:=FindStr+1; FindStr:=StrPos(FindStr,ASearchStr); //循环查找 end; end; exports SearchStr; begin end.
新建Delphi应用程序,在窗体上放置一个edit 一个memo和一个button控件,源代码如下:
unit CallTest; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMainForm = class(TForm) btnCallDLLFunc: TButton; lblSrchWrd: TLabel; mmoStr: TMemo; edtSearchStr: TEdit; procedure btnCallDLLFuncClick(Sender: TObject); end; var MainForm: TMainForm; count:integer; //全局计数变量 implementation {$R *.dfm} function SearchStr(ASrcStr,ASearchStr:PChar;AProc:TFarProc):Integer;stdcall;external ‘StrSrchLib.dll‘; //声明导入函数 procedure StrPosProc(AStrPsn:PChar);stdcall; //具体的回调函数类型 begin inc(count); end; procedure TMainForm.btnCallDLLFuncClick(Sender: TObject); var s,s2:string; begin count:=0; SetLength(s,mmoStr.GetTextLen); mmoStr.GetTextBuf(PChar(s),mmoStr.GetTextLen); //这两句功能是将memo控件内容赋值给s字符串 s2:=edtSearchStr.Text; SearchStr(PChar(s),PChar(s2),@StrPosProc); ShowMessageFmt(‘%s %s %d %s‘,[edtSearchStr.Text,‘occurs‘,count,‘times.‘]); end; end.
DLL还有其他许多功能,在此不在一一列举,源码参考了delphi5编程指南,在Delphi7下编译运行通过,关于DLL还需在项目中更多应用才可熟能生巧。
DLL文件的加载
最好把DLL文件放到Delphi安装目录下Lib或Imports下
1.Tool菜单下Library标签——>LibraryPathxx下,浏览找到DLL文件所在在文件夹(GDI+为例),
——>add,GUI+这个路径回显示到上面的对话框中,确定安装OK!
特别声明:GDI下的包不只是DLL文件还有一些GDIPAPI.dcu、GDIPAPI.das、GDIPOBJ.pas、
GDIPOBJ.dcu、GDIPUTIL.pas、DirectDraw.pas.DirectX.inc、Jedi.inc、DerectDraw.dcu
画圆就可以了:
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; implementation uses GDIPAPI,GDIPOBJ; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var g: TGPGraphics; p: TGPPen; begin g := TGPGraphics.Create(Canvas.Handle); p := TGPPen.Create(aclRed, 2); {参数1颜色; 参数2是笔宽, 笔宽是可选, 默认 1} g.DrawEllipse(p, 11, 11, 222, 111); p.Free; g.Free; end; end.
dll函数
type TDllFun = function (TestStr: PChar; Len: Integer): Integer; procedure TForm1.Button2Click(Sender: TObject); var GetStr: TDllFun; Dllhandle: HMODULE; TestStr: PChar; begin Dllhandle := LoadLibrary(‘Project2.dll‘); if Dllhandle <> 0 then begin try GetStr := GetProcAddress(Dllhandle, ‘GetStr‘); GetMem(TestStr, 100); //字符串长度,自己设置 GetStr(TestStr, 100); //使用 ShowMessage(TestStr); FreeMem(TestStr); finally FreeLibrary(Dllhandle); end; end; end;