昨天把MakeObjectInstance的代码详细研究了一下,当然还有众多前辈高手们的帮助,终于大致搞明白了是怎么回事。但是给我顿悟的,不是高手们的帖子,而是来自我自己的一个疑惑,TObjectInstance这么小,一共才13个字节,显然不可能存储整个MainWndProc的函数内容,更不用说WndProc函数的内容,而只能存储它们的地址。也不可能把窗口函数的内容拆散了放在不同的TObjectInstance里,那样虽然可以,但是何不把TObjectInstance设计的大一些呢,设计VCL代码的都是高手中的高手,不可能犯这样的低级错误。正是从这一点出发,我明白了,MakeObjectInstance函数不过是换种方式调用MainWndProc,而不是把MainWndProc的内容整个存储在MakeObjectInstance建立的区块里并直接执行它的汇编指令(过去我一直以来就是这么认为的),每个TObjectInstance小区块最终记住的是每个Delphi类(比如TButton)的MainWndProc函数地址,外加跳转语句。

与之而来的推论是,TInstanceBlock建立了314个小区块TObjectInstance的列表第一个小区块存储了Application.WndProc的地址不是虚函数,如果变成虚函数就不行了),第二个小区块存储了Form1.MainWndProc的地址,如果Form1上只有2个TButton,那么第三个区块存储了Button1.MainWndProc的地址,第四个区块存储了Button2.MainWndProc的地址,以此类推。一般情况下,程序员用的了314那么多带回调函数的GUI实例吗?好像不需要,而且只有界面Win控件(图像控件虽有WndProc"窗口函数",但它是通过Win控件转发执行的,所以仍然不需要。理论是这样,做例子验证了也是这样)才需要这个。万一超过了也不要紧,Delphi还会给我们建立下一个314列表。我不明白的是,这么浅显的结论,高手们为什么不明确说出来呢,像我这样举个例子多么容易理解啊,代码都不用看就可以懂的,真是郁闷,这么多年都高看了MakeObjectInstance的神秘之处,其实挺简单嘛!

----------------------------------------------------------------------------

做个实验:
把TApplication.FObjectInstance和TWinControl.FObjectInstance移到public区域,然后新建一个工程,上面只放2个TButton。输入以下代码(放在Button1和Button2里没有区别)

procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(IntToStr(Integer(Application.FObjectInstance)));
ShowMessage(IntToStr(Integer(Form1.FObjectInstance)));
ShowMessage(IntToStr(Integer(Button1.FObjectInstance)));
ShowMessage(IntToStr(Integer(Button2.FObjectInstance)));
end;

因为TInstanceBlock里的314个TObjectInstance是倒着用的,所以最后一个TObjectInstance的地址值最大,但是第一个FObjectInstance存储在这里(当然也就是Application的)。然后就可以观察输出值了:
4067311 (Application)
4067285 (Form1),减小了26,不知道为什么是相差2个TObjectInstance的距离?经过调试,发现是有一个THintWindow实例在Form1之前就占据了一个位置。
4067272 (Button1),减小13,正确
4067259 (Button2),减小13,正确

值得注意的是,如果把dfm文件里的Button1和Button2顺序颠倒,那么根据Delphi编译器实例化控件的顺序,会先实例化Button2,后实例化Button1,打印语句不变,输出结果就变成这样:
4067311 (Application)
4067285 (Form1)
4067259 (Button1),数值较小
4067272 (Button2),数值较大,此时Button2比Button1先实例化,因此也先占据一个TObjectInstance,地址值更大(倒着用TObjectInstance链表)

----------------------------------------------------------------------------

FHintWindow实例化的过程:

Controls单元初始化
initialization
InitControls;

调用
procedure InitControls;
begin
Screen := TScreen.Create(nil);
Application := TApplication.Create(nil);
Application.ShowHint := True; // 类属性
end;

类属性调用SetShowHint,就当场创建了一个FHintWindow,比Form1还要快
procedure TApplication.SetShowHint(Value: Boolean);
begin
if FShowHint <> Value then
begin
FShowHint := Value;
if FShowHint then
begin
FHintWindow := HintWindowClass.Create(Self);
FHintWindow.Color := FHintColor;
end else
begin
FHintWindow.Free;
FHintWindow := nil;
end;
end;
end;

----------------------------------------------------------------------------

参考:

http://blog.csdn.net/linzhengqun/article/details/1451088
http://www.wenhq.com/article/view_48.html
http://blog.csdn.net/sforiz/article/details/8057371

MakeObjectInstance的简单理解的更多相关文章

  1. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

  2. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  3. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  4. Js 职责链模式 简单理解

    js 职责链模式 的简单理解.大叔的代码太高深了,不好理解. function Handler(s) { this.successor = s || null; this.handle = funct ...

  5. Deep learning:四十六(DropConnect简单理解)

    和maxout(maxout简单理解)一样,DropConnect也是在ICML2013上发表的,同样也是为了提高Deep Network的泛化能力的,两者都号称是对Dropout(Dropout简单 ...

  6. Deep learning:四十二(Denoise Autoencoder简单理解)

    前言: 当采用无监督的方法分层预训练深度网络的权值时,为了学习到较鲁棒的特征,可以在网络的可视层(即数据的输入层)引入随机噪声,这种方法称为Denoise Autoencoder(简称dAE),由Be ...

  7. 简单理解dropout

    dropout是CNN(卷积神经网络)中的一个trick,能防止过拟合. 关于dropout的详细内容,还是看论文原文好了: Hinton, G. E., et al. (2012). "I ...

  8. 我们为之奋斗过的C#-----C#的一个简单理解

    我们首先来简单叙述一下什么是.NET,以及C#的一个简单理解和他们俩的一个区别. 1 .NET概述 .NET是Microsoft.NET的简称,是基于Windows平台的一种技术.它包含了能在.NET ...

  9. 简单理解ECMAScript2015中的箭头函数新特性

    箭头函数(Arrow functions),是ECMAScript2015中新加的特性,它的产生,主要有以下两个原因:一是使得函数表达式(匿名函数)有更简洁的语法,二是它拥有词法作用域的this值,也 ...

随机推荐

  1. 零基础学习Linux(三)linux与windows文件共享

    上次的博文零基础学习Linux(一)环境搭建中我们已经将linux环境部署完毕了,接下来我们就可以在linux上进行软件的安装和环境的配置.但在进行这些操作之前,我们还需要解决一个问题——Linux与 ...

  2. 使用xilinx ip core FIFO First- World First-Through (FWFT)模式的注意事项

    也许很多人知道xilinx ip core 中的fifo可以配成standard 模式和FWFT模式,并知道两者的区别是:standard模式下,当rd为高时,fifo会延时一个时钟输出数据(时序逻辑 ...

  3. powerdesigner 技巧

    1.修改建表脚本生成规则.如果每个表格都有相同的字段,可以如下修改: Database -> Edit Current DBMS 展开 Script -> Object -> Tab ...

  4. 目前国内外主流的linux发行版本

    1.linux其实是基于unix发展而来的,还有mac os也是类unix操作系统 2.目前主流的linux发行版本主要有:红帽系列(中国大陆,美洲地区,发源于美国),suse系列(欧洲地区流行,发源 ...

  5. 【Search Insert Position 】cpp

    题目: Given a sorted array and a target value, return the index if the target is found. If not, return ...

  6. 笔记本显示器坏了,从硬盘安装win7系统

    可以装的,从硬盘安装的话,步骤如下:一.将从网上下载的win7旗舰版ISO系统文件存放到D盘. 二.从网上下载虚拟光驱,打开安装后在任务栏右通知区显示“虚拟DAEMON管理器”图标,在我的电脑窗口显示 ...

  7. Python 删除列表中的重复数据

    list0=['b','c', 'd','b','c','a','a'] 方法1:使用set() list1=sorted(set(list0),key=list0.index) # sorted o ...

  8. Leetcode#97 Interleaving String

    原题地址 转化为二维地图游走问题. 比如s1="abab",s2="aab",s3="aabaabb",则有如下地图,其中"^&q ...

  9. 【转载】让c++ 函数返回一个数组

    在c++中是不允许数组作为函数的返回值的 int [] someFunction( ); //ILLEGAL 要想实现函数返回一个数组,那返回对应数组里面类型的指针 you must return a ...

  10. asp.net中实现群发邮件功能

    前段时间在帮老师开发的网站中需要用到一个群发邮件的功能,而自己之前学习cms系统的时候用的we7的群发邮件功能也有一些问题,于是乎便自己去网上查了一下资料,自己总结了一下,并且封装成了一个类,亲测有用 ...