车床调用程序OXXX按↓键执行,可是实际运行确实别的程序,怎么回事?? 1

【精品】数控类实习报告3篇

  隨着人们自身素质提升对我们来说并不陌生,报告成为了一种新兴产业为了让您不再为写报告头疼,下面是小编帮大家整理的数控类實习报告3篇欢迎阅读,希望大家能够喜欢

  在实习期间,我先后参加了车工数控机床,钳工焊工,刨工的实习从中我学到了佷多宝贵的东西,它让我学到了书本上学不到的东西增强自己的动手能力。

  车工是在车床上利用工件的旋转和刀具的移动来加工各種回转体的表面包括:内外圆锥面、内外螺纹、端面、沟槽等,车工所用的刀具有:车刀、镗刀、钻头等车销加工时,工件的旋转运動为主的运动刀具相对工件的横向或纵向移动为进给运动。面对着庞大的车床我们除了好奇外,对它也十分陌生老师给我们细心的講解车床的各个部件的名称和操作,我们逐渐熟悉车头进给箱,走刀箱托盘等主要部件的控制,老师要求我们先不开动车床重点进荇纵横向手动进给练习,要求达到进退动作准确、自如且要做到进给动作缓慢、均匀、连续。到一定程度后可开车练习每项操作都进荇到我们熟悉为止。

  经过师傅的讲解和我们的实际操作我们对于车床的加工范围和工件的加工顺序有了更深的了解,知道了什么样嘚结构在车车床上是可以轻松而精确加工的哪些是比较难加工的,这样如果我们需要做一些简单的设计时就能做到心中有数使结构尽鈳能合理,易于加工同时实际操作也增强了我们的动手能力。

  数控车床的操作是我们实习的第二个工种就是通过编程来控制车床進行加工。通过数控车床的操作及编程我深深的感受到了数字化控制的方便、准确、快捷,只要输入正确的程序车床就会执行相应的操作。比起我们前两天车床的操作要方便的多可以让机床自动连续完成多个步骤,同时在加工之前还可以进行模拟加工如果不成功的話,可以修给程序这样就减少了因为误操作而带来的原料的浪费。并且只要完成程序的编辑就可以用来重复加工,大大的提高了加工效率通过老师清晰明了重点突出的讲解,我们很快掌握了数控机床编程软件的应用对常用的功能能够熟练操作,并且学会基本语法和瑺用的编程语句能够进行简单的编程操作。随后我们开始按照图纸进行程序编辑工作开始的时候不太熟悉,总是出现加工出错的情况经过反复的研究和修改,第一个程序终于顺利完成了看着界面上成功模拟出加工的过程,加工出成品心中陡然升起一股成就感。

  钳工是我们这次金工实习中相对最累的一个工种我们的任务是要将一块条形的坯料加工成一个锤头。

  在操作之前师傅先给我们讲解了有关钳工工种和所用工具的一些内容我们了解到,钳工的种类是很多的例如说装配钳工、划线钳工等,钳工是金属加工中相当重偠的一个工种在产品的加工、机械维护以及修理中都需要钳工的参与。钳工所用的工具最重要的就是虎钳了还有手锯条,锉刀以及鑽床。我们知道了钳工的主要内容为刮研、钻孔、攻套丝、锯割、锉削、装配、划线;了解了锉刀的构造、分类、选用、锉削姿势、锉削方法和质量的检测首先要正确的握锉刀,锉削平面时保持锉刀的平直运动是锉削的关键锉削力有水平推力和垂直压力两种。锉刀推进时前手压力逐渐减小后手压力大则后小,锉刀推到中间位置时两手压力相同,继续推进锉刀时前手压力逐渐减小后压力加大。锉刀返囙时不施加压力这样我们锉削也就比较简单了。

  老师具体向我们介绍了几种连接方法焊接的概念、过程,常用焊接方法特别是掱弧焊,交流弧焊机焊条的种类、型号、组成和作用,工艺参数的选择等详细讲解了焊接的操作:引弧、运条、焊缝收尾,并一一向峩们演示指出各种大家易犯的错误,还说明了一些情况的处理最后,老师讲述了一些注意事项焊接所产生的气味和刺眼的光对人体嘟是有害的,我们在操作时要懂得保护自己带好手套和面罩。从老师的讲解中我了解到:焊条的角度一般在七十到八十之间要按照螺旋线来运条,运条的速度要求当然是匀速,然而在实际操作中我们往往是不快则慢,很难保持匀速因此焊出来的结果是很不流畅的,有的地方停留时间短则当然没有焊好还有裂纹,停留时间长的地方则经常会出现被焊透的毛病,出现了漏洞焊条的高度要求保持茬二至四毫米,然而在自己刚开始的时候也是漏洞百出因为在运条的同时,焊条在不断的减短因此要不断的改变焊条的原有高度,这控制起来就有些困难了高了则容易脱弧,而低了则容易粘住

  以前在金属工艺学上就学过有关焊接的知识,但只是停留在书本上的認识通过这两天的学习,我们更直接的认识了焊接设备掌握了手工电弧焊最基本的一些操作方法,虽然跟师傅比差的相当的多但我們所练习的是最基本也是最实用的东西,我想如果以后真的遇到需要的情况我能够成功的应付一些简单的情况了。

  为响应社会号召囷社会需求今年暑假我怀着高兴而又激动的心情来到xxx省xx市xx的一家工厂进行为期46天的社会实习,暑期数控社会实习报告此次实习的目的佷明确,一是走出课堂使自己所学的知识用到实习中去;二是锻炼自己为父母分忧,挣点生活费我学的是数控技术,数控技术应用重茬实习而东南沿海城市数控技术应用很多,因此我于7月8日打点行李来到广东省东莞市一家五金塑胶厂做一名暑假实习生――临时工该笁厂是一家分工厂,主要生产以塑胶为原料的各种牙箱为主以生产加工各种牙箱模具为辅,其主要产品有c-2901

内容摘要:CdeGear(Frm Brland) 公司公布了最新的Delphi 2007 Fr Win32版夲号作为一个 Delphi 的使用者,第一时间下载、安装并进行了体验现将一些使用感受记录例如以下

注:以下的对照主要是针对Delphi7与Delphi2007,以下列出嘚部分功能可能在Delphi8/中已存在

可在CdeGear官方站点下载试用版,或在VeryCD上寻找IS整个安装文件约 的反射、泛型等高级特性,节省编写IDE时间新的IDE确實比D7启动还要快,大概是五六秒时间左右就启动跟。这一点M$也做不到。DBX4新增加了Cnnectin Pl高级组件更令人心动的是,开放Driver Surce可自行扩展属性囷方法,哈哈ClreLab公司这回可高价卖不出去dbExpress驱动了。DBX4也全面支持Uicde

Win32支持Ajax技术—,由于给别人敲代码还要别人装无用的东西才干运行(当然对潒是企业的话没什么所谓);之后在CSDN听到一些残缺不全的消息说D2007又要装.Net了?转而失望;幸而从这里看仅仅是装.Net的开发时环境而已,运荇库并不须要至此疑虑全消。并且听说D2007还能针对2000、XP和Vista多种系统公布不同的程序这个功能太棒了!曾经写的程序,总是部分人能用部分囚不能想出多版本号的话,自己多装个系统在那个系统下编译吧这不是一般的麻烦。希望此功能是真的

2、启动和编译速度比D7还快,這个也非常吸引人Delphi的编译速度本来就非常有名了(用过C系列的就能对照出来)。之后听说D2006又用一种新技术改进了内存管理可惜D2006还没装,没能体验这下D2007竟然比D7还快了,希望不是仅仅针对特殊项目弄出来的“演示效果”

3、关于Unicde,强烈期待实现整个IDE环境的Unicde化某次写跟韩攵有关的程序已经被整慘过了.... -_,- 这点Delphi须要向C#靠拢。

4、尽管IntraWeb自上次写日志来还暂时没安排到学习时间。只是偶还是相信那位Delphi达人的话相信咜的前途。如今都出到平台的BDS 2006开发部门独立成立CdeGear 后,又回到原生Win32环境下的Delphi 2007 fr Win32江元麟24年程序开发经验,一路见证了Delphi的变化

从1987年開始接触Brland,江元麟用过Turb Pascal和Turb C1995年,由于工作须要開始使用Delphi2000年,他投入生物识别产业继续使用Delphi 5开发,他指出:「Delphi有一个非常好的长处是能够开发自巳的组件它的组件让我们的产品开发加速非常快。新进prject师能立即就作一些简单的开发这是Delphi最优秀的地方。」

相较于当时其它开发工具他觉得:「VB当时没办法全然用对象导向的方式去开发组件,比較不是给Engineer用而是给Pwer User使用。而C++要客制化组件难度颇高它的平台没有那么靈活。」

为何一直用Delphi江元麟解释说:「是由于它的平台,非常多Surce Cde都有释出所以你能够开发一些真的是自己会用到的基层组件。我们公司的组件已经累积5年到10年都有一个组件能够撑那么久,代表它非常稳定了相对的我们公司的产品出来质量是非常好的,这也是Delphi的贡献……这也是为什么我们宁可在Delphi上花力气结合C++来处理新挑战。」3年前知网的识别软件能让Pentium 4 处理器在1秒内辨识十万枚指纹,是当时国外最高速度的3倍他说:「这当中有一部份是由Delphi编译出来的程序代码效率相当好的贡献。」

尽管当天江元麟的问题没有立即的解决方式但对於脱离Brland后的GdeGear,他表示:「蛮喜欢分割出来的CdeGear曾经步调非常慢,如今步调非常快我比較喜欢,听李维传递的讯息感觉比較有活力,但唏望能维持曾经的速度和质量两年前看到Brland公司非常乱,觉得非常遗憾周围的人两年前已经慢慢转到C#去了。」他接着说:「我们本来詓年要考虑转成C#,如今要又一次考虑了

我在本文中要谈的不是编码的技术实现我所关注的是关于编码的风格的问题。我在编写了e速的编碼规范之后产生了要写一些关于程序编码风格的念头;因此,就有了以下的文章这些仅仅是本人的想法,可能在文章中还有一些未尽洳人意的地方所以肯请大家能够给与谅解。

非常多人在谈到编码的艺术时总会说我的程序怎么怎么的厉害,功能多么的强大好像什麼事情都能完毕一样;可是去运行他的程序,bug不断;连他自己都不知道错在了什么地方打开他的程序一看,代码写的凌乱不堪;命名上鈈规范为了偷懒和简便有些命名干脆就用一个字母或者其它的简单符号取代,甚至于有些代码连他自己也搞不清是干什么了更不要说怎样让别人去改动了….本人编码也快4个年头了,像上述的样例遇见过不少整个程序改动起来实在是头疼。

的确一件好的艺术品不在于其功能是多么的完好,而在于别人赞赏起来是否有它内在的美和是否非常easy就把它从杂货堆里一眼就能辨认出来;毕竟它是艺术品而非日用品我们敲代码也是同样,假设程序中的格式非常随意比如对数组做循环,一会儿採用下标变量从下到上的方式一会儿又用从上到下嘚方式;对字符串一会儿用s t r c p y做复制,一会儿又用f r循环做复制;等等这些变化就会使人非常难看清实际上究竟是怎么回事了。

写好一个程序当然须要使它符合语法规则、修正当中的错误和使它运行得足够快,可是实际应该做的远比这多得多程序不仅须要给计算机读,也偠给程序猿读一个写得好的程序比那些写得差的程序更easy读、更easy改动。经过了怎样写好程序的训练生产的代码更可能是正确的。

凝视:凝视是帮助程序读者的一种手段可是,假设在凝视中仅仅说明代码本身已经讲明的事情或者与代码矛盾,或是以精心编排的形式干扰讀者那么它们就是帮了倒忙。最好的凝视是简洁地点明程序的突出特征或是提供一种概观,帮助别人理解程序在标注凝视的同一时候,应该注意以下的问题:

不要大谈明显的东西凝视不要去说明明确白的事,比方i + +能够将i值加1等等凝视应该提供那些不能一下子从代碼中看到的东西,或者把那些散布在很多代码里的信息收集到一起当某些难以捉摸的事情出现时,凝视能够帮助澄清情况假设操作本身非常明了,反复谈论它们就是画蛇添足了;给函数和全局数据加凝视凝视当然能够有价值。对于函数、全局变量、常数定义、结构和類的域等以及不论什么其它加上简短说明就能够帮助理解的内容,我们都应该为之提供凝视全局变量常被分散使用在整个程序中的各個地方,写一个凝视能够帮人记住它的意义也能够作为參考。放在每个函数前面的凝视能够成为帮人读懂程序的台阶假设函数代码不呔长,在这里写一行凝视就足够了有些代码原本非常复杂,可能是由于算法本身非常复杂或者是由于数据结构非常复杂。在这些情况丅用一段凝视指明有关文献对读者也非常有帮助。此外说明做出某种决定的理由也非常有价值。

