CSDN博客

img sailerbai

Delphi代码的标准风格

发表于2001/12/28 10:01:00  809人阅读

Object Pascal Style Guide - By Charles Calvert
(对象Pascal编码风格向导 - 译:Tommy Tong)
    我们承认许多好的已经确定的工作室或个人,拥有他们自己的和本文里所说的不同的编程习惯, 但是,我们强烈建议你使用一个工具将你的代码转换为Borland风格的代码,然后再提交给Borland,Project JEDI或其他任何公开的源代码知识库。我们不想强迫你改变你的习惯,但我们坚持所有同Borland产品一起工作的的代码遵循本文描述的习惯。
    对象Pascal是一种优美的设计语言。较强的可读性就是它的一个优点。本文设计的标准将增强对象Pascal代码的可读性。当开发人员遵从本文展现的这些简单的习惯,他们也将成为标准,这将有益于所有的Delphi开发人员使用统一的易读的代码风格。执行这些标准的努力将增加开发人员的源代码的价值,特别是在维护和调试循环阶段。
    尽管我们相信并且赞美本文所宣扬的风格,但我们没有必要支持它,因为它本身是正确的而其它的则是错误的。然而我们相信绝大多数开发人员遵从的标准是有它的功效的,所以我们仍然支持并维护该风格。人类的大脑总在适应标准,并且找寻方法去快速组织所熟悉的模式,从而快速而有效地理解其含义。正是因这种要求而建立的标准将使大量的人尽可能容易的阅读代码。如果在初次使用我们的指导方针是感到陌生,那么我们请你坚持一会儿,你会发现你也变得习惯了。或者,如果你愿意,你也可以保持你自己的风格,并通过一个遵从我们标准的程序来转换,然后你可以将你的代码提交给Borland或其他知识库了。
    一些文本编辑器,象Visual SlickEdit可以帮助你按照一定的风格来格式化你的代码。

一个免费的由Egbert van Nes开发的格式化程序可以在以下的连接获得:
http://www.slm.wau.nl/wkao/delforexp.html

另一个针对Delphi的商业化程序是CrackerJax:
http://www.kineticsoftware.com/html/products.html

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


1.0 介绍
    本文不是为Object Pascal语言定义语法规则的一种尝试。例如:在else前面放置封号";"是违法的;编译器不允许这种用法。所以我不会在本文中展示语法规则。本文旨在在语言提供选择的地方定义适当的行为习惯。我通常在只有一种控制方法的地方保持沉默。

1.1 背景
    在本文出现的指导方针基于Delphi源代码的一部分。Delphi源代码恰好遵循这些指导方针。如果你发现了违反这些原则的情况,那么应该是这些原则而不是那些不确定的源代码成为你的指导方针。然而,你可以使用这些原代码作为这些原则的补充,至少它可以帮助你得到关于你自己的代码的形式的一般看法。

1.2 感谢
    本文这些格式是基于已完成的为Java语言定义的风格标准的工作的。Java在规则上对格式化Object Pascal源代码是没有任何影响的,但在Sun网站上的文档是本文的基础。 在某些特殊的地方本文的风格和格式受到"A Coding Style Guide for Java WorkShop and Java Studio Programming"(Achut Reddy, 《Java车间和Java工作室的编码向导》)的很大启发。该文章可在该URL找到:http://www.sun.com/workshop/java/wp-coding
    Delphi小组为本文的完成做出了重大贡献,事实上,如果没有它们的帮助,本文是无法完成的。

2.0 源文件
    Object Pascal源代码主要被分成单源文件和项目文件,他们都遵从相同的习惯。Delphi项目文件有一个.DPR的扩展名。它是项目的主文件。任何在项目中使用的单元文件都有一个.PAS的扩展名。其它的文件,象批处理文件、HTML文件或者DLLs也可以在项目中扮演一个角色,但本文只涉及项目文件和单元文件。

2.1 源文件命名
    Object Pascal支持长文件名。如果你使用几个单词来形成一个单一的名称,那么最好是为每个单词使用大写的开头字母:MyFile.pas。这被认为是插入式大写或驼峰式大写。扩展名应当使用小写形式。由于历史原因,Delphi源代码经常使用8:3式命名模式,但开发人员不必为上述规则所限制而转向Delphi小组的用法。
    如果你正在翻译一个C/C++头文件,那么你翻译的Pascal文件要与C/C++头文件保持相同的主文件名,扩展名用.PAS。例如:Windows.h -> Windows.pas。如果Pascal语法强迫你将几个头文件组合到一个单一的单元文件中,那么包含其他头文件的那个头文件的文件名将作为新单元文件的名称。例如:Windows.h包含了WinBase.h文件,则新的单元文件名为Windows.pas.

