Delphi 中的 procedure of object

Delphi 中的 procedure of object

 


其实要了解这些东西,适当的学些反汇编,WINDOWS内存管理机制,PE结构,看下李维的VCL架构剖析可以很好理解
type
  TMyEvent = procedure of object;
这是一种数据类型的定义,他定义了一个可以在类中使用的函数类型
区别于
type
  TMyProc = procedure;


TMyEvent 和 TMyProc 都定义了一个函数类型,他们的差别是,TMyProc 不可以用在类中定义事件,TMyEvent 却可以。


如果你想知道问什么,那就需要深入了解事件类型以及函数类型到底是个什么?


procedure a();
begin
  ShowMessage()
end;


var
  Func1: TMyProc;
  Func2: TMyEvent;


  func1 := A;


func1 := A;


这句到底发生了什么事情呢?


在32位的windows操作系统中,任何一个进程被执行,操作系统要完成的工作基本上包括:为这个进程开辟一个线性的虚拟地址表(从$00000000到$FFFFFFFF),然后把exe程序加载到这个地址表对应的内存中,然后跳入到exe程序的入口点,剩下的事情,就是exe自己从入口点开始一步一步干自己的事情了。
程序中,所有的函数都被编译到固定的位置,也就是每个函数都有一个地址与之对应,对函数的调用,实际上就是在寄存器或者堆栈中准备好参数,然后跳入到函数对应的地址继续执行。
func1 := A;
这个动作,完成的就是把函数A的地址赋值给func1这个变量。

 


那么,为Func2: TMyEvent 赋值又是完成了什么呢?


类中的函数也是有地址的,编译后,类中的函数也会被编译到一个固定的地址上。
但是,func2不是表示一个函数地址,他是一个记录类型的变量
这个可以通过 SizeOf(TMyEvent) 看到 SizeOf(TMyEvent) 返回值是8,而SizeOf(TMyProc)返回的是4
实际上,TMyEvent类型是包含两个域的一个记录,其中一个域是Code,也就是和TMyProc一样的,另一个域是Data,他保存着一个对象。


  Button2.OnClick := Button1Click;
这样的赋值,实际上是将窗体类的对象form1给data域,将Button1Click这个函数的地址给Code域


1.
TMyEvent = procedure of object; TMyEvent 是方法类型 就等于 String 是一种数据类型


如在一个Txxx类中定义了一个过程 
procedure Txxx.test;
begin
  showmessage('1');
end;


那么就可以把 Txxx.test 赋给 TMyEvent 了 (TMyEvent := Txxx.test);
因为 TMyEvent 的定义中有 of object 所以赋值给它的只能是类中的过程,而不能是普通过程。


2.
FOnHundred: TMyEvent; --> FOnHundred 是一个变量 它的类型是 TMyEvent, 
  就等于 icount : integer 这么简单


3.
property OnHundred: TMyEvent read FOnHundred write FOnHundred


OnHundred 是一个属性 它的类型也是 TMyEvent 通过 FOnHundred 变量来存取 这个属性的值。


当属性不用过程去存取的时候 (如上例)调用 OnHundred 和 FOnHundred 是相同的
 


delphi中经常见到以下两种定义


Type


TMouseProc = procedure (X,Y:integer);


TMouseEvent = procedure (X,Y:integer) of Object;


两者样子差不多但实际意义却不一样,


TMouseProc只是单一的函数指针类型;


TMouseEvent是对象的函数指针,也就是对象/类的函数/方法


区别在于类方法存在一个隐藏参数self,也就是说两者形参不一样,所以不能相互转换。


这也就是为什么delphi中可以这样赋值 button1.onClick:=button2.onClick;


却不能这样赋值 button1.onclick=buttonclick; (buttonclick为本地函数,button2.onclick为类方法)的原因!

 


方法类型定义:TMethod = procedure of object;


 


Procedural types allow you to treat procedures and functions as values that can be assigned to variables or passed to other procedures and functions. For example,suppose you define a function called Calc that takes two integer parameters and returns an integer:


function Calc(X,Y: Integer): Integer;


You can assign the Calc function to the variable F:


 


var F: function(X,Y: Integer): Integer;


F := Calc;


If you take any procedure or function heading and remove the identifier after the word procedure or function,what’s left is the name of a procedural type. You can use such type names directly in variable declarations (as in the example above) or to declare new types:


Type


TIntegerFunction = function: Integer;


TProcedure = procedure;


TStrProc = procedure(const S: string);


TMathFunc = function(X: Double): Double;


Var


F: TIntegerFunction;{ F is a parameterless function that returns an integer }


Proc: TProcedure;   { Proc is a parameterless procedure }


SP: TStrProc;       { SP is a procedure that takes a string parameter }


M: TMathFunc;       { M is a function that takes a Double (real) parameterand returns a Double }


procedure FuncProc(P: TIntegerFunction);  { FuncProc is a procedure whose only parameter is a parameterless integer-valued function }


The variables above are all procedure pointers—that is,pointers to the address of a procedure or function. If you want to reference a method of an instance object (see Classes and objects),you need to add the words of object to the procedural type name. For example


Type


TMethod = procedure of object;


TNotifyEvent = procedure(Sender: TObject) of object;


These types represent method pointers. A method pointer is really a pair of pointers; the first stores the address of a method,and the second stores a reference to the object the method belongs to. Given the declarations


Type


TNotifyEvent = procedure(Sender: TObject) of object;


TMainForm = class(TForm)


procedure ButtonClick(Sender: TObject);


...


end;


var


MainForm: TMainForm;


OnClick: TNotifyEvent


we could make the following assignment.OnClick := MainForm.ButtonClick;


Two procedural types are compatible if they have the same calling convention,the same return value (or no return value),and the same number of parameters,with identically typed parameters in corresponding positions. (Parameter names do not matter.)


Procedure pointer types are always incompatible with method pointer types. The value nil can be assigned to any procedural type.


Nested procedures and functions (routines declared within other routines) cannot be used as procedural values,nor can predefined procedures and functions. If you want to use a predefined routine like Length as a procedural value,write a wrapper for it:


function FLength(S: string): Integer;


begin


Result := Length(S);


end;


最后给大家个例子:

type  TNotifyEvent = procedure(Sender: TObject) of object;  TMainForm = class(TForm)    procedure ButtonClick(Sender: TObject);    ...  end;var  MainForm: TMainForm;  OnClick: TNotifyEvent im..... OnClick := MainForm.ButtonClick;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都是大家转来转去,原文出处我已经找不到了。这篇文章写的很不错,但最后部分“PermuteFunction 的终极版本”描述的不太清楚,完全按照该文章代码执行,是不行的。可能是作者故意这样做的?本文最后提供修正后的下载地址。原文如下:一、关于API Hook1.什么是API Hook不知道大家是否还记得,在DO
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都是大家转来转去,原文出处我已经找不到了。 这篇文章写的很不错,但最后部分“PermuteFunction 的终极版本”描述的不太清楚,完全按照该文章代码执行,是不行的。需要修改mess.pas中代码才行。其实文中提到的一个结构,代码中并没有使用typePIMAGE_IMPORT_DESCRIPTOR = ^IMA
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把部分api 翻译成了dephi版的 记录一下 地址 ffmpegvcl.zip
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)6个段寄存器(ES、CS、SS、DS、FS和GS)
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:(dst) <--(src) 1.dst和src类型必须匹配,即必须同为字节
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂,比较少用。 2.WinExec主要运行EXE文件。如:WinExec('Notepad.exe Readme.txt', SW_SHOW); 3.ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。 首先必须引用shellapi
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String, ByVal dwFlags As Long) 参数 类型及说明 lpExistingFileName String,欲移
附带通用控件安装方法: ---------- 基本安装 1、对于单个控件,Componet-->install component..-->PAS或DCU文件-->install; 2、对于带*.dpk文件的控件包,File-->Open(下拉列表框中选*.dpk)-->install即可; 3、对于带*.bpl文件的控件包,Install Packages-->Add-->bpl文件名即可; 4
type   TRec=Record     msg:string;     pic:TMemoryStream; end; procedure TForm2.BitBtn1Click(Sender: TObject); var   ms:TMemoryStream;   Rec1,Rec2:TRec;   cc:tmemorystream;   jpg:TJPEGImage; begin   R
program Project1; { Types and Structures Definition } type   WNDCLASSEX = packed record     cbSize: LongWord;     style: LongWord;     lpfnWndProc: Pointer;     cbClsExtra: Integer;     cbWndExtra: In
   在Windows大行其道的今天,windows界面程序受到广大用户的欢迎。对这些程序的操作不外乎两种,键盘输入控制和鼠标输入控制。有时,对于繁杂 的,或重复性的操作,我们能否通过编制程序来代替手工输入,而用程序来模拟键盘及鼠标的输入呢?答案是肯定的。这主要是通过两个API函数来实现的。      下面以Delphi为例来介绍一下如何实现这两个功能。模拟键盘我们用Keybd_event这个ap