职业程序猿也常被要求凝视他们的全蔀代码可是,应该看到盲目遵守这些规则的结果却可能是丢掉了凝视的真谛。凝视是一种工具它的作用就是帮助读者理解程序中的某些部分,而这些部分的意义不easy通过代码本身直接看到我们应该尽可能地把代码写得easy理解。在这方面你做得越好须要写的凝视就越少。好的代码须要的凝视远远少于差的代码

编码的风格:全局变量应该採用具有描写叙述意义的名字,局部变量用短名字函数採用动作性的名字。给神奇的数起个名字现实中存在很多命名约定或者本地习惯。常见的比方:指针採用以p结尾的变量名比如n d e p;全局变量用大寫开头的变量名,比如G l b a l;常量用全然由大写字母拼写的变量名如C N S T A N T S等。命名约定能使自己的代码更easy理解对别人写的代码也是一样。这些約定也使人在写代码时更easy决定事物的命名对于长的程序,选择那些好的、具有说明性的、系统化的名字就更加重要

保持一致性。要准確以缩行形式显示程序结构。使用表达式的自然形式利用括号排除歧义。分解复杂的表达式要清晰。当心副作用使用一致的缩行囷加括号风格。为了一致性使用习惯使用方法。用else-if 处理多路选择避免使用函数宏。给宏的体和參数都加上括号这些都是非常琐碎的倳情,但却又是非常有价值的就像保持书桌整洁能使你easy找到东西一样。与你的书桌不同的是你的程序代码非常可能还会被别人使用。

鼡缩行显示程序的结构採用一种一致的缩行风格,是使程序呈现出结构清晰的最省力的方法

用加括号的方式排除二义性。括号表示分組即使有时并不必要,加了括号也可能把意图表示得更清晰在混合使用互相无关的运算符时,多写几个括号是个好主意C语言以及与の相关的语言存在非常险恶的优先级问题,在这里非常easy犯错误比如,由于逻辑运算符的约束力比赋值运算符强在大部分混合使用它们嘚表达式中,括号都是必需的

利用语言去计算对象的大小。不要大谈明显的东西给函数和全局数据加凝视。不要凝视不好的代码应該重写。不要与代码矛盾澄清情况,不要添乱

界面的风格:隐蔽实现的细节。不要在用户背后搞小动作在各处都用同样方式做同样嘚事。释放资源与分配资源应该在同一层次进行在低层检查错误,在高层处理仅仅把异经常使用在异常的情况。

写良好的代码更easy阅读囷理解差点儿能够保证当中的错误更少。进一步说它们通常比那些马马虎虎地堆起来的、没有细致推敲过的代码更短小。在这个拼命偠把代码送出门、去赶上最后期限的时代人们非常easy把风格丢在一旁,让将来去管它们吧可是,这非常可能是一个代价非常昂贵的决定上面的一些陈述性的言语充分的说明了,假设对好风格问题重视不够程序中哪些方面可能出毛病。草率的代码是非常坏的代码它不僅难看、难读,并且经常崩溃好风格应该成为一种习惯。假设你在開始写代码时就关心风格问题假设你花时间去审视和改进它,你将會逐渐养成一种好的编程习惯一旦这样的习惯变成自己主动的东西,你的潜意识就会帮你照料很多细节问题甚至你在工作压力下写出嘚代码也会更好

Delphi面向对象的编程方法

Delphi的编程语言是以Pascal为基础的。Pascal语言具有可读性好、编写easy的特点这使得它非常适合作为基础的开发语言。同一时候使用编译器创建的应用程序仅仅生成单个可运行文件(.EXE),正是这样的结合使得Pascal成为Delphi这样的先进开发环境的编程语言。

本章中我们将讨论bject Pascal的主要特点,并解说怎样在事件处理过程和其它应用程序中使用它来编制程序代码。本章将解说Delphi应用程序中最经常使用的bject Pascal語法而不是Pascal语言的一切细节。假设您全然不熟悉Pascal编程请參阅一些基础的Pascal教程。假设您具有编程经验并能熟练地使用其它流行程序语訁,您将在本章的bject Pascal中发现一些同样的概念假设您已经熟悉了Brland Pascal,就能够高速浏览或跳过本章

在前边的章节中,我们通过例程已经编写叻几行简单的代码。在本章中我们将从熟悉Pascal编程的角度,配合实例解说bject Pascal编程的基本方法。

Pascal程序时要注意程序的可读性。Pascal语言是英式結构语言在程序中选择合适的缩排、大写和小写风格,并在须要时将程序代码分行会使得程序代码能够非常easy地被自己和他人读懂。一般的程序猿都有这样的体验:假设不给程序加上适当的注解一段时间后,自己也难以理清程序的流程给程序及时地加上凝视是良好的編程习惯。Delphi的凝视须要加注在{}之间编辑器会把它们处理成为空白。Delphi保留了Brland Pascal编辑器的风格keywrd採用黑体字,被凝视的部分会变暗这使得编程风格良好,易读易写

在事件处理过程中,最经常使用到的工作就是把一个新值赋给一个属性或变量在设计用户界面时,能够使用bject Inspectr(bject Inspectr)来妀变其属性;但有时须要在程序运行时改变属性的值并且有些属性仅仅能在运行时改变,这些属性在Delphi的在线帮助的“Prprety”主题中被标为运荇期属性进行这样的改变,就必须使用赋值语句

下文的赋值语句表征一个nClick事件。当buttn按动后将编辑框部件Edit1的Clr属性置为clRed:

当按动buttn后赋值语呴被运行,编辑框变成红色

在语句中,部件的名称在属性前中间用“.”表示属性的所属关系。这样就准确地指定了要将clRed值赋给哪一部件的哪一属性赋值号为“:=”,不论给属性还是给变量赋值都是将右边的值赋给左边的属性或变量。

当将一个属性值、变量、常量或文夲数据赋给属性或变量时所赋值的类型和接受此值的属性或变量的类型应同样或兼容。一个属性或变量的类型定义了此属性或变量的可能值集合也定义了程序代码能够运行的运算。在前边的例程中编辑框部件的Clr属性和clRed的类型都是TClr。能够在在线帮助中找到一个属性的类型;第二种方法是在bject Inspectr中选定该属性值段并按下F1键,则类型将在属性说明的结尾处列出比如Clr属性列出下边的语句:

有些属性是仅仅读(Read nly)的,它们仅仅能被读取不能被改变。请查阅在线帮助在Delphi中这些仅仅读属性都有注解。

2.1.2 标识符的说明与使用

标识符是Delphi应用程序中一些量的洺称这些量包括变量(var)、常量(cnst)、类型(type)、过程(prcedure)、方法(Methd)及其它,bject Pascal 在应用标识符时必须首先说明它们。bject Pascal是强类型语言它的编译器能够检查确保赋给变量或属性的值是正确的类型,以便于您改正错误由于bject Pascal是编译语言,所以Delphi的运行速度要比使用解释语言快得多在使用标识符前說明它们,能够降低程序错误并增加代码的效率

变量是程序代码中代表一个内存地址的标识符,而此地址的内存内容在程序代码运行时能够被改变在使用变量前必须对它进行说明,即对它进行命名并说明它的类型。在全部变量说明曾经加上保留字var变量说明左边是变量的名称,右边则是该变量的类型中间用(:)隔开。

在窗口中增加一个名称为Edit1的编辑框再增加一个名称(属性Name)为Add的buttn部件,并建立例如以下的倳件处理过程:

在本例中当按动ADDbuttn时,编辑框中显示值120在bject Pascal中,必须确保变量或属性被赋予类型同样或兼容的值您能够尝试将赋给X的值妀为100.0,或去掉IntTStr函数在编译时会出现类型不匹配的错误,这也说明了bject Pascal强类型语言的特点

bject Pascal有多个提前定义的数据类型,您能够说明不论什麼这些类型的变量:

实型:Single能够包括7到8位有效小数部分占用4字节的内存;Duble类能够包括15到16位有效小数部分,占用8字节的内存;Extended类型包括19到20位有效小数部分占用10字节内存;Cmp能够包括19到20位有效小数部分,占用8字节内存以上实数类型仅仅有在选项[N+]打开才干够使用。Real能够包括11到12位有效小数部分占用6字节内存。它仅仅有在和曾经Brland

布尔型:Blean仅仅包括true或False两个值,占用1字节内存

字符型:Char,一个ASCII字符;字符串类型String一串最长可达255个ASCII字符

指针型:Pinter,能够指向不论什么特定类型

字符串型:PChar,是一个指向以零结尾的字符串的指针

除了提前定义类型外,Delphi還有自行定义的类型上述例程的TClr就是这样的类型。此外用户还能够定义自己的数据类型,这部分内容将在下文中具体讲述

整型类别囷实型类别都各有五种类型,同一类别中全部的类型与其它同类别的都相容,您能够将一种类型的值赋给同样类别中不同类型的变量或屬性而仅仅须要这个值的范围在被赋值的变量或属性的可能值范围内。比如对于一个Shrtint型的变量,能够接受在-128到127范围内的随意整数比洳Shrtint类型的7;您不能将300赋给它,由于300已经超出了Shrtint的范围了将范围检查功能打开(选用ptins|Prject,并在Cmpiler ptins Page中选择Range Checking)将会检查出一个范围错误;假设Range Checking没有被咑开,那么程序代码将能够运行但被赋值的值将不是您期望的值。

在一些情况下您能够进行不同类型的变量或属性的赋值。一般来说能够将一个较小范围的值赋给一个较大范围的值。比如您能够将整型值10赋给一个接受实型值的Duble属性而使得值成为10.0,但假设将一个Duble类型嘚值赋给整形变量则会出现类型错误。假设您不清晰类型的兼容性能够參阅Delphi的在线帮助中“Type Cmpatibility and Assignment

常量在说明时就被赋予了一个值,在程序運行过程中是不可改变的以下的样例说明了三个常量:

象变量一样,常量也有类型不同的是,常量假设其类型就是常量说明中其所代表的值的类型上文的三个常量的类型各自是real型、整形、字符串型。常量用“= " 表示两边的值是相等的

过程与函数是程序中运行特定工作嘚模块化部分。Delphi的运行库包括很多过程与函数以供您的应用程序调用您不必了解过程与函数的逻辑,但要知道过程与函数的用途在对潒中说明的过程和函数称为方法(Methd)。全部的事件处理过程都是过程以保留字prcedure开头。每个事件处理过程仅仅包括了当这一事件发生时须要运荇的程序代码在事件处理过程中使用Delphi已经存在的过程与函数,仅仅需在程序代码中调用它们就可以

下文将通过对一个Mem部件的文本进行剪切、拷贝、粘贴、清除等编辑的应用程序编制,介绍使用Delphi过程和函数的调用方法

Mem(备注)部件有一个CutTClipbard方法,实现将用户在mem中选择的文本移箌剪贴板上去由于这个功能已经被建立在此方法中了,所以您仅仅需知道这种方法做什么以及怎样使用它就可以

通过指定Mem1的名称,说奣调用哪一个部件的CutTClipbard方法假设不指明对象名称,Delphi会显示Unknwn identifier错误当该事件处理过程被触发,程序会运行CutTclipbard中的语句将Mem1中的文本剪贴到剪贴板上去。

下文的例程展示了怎样调用Delphi的方法实现将备注部件的文本信息剪切、复制到剪贴板上;将剪贴板上的标记文本粘贴到备注中,清除备注部件中的全部文本等四个功能

打开一个新的空窗口,增加一个mem部件和四个buttn并排列整齐。改变buttn部件的Name属性分别命名为Cut,Cpy,Paste,Clear。您会發现当Name属性发生改变时,Captin属性将发生对应的变化在Captin属性前加标“&”号设立加速键

将mem部件的ScrllBars属性设为ScVertical,以便加上滚行条将WrdWrap属性设置为True,这样当用户输入文本到达Mem部件的右边缘时会自己主动回行将Line属性第一行的Mem1文本删除,使得mem部件在初始显示时为空的

为每个buttn建立例如鉯下的事件处理过程:

运行此程序。您能够在备注部件中输入文本在进行了文本的标记后,能够随意地进行剪切、拷贝、粘贴和清除當buttn被按动时,就调用对应的过程进行处理用户能够通过查阅在线帮助进行Mem部件的Tpic Search,在Mem Cmpnent项中查阅Methd会得到以上过程的具体说明。

有些过程偠求用户指明參数被调用的过程会在运行时使用传入的參数值,这些值在过程中被觉得是已经被说明的变量比如,LadFrmFile方法在TString对象中被说奣为:

在调用这一过程时应指明FileName參数是要装入的文件名。以下的程序将先打开pen对话框当您选择了一个文件后,Delphi将把该文件读入一个Mem部件:

与过程一样函数的程序代码也运行特定的工作。它和过程的差别为:函数运行时会返回一个值而过程则没有返回值。函数能够用來赋给一个属性或变量;也能够使用返回值来决定程序的流程

前文中我们实际上已经接触过了函数。在讲述变量时曾用到过以下的程序段: Edit1.Text := IntTStr(X + Y);当中,IntTStr(Value)把一个LngInt类型的数值转化为字符串的值Value是IntTStr唯一的參数,它能够是一个整形的值、变量、属性或产生整形值的表达式调用函数,必须把返回值赋给和此返回值类型兼容的变量或属性

有些函数返回一个True或False的布尔量,用户的程序能够依据返回值来决定跳转下攵的例程讲述了函数返回值为Blean的推断使用方法:

if语句会计算一个表达式,并依据计算结果决定程序流程在上文的例程中,依据ClrDialg.Execute的返回值决定窗口的背景颜色。if保留字后尾随一个生成Blean值True或False的表达式一般用“=”作为关系运算符,比較产生一个布尔型值当表达式为True时,运荇then后的语句否则运行else后的代码,if语句也能够不含else部分表达式为False时自己主动跳到下一行程序。

if语句能够嵌套当使用复合语句表达时,複合语句前后需加上begin…endelse保留字前不能加“;”,并且编译器会将else语句视为属于最靠近的if语句。必要时须使用begin…end保留字来强迫else部分属於某一级的if语句。

case语句适用于被推断的变量或属性是整形、字符型、枚举型或子界型时(LngInt除外)用case语句进行逻辑跳转比编写复杂的if语句easy阅读,并且程序代码整形较快

以下的例程显示一个使用case语句的窗口:

建立例如以下的事件处理过程:

运行程序,当Edit1部件接受到一个值并按動“K”buttn触发程序后,Number便被赋值为用户输入的数值case语句依据Number的值推断该运行哪一条语句。象if语句一样case语句也有可选择的else部分。case语句以end结尾

repeat语句会反复运行一行或一段语句直到某一状态为真。语句以repeat開始以until结束,其后尾随被推断的布尔表达式參阅以下的例程:

当此语呴被运行时,窗口的下方会出现1到10的数字布尔表达式 i=10 (注意,与其它语言不同的是“=”是关系运算符,而不能进行赋值操作)直到repeat..until程序段嘚结尾才会被计算这意味着repeat语句至少会被运行一次。

while语句和repeat语句的不同之处是它的布尔表达式在循环的开头进行推断。while保留字后面必須跟一个布尔表达式假设该表达式的结果为真,循环被运行否则会退出循环,运行while语句后面的程序

以下的例程达到和上面的repeat例程达箌同样的效果:

fr语句的程序代码会运行一定的次数。它须要一个循环变量来控制循环次数您须要说明一个变量,它的类型能够是整形、咘尔型、字符型、枚举型或子界型

以下的程序段会显示1到5的数字,i为控制变量:

以上介绍了三种循环语句假设您知道循环要运行多少佽的话,能够使用fr语句fr循环运行速度快,效率比較高假设您不知道循环要运行多少次,但至少会运行一次的话选用repeat..until语句比較合适;當您觉得程序可能一次都不运行的话,最好选用while..d语句

程序模块在bject Pascal中是非常重要的概念。它们提供了应用程序的结构决定了变量、属性徝的范围及程序运行的过程。它由两个部分组成:可选择的说明部分和语句部分假设有说明部分,则必在语句部分之前说明部分包括變量说明、常量说明、类型说明、标号说明、程序,函数方法的说明等。语句部分叙述了可运行的逻辑行动

在Delphi中,最常见的程序模块便是事件处理过程中的程序模块以下的事件处理过程是含有变量说明部分的程序模块:

库单元也是程序模块。库单元的interface部分含有库函数、类型、私有公有域的说明,也能够含有常量、变量的说明这一部分能够作为程序模块的说明部分。在库单元的implementatin部分中通常含有各种倳件处理过程它们能够视为模块的语句部分,是事件处理模块库单元模块结束于库单元结束的end.处。

程序模块中能够包括其它的程序模塊上文库单元模块中含有事件处理模块。而库单元模块实际是在prject程序模块中

全部的Delphi应用程序都有同样的基本结构。当程序逐渐复杂时在程序中增加模块就可以。比如在库单元模块中增加事件处理模块向prject中增加库单元模块等。模块化编程使得程序结构良好并且对数據具有保护作用。

一个变量、常量、方法、类型或其它标识符的范围定义了这个标识符的活动区域对于说明这个标识符的最小程序模块洏言,此标识符是局部的当您的应用程序在说明一个标识符的程序模块外运行时,该标识符就不在此范围内这意味着此时运行的程序無法訪问这个标识符,仅仅有当程序再度进入说明这个标识符的程序模块时才干够訪问它。

以下的示意图表示一个含有两个库单元的prject烸个库单元中又各有三个过程或事件处理过程。

2.1.7.2 訪问其它程序模块中的说明

您能够在当前的程序模块中訪问其它程序模块中的说明比如您在库单元中编写一个事件处理过程来计算利率,则其它的库单元能够訪问这个事件处理过程要訪问不在当前库单元中的说明,应在这個说明之前加上其它应用程序的名称和一个点号(.)比如,在库单元Unit1中有事件处理过程CalculateInterest过程如今您想在库单元Unit2中调用这一过程,则能够在Unit2嘚uses子句中增加Unit1并使用以下的说明:

应用程序的代码不能在一个模块外訪问它说明的变量。事实上当程序运行跳出一个模块后,这些变量就不存在于内存中了这一点对于不论什么标识符都是一样的,无论事件处理过程、过程、函数还是方法都具有这一性质。这样的标識符称为局部变量

2.1.7.3 依照作用范围说明标识符

您能够在应用程序的不同地方说明一个标识符,而仅仅需保证它们的有效范围不同就可以編译器会自己主动訪问最靠近当前范围的标识符。

库单元的全局变量一般能够说明在保留字implementatin后面比如,以下的例程实现将两个编辑框中嘚整数相加显示在第三个编辑框中。用到了一个整形的全局变量Cunt:

为了实现每按动一次buttnCunt增加一次必须对全程变量Cunt进行初始化处理。在程序库单元的结尾处最后一个end.保留字之前,增加保留字initializatin和初始化Cunt的代码:

这样当事件处理过程AddClick被触发时Cunt就会被增加一次,以表征计算佽数假设用面向对象编程,则Cunt能够说明成窗口的一个域这在下一节中将有讲述。

2.1.8 编写一个过程或函数

在您开发Delphi应用程序时所需的大蔀分代码都编写在事件处理过程中,但有时仍然须要编写不是事件处理过程的函数或过程比如,您能够把在多个事件处理过程中用得到語句编写成过程然后不论什么事件处理过程、过程、函数都能够象调用已经存在的过程或函数一样直接调用它。长处是您仅仅需编写一佽代码并且程序代码会比較清晰。

2.1.8.1 一个自行编写的函数例程

在上文两个数相加的程序中假设编辑框中无值,则会使得程序出错中断為避免这样的情况,编写以下的函数检查编辑框中是否有值,如无值则提醒用户输入:

NValue函数会检查编辑框是否为空,假设是编辑框顏色变红,并提醒用户输入一个整数然后函数返回真值;Result保留字在Delphi中用来专指函数返回值。在上文的例程中增加NValue函数:

假设当中的不论什么一个返回真值则表示有编辑框空,会运行exit过程使得当前的程序模块停止运行,并使得编辑框出现输值提示当新值被输入后,再運行程序时红色提示被隐去,恢复正常的计算状态

每个过程或函数都以标题開始,当中包括过程或函数的名称和它使用的參数过程鉯保留字prcedure開始,函数以保留字functin開始參数位于括号中面,每个參数以分号分隔比如:

您也能够将同样类型的參数组合在一起,则上述过程头写作:

函数在标题中还多了一项:返回值的类型以下是一个返回值为Duble型的函数标题:

2.1.8.3 函数和过程中的类型说明

一个过程或函数程序模块也含有说明部分和语句部分。说明部分能够包括类型说明、变量说明、常量说明等除了bject Pascal语言中已经定义的类型之外,Delphi的应用程序还能够建立新的数据类型类型说明部分有保留字type開始。以下是一些类型的说明:

在类型标识符后面用“=”号定义了新的类型。类型界萣了变量的取值范围比如,TCunt类型的变量必须是整形值;一个TPrimaryClr类型的变量仅仅能是red、yellw或blue等等每个类型的名称都是由字母T開始,这并不是必须的但它是Delphi的惯例,在差别类型名和标识符时非常实用类型说明能够是局部的,也能够是全局的假设您把它放在implementatin后面,则表明对於库单元来讲它是全局的,全部的事件处理过程和其它的过程、函数都能够调用它假设类型是在过程中被说明的,则是局部的离开這一过程,该类型将失效

一般来讲,在过程和函数中不论什么类型说明都在变量说明之前,而不论什么变量说明都在常量之前可是,仅仅要遵从说明必须在过程与函数的标题之后并且在程序代码之前,即是有效的

2.1.8.4 过程和函数的语句部分

过程或函数的语句部分由begin開始,end结束函数须要一个返回值。能够将返回值赋给函数名称也能够将返回值赋给Result变量。以下的例程将返回值赋给函数名称:

将返回值賦给Result变量也是能够的则上面的程序改为:

以下是这个函数的调用方法:

在Implementatin后面的过程和函数,能够且仅仅能被此库单元的事件处理过程使用要让过程和函数能够被其它的程序库单元使用,则须要将过程或函数的标题部分放在库单元中的interface部分而把含标题的整个过程或函數放在库单元的inplementatin部分,并在要訪问这个过程或函数的库单元的uses子句中增加说明这个过程或函数的库单元名称

在bject Pascal中,过程或函数必须先说奣再调用上文的NValue函数必须在使用它的事件处理过程之前说明和运行,否则程序会报告一个未知标识符的错误

以上规则在递归调用时是唎外情况。所谓递归调用是指函数A调用函数B,而函数B又调用函数A的情况在递归调用中,函数要进行前置即在函数或过程的标题部分朂后加上保留字frwrd。下文的例程是一个递归调用的典型样例:

buttn的nClick事件处理过程给Alpha赋初值并实现先减1再除2的循环递归调用,直到Alpha小于0为止

當您的程序代码在调用一个过程或函数时,通经常使用參数传递数据到被调用的过程或函数中最经常使用的參数有数值參数、变量參数囷常量參数三种。

由被调用过程或函数定义的參数为形參而由调用过程或函数指明的參数叫实參。在NValue函数中说明函数体中的AnEditBx是形參,洏调用时在if NValue(Edit1)…中Edit1是实參。

数值參数在运行过程中仅仅改变其形參的值不改变事实上參的值,即參数的值不能传递到过程的外面试看鉯下的例程:

用以下例程调用Calculate函数:

Number接受由编辑框1输入的数值,经Calculate过程运算它是一个数值型实參。在进入Calculate函数后会把Number实參拷贝给形參CalN,在过程中CalN增大十倍但并未传递出来,因此Number值并未改变在编辑框2中显示仍然是编辑框1中的输入值。形參和实參占用不同的内存地址茬过程或函数被调用时,将实參的值复制到形參占用的内存中因此出了过程或函数后,形參和实參的数值是不同的但实參的值并不发苼变化。

假设您想改变传入的參数值就须要使用变量參数,即在被调用程序的參数表中的形參前加上保留字var比如:

则CalN并不在内存中占領一个位置,而是指向实參Number当一个变參被传递时,不论什么对形參所作的改变会反映到实參中这是由于两个參数指向同一个地址。将仩一个例程中过程头的形參CalN前面加上var再以同样的程序调用它,则在第二个编辑框中会显示计算的结果把第一个编辑框中的数值放大十倍。这时形參CalN和实參Number的值都是Nnmber初始值的10倍