2.2 源文件组织
    所有的Object Pascal单元文件应当按照以下的顺序包含下列元素:
版权/标识块注释
单元名
接口段
实现部分
一个结束符"end."

每个部分之间至少空一行。

其它的元素应当被结构化成你认为最适当的顺序。但版权应当出现在文件的最开始,然后是单元名,然后是任何条件定义、编译器指示符或包含语句,然后是uses字句:


{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ }
{ Copyright (c) 1995,98 Inprise Corporation }
{ }
{*******************************************************}

unit Buttons;

{$S-,W-,R-}
{$C PRELOAD}

interface

uses
  Windows, Messages, Classes,
  Controls, Forms, Graphics,
  StdCtrls, ExtCtrls, CommCtrl;




如果你将type段放到const段之前,或者将它们两者混合,那是没有什么影响的。

实现部分需要首先将implementation写出来,然后是uses字句,然后是其它的包含声明或别的指示符:


implementation

uses
  Consts, SysUtils, ActnList,
  ImgList;




{$R BUTTONS.RES}

2.2.1 版权/标识块注释
    每一个源文件都应当以一个包含版本信息和标准版权布告块注释开始。版本信息可以象下面这样:


{*******************************************************}
{ }
{ Widgets Galore }
{ }
{ Copyright (c) 1995,98 Your Company }
{ }
{*******************************************************}




版权布告至少需要包含以下行:
    版权所有(C) 年份 版权所有者

如果你是为Borland开发软件的第三方,你可以在版权的最后加入你自己的名字:


{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ Copyright (c) 1995,99 Borland International }
{ Created by Project JEDI }
{ }
{*******************************************************}




2.2.2 unit声明
    每一个单元文件要有一个unit声明。unit是一个保留字,因此它需要小写。单元的名称可以是大小写混合的,但必须和单元文件的文件名相同。例如:
unit MyUnit;

则单元文件的名称应当为MyUnit.pas。在文件系统中,它作为这个文件的入口。

2.2.3 uses声明
    在单元内部,uses声明应当使用小些的uses引导。被引用的单元名要遵循在他自己的单元中被定义时使用的大写习惯:
uses MyUnit;
    每一个单元名被一个逗号同其相邻的单元名分开,最后一个单元名后面跟一个分号:


uses
  Windows, SysUtils, Classes, Graphics, Controls, Forms,
  TypInfo;
    在uses的下一行开始加入单元名和在uses后面直接加入单元名同样都是正确的。
uses Windows, SysUtils, Classes, Graphics, Controls, Forms,
  TypInfo;


    你可以格式化你的单元名列表,可以在80个字符限制下换行,或者每个单元名一行。

2.2.4 类和接口定义
    类的定义以两个空格开始,然后是一个前缀"T"。 前缀要大写,每个内嵌的单词要大写开头。不要在Object Pascal源代码中使用制表符"Tab"。例:
TMyClass
    在标识符之后接一个空格,然后是等号,然后是class单词,class要小写:
  TMyClass = class
    如果你的类是从祖先继承来的,则需要加入包含着祖先类的左右括号:
  TMyClass = class(TObject)
    范围指示符离页边两个空格,并以下面的顺序出现:
  TMyClass = clss(TObject)
  private
  protect
  public
  published
  end;
    数据通常只在private段声明,并且它们的标识符以"F"开始。所有此类的声明离页边4个空格:


  TMyClass = class(TObject)
  private
    FMyDate: Integer;
    function GetDate: Integer;
    procedure SetData(Value: Integer);
  public
  published
    property MyData: Integer read GetData write SetData;
  end;


    接口遵从同类相同的规则,除了你应当忽略范围指示符和私有数据,并且使用interface单词代替class单词。
    命名习惯
    除了保留字和指示符是小写外,所有的Pascal标识符应当使用驼峰式格式,即每个标识符开头字母要大写,内嵌单词的首字母也要大写,只取首字母的缩写词也一样。