delphi中经常见到以下两种定义 Type TMouseProc = procedure (X,Y:integer); TMouseEvent = procedure (X,Y:integer) of Object; 两者样子差不多但实际意义却不一样, TMouseProc只是单一的函数指针类型; TMouseEvent是对象的函数指针,也就是对象/类的函数/方法 区
Windows 2000/XP和2003等支持一种叫做"服务程序"的东西.程序作为服务启动有以下几个好处:     (1)不用登陆进系统即可运行.     (2)具有SYSTEM特权.所以你在进程管理器里面是无法结束它的.     笔者在2003年为一公司开发机顶盒项目的时候,曾经写过课件上传和媒体服务,下面就介绍一下如何用Delphi7创建一个Service程序.     运行Delphi7,选
方法一: 1.调试delphi 写的服务程序,有这么一个办法。原来每次都是用attach to process方法,很麻烦。并且按照服务线程的执行线路,可能会停不到想要的断点。笨办法是,在procedure TsvcFrm.ServiceExecute(Sender: TService);中想要下断的语句前加个人定胜天的sleep(20000),但实际上这种办法是主观臆测的。可行,没问题。记得大学
Delphi For iOS开发指南(17):让应用程序禁止竖屏(也就是只显示横屏)     最近好多人问,怎么样让Delphi For iOS开发的应用程序禁止竖屏,也就是想让它一直横屏显示,横屏是好,一行可以放好几个控件,表格的话也可以多显示几列,看起来方便。 只要一句代码就可以让Delphi For iOS开发的应用程序禁止竖屏,如下: Application.FormFactor.Orie
一个比较完整的Inno Setup 安装脚本,增加了对ini文件设置的功能,一个安装包常用的功能都具备了。 [Setup] ; 注: AppId的值为单独标识该应用程序。 ; 不要为其他安装程序使用相同的AppId值。 ; (生成新的GUID,点击 工具|在IDE中生成GUID。) AppId={{A9861883-31C5-4324-BD9A-DC3271EEB675} ;程序名 AppName
在Delphi自带的Indy控件中其实是提供了MD2,MD4,MD5对象的,我们可以直接使用它们来完成MD5的签名算法。而不需要再去找其它的DLL或是Pas了。 在Uses单元中引用 IdHashMessageDigest,IdGlobal, IdHash 单元,再写如下代码即可以达到MD5的实现。 示例代码 procedure TForm1.Button1Click(Sender: TObjec
在Delphi 7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下: 1 2 3 4 5 6 7 8 9 _NOTIFYICONDATAA = record    cbSize: DWORD;    Wnd: HWND;    uID: UINT;    uFlags: UINT;    uCallback
声明: 1. type Name = Existing type; 2. type Name = type Existing type; 3. type Name = (EnumValue1 [=value], EnumValue2 [=value] ...); 4. type Name = Expression1..Expression2; 5. type Name = ^Existing ty