假设当过程或函数运行是要求不改变形參的值,最保险的办法是使用常量參数在參数表的參數名称前加上保留字cnst能够使一个形參成为常量參数。使用常量參数取代数值參数能够保护您的參数使您在不想改变參数值时不会意外地將新的值赋给这个參数。

2.1.9 定义新的数据类型

bject Pascal有一些系统提前定义的数据类型在2.1.2中已经对它们作了介绍。您能够利用这些数据类型以建立噺的数据类型来满足程序的特定须要以下简单地叙述了您能建立的主要数据类型,如枚举型、子界型、数组型、集合型、记录型、对象型等

一个枚举型的说明列出了全部这样的类型能够包括的值:

能够定义上述枚举类型的变量:

在枚举型中,括号中的每个值都有一个由說明它的位置决定的整形值比如Sunday有整形值0,Mnday有整形值1等您能够把DayfWeek说明为一个整形变量,并将一星期的每一天赋一个整形值以达到同样嘚效果但用枚举型会使得程序可读性好,编写easy当您在枚举型中列出值时,您同一时候说明了这个值是一个标识符比如您的程序中假設已经含有TDays类型且说明了DayfWeeks变量,则程序中便不能使用Mnday变量由于它已经被说明为标识符了。

子界型是下列这些类型中某范围内的值:整形、布尔量、字符型或枚举型在您想限制一个变量的取值范围时,子界型是非常实用的

子界型限定了变量的可能取值范围。当范围检查咑开时(在库单元的Implementatin后面有{$R*.DFM}字样表示范围检查打开,否则您能够在ptins|Prject|Cmplier ptins中选择Range Cheking来打开范围检查)假设变量取到子界以外的值,会出现一个范围檢查错误

数组是某种数据类型的有序组合,当中每个元素的值由其相对位置来指定您能够在数组的某个位置上放置数据,并在须要时使用这些数据以下的类型说明了一个Duble型的数组变量:

它表示Check指向一个含有10个Duble型元素的数据串列,代表每个元素的是1到10之间的数字称为索引。数组的每一项由数组名称加上[]中的索引来表示Check包括10个变量,Check[1]表示第一个变量您也能够把数组定义成类型:

您能够通过给数组赋徝等方法来使用数组。以下的语句将0.0赋给Check数组中的全部元素:

数组也能够是多维的以下的类型定义了一个20行、20列的数组。

想将这一表格嘚全部数据初始化为0.0您能够使用fr循环:

字符串类型事实上是一个一维的字符数组。当您说明一个字符串型的变量时您应当指明这个字苻串的大小,以下是说明字符串类型的样例:

则变量MyName被说明成为最多能够包括15个字符假设您没有说明字符串的大小,Delphi会觉得字符串包括朂大值255个字符给字符串赋值能够直接使用单引號括起的字串赋值:

由于MyName是一个能够包括15个字符的MyString型变量,上文的两个的变量都是有效的一个汉字能够视作两个字符。当您给字符串型变量赋的值多于定义数值时比如将MyName赋为‘FrankSmith.Franklin’,则Delphi仅仅会接受前15个字符‘FrankSmith.Fran’在内存中,芓符串通常占用比所说明的大小多一个字节的空间由于第一个位置是一个包括这个数组大小的字节。您能够使用索引值来訪问字符串的芓符MyName[1]能够得到MyName的第一个字符'F'。

您能够使用Delphi丰富的运算符、过程和函数来处理字符串型的变量和属性以下介绍几个经常使用的运算符和Delphi過程或函数:

Cncat和(+)功能同样,都能够将多个字符串组合在一起建立一个较大的字符串;Cpy会返回一个字符串中的子字符串;Delete在一个字符串中從一个指定位置起删除一定数目的字符;Insert在一个字符串中插入一个字符串;Length返回字符串的长度;Ps返回一个子字符串在一个字符串中的位置,即索引值

集合类型是一群同样类型元素的组合,这些类型必须是有限类型如整形、布尔型、字符型、枚举型和子界型在检查一个值昰否属于一个特定集合时,集合类型非常实用以下的例程能够说明集合类型的使用方法:

在窗口上增加一个编辑框和一个buttn,清除编辑框Φ的文字在其上加上Captin为“输入元音”的标签Label,并在编辑框的下方增加一个空的标签将buttn的Default属性改为True,建立buttn的事件处理步骤例如以下:

运荇这个程序在编辑框中输入字母,表达式Edit1.Text[1] in Vwels的结果是布尔型的in是运算符,用来推断字母是否存在于集合中输入的判别结果会显示在编輯框的下方。以上就用到了集合类型TVwels

记录是您的程序能够成组訪问的一群数据的集合。以下的例程说明了一个记录类型的使用方法:

记錄包括能够保存数据的域每个域有一个数据类型。上文的记录TEmplyee类型就含有四个域您能够用以下的方式说明记录型的变量:

用例如以下嘚方法能够訪问记录的单域:

编写例如以下的语句能够给整个记录赋值:

您的程序能够将记录当成单一实体来操作:

以上介绍了用户经常使用的自己定义类型。在Delphi的编程中对象是非常重要的用户自己定义数据类型。象记录一样对象是结构化的数据类型,它包括数据的域(Field)也包括作为方法的过程和函数。在Delphi中当您向窗口中增加一个部件,也就是向窗口对象中增加了一个域;每个部件也是对象每当您建竝一个事件处理过程使得部件能够响应一个事件时,您即自己主动地在窗口中增加了一个方法在本章第2节中,将具体讲述Delphi面向对象编程嘚方法和技巧

Units是常量、变量、数据类型、过程和函数的集合,并且能够被多个应用程序所共享Delphi已经拥有很多提前定义的程序库单元可供您建立您的程序库单元使用。Delphi的Visual Cmpnent Library由多个程序库单元组成它们说明了对象、部件以供您的应用程序用来设计用户界面。比如当您在窗ロ中增加一个Check Bx时,Delphi自己主动在您的程序库单元中增加了Stdctrls库单元由于TCheckBx部件是在StdCtrls库单元中说明的。

当您设计您的窗口时Delphi自己主动建立一个囷您的窗口有关的库单元。您的库单元不必都和窗口有关也能够使用提前定义的仅仅包括数学运算函数的库单元,或是自行编写数学函數库单元在一个库单元中全部的说明都相互有关系,比如CDialgs程序库单元包括了在您的应用程序中使用的普通对话框的全部说明。

无论一個库单元是否和一个窗口有关库单元的结构都是同样的。其结构例如以下:

2.1.10.2 程序库单元的接口部分

interface是库单元的接口部分它决定了本库單元对其它不论什么库单元或程序的可见(可訪问)部分。您能够在接口部分说明变量、常量、数据类型、过程和函数等等Delphi在您设计窗口的庫单元中,将窗口数据类型、窗口变量和事件处理过程都说明在这一部分

interface标志库单元接口部分的開始。在interface中的说明对要使用这些说明的其它库单元或应用程序是可见的一个库单元能够使用其它Unit的说明,仅仅须要在uses子句中指明那些库单元就可以比如,您在库单元A中编敲玳码代码且您想调用UnitB于interface部分说明的程序。您能够把库单元B的名称增加到A的interface部分的uses子句中则不论什么A中的程序都能够调用B中说明的程序。并且假设B中interface部分的uses子句中出现C库单元,尽管A中未曾出现CA同样能够调用B、C库单元在interface中说明的程序。但假设B出如今A的interface部分的uses子句中那麼库单元A便不能出如今B的interface的uses子句中。由于这样会产生对库单元的循环訪问当试图编译时,会产生出现错误信息

2.1.10.3 程序库单元的实现部分

實现部分implementatin中包括interface中说明的过程、函数、事件处理过程的具体实现程序代码。这一部分能够有自己的额外说明但这些说明是私有的,外部程序不能调用这些说明在interface中说明的函数实体必须在implementatin部分出现,能够使用标题简写:仅仅输入prcedure或functin保留字后面跟过程或函数的名称就可以,其后则是程序的实现部分了假设您在implementatin部分说明不论什么常式,其标题并未出如今interface部分则必须写全其标题部分。

在implementatin部分的uses子句中指定嘚库单元仅仅供给本库单元的程序使用其interface中说明的程序。其它使用本库单元的库单元不能訪问这些在implementatin的udes子句中库单元的说明,由于在implementatin後进行的库单元包括是私有的所以上例中,假设C出如今B的implementatin部分则A不能使用C的公有部分,除非C出如今A的uses子句中在implementatin中出现的循环訪问是Delphi所同意的,假设A的implemetatin的uses子句中出现B则B的implementatin部分也能够出现A。

2.1.10.4 程序库单元的初始化部分

初始化当前库单元所使用的数据或是通过interface部分将数据提供给其它应用程序、库单元使用时,您能够在库单元中增加一个initializatin部分在库单元的end前加上您的初始化语句。当一个应用程序使用一个库單元时在库单元中的initializatin部分会先于其它的代码运行。假设一个应用程序使用了多个库单元则每个库单元的初始化部分都会在全部的程序玳码前运行。

当您在窗口中增加可视化部件时假设该部件在可视化部件库中,Delphi会在您的库单元的interface部分的uses子句中自己主动加上须要使用的庫单元名称但有些对象在Delphi的环境中并没有可视化部件存在,比如您想在库单元中增加一个提前定义的信息框,则您必须把MsgDlg库单元增加您的uses子句中假设您要使用TPrinter对象的话,必须将Printer库单元增加uses子句中在在线帮助中能够查到对象所属的提前定义库单元。

要使用在其它库单え中说明的函数应在函数的前面加上这一库单元的名称,并用‘.’号隔开比如,要在Unit2中使用Unit1中说明的Calculate函数应使用以下的方法:

您能夠在不论什么标识符如属性、常量、变量、数据类型、函数等之前加上库单元的名称。您能够在自由地在不论什么Delphi库单元中增加程序代码但不要改变由Delphi生成的程序。

2.1.10.6 建立与窗口无关的新库单元

假设您想在prject中建立一个和不论什么窗口无关的新库单元能够现选用File|New Unit。这时一个噺的库单元增加了prject新库单元的代码例如以下:

Delphi将依据您的prject中的文件数目为您的库单元选择名称,您能够在程序骨架间增加您的程序代码

当编译您的prject时,这个新增加的库单元会被编译为一个具有.DCU后缀的文件这个新生成的文件是链接到prject的可运行文件上的机器代码。

将库单え增加prject是比較简单的无论是您自己建立的库单元还是Delphi建立的与窗口有关的库单元,假设已经完毕则先打开您想增加库单元的prject(能够用pen Prject打開prject);再选用File|pen File,然后选择您想增加的源程序(.PAS文件)并选择K就可以。则库单元被增加到应用程序中

Delphi是基于面向对象编程的先进开发环境。面姠对象的程序设计(P)是结构化语言的自然延伸P的先进编程方法,会产生一个清晰而又easy扩展及维护的程序一旦您为您的程序建立了一个对潒,您和其它的程序猿能够在其它的程序中使用这个对象全然不必又一次编制繁复的代码。对象的反复使用能够大大地节省开发时间切实地提高您和其它人的工作效率。

一个对象是一个数据类型对象就象记录一样,是一种数据结构按最简单的理解,我们能够将对象悝解成一个记录但实际上,对象是一种定义不确切的术语它经常使用来定义抽象的事务,是构成应用程序的项目其内涵远比记录要豐富。在本书中对象可被理解为可视化部件如buttn、标签、表等。

了解对象最关键的是掌握对象的特性。一个对象其最突出的特征有三個:封装性、继承性、多态性。

对对象最基本的理解是把数据和代码组合在同一个结构中这就是对象的封装特性。将对象的数据域封闭茬对象的内部使得外部程序必需并且仅仅能使用正确的方法才干对要读写的数据域进行訪问。封装性意味着数据和代码一起出如今同一結构中假设须要的话,能够在数据周围砌上“围墙”仅仅实用对象类的方法才干在“围墙”上打开缺口。

继承性的含义直接并且显然它是指把一个新的对象定义成为已存在对象的后代;新对象继承了旧类的一切东西。在往新对象中增加不论什么新内容曾经父类的每個字段和方法都已存在于子类中,父类是创建子类的基石

多态性是在对象体系中把设想和实现分开的手段。假设说继承性是系统的布局掱段多态性就是其功能实现的方法。多态性意味着某种概括的动作能够由特定的方式来实现这取决于运行该动作的对象。多态性同意鉯相似的方式处理类体系中相似的对象依据特定的任务,一个应用程序被分解成很多对象多态性把高级设计处理的设想如新对象的创建、对象在屏幕上的重显、程序运行的其它抽象描写叙述等,留给知道该怎样完美的处理它们的对象去实现

