在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一 Dll的制作一般步骤
在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:
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;
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
library Project2; uses SysUtils, 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, ShowCCC; 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 ShowCCC;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与其他语言的混合编程中常遇问题: 开始处写:CoInitialize(nil); PChar的内存分配和释放在调用函数处理:GetMem(p, Size);FreeMem(p); procedure CommonDLL(AHnd: THandle; //AApp: TApplication; ADllFileName: PChar; AConnStr: PChar; AUserID: integer; ABillTypeID: integer); var LPtr:PLongint; strCon: widestring; 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; DLL_PROCESS_DETACH: begin Application.Handle := OldHnd; // OldApp := GApplication; OldScr := GScreen; end; end; end; begin DllProc := @InitDll; InitDll(DLL_PROCESS_ATTACH); end.
现在,让我们来看看有哪些需要注意的地方。 一、在DLL中编写的函数或过程都必须加上stdcall调用参数。 二、所写的函数和过程应该用exports语句声明为外部函数。
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.
一、调用参数用stdcall。
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。 静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些; 但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。 动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程; 但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,笔者建议您使用静态方法,待熟练后再使用动态调用方法。
(* for CWindows 3.1 *) unit Ime31; interface uses SysUtils, WinTypes, WinProcs, Dialogs; 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): boolean;far; external ’winnls.dll’; (* end 呼叫 winnls.dll export 函数的宣告 *) (* -------------------------------------------------- *) (* SetIme(const sImeFileName: string): boolean; (* ====== (* 切换到某一特定的输入法 (* (* 传入引数: (* sImeFileName: 输入法 IME 档名, 例: phon.ime; (* 空字串: 英数输入法 (* (* 传回值: (* True: 切换成功 (* False: 失败 (* -------------------------------------------------- *) 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 (* 空字串, 还原到英数输入法 *) pImePro^.szName[0] := 0 else StrPCopy(@pImePro^.szName, sImeFileName); Result := ImpSetIme(0, pImePro); (* 呼叫 ImpSetIme *) finally Dispose(pImePro); end; { of try } end; end; { of SetIme } end. ;
DELPHI 中DLL开发常见问题的讨论: 而在被调用函数写的方式应该是:
procedure GetStr(var Pstr: PChar);
var
str: string
begin
str := 'return string';
strCopy(PStr, PChar(str));
end;
调用函数写法:
TGetStr= procedure(var Pstr: PChar);
funtion GetDllStr: string
var
DllHnd: THandle;
GetStr: TGetStr;
Str: PChar;
strPath: string;
begin
AHaveWhere := 0;
DllHnd := LoadLibrary(PChar('testdll'));
try
if (DllHnd <> 0) then
begin
@GetStr :=GetProcAddress(DllHnd, 'GetStr');
if (@GetStr<>nil) then
begin
GetMem(Str, 1024);
try
GetStr(Filter);
result := StrPas(Filter);
finally
FreeMem(Str);
end;
end
else
begin
application.MessageBox(PChar('DLL加载出错,DLL可能不存在!'), PChar('错误'),
MB_ICONWARNING or MB_OK);
end;
end;
finally
FreeLibrary(DllHnd);
end;
一 Dll的制作一般步骤
在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:
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;
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
library Project2; uses SysUtils, 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, ShowCCC; 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 ShowCCC;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;
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论