MyIdentifier
MyFTPClass
    对此规则主要的例外是头文件翻译的情况,应当遵循在原头文件中的命名习惯。例如:
    WM_LBUTTONDOWN,不要写成wm_LButtonDown.
    除了头文件翻译外,不要使用下划线分割单词。类名应当是名词或名词短语。接口或类的名称依赖于接口的显而易见的目的、用途。

好的名字:
    AddressForm, ArrayIndexOutOfBoundsException
低劣的名字:
    ManageLayout //使用动词短语
    delphi_is_new_to_me //使用下划线

3.1 单元命名
    参见单元声明

3.2 类/接口命名
    参见类/接口声明

3.3 域/字段命名
    使用驼峰式格式。以大写的"F"开始,并且在private中声明所有的数据,使用属性或获取者(getter)和安装者(setter)来提供公共的存取操作。例如:使用名字GetSomething来命名一个返回内部域/字段值的函数,使用SetSomething来命名一个设置域/字段值的过程。
    不要在const段全部使用大写,除非是头文件翻译的需要。
    Delphi是在加利福尼亚开发的,所有我们阻止记号的使用,除非是头文件翻译的需要。
正确:
  FMyString: string;
不正确:
  lpstrMyString: string;
    当然在枚举类型定义中保留了匈牙利命名法:
    TBitBtnKind = (bkCustom, bkOK, bkCancel, bkHelp,
      bkYes, bkNo, bkClose, bkAbort, bkRetry,
      bkignore, bkAll);
    在这种情况下字符bk被插入到这个枚举类型的每一个元素前。bk意味着ButtonKind。
    在考虑命名习惯时,要避免使用单个字符的名称,但零时变量和循环变量除外。
    避免使用"l"(L)变量,因为它和"1"(one)无论在打印机还是在显示器上都难以分辨。

3.4 方法命名
    方法命名也使用驼峰格式。方法命名习惯同非常量域的命名方法是相同的,但可以从上下文区分它们。方法命名应当强制使用动词或动词短语。例如:
//好的方法命名:
ShowStatus, DrawCircle, AddLayoutComponent
//差的方法命名:
MouseButton //名词短语,没有描述功能
drawCircle //以小写字母开头
add_layout_component //使用了下划线

//以下方法的功能不够明确。它是开始运行一个服务呢(更好:StartServer)还是判断一个服务是否在运行(更好:IsServerRunning)?
ServerRunning //动词短语,但不是命令
    一个获取或者设置一些类属性的方法应当分别被称为GetProperty或者SetProperty,Property代表该属性的名称。例如:
GetHeight, SetHeight
    一个测试类的布尔属性的方法应当被命名为IsVisible,Visible代表属性的名称。例如:
    IsResizable, IsVisible

3.5 局部变量命名
    除了不使用"F"外,局部变量的命名规则同域/字段的命名规则一样。参见3.3节。

3.6 保留字
    保留字和指示符要全部小写。这有时有些混乱。例如:Integer是一个标识符,并且以首字母大写出现。而string保留字则全部小写。

3.7 类型声明
    所有类型名称声明以字母T开始,接下来和类的命名相同。

4.0 空白用法
    4.1 空白行
        空白行可以通过将逻辑相关的代码段分组来提高可读性。一个空白行也可以在下列地方使用:
        在版权注释块之后,包声明(package),导入段(import)。
        类声明之间。
        方法声明之间。
    4.2 空格
        Object Pascal是一种非常清晰易读的语言。通常,你不需要在代码里加入很多空格来分隔行。以下几条提供了一些原则该如何使用空格:
            4.2.2 不应当使用空格:
                在方法名和左括号之间;
                在.(dot)操作符之前或之后;
                在一元操作符和它的操作数之间;
                在一个类型和被它强制转换的表达式之间;
                在左括号之后和右括号之前;
                在左方括号之后和右方括号之前;
                在一个封号前;
                例如:
                //正确用法:
                function TMyClass.MyFunc(var Value: Integer);
                MyPointer := @MyRecord;
                MyClass := TMyClass(MyPointer);
                MyInteger := MyIntegerArray[5];
                //错误用法:
                function TMyClass.MyFunc( var Value: Integer ) ;
                MyPointer := @ MyRecord;
                MyClass := TMyClass ( MyPointer ) ;
                MyInteger := MyIntegerArray [ 5 ] ;