让我们结合Delphi的实例讨论对象嘚概念:

当您要建立一个新prject时,Delphi 将显示一个窗口作为设计的基础在程序编辑器中,Delphi将这个窗口说明为一个新的对象类型并同一时候在与窗口相关联的库单元中生成了创建这个新窗口对象的程序代码。

新的窗口类型是TFrm1它是从TFrm继承下来的一个对象。它具有对象的特征:含有域或方法由于您未给窗口增加不论什么部件,所以它仅仅有从TFrm类中继承的域和方法在窗口对象的类型说明中,您是看不到不论什么域、方法的说明的Frm1称为TFrm1类型的实例(instance)。您能够说明多个对象类型的实例比如在多文档界面(MDI)中管理多个子窗口时就要进行这样的说明。每个實例都有自己的说明但全部的实例却共用同样的代码。

假设您向窗口中增加了一个buttn部件并对这个buttn建立了一个nClick事件处理过程。再查看Unit1的源程序会发现TFrm1的类型说明部分例如以下:

如今TFrm1对象有了一个名为Buttn1的域:它是您在窗口中增加的buttn。TButtn是一个对象类型Buttn1是Tbuttn的一个实例。它被TFrm1對象所包括作为它的数据域。每当您在窗口中增加一个部件时部件的名称就会作为TFm1的域增加到类型说明中来。在Delphi中您所编写的事件處理过程都是窗口对象的方法。每当您建立一个事件处理过程就会在窗口的对象类型中说明一个方法。

当您使用bject Inspectr来改变对象(部件)的名称時这个名称的改变会反映到程序中。比如在bject Inspectr中将Frm1的Name属性命名为ClrBx,您会发如今类型说明部分会将前文的TFrm1改为:

并且在变量说明部分,會说明ClrBx为TClrBx类型的变量由Delphi自己主动产生的事件处理过程名称会自己主动改为TClrBx.Buttn1Click;但您自行编写的实现部分的代码却不会被自己主动改动。因此假设您在改变Name属性前编写了程序,则您必须将事件处理过程中的对象名称进行改变所以,原先的Frm1.Clr要改为ClrBx.Clr

2.2.2 从一个对象中继承数据和方法

前面的TFrm1类型是非常简单的,由于它仅仅含有域Buttn1和方法Buttn1Click可是在这个窗口上,您能够改变窗口的大小、增加或删除窗口的最大最小化buttn戓设置这个窗口为MDI界面。对于一个仅仅包括一个域和方法的对象来讲您并没有看到显式的支持程序。在窗口上单击鼠标或用bject Inspectr的上端的bject Selectr选ΦFrm1对象按动F1查阅它的在线帮助,您会在Prperties和Methd中找到它的继承到的全部属性和方法这些是在TFrm类型中说明的,TFrm1是TFrm的子类直接继承了它全部嘚域、方法、属性和事件。比如窗口的颜色属性Clr就是在TFrm中说明的当您在prject中增加一个新窗口时,就等于增加了一个基本模型通过不断地茬窗口中增加部件,您就自行定义了一个新的窗口要自己定义不论什么对象,您都将从已经存在的对象中继承域和方法建立一个该种對象的子类。比如对象TFrm1就被说明为对象TFrm的子类拥有一个窗口部件的基本属性或方法。仅仅有当您在窗口中增加了部件或编写了事件处理過程时Frm1才成为您自己的类型。

一个比較特殊的对象是从一个范围较广或较一般的对象中继承下来的它是这个特别对象的祖先,这个对潒则称为祖先的后代一个对象仅仅能有一个直接的祖先,可是它能够有很多后代TFrm是TFrm1类型的祖先,全部的窗口对象都是TFrm的后代

用F1查阅窗口的在线帮助时,您会发现TFrm被称为cmpnent(部件)这是由于全部的部件都是对象。

在这个结构中全部的部件都是对象部件类型TCmpnent从Tbject类型中继承数據和程序代码,并具有额外的能够用作特殊用途的属性、方法、事件所以部件能够直接和用户打交道,记录它的状态并存贮到文件里等等控制类型TCntrl从TCmpnent中继承而来,又增加了新的功能如它能够显示一个对象。在上图中尽管TCheckBx不是直接由Tbject继承来的,可是它仍然有不论什么對象所拥有的属性由于在VCL结构中,TCheckBx终究还是从Tbject 中继承了全部功能的特殊对象但它还有些自行定义的独到的功能,如能够选择记录状态等

一个对象的范围决定了它的数据域、属性值、方法的活动范围和訪问范围。在一个对象的说明部分说明的数据域、属性值、方法都仅僅是在这个对象的范围中并且仅仅有这个对象和它的后代才干拥有它们。尽管这些方法的实际程序代码可能是在这个对象之外的程序库單元中但这些方法仍然在这个对象的范围内,由于它们是在这个对象的说明部分中说明的

当您在一个对象的事件处理过程中编敲代码玳码来訪问这个对象的属性值、方法或域时,您不须要在这些标识符之前加上这个对象变量的名称比如,假设您在一个新窗口上增加一個buttn和一个编辑框并为这个buttn编写nClick事件处理过程:

当中的第一行语句是为整个窗口Frm1着色。您也能够编写例如以下:

但您能够不必加上Frm1.由于Buttn1Click方法是在TFrm1对象的范围里。当您在一个对象的范围中时您能够省略全部这个对象中的属性值、方法、域之前的对象标识符。可是当您编写苐二个语句改变编辑框的底色时由于此时您想訪问的是TEdit1对象的Clr属性,而不是TFrm1类型的所以您须要通过在属性前面加上编辑框的名称来指奣Clr属性值的范围。假设不指明Delphi会象第一个语句一样,将窗口的颜色变成绿色由于Edit1部件是在窗口中的,它是窗口的一个数据域所以您哃样不必指明其从属关系。

假设Edit1是在其它窗口中那么您须要在编辑框之前加上这个船体对象的名称了。比如假设Edit1是在Frm2之中,那它是Frm2说奣的一个数据域并位于Frm2的范围中,那么您须要将第二句改为:

一个对象的范围扩展到这个对象的全部后代TFrm的全部属性值、方法和事件嘟在TFrm1的范围中,由于TFrm1是TFrm的后代您的应用程序不能说明和祖先的数据域重名的类型、变量等。假设Delphi显示了一个标识符被反复定义的信息僦有可能是一个数据域和其祖先对象(比如TFrm)的一个数据域有了同样的名称。能够尝试改变这个标识符的名称

您能够重载(verride)一个方法。通过在後代对象中说明一个与祖先对象重名的方法就能够重载一个方法。假设想使这种方法在后代对象中作和祖先对象中一样的工作可是使用鈈同的方式时您就能够重载这种方法。Delphi不推荐您经常重载方法除非您想建立一个新的部件。重载一个方法Delphi编译器不会给出错误或警告提示信息。

2.2.4 对象公有域和私有域的说明

当使用Delphi的环境来建立应用程序时您能够在一个TFrm的后代对象中增加数据域和方法,也能够通过直接改动对象类型说明的方法来为一个对象加上域和方法而不是把一个部件增加窗口或事件处理过程中。

Pascal的保留字当您在prject中增加新的窗ロ时,Delphi開始建立这个新窗口对象每个新的对象都包括public和private指示,以便您在代码中增加数据域和方法在public部分中说明其它库单元中对象的方法也能够訪问的数据域或方法。在private部分的说明有訪问的限制假设您在private中说明域和方法,那么它在说明这个对象的库单元外是不透明的並且不能被訪问。private中能够说明仅仅能被本库单元方法訪问的数据域和本库单元对象訪问的方法过程或函数的程序代码能够放在库单元的implementatin蔀分。

2.2.5 訪问对象的域和方法

当您想要改变一个窗口对象的一个域的某个属性或是调用它的一个方法时,您必须在这个属性名称或调用方法之前加上这个对象的名称比如,假设您的窗口上有一个编辑框部件而您须要在运行中改变它的Text属性,须要编写下列的代码:

同样清除编辑框部件中选中的文本,能够调用TEdit部件的对应方法:

假设您想改变一个窗口对象中一个对象域的多个属性或调用多个方法时使用with語句能够简化您的程序。with语句在对象中能够和在记录中一样方便地使用以下的事件处理过程在响应nClick事件时,会对一个列表框作多个调整:

假设使用了With语句则程序例如以下:

使用with语句,您不必在每个属性或方法前加上ListBx1标识符在With语句之内,全部的属性或调用方法对于ListBx这个對象而言都是在它的范围内的

2.2.6 对象变量的赋值

假设两个变量类型同样或兼容,您能够把当中一个对象变量赋给还有一个对象变量比如,对象TFrm1和TFrm2都是从TFrm继承下来的类型并且Frm1和Frm2已被说明过,那么您能够把Frm1赋给Frm2:

仅仅要赋值的对象变量是被赋值的对象变量的祖先类型您就能夠将一个对象变量赋给还有一个对象变量。比如以下是一个TDataFrm的类型说明,在变量说明部分一共说明了两个变量:AFrm和DataFrm

由于TDataFrm是TFrm类型的后代,所以Datafrm是AFrm的后代因此以下的赋值语句是合法的:

这一点在Delphi中是极为重要的。让我们来看一下应用程序调用事件处理过程的过程以下是┅个buttn部件的nClick事件处理过程:

您能够看到Tbject类在Delphi的Visual Cmpnent Library的顶部,这就意味着全部的Delphi对象都是Tbject的后代由于Sender是Tbject类型,所以不论什么对象都能够赋值给咜尽管您没有看见赋值的程序代码,但事实上发生事件的部件或控制部件已经赋给Sender了这就是说Sender的值是响应发生事件的部件或控制部件嘚。

您能够使用保留字is来測试Sender以便找到调用这个事件处理过程的部件或控制部件的类型Delphi中的一个显示drag-and-drp的DRAGDRP.DPRprject。载入它能够查阅到DRPFNT.PAS库单元的玳码,在Mem1Dragver方法中检查了一个对象变量的类型在这样的情形下,參数是Surce而不是Sender

Surce參数也是Tbject类型,Surce被赋值为那个被拖曳的对象用Mem1Dragver方法的目嘚是确保仅仅有标签能够被拖曳。Accept是布尔型參数假设Accept为True,那么用户选择的部件能够被拖曳;反之当Accept的值为False时用户就不能够拖曳选择控淛部件。is保留字检查Surce是否TLabel的类型所以Accept仅仅有在用户拖曳一个标签时才为真,并作为变參输出到函数之外

以下的drag-and-drp展示的Mem1DragDrp事件处理过程中吔使用了Surce參数。这种方法是为了把Mem部件的字型改变成和放入这个备注控制部件的标签一样的字型:

当您在这个事件处理过程中编写赋值语呴时开发者并不知道用户会放入哪一个标签,仅仅有通过參考这个标签的名称(Surce as TLabel)用户才干知道并把标签类型赋给Mem1.TFnt。Surce包括了用户拖放控制蔀件的名称仅仅有当Surce是一个标签时,这个事件处理过程才同意这个赋值发生

2.2.7 建立非可视化对象

您在Delphi中使用的大部分对象都是您在设计囷运行期间能够看见的部件,比如编辑框、buttn等;一些部件如通用对话框(Cmmn dialg bx)等,在设计时看不见而在运行时能够看见;另外有些部件,比洳计时器(Timer)、数据源(Data Surce)部件等在程序的运行期间没有不论什么可视化的显示,但您却能够在您的应用程序中使用它们

2.2.7.1说明一个非可视化对潒

以下,通过一个简单的样例讲述怎样建立自己的非可视化对象:

您能够用例如以下的方法建立一个自己的TEmplyee非可视化对象:

在这样的情況下,TEmplyee从Tbject继承下来且包括三个域和一个方法。把您建立的类型说明放在库单元中的说明部分并和窗口说明放在一起。在这个程序库单え的变量说明部分说明一个新类型的变量:

TEmplyee仅仅是一个对象类型。除非通过一个构造函数的调用从而被实例取代或创建否则一个对象並不存储在内存中。构造函数是一个方法它为新对象配置内存并且指向这个新的对象。这个新的对象也被称为这个对象类型的一个实例

建立一个对象的实例,须要调用Create方法然后构造函数把这个实例赋给一个变量。假设您想说明一个TEmplyee类型的实例在您訪问这个对象的不論什么域之前,您的程序代码必须调用Create

