【荣耀8内核源码】【pybind11源码】【idea无法debug源码】扒皮源码源码_扒皮游戏分享

时间:2024-11-26 10:30:30 来源:javajdk实例宝典源码 分类:知识

1.30岁学java可以吗
2.java学习心得
3.MFC中的扒皮扒皮InitInstance()函数应该怎样理解

扒皮源码源码_扒皮游戏分享

30岁学java可以吗

       å²å¯ä»¥å­¦java,不会很晚。

       Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

       Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。

       ç¼–程工具:

       Eclipse:一个开放源代码的、基于Java的可扩展开发平台。

       NetBeans:开放源码的Java集成开发环境,适用于各种客户机和Web应用。

       IntelliJ IDEA:在代码自动提示、代码分析等方面的具有很好的功能。

       MyEclipse:由Genuitec公司开发的一款商业化软件,是应用比较广泛的Java应用程序集成开发环境。

       EditPlus:如果正确配置Java的编译器“Javac”以及解释器“Java”后,可直接使用EditPlus编译执行Java程序。

java学习心得

       Java学习心得

       å¼•è¨€

        软件开发之路是充满荆棘与挑战之路,也是充满希望之路。Java学习也是如此,没有捷径可走。梦想像《天龙八部》中虚竹一样被无崖子醍醐灌顶而轻松获得一甲子功力,是很不现实的。每天仰天大叫"天神啊,请赐给我一本葵花宝典吧",殊不知即使你获得了葵花宝典,除了受自宫其身之苦外,你也不一定成得了"东方不败",倒是成"西方失败"的几率高一点。

        "不走弯路,就是捷径",佛经说的不无道理。

        1.如何学习程序设计?

        Java是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于Java,对C++等其他程序设计语言也一样管用。有编程高手认为,Java也好C也好没什么分别,拿来就用。为什么他们能达到如此境界?我想是因为编程语言之间有共通之处,领会了编程的精髓,自然能够做到一通百通。如何学习程序设计理所当然也有许多共通的地方。

        1.1 培养兴趣

        兴趣是能够让你坚持下去的动力。如果只是把写程序作为谋生的手段的话,你会活的很累,也太对不起自己了。多关心一些行业趣事,多想想盖茨。不是提倡天天做白日梦,但人要是没有了梦想,你觉得有味道吗?可能像许多深圳本地农民一样,打打麻将,喝喝功夫茶,拜拜财神爷;每个月就有几万十几万甚至更多的进帐,凭空多出个"食利阶层"。你认为,这样有味道吗?有空多到一些程序员论坛转转,你会发现,他们其实很乐观幽默,时不时会冒出智慧的火花。

        1.2 慎选程序设计语言

        男怕入错行,女怕嫁错郎。初学者选择程序设计语言需要谨慎对待。软件开发不仅仅是掌握一门编程语言了事,它还需要其他很多方面的背景知识。软件开发也不仅仅局限于某几个领域,而是已经渗透到了各行各业几乎每一个角落。

       å¦‚果你对硬件比较感兴趣,你可以学习C语言/汇编语言,进入硬件开发领域。如果你对电信的行业知识及网络比较熟悉,你可以在C/C++等之上多花时间,以期进入电信软件开发领域。如果你对操作系统比较熟悉,你可以学习C/Linux等等,为Linux内核开发/驱动程序开发/嵌入式开发打基础。

       å¦‚果你想介入到应用范围最广泛的应用软件开发(包括电子商务电子政务系统)的话,你可以选择J2EE或.NET,甚至LAMP组合。每个领域要求的背景知识不一样。做应用软件需要对数据库等很熟悉。总之,你需要根据自己的特点来选择合适你的编程语言。

        1.3 要脚踏实地,快餐式的学习不可取

        先分享一个故事。

        有一个小朋友,他很喜欢研究生物学,很想知道那些蝴蝶如何从蛹壳里出来,变成蝴蝶便会飞。有一次,他走到草原上面看见一个蛹,便取了回家,然后看着,过了几天以后,这个蛹出了一条裂痕,看见里面的蝴蝶开始挣扎,想抓破蛹壳飞出来。这个过程达数小时之久,蝴蝶在蛹里面很辛苦地拼命挣扎,怎么也没法子走出来。这个小孩看着看着不忍心,就想不如让我帮帮它吧,便随手拿起剪刀在蛹上剪开,使蝴蝶破蛹而出。但蝴蝶出来以后,因为翅膀不够力,变得很臃肿,飞不起来。

        这个故事给我们的启示是:欲速则不达。

        浮躁是现代人最普遍的心态,能怪谁?也许是贫穷落后了这么多年的缘故,就像当年的大跃进一样,都想大步跨入***主义社会。现在的软件公司、客户、政府、学校、培训机构等等到处弥漫着浮躁之气。就拿我比较熟悉的大连大工IT职业培训来说吧,居然打广告宣称"多年的计算机职业教育,辽宁省十佳学校",殊不知中国计算机发展才几年,软件发展才几年,居然去报名的学生不少,简直是藐视天下程序员。培训出来的“程序员”大多不知道OO,OP为何物?社会环境如是,我们不能改变,只能改变自己,闹市中的安宁,弥足珍贵。许多初学者C++/Java没开始学,立马使用VC/JBuilder,会使用 VC/JBuilder开发一个Hello World程序,就忙不迭的向世界宣告,"我会软件开发了",简历上也大言不惭地写上"精通VC/Java"。结果到软件公司面试时要么被三两下打发走了,要么被驳的体无完肤,无地自容。到处碰壁之后才知道捧起《C++编程思想》《Java编程思想》仔细钻研,早知如此何必当初呀。

       "你现在讲究简单方便,你以后的路就长了",好象也是佛经中的劝戒。

        1.4 多实践,快实践

        彭端淑的《为学一首示子侄》中有穷和尚与富和尚的故事。

        从前,四川边境有两个和尚,一个贫穷,一个有钱。一天,穷和尚对富和尚说:"我打算去南海朝圣,你看怎么样?"富和尚说:"这里离南海有几千里远,你靠什么去呢?"穷和尚说:"我只要一个水钵,一个饭碗就够了。"富和尚为难地说:"几年前我就打算买条船去南海,可至今没去成,你还是别去吧!" 一年以后,富和尚还在为租赁船只筹钱,穷和尚却已经从南海朝圣回来了。

       è¿™ä¸ªæ•…事可解读为:任何事情,一旦考虑好了,就要马上上路,不要等到准备周全之后,再去干事情。假如事情准备考虑周全了再上路的话,别人恐怕捷足先登了。软件开发是一门工程学科,注重的就是实践,"君子动口不动手"对软件开发人员来讲根本就是错误的,他们提倡"动手至上",但别害怕,他们大多温文尔雅,没有暴力倾向,虽然有时候蓬头垢面的一副"比尔盖茨"样。有前辈高人认为,学习编程的秘诀是:编程、编程、再编程,笔者深表赞同。不仅要多实践,而且要快实践。我们在看书的时候,不要等到你完全理解了才动手敲代码,而是应该在看书的同时敲代码,程序运行的各种情况可以让你更快更牢固的掌握知识点。

        1.5 多参考程序代码

        程序代码是软件开发最重要的成果之一,其中渗透了程序员的思想与灵魂。许多人被《仙剑奇侠传》中凄美的爱情故事感动,悲剧的结局更有一种缺憾美。为什么要以悲剧结尾?据说是因为写《仙剑奇侠传》的程序员失恋而安排了这样的结局,他把自己的感觉融入到游戏中,却让众多的仙剑迷扼腕叹息。

        多多参考代码例子,对Java而言有参考文献[4.3],有API类的源代码(JDK安装目录下的src.zip文件),也可以研究一些开源的软件或框架。

        1.6 加强英文阅读能力

        对学习编程来说,不要求英语, 但不能一点不会,。最起码像Java API文档(参考文献[4.4])这些东西还是要能看懂的,连猜带懵都可以;旁边再开启一个"金山词霸"。看多了就会越来越熟练。在学Java的同时学习英文,一箭双雕多好。另外好多软件需要到英文网站下载,你要能够找到它们,这些是最基本的要求。英语好对你学习有很大的帮助。口语好的话更有机会进入管理层,进而可以成为剥削程序员的"周扒皮"。

        1.7 万不得已才请教别人

        笔者在Martix与Java论坛的在线辅导系统中解决学生问题时发现,大部分的问题学生稍做思考就可以解决。请教别人之前,你应该先回答如下几个问题。

        你是否在google中搜索了问题的解决办法?

        你是否查看了Java API文档?

        你是否查找过相关书籍?

        你是否写代码测试过?

        如果回答都是"是"的话,而且还没有找到解决办法,再问别人不迟。要知道独立思考的能力对你很重要。要知道程序员的时间是很宝贵的。

        1.8 多读好书

        书中自有颜如玉。比尔盖茨是一个饱读群书的人。虽然没有读完大学,但九岁的时候比尔盖茨就已经读完了所有的百科全书,所以他精通天文、历史、地理等等各类学科,可以说比尔?茨不仅是当今世界上金钱的首富,而且也可以称得上是知识的巨富。

       ç¬”者在给学生上课的时候经常会给他们推荐书籍,到后来学生实在忍无可忍开始抱怨,"天呐,这么多书到什么时候才能看完了","学软件开发,感觉上了贼船 "。这时候,我的回答一般是,"别着急,什么时候带你们去看看我的书房,到现在每月花在技术书籍上的钱元,这在软件开发人员之中还只能够算是中等的 ",学生当场晕倒。(注:这一部分学生是刚学软件开发的)

        1.9 使用合适的工具

        工欲善其事必先利其器。软件开发包含各种各样的活动,需求收集分析、建立用例模型、建立分析设计模型、编程实现、调试程序、自动化测试、持续集成等等,没有工具帮忙可以说是寸步难行。工具可以提高开发效率,使软件的质量更高BUG更少。组合称手的武器。到飞花摘叶皆可伤人的境界就很高了,无招胜有招,手中无剑心中有剑这样的境界几乎不可企及。

        2.软件开发学习路线

        两千多年的儒家思想孔孟之道,中庸的思想透入骨髓,既不冒进也不保守并非中庸之道,而是找寻学习软件开发的正确路线与规律。

       ä»Žè½¯ä»¶å¼€å‘人员的生涯规划来讲,我们可以大致分为三个阶段,软件工程师→软件设计师→架构设计师或项目管理师。不想当元帅的士兵不是好士兵,不想当架构设计师或项目管理师的程序员也不是好的程序员。我们应该努力往上走。让我们先整理一下开发应用软件需要学习的主要技术。

        A.基础理论知识,如操作系统、编译原理、数据结构与算法、计算机原理等,它们并非不重要。如不想成为计算机科学家的话,可以采取"用到的时候再来学"的原则。

        B.一门编程语言,现在基本上都是面向对象的语言,Java/C++/C#等等。如果做WEB开发的话还要学习HTML/JavaScript等等。

        C.一种方法学或者说思想,现在基本都是面向对象思想(OOA/OOD/设计模式)。由此而衍生的基于组件开发CBD/面向方面编程AOP等等。

        D.一种关系型数据库,ORACLE/SqlServer/DB2/MySQL等等

        E.一种提高生产率的IDE集成开发环境JBuilder/Eclipse/VS.NET等。

        F.一种UML建模工具,用ROSE/VISIO/钢笔进行建模。

        G.一种软件过程,RUP/XP/CMM等等,通过软件过程来组织软件开发的众多活动,使开发流程专业化规范化。当然还有其他的一些软件工程知识。

        H.项目管理、体系结构、框架知识。

        正确的路线应该是:B→C→E→F→G→H。

        还需要补充几点:

        1).对于A与C要补充的是,我们应该在实践中逐步领悟编程理论与编程思想。新技术虽然不断涌现,更新速度令人眼花燎乱雾里看花;但万变不离其宗,编程理论与编程思想的变化却很慢。掌握了编程理论与编程思想你就会有拨云见日之感。面向对象的思想在目前来讲是相当关键的,是强势技术之一,在上面需要多投入时间,给你的回报也会让你惊喜。

        2).对于数据库来说是独立学习的,这个时机就由你来决定吧。

        3).编程语言作为学习软件开发的主线,而其余的作为辅线。

        4).软件工程师着重于B、C、E、D;软件设计师着重于B、C、E、D、F;架构设计师着重于C、F、H。

        3.如何学习Java?

        3.1 Java学习路线

        3.1.1 基础语法及Java原理

        基础语法和Java原理是地基,地基不牢靠,犹如沙地上建摩天大厦,是相当危险的。学习Java也是如此,必须要有扎实的基础,你才能在J2EE、 J2ME领域游刃有余。参加SCJP(SUN公司认证的Java程序员)考试不失为一个好方法,原因之一是为了对得起你交的大洋考试费,你会更努力学习,原因之二是SCJP考试能够让你把基础打得很牢靠,它要求你跟JDK一样熟悉Java基础知识;但是你千万不要认为考过了SCJP就有多了不起,就能够获得软件公司的青睐,就能够获取高薪,这样的想法也是很危险的。获得"真正"的SCJP只能证明你的基础还过得去,但离实际开发还有很长的一段路要走。

        3.1.2 OO思想的领悟

        掌握了基础语法和Java程序运行原理后,我们就可以用Java语言实现面向对象的思想了。面向对象,是一种方法学;是独立于语言之外的编程思想;是 CBD基于组件开发的基础;属于强势技术之一。当以后因工作需要转到别的面向对象语言的时候,你会感到特别的熟悉亲切,学起来像喝凉水这么简单。

       ä½¿ç”¨é¢å‘对象的思想进行开发的基本过程是:

        ●调查收集需求。

        ●建立用例模型。

        ●从用例模型中识别分析类及类与类之间的静态动态关系,从而建立分析模型。

        ●细化分析模型到设计模型。

        ●用具体的技术去实现。

        ●测试、部署、总结。

        3.1.3 基本API的学习

        进行软件开发的时候,并不是什么功能都需要我们去实现,也就是经典名言所说的"不需要重新发明轮子"。我们可以利用现成的类、组件、框架来搭建我们的应用,如SUN公司编写好了众多类实现一些底层功能,以及我们下载过来的JAR文件中包含的类,我们可以调用类中的方法来完成某些功能或继承它。那么这些类中究竟提供了哪些方法给我们使用?方法的参数个数及类型是?类的构造器需不需要参数?总不可能SUN公司的工程师打国际长途甚至飘洋过海来告诉你他编写的类该如何使用吧。他们只能提供文档给我们查看,Java DOC文档(参考文献4.4)就是这样的文档,它可以说是程序员与程序员交流的文档。

        基本API指的是实现了一些底层功能的类,通用性较强的API,如字符串处理/输入输出等等。我们又把它成为类库。熟悉API的方法一是多查Java DOC文档(参考文献4.4),二是使用JBuilder/Eclipse等IDE的代码提示功能。

        3.1.4 特定API的学习

        Java介入的领域很广泛,不同的领域有不同的API,没有人熟悉所有的API,对一般人而言只是熟悉工作中要用到的API。如果你做界面开发,那么你需要学习Swing/AWT/SWT等API;如果你进行网络游戏开发,你需要深入了解网络API/多媒体API/2D3D等;如果你做WEB开发,就需要熟悉Servlet等API啦。总之,需要根据工作的需要或你的兴趣发展方向去选择学习特定的API。

        3.1.5 开发工具的用法

        在学习基础语法与基本的面向对象概念时,从锻炼语言熟练程度的角度考虑,我们推荐使用的工具是Editplus/JCreator+JDK,这时候不要急于上手JBuilder/Eclipse等集成开发环境,以免过于关注IDE的强大功能而分散对Java技术本身的注意力。过了这一阶段你就可以开始熟悉 IDE了。

       ç¨‹åºå‘˜æ—¥å¸¸å·¥ä½œåŒ…括很多活动,编辑、编译及构建、调试、单元测试、版本控制、维持模型与代码同步、文档的更新等等,几乎每一项活动都有专门的工具,如果独立使用这些工具的话,你将会很痛苦,你需要在堆满工具的任务栏上不断的切换,效率很低下,也很容易出错。在JBuilder、 Eclipse等IDE中已经自动集成编辑器、编译器、调试器、单元测试工具JUnit、自动构建工具ANT、版本控制工具CVS、DOC文档生成与更新等等,甚至可以把UML建模工具也集成进去,又提供了丰富的向导帮助生成框架代码,让我们的开发变得更轻松。应该说IDE发展的趋势就是集成软件开发中要用到的几乎所有工具。

        从开发效率的角度考虑,使用IDE是必经之路,也是从一个学生到一个职业程序员转变的里程碑。

        Java开发使用的IDE主要有Eclipse、JBuilder、JDeveloper、NetBeans等几种;而Eclipse、JBuilder 占有的市场份额是最大的。JBuilder在近几年来一直是Java集成开发环境中的霸主,它是由备受程序员尊敬的Borland公司开发,在硝烟弥漫的 Java IDE大战中,以其快速的版本更新击败IBM的Visual Age for Java等而成就一番伟业。IBM在Visual Age for Java上已经无利可图之下,干脆将之贡献给开源社区,成为Eclipse的前身,真所谓"柳暗花明又一村"。浴火重生的Eclipse以其开放式的插件扩展机制、免费开源获得广大程序员(包括几乎所有的骨灰级程序员)的青睐,极具发展潜力。

        3.1.6 学习软件工程

        对小型项目而言,你可能认为软件工程没太大的必要。随着项目的复杂性越来越高,软件工程的必要性才会体现出来。参见"软件开发学习路线"小节。

        3.2学习要点

        确立的学习路线之后,我们还需要总结一下Java的学习要点,这些要点在前文多多少少提到过,只是笔者觉得这些地方特别要注意才对它们进行汇总,不要嫌我婆婆妈妈啊。

        3.2.1勤查API文档

        当程序员编写好某些类,觉得很有成就感,想把它贡献给各位苦难的同行。这时候你要使用"Javadoc"工具(包含在JDK中)生成标准的Java DOC文档,供同行使用。J2SE/J2EE/J2ME的DOC文档是程序员与程序员交流的工具,几乎人手一份,除了菜鸟之外。J2SE DOC文档官方下载地址:/j2se/1.5.0/download.jsp,你可以到google搜索CHM版本下载。也可以在线查看:/j2se/1.5.0/docs/api/index.html。

        对待DOC文档要像毛语录,早上起床念一遍,吃饭睡觉前念一遍。

        当需要某项功能的时候,你应该先查相应的DOC文档看看有没有现成的实现,有的话就不必劳神费心了直接用就可以了,找不到的时候才考虑自己实现。使用步骤一般如下:

        ●找特定的包,包一般根据功能组织。

        ●找需要使用类,类命名规范的话我们由类的名字可猜出一二。

        ●选择构造器,大多数使用类的方式是创建对象。

        ●选择你需要的方法。

        3.2.2 查书/google->写代码测试->查看源代码->请教别人

        当我们遇到问题的时候该如何解决?

        这时候不要急着问别人,太简单的问题,没经过思考的问题,别人会因此而瞧不起你。可以先找找书,到google中搜一下看看,绝大部分问题基本就解决了。而像"某些类/方法如何使用的问题",DOC文档就是答案。对某些知识点有疑惑是,写代码测试一下,会给你留下深刻的印象。而有的问题,你可能需要直接看 API的源代码验证你的想法。万不得已才去请教别人。

        3.2.3学习开源软件的设计思想

        Java领域有许多源代码开放的工具、组件、框架,JUnit、ANT、Tomcat、Struts、Spring、Jive论坛、PetStore宠物店等等多如牛毛。这些可是前辈给我们留下的瑰宝呀。入宝山而空手归,你心甘吗?对这些工具、框架进行分析,领会其中的设计思想,有朝一日说不定你也能写一个XXX框架什么的,风光一把。分析开源软件其实是你提高技术、提高实战能力的便捷方法。

        3.2.4 规范的重要性

        没有规矩,不成方圆。这里的规范有两层含义。第一层含义是技术规范,多到/docs/codeconv/,中文的也有,啊,还要问我在哪,请参考3.2.2节。

        3.2.5 不局限于Java

        很不幸,很幸运,要学习的东西还有很多。不幸的是因为要学的东西太多且多变,没时间陪老婆家人或女朋友,导致身心疲惫,严重者甚至导致抑郁症。幸运的是别人要抢你饭碗绝非易事,他们或她们需要付出很多才能达成心愿。

        Java不要孤立地去学习,需要综合学习数据结构、OOP、软件工程、UML、网络编程、数据库技术等知识,用横向纵向的比较联想的方式去学习会更有效。如学习Java集合的时候找数据结构的书看看;学JDBC的时候复习数据库技术;采取的依然是"需要的时候再学"的原则。

        4.结束语

        需要强调的是,学习软件开发确实有一定的难度,也很辛苦,需要付出很多努力,但千万不要半途而废。本文如果能对一直徘徊在Java神殿之外的朋友有所帮助的话,笔者也欣慰了。哈哈,怎么听起来老气横秋呀?没办法,在电脑的长期辐射之下,都快变成小老头了。最后奉劝各位程序员尤其是MM程序员,完成工作后赶快远离电脑,据《胡播乱报》报道,电脑辐射会在白皙的皮肤上面点缀一些小黑点,看起来鲜艳无比…… 拖起明天的梦想还得靠自己!

