delphi dll调用问题

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;
View Code

原函数是

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;
View Code

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.
View Code

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;
View Code

dll传进传出字符串

需要别人的封装的dll,我想把封装的函数做一个dll在pb中调用,写的dll函数中需要传入传出字符串,我是用的pchar
函数如下:

function p_string(var s:pchar):pchar;stdcall;
begin 
s := '123';
Result := s;

end;

exports p_string;
View Code

做好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.
View Code

我在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;
View Code

我不熟悉 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应该如何定义呢,程序又改如何调用呢
View Code
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));
View Code

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;
View Code
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的约定写代码就行了
View Code
//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;
View Code
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的标准数据类型。
View Code
要分两种情况,主要是看谁分配内存。

第一种情况,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;

按照个人的用途可选用不同的内存分配函数。
View Code

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;
View Code

修改了下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;
View Code

调用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.
View Code

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.
View Code

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.
View Code

5. 修改Project1.dpr文件,加上Sharemem:
Sharemem已经说的很清楚了,如果的导出函数中参数或返回值有string类型,那么就需要引用ShareMem
至于你dll内部使用string类型跟引不引用ShareMem没关系,ShareMem只是解决dll中直接与外界
发生交互的string变量内存管理问题,比如何时释放啊该不该释放

uses
Sharemem ,Forms,
Unit_main in 'Unit_main.pas' {Form1};
View Code

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。
View Code

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.
View Code

调用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.
View Code

新建一个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.
View Code

新建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.
View Code

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.
View Code

 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;
View Code

猜你喜欢

转载自www.cnblogs.com/blogpro/p/11344465.html