Create方法并没有在TEmplyee类型中说明,它继承自Tbject类型由于TEmplyee是Tbject的子类,所以它能够调用Create方法而创建一个TEmplyee实例然后把它赋给Emplyee变量。在创建了一个这样的对象后您就能够象使用其它的Delphi对象一样訪问Emplyee对象了。

当您使用完对象后您应该及时撤销它,以便把这个对象占用的内存释放出来您能够通过调用一个注销方法来撤销您的对象,它会释放分配给这个对象的内存

Delphi的注销方法有兩个:Destry和Free。Delphi建议使用Free由于它比Destry更为安全,同一时候调用Free会生成效率更高的代码

您能够用下列的语句释放用完的Emplyee对象:

和Create方法一样,Free方法也是TEmplyee从Tbject中继承过来的把您的注销放在try…finally程序模块的finally部分,而把对象的程序代码放在try部分是编程的好习惯这样,即使您的程序代码在使用对象时发生了异常事件也会确保您为这个对象分配的内存会被释放。关于异常处理和try…finally程序模块的信息以及建立非可视化对象的样唎在后文中还将细致讲述。

hk实现dll注入具体解释

CM 原理与应用》学习笔记 - 第一部分 CM原理

CM 是由 Micrsft 提出的组件标准它不仅定义了组件程序之間进行交互的标准,并且也提供了组件程序运行所需的环境在 CM 标准中,一个组件程序也被称为一个模块它能够是一个动态链接库,被稱为进程内组件(in-prcess cmpnent);也能够是一个可运行程序(即 EXE 程序)被称作进程外组件(ut-f-prcess cmpnent)。一个组件程序能够包括一个或多个组件对象由于 CM 是以对象为基夲单元的模型,所以在程序与程序之间进行通信时通信的两方应该是组件对象,也叫做 CM 对象而组件程序(或称作 CM 程序)是提供 CM 对象的代码載体。

CM 对象不同于一般面向对象语言(如 C++ 语言)中的对象概念CM 对象是建立在二进制可运行代码级的基础上,而 C++ 等语言中的对象是建立在源码級基础上的因此 CM 对象是语言无关的。这一特性使用不同编程语言开发的组件对象进行交互成为可能

相似于 C++ 中对象的概念,对象是某个類(class)的一个实例;而类则是一组相关的数据和功能组合在一起的一个定义使用对象的应用(或还有一个对象)称为客户,有时也称为对象的用戶

接口是一组逻辑上相关的函数集合,其函数也被称为接口成员函数依照习惯,接口名常是以“I”为前缀对象通过接口成员函数为愙户提供各种形式的服务。

在 CM 模型中对象本身对于客户来说是不可见的,客户请求服务时仅仅能通过接口进行。每个接口都由一个 128 位嘚全局唯一标识符(GUIDGlbal Unique Identifier)来标识。客户通过 GUID 来获得接口的指针再通过接口指针,客户就能够调用其对应的成员函数

CM 原理与应用》学习笔记 - 苐一部分 CM原理

与接口相似,每个组件也用一个 128 位 GUID 来标识称为 CLSID(class identifer,类标识符或类 ID)用 CLSID 标识对象能够保证(概率意义上)在全球范围内的唯一性。實际上客户成功地创建对象后,它得到的是一个指向对象某个接口的指针由于 CM 对象至少实现一个接口(没有接口的 CM 对象是没有意义的),所以客户就能够调用该接口提供的全部服务依据 CM 规范,一个 CM 对象假设实现了多个接口则能够从某个接口得到该对象的随意其它接口。從这个过程我们也能够看出客户与 CM 对象仅仅通过接口打交道,对象对于客户来说仅仅是一组接口

CM 所提供的服务组件对象在实现时有两種进程模型:进程内对象和进程外对象。假设是进程内对象则它在客户进程空间中运行;假设是进程外对象,则它运行在同机器上的还囿一个进程空间或者在远程机器的空间

服务程序被载入到客户的进程空间,在 Windws 环境下通常服务程序的代码以动态连接库(DLL)的形式实现。

垺务程序与客户程序运行在同一台机器上服务程序是一个独立的应用程序,通常它是一个 EXE 文件

服务程序运行在与客户不同的机器上,咜既能够是一个 DLL 模块也能够是一个 EXE 文件。假设远程服务程序是以 DLL 形式实现的话则远程机器会创建一个代理进程。

尽管 CM 对象有不同的进程模型但这样的差别对于客户程序来说是透明的,因此客户程序在使用组件对象时能够无论这样的差别的存在仅仅要遵照 CM 规范就可以。然而在实现 CM 对象时,还是应该谨慎选择进程模型进程内模型的长处是效率高,但组件不稳定会引起客户进程崩溃因此组件可能会危及客户;(savetime 注:这里有点问题,假设组件不稳定进程外模型也同样会出问题,可能是由于进程内组件和客户同处一个地址空间出现冲突的可能性比較大?)进程外模型的长处是稳定性好组件进程不会危及客户程序,一个组件进程能够为多个客户进程提供服务但进程外組件开销大,并且调用效率相对低一点

CM 原理与应用》学习笔记 - 第一部分 CM原理

由于 CM 标准是建立在二进制代码级的,因此 CM 对象的可重用性與一般的面向对象语言如 C++ 中对象的重用过程不同对于 CM 对象的客户程序来说,它仅仅是通过接口使用对象提供的服务它并不知道对象内蔀的实现过程,因此组件对象的重用性可建立在组件对象的行为方式上,而不是具体实现上这是建立重用的关键。CM 用两种机制实现对潒的重用我们假定有两个 CM 对象,对象1 希望能重用对象2 的功能我们把对象1 称为外部对象,对象2 称为内部对象

对象1 包括了对象2,当对象1 須要用到对象2 的功能时它能够简单地把实现交给对象2 来完毕,尽管对象1 和对象2 支持同样的接口但对象1 在实现接口时实际上调用了对象2 嘚实现。

对象1 仅仅需简单地把对象2 的接口递交给客户就可以对象1 并没有实现对象2 的接口,但它把对象2 的接口也暴露给客户程序而客户程序并不知道内部对象2 的存在。

⊙ 第二章 CM 对象模型

全局唯一标识符 GUID

CM 规范採用了 128 位全局唯一标识符 GUID 来标识对象和接口这是一个随机数,并鈈须要专门机构进行分配和管理由于 GUID 是个随机数,所以并不绝对保证唯一性但发生标识符相重的可能性非常小。从理论上讲假设一囼机器每秒产生 个 GUID,则能够保证(概率意义上)的 3240 年不反复)

GUID 在 C/C++ 中能够用这样的结构来描写叙述:

在 CM 规范中,并没有对 CM 对象进行严格的定义泹 CM 提供的是面向对象的组件模型,CM 组件提供给客户的是以对象形式封装起来的实体客户程序与 CM 程序进行交互的实体是 CM 对象,它并不关心組件模型的名称和位置(即位置透明性)但它必须知道自己在与哪个 CM 对象进行交互。

从技术上讲接口是包括了一组函数的数据结构,通过這组数据结构客户代码能够调用组件对象的功能。接口定义了一组成员函数这组成员函数是组件对象暴露出来的全部信息,客户程序利用这些函数获得组件对象的服务

通常我们把接口函数表称为虚函数表(vtable),指向 vtable 的指针为 pVtable对于一个接口来说,它的虚函数表是确定的洇此接口的成员函数个数是不变的,并且成员函数的先后先后顺序也是不变的;对于每个成员函数来说其參数和返回值也是确定的。在┅个接口的定义中全部这些信息都必须在二进制一级确定,无论什么语言仅仅要能支持这样的内存结构描写叙述,就能够使用接口

烸个接口成员函数的第一个參数为指向对象实例的指针(=this),这是由于接口本身并不独立使用它必须存在于某个 CM 对象上,因此该指针能够提供对象实例的属性信息在被调用时,接口能够知道是对哪个 CM 对象在进行操作

在接口成员函数中,字符串变量必须用 Unicde 字符指针CM 规范要求使用 Unicde 字符,并且 CM 库中提供的 CM API 函数也使用 Unicde 字符所以假设在组件程序内部使用到了 ANSI 字符的话,则应该进行两种字符表达的转换当然,在即建立组件程序又建立客户程序的情况下能够使用自己定义的參数类型,仅仅要它们与 CM 所能识别的參数类型兼容

BSTR 是双字节宽度字符串,它是最经常使用的自己主动化数据类型

接口描写叙述语言 IDL

CM 规范在採用 SF 的 DCE 规范描写叙述远程调用接口 IDL (interface descriptin language,接口描写叙述语言)的基础上进荇扩展形成了 CM 接口的描写叙述语言。接口描写叙述语言提供了一种不依赖于不论什么语言的接口的描写叙述方法因此,它能够成为组件程序和客户程序之间的共同语言

CM 规范使用的 IDL 接口描写叙述语言不仅可用于定义 CM 接口,同一时候还定义了一些经常使用的数据类型也能夠描写叙述自己定义的数据结构,对于接口成员函数我们能够定义每个參数的类型、输入输出特性,甚至支持可变长度的数组的描写叙述IDL 支持指针类型,与 C/C++ 非常相似比如:

CM 对象的接口原则

1. 对于同一个对象的不同接口指针,查询得到的 IUnknwn 接口必须全然同样也就是说,每個对象的 IUnknwn 接口指针是唯一的因此,对两个接口指针我们能够通过推断其查询到的 IUnknwn 接口是否相等来推断它们是否指向同一个对象。

2. 接口洎反性对一个接口查询其自身总应该成功,比方:

3. 接口对称性假设从一个接口指针查询到还有一个接口指针,则从第二个接口指针再囙到第一个接口指针必然成功比方:

4. 接口传递性。假设从第一个接口指针查询到第二个接口指针从第二个接口指针能够查询到第三个接口指针,则从第三个接口指针一定能够查询到第一个接口指针

5. 接口查询时间无关性。假设在某一个时刻能够查询到某一个接口指针則以后不论什么时间再查询同样的接口指针,一定能够查询成功

总之,无论我们从哪个接口出发我们总能够到达不论什么一个接口,並且我们也总能够回到最初的那个接口

⊙ 第三章 CM 的实现

假设 CM 组件支持同样一组接口,则能够把它们分到同一类中一个组件能够被分到哆个类中。比方全部的自己主动化对象都支持 IDispatch 接口则能够把它们归成一类“Autmatin bjects”。类别信息也用一个 GUID 来描写叙述称为 CATID。组件类别最基本嘚用处在于客户能够高速发现机器上的特定类型的组件对象否则的话,就必须检查全部的组件对象并把组件对象装入到内存中实例化,然后依次询问是否实现了必要的接口如今使用了组件类别,就能够节省查询过程

对于进程外组件程序,情形稍有不同由于它自身昰个可运行程序,并且它也不能提供入口函数供其它程序使用因此,CM 规范中规定支持自注冊的进程外组件必须支持两个命令行參数 /RegServer 和 /UnregServer,以便完毕注冊和注销操作命令行參数大写和小写无关,并且 “/” 能够用 “-” 替代假设操作成功,程序返回 0否则,返回非 0 表示失败

类厂(class factry)是 CM 对象的生产基地,CM 库通过类厂创建 CM 对象;对应每个 CM 类有一个类厂专门用于该 CM 类的对象创建操作。类厂本身也是一个 CM 对象它支歭一个特殊的接口 IClassFactry:

CreateInstance 成员函数用于创建对应的 CM 对象。第一个參数 pUnknwnuter 用于对象类被聚合的情形一般设置为 NULL;第二个參数 iid 是对象创建完毕后客戶应该得到的初始接口 IID;第三个參数 ppv 存放返回的接口指针。

LckServer 成员函数用于控制组件的生存周期

CM 库在接到对象创建的指令后,它要调用进程内组件的 DllGetClassbject 函数由该函数创建类厂对象,并返回类厂对象的接口指针CM 库或客户一旦拥有类厂的接口指针,它们就能够通过 IClassFactry 的成员函数 CreateInstance 創建对应的 CM 对象

在 CM 库中,有三个 API 可用于对象的创建它们各自是 CGetClassbject、CCreateInstnace 和 CCreateInstanceEx。通常情况下客户程序调用当中之中的一个完毕对象的创建,并返回对象的初始接口指针CM 库与类厂也通过这三个函数进行交互。

函数并返回类厂对象的接口指针。通常情况下 iid 为 IClassFactry 的标识符 IID_IClassFactry假设类厂對象还支持其它可用于创建操作的接口,也能够使用其它的接口标识符比如,可请求 IClassFactry2 接口以便在创建时,验证用户的许可证情况IClassFactry2 接ロ是对 IClassFactry 的扩展,它加强了组件创建的安全性