MFC中的InitInstance()函数应该怎样理解

       不是,是源码源码游戏实例的初始化函数;比如分配内存空间啊什么的;

       MFC的WinMain

        使用MFC编程的程序员刚开始都会提出这样一个问题:我的程序是从哪儿开始执行的?回答是:从WinMain()开始执行的。提出这样的分享问题是由于在他们所编写的MFC应用中看不到WinMain()函数。这个函数是扒皮扒皮隐藏在MFC框架中,MFC的源码源码游戏设计者将它作得很通用(这主要得益于Window的消息驱动的编程机制,使得作一个通用的分享荣耀8内核源码WinMain()很容易),因此在一般情况下,扒皮扒皮无需更改WinMain()的源码源码游戏代码,MFC的分享设计者也不提倡程序员修改WinMain()的代码。在MFC中,扒皮扒皮实际实现WinMain()的代码是AfxWinMain()函数(根据其前缀Afx就知道这是一个全局的MFC函数)。

        一个Win应用程序(或进程)是源码源码游戏由一个或多个并发的线程组成的,其中第一个启动的分享线程称为主线程,在Window下,扒皮扒皮一般将线程分成两大类,源码源码游戏界面线程和工作线程,分享工作线程就是一般的线程,它没有窗口,没有消息队列等,pybind11源码界面线程拥有一个或多个窗口,拥有一个消息队列和其他专属于界面线程的元素。在讨论AfxWinMain()之前,首先要简略提一下MFC中的两个重要的类,CWinThread和CWinApp,CWinThread是用来封装界面线程的类,CWinApp是从CWinThread派生而来的。在CWinThread中,有两个很重要的虚拟函数InitInstance()和ExitInistance(),MFC的程序员应该对这两个函数应该很熟悉。在CWinApp中,增加了另外一个虚拟函数InitApplication(),讨论AfxWinMain()的主要目的是看这些函数是如何被调用的。

        AfxWinMain()的代码如下:

        int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

        LPTSTR lpCmdLine, int nCmdShow)

        {

        ASSERT(hPrevInstance == NULL); file://在win下,hPrevInstance始终为NULL

        int nReturnCode = -1;

        CWinThread* pThread = AfxGetThread();

        CWinApp* pApp = AfxGetApp();

        // AFX internal initialization

        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

        goto InitFailure;

        // App global initializations (rare)

        if (pApp != NULL && !pApp->InitApplication())

        goto InitFailure;

        // Perform specific initializations

        if (!pThread->InitInstance())

        {

        if (pThread->m_pMainWnd != NULL)

        {

        TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");

        pThread->m_pMainWnd->DestroyWindow();

        }

        nReturnCode = pThread->ExitInstance();

        goto InitFailure;

        }

        nReturnCode = pThread->Run();

        InitFailure:

        AfxWinTerm();

        return nReturnCode;

        }

        在上面的代码中,AfxGetThread()返回的是当前界面线程对象的指针,AfxGetApp()返回的idea无法debug源码是应用程序对象的指针,如果该应用程序(或进程)只有一个界面线程在运行,那么这两者返回的都是一个全局的应用程序对象指针,这个全局的应用程序对象就是MFC应用框架所默认的theApp对象(每次使用AppWizard生成一个SDI或MDI应用程序时,AppWizard都会添加CYourApp theApp这条语句,AfxGetApp()返回的就是这个theApp的地址)。

       CWinApp::InitApplication(), CWinThread::InitInstance(), CWinThread::ExitInstance()是如何被调用的,从上面的代码一看就知,我不再赘述。下面我们把焦点放在CWinThread::Run()上。

       MFC的控制中心――CWinThread::Run()

        说CWinThread::Run()是MFC的控制中心,一点也没有夸大。在MFC中,所有来自于消息队列的消息的分派都是在CWinThread::Run()函数中完成的,同AfxWinMain()一样,这个函数也是对程序员是不可见的,其道理同AfxWinMain()的一样。

        首先要提的联动自动发卡源码一点是,对每条从消息队列取出来的消息,MFC根据消息的类型,按照某个特定的模式进行分发处理,这个分发模式是MFC自己定义的。固定的消息分发流程和在这个流程中的可动态改变其行为的虚拟函数就构成了MFC的消息分发模式。应用程序可以通过重载这些虚拟函数,来局部定制自己的的消息分发模式。正是通过这些虚拟函数,MFC为应用程序提供了足够的灵活性。下面讨论的所有代码都来自于MFC源代码中的threadcore.cpp文件,它们都是CWinThread的成员。

        CWinThread::Run()的结构

        CWinThread::Run()的代码如下:

        int CWinThread::Run()

        {

        ASSERT_VALID(this);

        // for tracking the idle time state

        BOOL bIdle = TRUE;

        LONG lIdleCount = 0;

        // acquire and dispatch messages until a WM_QUIT message is received.

        for (;;)

        {

        // phase1: check to see if we can do idle work

        while (bIdle &&

        !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))

        {

        // call OnIdle while in bIdle state

        if (!OnIdle(lIdleCount++))

        bIdle = FALSE; // assume "no idle" state

        }

        // phase2: pump messages while available

        do{

        // pump message, but quit on WM_QUIT

        if (!PumpMessage()) return ExitInstance();

        // reset "no idle" state after pumping "normal" message

        if (IsIdleMessage(&m_msgCur))

        {

        bIdle = TRUE;

        lIdleCount = 0;

        }

        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));

        }

        ASSERT(FALSE); // not reachable

        }

       CWinThread::Run()的处理过程如下:

        先根据空闲标志以及消息队列是否为空这两个条件判断当前线程是否处于空闲状态(这个“空闲”的含义同操作系统的含义不同,是MFC自己所谓的“空闲”),如果是,就调用CWinThread::OnIdle(),这也是我们比较熟悉的一个虚拟函数。

        如果不是用源码快速建站,从消息队列中取出消息,进行处理,直到消息队列为空。

        在这里,我们发现,MFC不是调用GetMessage()从线程消息队列中取消息,而是调用PeekMessage()。其原因在于,GetMessage()是一个具有同步行为的函数,如果消息队列中没有消息,GetMessage()会一直阻塞,使得线程处于睡眠状态,直到消息队列中有一条或多条消息,操作系统才会唤醒该线程,GetMessage()才会返回,如果线程处于睡眠状态了,就不会使线程具有MFC所谓的“空闲”状态了;而PeekMessage()则是一个具有异步行为的函数,如果消息队列中没有消息,它马上返回0,不会导致线程处于睡眠状态。

        在上面的代码中,有两个函数值得探讨,一个是空闲处理函数OnIdle(),另外一个是消息分发处理函数PumpMessage()。不要忽视CWinThread的OnIdle()函数,它作了很多有意义的事情。下面讨论PumpMessage(),OnIdle()将在后面的章节里讨论。

        CWinThread::Run()的核心――CWinThread::PumpMessage()

        标题强调了PumpMessage()的重要性,Run()是MFC的控制中心,而PumpMessage()又是Run()的核心,所以从MFC的真正控制中心是PumpMessage()。PumpMessage()的代码极其简单:

        BOOL CWinThread::PumpMessage()

        {

        ASSERT_VALID(this);

        if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))

        return FALSE;

        // process this message

        if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))

        {

        ::TranslateMessage(&m_msgCur);

        ::DispatchMessage(&m_msgCur);

        }

        return TRUE;

        }

        首先,PumpMessage()调用GetMessage()从消息队列中取一条消息,由于PumpMessage()是在消息队列中有消息的时候才被调用的,所以GetMessage()会马上返回,根据其返回值,判断当前取出的消息是不是WM_QUIT消息(这个消息一般对是通过调用PostQuitMessage()放入线程消息队列的),如果是,就返回FALSE,CWinThread::Run()该退出了,CWinThread::Run()直接调用CWinThread::ExitInstance()退出应用程序。在GetMessage()的后面是我们所熟悉的TranslateMessage()和DispatchMessage()函数。

       可以看出,是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。

        就我个人观点而言,正是有了这个PreTranslateMessage(),才使得MFC能够灵活的控制消息的分发模式,可以说,PreTranslateMessage()就是MFC的消息分发模式。

       <三>MFC的特色――PreTranslateMessage()

        经过层层扒皮,终于找到了CWinThread::Run()最具特色的地方,这就是PreTranslateMessage()函数。同前面使用SDK编写的显示”Hello, world!”程序的消息循环不同的地方在于,MFC多了这个PreTranslateMessage(),PreTranslateMessage()最先获得了应用程序的消息处理权!下面我们对PreTranslateMessage()进行剥皮式分析。同前面一样,首先看看实际的PreTranslateMessage()的代码:

       BOOL CWinThread::PreTranslateMessage(MSG* pMsg)

        {

        ASSERT_VALID(this);

        // if this is a thread-message, short-circuit this function

        if (pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg)) return TRUE;

        // walk from target to main window

        CWnd* pMainWnd = AfxGetMainWnd();

        if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg)) return TRUE;

        // in case of modeless dialogs, last chance route through main

        // window's accelerator table

        if (pMainWnd != NULL)

        {

        CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);

        if (pWnd->GetTopLevelParent() != pMainWnd)

        return pMainWnd->PreTranslateMessage(pMsg);

        }

        return FALSE; // no special processing

        }

        PreTranslateMessage()的处理过程如下:

        首先判断该消息是否是一个线程消息(消息的窗口句柄为空的消息),如果是,交给DispatchThreadMessageEx()处理。我们暂时不管DispatchThreadMessageEx(),它不是我们讨论的重点。

        调用CWnd::WalkPreTranslateTree()对该消息进行处理,注意该函数的一个参数是线程主窗口的句柄,这是PreTranslateMessage()的核心代码,在后面会对这个函数进行详细的分析。

        对于非模式对话框,这特别的、额外的处理。

        下面详细讨论一下CWnd::WalkPreTranslateTree()函数,它的代码很简单:

        BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)

        {

        ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));

        ASSERT(pMsg != NULL);

        // walk from the target window up to the hWndStop window checking

        // if any window wants to translate this message

        for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))

        {

        CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

        if (pWnd != NULL)

        {

        // target window is a C++ window

        if (pWnd->PreTranslateMessage(pMsg))

        return TRUE; // trapped by target window (eg: accelerators)

        }

        // got to hWndStop window without interest

        if (hWnd == hWndStop)

        break;

        }

        return FALSE; // no special processing

        }

       CWnd::WalkPreTranslateTree()的所使用的策略很简单,拥有该消息的窗口最先获得该消息的处理权,如果它不想对该消息进行处理(该窗口对象的PreTranslateMessage()函数返回FALSE),就将处理权交给它的父亲窗口,如此向树的根部遍历,直到遇到hWndStop(在CWinThread::PreTranslateMessage()中,hWndStop表示的是线程主窗口的句柄)。记住这个消息处理权的传递方向,是由树的某个一般节点或叶子节点向树的根部传递!

        小结:

        下面对这一章作一个小结。

        MFC消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage(),通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来,在下面的一章会对MFC的实现作详细介绍。

        只有穿过消息队列的消息才受PreTranslateMessage()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在

        传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理,在某些情况下,要仔细处理,以免漏掉消息。