4.3 缩进
    你应当总是为所有的缩进层次缩进两个空格。换句话说就是,第一层缩进两个空格,第二层缩进四个空格,第三层缩进六个空格……。不要使用制表符Tab。
    当然,仍然有少量的例外。保留字象unit, uses, type, interface, implementation, initialization 和finalization总是顶格的。单元的最后一个end标识符也是顶格的。在项目文件中,program和主begin、end也是顶格的。在主begin..end块内则需要缩进至少两个空格。

4.4 续行
    行应当限制在80列以内。超过80列的行应当被分成多个连续的行。所有的后续行应当排列在该声明的第一行之后,并且缩进两个字符的空格。
    例如:
//正确:


function CreateWindowEx(dwExStyle: DWORD;
  lpClassName: PChar; lpWindowName: PChar;
  dwStyle: DWORD; X, Y, nWidth, nHeight: Integer;
  hWndParent: HWND; hMenu: HMENU; hInstance: HINST;
  lpParam: Pointer): HWND; stdcall;

if ((X = Y) or (Y = X) or
  (Z = P) or (F = J) then
begin
  S := J;
end;


    不要在参数和它的类型之间换行,除非列表是由逗号分隔,那样的话要在最后一个参数前换行,这样类型名就在下一行开头了。冒号和它的变量之间不应该有空格,而冒号和类型名之间要有一个空格。
//正确:
procedure Foo(Param1: Integer; Param2: Integer);

//错误:
procedure Foo( Param :Integer; Param2:Integer);
    一个后续行不应以一个二进制操作符开始。避免在通常不出现空白的地方割断一行,比如在方法名和它的左括号之间,或者在一个数组名和它的左方括号之间。如果你必须在上述情况下割断行,那么应当在左括号或左方括号之后换行。不要把begin放在其它代码的同一行。
例如:
//错误:


while (LongExpression1 or LongExpression2) do begin
  //DoSomething
  //DoSomethingElse;
end;




//正确


while (LongExpression1 or longExpression2) do
begin
  //DoSomething
  //DoSomethingElse;
end;

if (LongExpressiong1) or
  (LongExpression2) or
  (LongExpression3) then





5.0 注释
    Object Pascal语言支持两种注释:块和单行注释。以下是一些注释用法原则:
    ·在单元顶部放置注释用以解释单元的用途是有益的
    ·在类声明前放置注释是有益的
    ·在方法声明前设置注释是有益的
    ·避免语句含义明显的注释
        i := i + 1; //Add one to i
    ·记住,容易误解的注释比没有注释更加有害。
    ·避免在注释里放入看上去要失效的信息
    ·避免在注释的边框里嵌入星号或其他的排版符号
    ·零时的注释,即需要被改变或删除的注释,要在他们之前加上"???:"标记,这样易于查找。从观念上来说,所有的零时注释都应当在程序发布前删除。
    // ???: Change this to call Sort when it is fixed
    List.MySort;


5.1 块注释
    Object Pascal支持两种类型的块注释。最常用的是一对花括号{}括起来的注释。Delphi小组尽可能的保持该注释少而简单。例如:你应当避免在你的注释里使用星号来创建图案或行。相反,使用空格来分隔你的注释,就象你在字处理文档里做的一样。你的注释里的单词应当在第一个花括号的同一行开始,就象下面从DsgnIntf.pas中摘录的一样:

{ TPropertyEditor
  Edits a property of a component, or list of components,
  selected into the Object Inspector. The property
  editor is created based on the type of the
  property being edited as determined by the types
  registered by...
  etc...
    GetXxxValue
      Gets the value of the first property in the
      Properties property. Calls the appropriate
      TProperty GetXxxValue method to retrieve the
      value.
    SetXxxValue Sets the value of all the properties
      in the Properties property. Calls the appropriate
      TProperty SetXxxxValue methods to set the value. }
    块注释通常被用在版权注释中。也被用来注释掉一些代码行。
    用于解释方法的用途的块注释应当被访在方法的声明前面。
    例如:
// CORRECT

{ TMyObject.MyMethod
  This routine allows you to execute code. }

procedure TMyObject.MyMethod;
begin
end;

// INCORRECT

procedure TMyObject.MyMethod;
{******************************************************
  TMyObject.MyMethod
  This routine allows you to execute code.
*******************************************************}
begin
end;
    第二种块注释包含了两个字符,括号和星号:(* *)。这有时被称为星括号注释。这些注释一般只在代码开发时有用,它的主要好处是允许嵌套注释,注释嵌套少于两层。Object Pascal不支持同类型的注释嵌套,因此事实上只有一层嵌套:花括号在星括号里面,或者星括号在花括号里面。 只要在你不嵌套它们时,在该类型的注释中的其它类型的标准Pascal注释将被忽略。因此,你可以使用该语法注释一大块既有代码又有注释的代码:

(* procedure TForm1.Button1Click(Sender: TObject);


begin
  DoThis; // Start the process
  DoThat; // Continue iteration
  { We need a way to report errors here, perhaps using
    a try finally block ??? }

  CallMoreCode; // Finalize the process
end; *)


    在本例中,整个Button1Click方法被注释掉了,包括其中的任何子注释。

5.2 单行注释
    单行注释由注释符//及其引导的文本组成,在文本和注释符之间有一个空格。单行注释同代码在不同行的,要同代码有相同的缩进层次。你可以使用多个单行注释形成大的注释。
    在单行注释或注释组之前要有一个空行,除非它是一个块的第一行。如果注释用于几条语句,那么注释和注释组之后要跟一个空行。如果注释仅解释它后面的一行声明,则不必跟一个空行。
例如:
// Open the database
Table1.Open;
    单行注释也可以跟在他们解释的代码声明后面。这类注释有时被引用为跟踪注释。在他们和代码之间至少要有一个空格。如果有多个跟踪注释在一个代码块中同时出现,那么这些注释需要被对齐。
例如:


if (not IsVisible) then
    Exit; // nothing to do
Inc(StrLength); // reserve space for null terminator


    要避免对每行可执行代码进行跟踪注释。在一个方法或函数的begin..end块之间限制使用注释、甚至让其为空,则在通常情况下是最好的。长的注释可以出现在方法、函数的定义之前的块注释当中。


6.1 类体的组织
    类体的组织应当遵循下列顺序:
    ·域/字段声明
    ·方法声明
    ·属性定义
    域/字段、属性、方法应当按它们的名称进行字母索引排列。
    6.1.1 存取级别
        除了由IDE生成的代码,类的范围指示符应当按以下顺序:
        ·private 声明
        ·protect声明
        ·public声明
        ·published声明
        在Object Pascal中,类成员有四种存取级别:发布的、公开的、受保护的和私有的--按存取能力递减的顺序排列。默认的存取级别是published。一般,一个成员应当被赋予最合适它的最低的存取级别。例如:只能在同一单元中被其他类存取的成员就应当被声明为私有的。同时,声明低存取级别的成员也给了编译器提高优化的机会。当然,另一方面,使用低存取级别对子类的扩展造成了困难。如果有理由认为某个类在将来某个时候会被子类化,那么应当将那些需要被子类继承扩展的成员声明为受保护的,用于存取私有数据的属性也可以提供这方面的保护。
        你应当禁止对数据的公开存取。数据通常在private段声明,任何对他的公开存取应当通过GetXXX、SetXXX方法或属性来操作。
    6.1.8 构造函数声明
        方法需要按字母索引排列。将构造函数和析构函数放在public段的开始或按照字母索引排列都是正确的。
        如果有多个构造函数或你使用了多个相同的名字,那么应当根据形参列表来排列,参数少的在参数多的前面。这意味着如果存在没有参数的构造函数的话,那么它必定出现在第一个。为了和C++Builder保持最好的兼容,应当保证构造函数的参数列表的唯一性。C++不是根据构造函数的名称来调用它的,所以区别多个构造函数的唯一方法是通过它的参数列表。

6.2 方法声明
    如果可能,方法声明要出现在单独一行上。
例如:
Examples:



procedure ImageUpdate(Image img, infoflags: Integer,
  x: Integer, y: Integer, w: Integer, h: Integer)




7.0 接口
    接口的声明与类的声明有相同的形式:


  InterfaceName = interface([inherited Interface])
    InterfaceBody
  end;


  接口声明应当被缩进两格,接口体缩进四格,end结束符缩进两格。
  在接口声明中没有域/字段。但属性可以出现。
  所有的接口方法天生就是公开的和抽象的,用不着在接口声明中包含此类关键字。
  除非有其他的注意事项,否则接口的声明同类的声明具有相同的风格。

7.1 接口体组织
    接口体的组织可以按以下的顺序:
    ·接口方法声明
    ·接口属性声明
    接口方法和属性的声明和类具有相同的风格。

8.0 声明
    声明是由封号结尾的一行或几行代码。单一声明只有一个封号,复合声明中有多个封号。
//这是单一声明:
A := B;

//这是复合声明:


begin
  B := C;
  A := B;
end;


    8.0.1 单一声明
        如果需要将一个单一声明换行,则需要参照上一行缩进两格。
//例如:


MyValue :=
  MyValue + (SomeVeryLongStatement / OtherLongStatement);




8.1.1 赋值和表达式声明
每一行最多有一条声明。
例如:


a := b + c; Inc(Count); //错误
a := b + c; //正确
Inc(Count); //正确




8.1.2 局部变量声明
    局部变量也使用驼峰格式,不要使用引导符"F",这是为类声明中域/字段保留的。
例如:


var
  MyData: Integer;
  MyString: string;


    你可以在同一行声明多个类型相同的变量:


var
  ArraySize, ArrayCount: Integer;


    这种声明习惯在类声明中是不提倡。

8.1.3 数组声明
    通常总是在左方括号之前和右方括号之后放置一个空格:


type
  TMyArray = array [0..100] of Char;




8.2.3 if语句
    if语句至少要以两行的形式出现:
例如:
//错误:


if A = B then DoSomething;



//正确


if A = B then
  DoSomething;


    如果是复合的if语句,则应当每个分隔符一个新行:
//错误:


if A = B then begin
  DoSomething;
  DoSomethingElse;
end else begin
  DoThis;
  DoThat;
end;



//正确


if A = B then
begin
  DoSomething;
  DoSomethingElse;
end
else
begin
  DoThis;
  DoThat;
end;


    以下的少数变化可以被采用:
//正确


if Condition then
begin
  DoThis;
end else
begin
  DoThat;
end;




//正确


if Condition then
begin
  DoThis;
end
else
  DoSomething;




//正确


if Condition then
begin
  DoThis;
end else
  DoSoemthing;




//下面的方式可能不被关心,但却是值得赞扬的:


if Condition then
  DoThis
else DoThat;




8.2.4 for语句
Example:
// INCORRECT


  for i := 0 to 10 do begin
    DoSomething;
    DoSomethingElse;
  end;




// CORRECT


  for i := 0 to 10 do
  begin
    DoSomething;
    DoSomethingElse;
  end;




8.2.5 while 语句
Example:
// INCORRECT


  while x < j do begin
    DoSomething;
    DoSomethingElse;
  end;




// CORRECT


  while x < j do
  begin
    DoSomething;
    DoSomethingElse;
  end;




8.2.6 repeat until 语句
Example:
  // CORRECT


  repeat
    x := j;
    j := UpdateValue;
  until j = 25;




8.2.7 case 语句
Example:
// CORRECT


  case Control.Align of
    alLeft, alNone: NewRange := Max(NewRange, Position);
    alRight: Inc(AlignMargin, Control.Width);
  end;



  // CORRECT


  case x of
    csStart:
      begin
        j := UpdateValue;
      end;
    csBegin: x := j;
    csTimeOut:
      begin
        j := x;
        x := UpdateValue;
      end;
  end;


  // CORRECT


  case ScrollCode of
    SB_LINEUP, SB_LINEDOWN:
      begin
        Incr := FIncrement div FLineDiv;
        FinalIncr := FIncrement mod FLineDiv;
        Count := FLineDiv;
      end;
    SB_PAGEUP, SB_PAGEDOWN:
      begin
        Incr := FPageIncrement;
        FinalIncr := Incr mod FPageDiv;
        Incr := Incr div FPageDiv;
        Count := FPageDiv;
      end;
  else
    Count := 0;
    Incr := 0;
    FinalIncr := 0;
  end;





8.2.8 try 语句

// Correct


  try
    try
      EnumThreadWindows(CurrentThreadID, @Disable, 0);
      Result := TaskWindowList;
    except
      EnableTaskWindows(TaskWindowList);
      raise;
    end;
  finally
    TaskWindowList := SaveWindowList;
    TaskActiveWindow := SaveActiveWindow;
  end;
0 0

相关博文

我的热门文章

img
取 消
img