參数 dwClsCntext 指定组件类别,能够指定为进程内组件、进程外组件或者进程内控制对象(相似于进程外組件的代理对象主要用于 LE 技术)。參数 iid 和 ppv 分别对应于 DllGetClassbject 的參数用于指定接口 IID 和存放类对象的接口指针。參数 pServerInf 用于创建远程对象时指定server信息在创建进程内组件对象或者本地进程外组件时,设置 NULL

假设 CGetClassbject 函数创建的类厂对象位于进程外组件,则情形要复杂得多首先 CGetClassbject 函数启动组件进程,然后一直等待直到组件进程把它支持的 CM 类对象的类厂注冊到 CM 中。于是 CGetClassbject 函数把 CM 中对应的类厂信息返回因此,组件外进程被 CM

不同一个是表示对象的接口信息,一个是表示类厂的接口信息)參数 pUnknwnuter 与类厂接口的 CreateInstance 中对应的參数一致,主要用于对象被聚合的情况CCreateInstance 函数把通过类厂创建对象的过程封装起来,客户程序仅仅要指定对象类的 CLSID 和待输出的接口指针及接口 ID客户程序能够不与类厂打交道。CCreateInstance 能够用以丅的代码实现:

从这段代码我们能够看出CCreateInstance 函数首先利用 CGetClassbject 函数创建类厂对象,然后用得到的类厂对象的接口指针创建真正的 CM 对象最后把類厂对象释放掉并返回,这样就把类厂屏蔽起来

前三个參数与 CCreateInstance 一样,pServerInf 与 CGetClassjbect 的參数一样用于指定server信息,最后两个參数 dwCunt 和 rgMultiQI 指定了一个结构数組能够用于保存多个对象接口指针,其目的在于一次获得多个接口指针以便降低客户程序与组件程序之间的频繁交互,这对于网络环境下的远程对象是非常有意义的

调用 CM 库的函数之前,为了使函数有效必须调用 CM 库的初始化函数:

pMallc 用于指定一个内存分配器,可由应用程序指定内存分配原则普通情况下,我们直接把參数设为 NULL则 CM 库将使用缺省提供的内存分配器。

返回值:S_K 表示初始化成功

S_FALSE 表示初始化成功但这次调用不是本进程中首次调用初始化函数

S_UNEXPECTED 表示初始化过程中发生了错误,应用程序不能使用 CM 库

通常一个进程对 CM 库仅仅进行一次初始化,并且在同一个模块单元中对 CM 库进行多次初始化并没有意义。唯一不须要初始化 CM 库的函数是获取 CM 库版本号的函数:

返回值:高 16 位 主版本号号

低 16 位 次版本号号

CM 程序在用完 CM 库服务之后一般是在程序退出之前,一定要调用终止 CM 库服务函数以便释放 CM 库所维护的资源:

注意:凡是调用 CInitialize 函数返回 S_K 的进程或程序模块一定要有对应的 CUninitialize 函数调用,以保证 CM 库有效地利用资源

(? 假设在一个模块中调用 CInitialize 返回 S_K那么它调鼡 CUnitialize 函数后,其它也在使用 CM 库的模块是否会出错误还是 CM 库会自己主动检查有哪些模块在使用?)

由于 CM 组件程序和客户程序是通过二进制级标准建立连接的所以在 CM 应用程序中凡是涉及客户、CM 库和组件三者之间内存交互(分配和释放不在同一个模块中)的操作必须使用一致的内存管悝器。CM 提供的内存管理标准实际上是一个 IMallc 接口:

CGetMallc 函数的第一个參数 dwMemCntext 用于指定内存管理器的类型。CM 库中包括两种内存管理器一种就是在初始化时指定的内存管理器或者其内部缺省的管理器,也称为作业管理器(task allcatr)这样的管理器在本进程内有效,要获取该管理器在 dwMemCntext 參数中指萣为 MEMCTX_TASK;还有一种是跨进程的共享分配器,由 LE 系统提供要获取这样的管理器,dwMemCntext 參数中指定为 MEMCTX_SHARED使用共享管理器的便利是,能够在一个进程內分配内存并传给第二个进程在第二个进程内使用此内存甚至释放掉此内存。

仅仅要函数的返回值为 S_K则 ppMallc 就指向了 CM 库的内存管理器接口指针,能够使用它进行内存操作使用完毕后,应该调用 Release 成员函数释放控制权

CM 库封装了三个 API 函数,可用于内存分配和释放:

在调用 CM 函数 PrgIDFrmCLSID 返回之后由于 CM 库为输出变量 pwPrgID 分配了内存空间,所以应用程序在用完 pwPrgID 变量之后一定要调用 CTaskMemFree 函数释放内存。该样例说明了在 CM 库中分配内存而在调用程序中释放内存的一种情况。CM 库中其它一些函数也有相似的特性尤其是一些包括不定长度输出參数的函数。

在 CM 库的 CGetClassbject 函数中當它发现组件程序是 EXE 文件(由注冊表组件对象信息中的 LcalServer 或 LcalServer32 值指定)时,CM 库创建一个进程启动组件程序并带上“/Embedding”命令行參数,然后等待组件程序;而组件程序在启动后当它检查到“/Embedding”命令行參数后,就会创建类厂对象然后调用 CRegisterClassbject 函数把类厂对象注冊到 CM 中。当 CM 库检查到组件对潒的类厂之后CGetClassbject 函数就把类厂对象返回。由于类厂与客户程序运行在不同的进程中所以客户程序得到的是类厂的代理对象。一旦客户程序或 CM 库得到了类厂对象它就能够完毕组件对象的创建工作。

进程内对象和进程外对象的不同创建过程仅仅影响了 CGetClassbject 函数的实现过程对于愙户程序来说是全然透明的。

仅仅有当组件程序满足了两个条件时它才干被卸载,这两个条件是:组件中对象数为 0类厂的锁计数为 0。滿足这两个条件时DllCanUnladNw 引出函数返回 TRUE。CM 提供了一个函数 CFreeUnusedLibraries它会检測当前进程中的全部组件程序,当发现某个组件程序的 DllCanUnladNw 函数返回 TRUE 时就调用 FreeLibrary 函数(实际上是 CFreeLibrary 函数)把该组件从程序从内存中卸出。

该由谁来调用 CFreeUnusedLibraries 函数呢由于在组件程序运行过程中,它不可能把自己从内存中卸出所鉯这个任务应该由客户来完毕。客户程序随时都能够调用 CFreeUnusedLibraries 函数完毕卸出工作但通常的做法是,在程序的空暇处理过程中调用 CFreeUnusedLibraries 函数这样莋既能够避免程序中处处考虑对 CFreeUnusedLibraries 函数的调用,又能够使不再使用的组件程序得到及时清除提高资源的利用率,CM 规范也推荐这样的做法

進程外组件的卸载比較简单,由于组件程序运行在单独的进程中一旦其退出的条件满足,它仅仅要从进程的主控函数返回就可以在 Windws 系統中,进程的主控函数为 WinMain

前面曾经说过,在组件程序启动运行时它调用 CRegisterClassbject 函数,把类厂对象注冊到 CM 中注冊之后,类厂对象的引用计数始终大于 0因此单凭类厂对象的引用计数无法控制进程的生存期,这也是引入类厂对象的加锁和减锁操作的原因进程外组件的载条件与 DllCanUnladNw Φ的推断相似,也须要推断 CM 对象是否还存在、以及推断是否锁计数器为 0仅仅有当条件满足了,进程的主函数才干够退出

从原则上讲,進程外组件程序的卸载就是这么简单但实际上情况可能复杂一些,由于有些组件程序在运行过程中能够创建自己的对象或者包括用户堺面的程序在运行过程中,用户手工关闭了进程那么进程对这些动作的处理要复杂一些。比如组件程序在运行过程中,用户又打开了┅个文件并进行操作那么即使原先创建的对象被释放了,并且锁计数器也为 0进程也不能退出,它必须继续为用户服务就像是用户打開的进程一样。对这样的程序能够增加一个“用户控制”标记 flag,假设 flag 为 FALSE则能够按简单的方法直接退出程序就可以;假设 flag 为 TRUE,则表明用戶參与了控制组件进程不能立即退出,但应该调用 CRevkeClassbject 函数以便与 CRegisterClassbject 调用相响呼应把进程留给用户继续进行。

假设组件程序在运行过程中鼡户要关闭进程,而此时并不满足进程退出条件那么进程能够採取两种办法:第一种方法,把应用隐藏起来并把 flag 标记设置为 FALSE,然后组件程序继续运行直到卸载条件满足为止;还有一种办法是调用 CDiscnnectbject 函数,强迫脱离对象与客户之间的关系并强行终止进程,这样的方法比較粗暴不提倡採用,但不得已时能够也使用以保证系统完毕一些高优先级的操作。

CM 库经常使用函数

大多数 CM 函数以及一些接口成员函数嘚返回值类型均为 HRESULT 类型HRESULT 类型的返回值反映了函数中的一些情况,其类型定义规范例如以下:

类别码 (30-31) 反映函数调用结果:

自己定义标记(29) 反映结果是否为自己定义标识1 为是,0 则不是;

操作码 (16-28) 标识结果操作来源在 Windws 平台上,其定义例如以下:

操作结果码(0-15) 反映操作的状态WinErrr.h 定义叻 Win32 函数全部可能返回结果。

以下是一些经经常使用到的返回值和宏定义:

S_K 函数运行成功其值为 0 (注意,其值与 TRUE 相反)

S_FAIL 函数运行失败失败原洇不确定

E_UTFMEMRY 函数运行失败,失败原由于内存分配不成功

E_NTIMPL 函数运行失败成员函数没有被实现

E_NTINTERFACE 函数运行失败,组件没有实现指定的接口

组件对潒在接口的实现代码中运行自身创建的还有一个组件对象的接口函数(客户/server模型)这个对象同一时候实现了两个(或很多其它)接口的代码。

组件对象在接口的查询代码中把接口传递给自已创建的还有一个对象的接口查询函数而不实现该接口的代码。还有一个对象必须实现聚合模型(也就是说它知道自己正在被还有一个组件对象聚合),以便 QueryInterface 函数能够正常运作

在组件对象被聚合的情况下,当客户请求它所不支持嘚接口或者请求 IUnknwn 接口时它必须把控制交给外部对象,由外部对

自己开发的一个Frm主要在第一个Frm1Φ符合条件的情况下跳出另一个Frm2出来,但是当关闭Frm2的时候出现红条,即进度或进展条
首先找到APP_CUSTM程序单元,看看是否初始设置没有设置退出窗口的情况结果设置的没错。
然后发现是因为Frm2的导航数据块的属性没有设置只需要设置对应的前一个导航数据块和后一个导航数據块就解决。
解决2:在该画布上必须要有一个可以导航的item该ITEM必须满足以下其中一个条件:
  1.该item是可用的,并且该ITEM所属的块必须是数据塊
设置要关闭的窗口的前一个导航快为目的数据块,然后在APP_CUSTM* (程序包主体)中进行G_blck(‘数据块名称’)即可

2:LV使用问题 在Frm中使用LV时,LV的Recrd Grup 中的语呴不要有用’–’ Mark掉的东东在里面如果有的话,’–'后面的所有语句都会被mark掉因为Recrd Grup 的Query语句会全部被放在一行中。切记

3:Blck查询后灰暗无法进行插入功能 基于view的blck在CRTL+F11查询后变为灰色,无法进行新增等操作关闭画面重新打开后,画面显示正常一旦执行查询完毕则变

4:pst-query使用問题 有时候在pst-query里面对某个要显示的非数据库item赋值,这样会造成在鼠标切换到另一条记录时以及查询完毕没有做任何改动却被


prcedure等的spec和bdy参数不┅致的时候编译会报这个错误。

8:复选框背景色及前景色无法显示成canvas底色、白字 解决办法:将背景色、前景色改成别的颜色,再分别妀回autmatic、autmatic、transparent.

9:将查询块字段放在主画布上点击查询字段LV,弹出查询窗口 将查询块字段放在主画布上点击查询字段LV,弹出查询窗口


解决办法:应该是定位到查询块的新建按钮了如果不需要就删除新建按钮,同时可以把不需要的数据块和项等删除免得出现未知的错误。

10:frm裏面使用汇总功能出现报错


解决办法设置汇总项所在的块的单记录属性为是(YES),设置需要汇总的块的单记录属性为否(NI)

11:打开菜单出現如下问题:

13:Flder中拖动“标题”换位置的时候报下图错误后,再换位置:frm-99999错误
但是这种解决方案对我无用我在设计的时候没有设置Blck的“Shw Scrll Bar”属性为“Yes”。把此属性改为“Yes”并把滚动条放到驻华不(内容画布)即可。
但是如果把滚动条放到了堆叠画布上就会出现如下问題:
对于此问题的解决:把“Scrll BarCanvas”的属性值设置为主画布即可。

14:日历窗口出现“S”BUG

15:日期格式问题 根据系统默认的时间格式使用配置文件来确定参数的时间格式

16:将查询块字段放在主画布上,点击查询字段LV弹出查询窗口
将查询块字段放在主画布上,点击查询字段LV弹出查询窗口
应该是查询块的项启用了键盘导航才定位到查询块的新建按钮了,如果不需要就删除新建按钮同时可以把不需要的数据块和项等删除,免得出现未知的错误

18:RA-01445:无法从不带保留关键字的表的联接视图中选择RWID或采样
解决方案:对于这个问题,是因为没有在blck里面写n-lck触發器写了n-lck触发器后问题解决。

19:在删除主从块当从块没有数据时报出如下错误!
解决方案:在主块下面的关系里面,把Delete Recrd Behavir属性设置为:Islated(当删除主块时,要级联删除从快设置此属性)

20:在FIXED画布上有固定列时,把光标从tab上移动到固定列上page上的STK画布上的内容会消失掉

在FIXED画布仩有固定列时,把光标从tab上移动到固定列上page上的STK画布上的内容会消失掉,这个时候是因为FIXED画布上的列宽度占了STK画布一部分FIXED画布把STK画布覆盖掉了,只要把FIXED画布的列宽设置小一点就行了!

22:在货位弹性域段中出现问题
请在 接收货位 弹性域中输入要求用于 货位段1 段的值
原因:對应的弹性域中没有此记录

解决办法:内容画布的size设置问题

这个关联到prfile:INV:调试跟踪 一般不会有这个问题,发生可能是因为其他问题导致解决其他问题的同时,此问题也可以得到解决

30:通用导入验证数据时,临时表报触发器/函数不能读该表
原因:是在更新这个临时表的時候调用一个Functin或者prcedure中代码对这张临时表进行了select操作才会导致报错。
解决办法:更新表的时候不对该表进行DML操作

31:修改标准Frm名称点击功能时画布消失
解决办法:不要修改Mdule里面的名字,就用原来的名字文件名修改CUX就可以了。

34:Frm界面中历史记录出不来 原因:因为界面没有进荇查询记录所以无法显示历史记录


原因:check_bx的宽度设置太小,应与高度设置一致均为0.25即可。

36:通用导入选取文件按钮无效 点击按钮导入攵件没有反应

2:EBS报表输出XML时标签错误问题
在开发EBS报表将报表内容输出为XML格式文件时出现了如下的错误:
出现如上错误是因为,输出内容Φ含有<>括起来的字符串而<>被认为是XML标签了,由于前后不匹配就认为无法输出,而导致XML文件有问题解决上面这样的问题,可以从两个兩个方面去考虑:

1)、使用CDATA CDATA指的是不由XML解析器进行解析的文本数据在标记CDATA下,所有的标记、实体引用都被忽略而被XML处理程序当作纯粹的芓符数据对待。格式如下:<![CDATA[文本内容]]>

2)、使用转义字符 就是使用转义字符将可能被XML解析程序错误解析的字符进行转义,比如将<>分别解析成<囷>


在XML中有5个预定义的实体引用:

下面是PL/SQL中的一段转义代码,可以用作其他程序语言的参考来修改:

在对XML中的内容进行输出时都首先用get_string_xml()方法进行转义一下,然后再进行输出

问题描述:做报表的过程中,经常会遇到乱码的情况
1、 查看首选项里面的客户机字符编码是不是Unicde(UTF-8)
2、 查看系统管理员>安装>浏览器选项 里面对应的输出文件格式‘允许本地客户机编码’是否勾选

4:报表输出保存文件名乱码问题
问题描述:莋报表的过程中,经常会遇到乱码的情况

5:XMLP报表乱码问题
问题描述:在使用XMLP做报表的过程中,经常会遇到乱码的情况
导致乱码的原因囿两种:字符集的问题和字体定义的问题。
字符集引起的乱码 :一般乱码成不规则性的
字体定义引起的乱码:一般乱码是规则的,一般為(反?)
1).在PL/SQL中输出XML时头信息的编码为:
2).修改EBS系统首选项: 客户机字符编码修改为:Unicde(UTF-8),修改首选项会影响到配置文件
RACLE的字符集命名(非国际标准)囷XML规范(IANA国际标准)不一致,我们还不能直接根据racle的字符集来设置XML字符集
3. 重启应用。问题就可以解决
4. 原理:默认情况下,XMLP不支持中文原因仅仅是缺少字体。因为XMLP采用Java编写理论上Java支持任何语种。EBS自带了中文字体但没有安装到XMLP目录。因此要做个拷贝.
在racle EBS环境下运行BIP报表打印PDF报表,如果报表内容中包括了阿拉伯字符如中文字符则会显示为问号(?),这是由于JVM运行时缺少了True Type字体(.ttf)文件导致的解决这个问题只偠将字体拷贝相应的字体文件到JRE环境下即可。

7:XML模板未上传调用报错(RTF模板上传了)
如果RTF模板已经上传,还会出现类似报错则是输出數据中国出现了浏览器无法解析字符,需要使用解析函数进行解析即可

8:请求日志过多引起并发黄色警告
由于请求日志信息是存储于EBS应鼡服务器中的。当日志信息数据逐渐增大的时候相应的应用服务器的存储空间就在逐渐减小。是此消彼长的关系当应用服务器存储空間剩余非常非常小,接近为0的时候提交新的请求生成的日志信息就无法保存,导致新提交的请求无法正确执行进而飘黄报错。就如同這次发生的情况一样

而导致EBS应用服务器存储空间迅速变小的直接原因,是启用调试后请求会输出非常详细(数据量很多)的日志信息並存储到应用服务器。而长时间未关闭调试且在这一段时间内不停地跑请求,最终导致耗尽应用服务器的存储空间进而报错:表空间鈈足。
对于启用调试后产生详细的日志信息,racle官方提供了一个prgram去清理在系统管理员职责下提交“清除并发请求和(或)管理器数据”。


此程序默认是计划每天执行一次并清理7天前的l日志数据。
具体会清理以下这些表:(这些表都是包含debug或者errr信息)

9:EBS 并发管理器问题之偅启与修复
并发管理的问题在EBS中一直是最容易出现的当然也是最容易解决的,下面分享一下我的方法:
有些时候我们重启应用之后,並发管理器没有启动则需要进行手工启动启动步骤如下:

然后查看进程是否存在:

内部并发管理器没有开启,使用命令重启并发管理器吔无法启动并发管理器


点击修复并发管理器然后根据提示操作即可
点并发管理器修复的时候如果报错,说不满足条件此时需要手动把內部管理器停掉,修复过程中要有所有待定、运行中的请求都要取消掉
环境正常运行之后,到系统管理员下跑个【有效用户】这个既鈳以检查请求是否能正常跑,又可以检查报表能不能正常打印

1:PDA模拟端配置问题

1:只使用GUI客户机
修改deviceIP文件,把其他的客户端全部注释掉即可
2:PDA使用时按键CRTL+X无法出现页分类等信息
启用GUI客户端并修改GUI_KEY.ini文件,把字符集改为GBK同时可以解决GUI客户端乱码的情况


2:MWA(PDA)开发常见问题鉯及解决办法 1:这个错误可能是当前JDK版本不符合项目需求,看下JDk版本是否需要进行修改


2:注意:PDA中有部分LV的参数值获取为空,或者是 CuxWmsCusListener这個里面的fieldEntered函数没有执行则可能是mwa下面的CustmListener文件有问题,编译正确的文件即可
3:注意:如果PDA界面按F2退出后,界面会卡死可能是该菜单挂載的功能过多的原因,
如果PDA界面的LV没有办法获取到值则可能添加了多余的get和Set 方法,比如Prmpt,Listener,Sessin等没有必要的多余的方
4:这个快捷键可以快速生荿需要的Get和Set函数
6:当界面字段变灰暗之后监听器是无法监听到该字段的所有动作的,
登录MWA在输入账户和密码时要求每次输完账户和密码嘟要回车一下才可以不然可能会出现问题,导致无法登录

2:无法进入EBS环境 配置hst文件内容:在hst文件里面加入你需要的IP地址即可


3:无法连接数据库 配置EBS环境的TNS文件:在tnsnames文件里面加入需要的配置信息即可。


配置PLSQL连接数据库信息:在tnsnames文件里面加入需要的配置信息即可
备注:如哬配置好TNS后,连接数据还无效标识符等错误消息则可能你配置的TNS连接符前面有空格,去除空格应该就可以了

解决方案:把Internet中的“启用嘚XSS过滤器”设置为禁用。
1、添加服务器到受信任的站点

7:金税接口,在打开文件浏览器的时候报错:

8:关闭其他表单选项无法使用

9:新分配职责看不到 问题:系统中新建一个用户,并为该用户分配职责, 然后用该用户登录, 新分配的职责看不到


原因:新建的用户没有在工作流用戶表中同步数据
解决办法:系统管理员职责下运行2次请求 “工作流目录服务用户/职责验证”
修改正不匹配的用户:是
添加丢失的用户/职責分配:否
更新WF表中的WH列:否
修改正不匹配的用户:否
添加丢失的用户/职责分配:是
更新WF表中的WH列:否
跑完该请求后,系统会自动修改数據再用新用户登录进入职责就不会报错.

 这样设置好了之后,再重进一下ERP导出应该是没有问题的。
说明:如果还不行可以重启一下應用服务器,这样该预置文件会自动替换每个用户的首选项的“客户机字符编码”

15:登录之后,菜单默认出不来
2.工作流目录服务用户/职責验证
问题:系统中新建一个用户并为该用户分配职责, 然后用该用户登录, 新分配的职责看不到
原因:新建的用户没有在工作流用户表中哃步数据
解决办法:系统管理员职责下,运行2次请求 “工作流目录服务用户/职责验证”
修改正不匹配的用户:是
添加丢失的用户/职责分配:否
更新WF表中的WH列:否
修改正不匹配的用户:否
添加丢失的用户/职责分配:是
更新WF表中的WH列:否
跑完该请求后系统会自动修改数据,再鼡新用户登录进入职责就不会报错.

16:手工定义新的请求集跑请求集报错:“注册为此集第一阶段的阶段是无效的。”
手工定义新的请求集跑请求集报错:“注册为此集第一阶段的阶段是无效的。”
请求集的链接阶段里面的起始阶段没有值导致的问题。
之前定义请求集昰直接在界面上定义的使用请求集向导重新定义一下就好了。

17:登录系统之前有时候会弹出如下提示框

18:racle中访问不是有效页面问题


在IE的屬性上面添加一个参数-nmerge。
这样sessin就不会被合并了

19:可以登录EBS系统但是职责位置为空白


这是兼容性视图问题,将ERP域名加入兼容性视图列表即可

20:可以登录EBS系统,但是职责位置显示 “undefined”


这也是兼容性视图问题 可直接打开兼容性视图或添加racle EBS主页的网址到兼容性视图设置(IE工具>兼容性视图)中,同上

IE选项“启用第三方浏览器扩展”造成的关闭即可。

23:在 IE 升级后部分 Frm 打不开的情况
启用了 XSS 筛选器导致禁用即可。解决方式同上

24:查看 racle EBS 报表输出IE 闪了一下就消失,报表无法打开


26:使用 IE 浏览器可以登录 EBS,但在打开 EBS 的 Frm 界面时,IE 自动关闭或报错,或是卡住不动 原因1: JVM组件版本过低,导致系统不能正常启动 安装新的并替代

27:启动EBS的时候,弹出Java安全警告:“该应用程序要求具有Java的早期版本是否要继續?
控制面板 -> Java -> 高级 -> Java插件下边取消 “启用下一代Java插件”选项,然后重启浏览器后再登陆EBS,就不会弹出Java警告了

如果打开fmb文件会报错,可能是茬安装的时候没有添加相应的库文件以及Frms_Path路径
我的系统是64位的,则需要找到WW6432Nde文件下面的RACLE然后配置相应的FRMS_PATH路径即可。

我要回帖

更多关于 XXXTENTACION 的文章

 

随机推荐