Form Style - fsStayOnTop 효과

 SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE)

<-> SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);

 

출처 :  http://www.delmadang.com/community/bbs_view.asp?bbsNo=17&bbsCat=41&indx=405581&keyword1=fsStayOnTop&keyword2=

이 글은 스프링노트에서 작성되었습니다.

다음은 동적(Static) DLL로 구현 되어져 있다.

  • 정적(Static) DLL 이란? 본래의 DLL이라기 보다는 코드의 큰 함수들을 따로 모듈별로 분리 했다가 실행 시 함께 처리한다.
  • 동적(Dynamic) DLL(런타임 로딩) 이란 ? DLL은 GetProcAddress라는 API를 사용하여 필요에 따라 첨가하고 필요에 따라 해제시킬 수 있다.

DLL 소스 및 정적 DLL 호출 방법은 다음 글을 참고 하기 바란다.

2010/04/27 - [Language/Delphi] - [Delphi] DLL 호출 규칙(Calling Convention) 테스트용 DLL 및 Source

다음 소스는 Delphi 2010에서 제작 되었으나 기본 사용법은 동일하다.


  1: unit UB_Main_DynDLL;
  2: 
  3: interface
  4: 
  5: uses
  6:   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7:   Dialogs, StdCtrls;
  8: 
  9: type
 10:   TfrmUBMainDynDLL = class(TForm)
 11:     btnPascal: TButton;
 12:     edtPascal: TEdit;
 13:     btnCdecl: TButton;
 14:     edtCdecl: TEdit;
 15:     btnStdcall: TButton;
 16:     edtStdcall: TEdit;
 17:     procedure btnPascalClick(Sender: TObject);
 18:     procedure btnCdeclClick(Sender: TObject);
 19:     procedure btnStdcallClick(Sender: TObject);
 20:   private
 21:     { Private declarations }
 22:   public
 23:     { Public declarations }
 24:   end;
 25: 
 26: var
 27:   frmUBMainDynDLL: TfrmUBMainDynDLL;
 28: 
 29: implementation
 30: 
 31: const
 32:   ImportDLLFile = 'UPCallTypeDLLTest.dll';
 33:   Msg = '안녕! 세계 (Hellow World!)';   // Hellow World! 국산화 버전 ㅎㅎ
 34: 
 35: var
 36:   DLLCallTypePascal : function (AStr : string)  : PChar;  pascal;
 37:   DLLCallTypeCdecl  : function (AStr : string)  : PChar;  cdecl;
 38:   DLLCallTypeStdcall: function (AStr : string)  : PChar;  stdcall;
 39: 
 40: {$R *.dfm}
 41: 
 42: procedure TfrmUBMainDynDLL.btnCdeclClick(Sender: TObject);
 43: var
 44:   H : HINST;
 45:   S : PChar;
 46: begin
 47:   H := LoadLibrary(PChar(ImportDLLFile));
 48:   if H <= 0 then
 49:   begin
 50:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 51:   end else begin
 52:     try
 53:       @DLLCallTypeCdecl := GetProcAddress(H, Pchar('DLLCallTypeCdecl'));
 54:       S := DLLCallTypeCdecl(Msg);
 55:       if H <> 0 then
 56:         edtCdecl.Text := S
 57:       else
 58:         edtCdecl.Text := 'ERROR!!';
 59:     finally
 60:       FreeLibrary(H);
 61:     end;
 62:   end;
 63: end;
 64: 
 65: procedure TfrmUBMainDynDLL.btnPascalClick(Sender: TObject);
 66: var
 67:   H : HINST;
 68:   S : PChar;
 69: begin
 70:   H := LoadLibrary(PChar(ImportDLLFile));
 71:   if H <= 0 then
 72:   begin
 73:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 74:   end else begin
 75:     try
 76:       @DLLCallTypePascal := GetProcAddress(H, Pchar('DLLCallTypePascal'));
 77:       S := DLLCallTypePascal(Msg);
 78:       if H <> 0 then
 79:         edtPascal.Text := S
 80:       else
 81:         edtPascal.Text := 'ERROR!!';
 82:     finally
 83:       FreeLibrary(H);
 84:     end;
 85:   end;
 86: end;
 87: 
 88: procedure TfrmUBMainDynDLL.btnStdcallClick(Sender: TObject);
 89: var
 90:   H : HINST;
 91:   S : PChar;
 92: begin
 93:   H := LoadLibrary(PChar(ImportDLLFile));
 94:   if H <= 0 then
 95:   begin
 96:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 97:   end else begin
 98:     try
 99:       @DLLCallTypeStdcall := GetProcAddress(H, Pchar('DLLCallTypeStdcall'));
100:       S := DLLCallTypeStdcall(Msg);
101:       if H <> 0 then
102:         edtStdcall.Text := S
103:       else
104:         edtStdcall.Text := 'ERROR!!';
105:     finally
106:       FreeLibrary(H);
107:     end;
108:   end;
109: end;
110: 
111: end.
112: 





출처 : 자작(http://userpark.net)

DLL호출 규칙에 대하여 먼저 언급하고자 한다.

Delphi는 다른 랭귀지에서 사용된 함수들을 쉽게 호출 할 수 있도록 여러 가지 호출 규칙을 가진다.

아래와 같이 5가지 방법이 있다.

  1. Register(__fastcall) : 레지스터에 등록하여 호출하는 방식
  2. stdcall(__stdcall) : 가장 일반적으로 활용하는 방식으로 윈도우 표준
  3. cdecl(__cdecl) : 가변인자가 있는 경우
  4. pascal(__pascal) : Delphi 최적화 코드를 생성하고자 할 때 스택으로 인자를 저장하는 방식보다는 레지스터를 경유하여 속도 향상
  5. safecall : OLE 방식에서 이용

참고 : http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=42&indx=195902&keyword1=dll&keyword2=호출규칙

※pascal 경우 속도 향상이 된다고 책에는 나와있으나 실제 테스트는 하지 않음.

본 글에서는 stdcall,cdecl,pascal 3가지에 대해서만 샘플을 제공하여 드리겠습니다.

아래 소스를 콜타입들을 바꿔가면서 DLL과 App에서 서로 테스트 해보기시기 바랍니다.

그런데 이상하게도 테스트 하면서 stdcall과 pascal은 서로 상호 호환이 완벽하게 이루어졌습니다. 이 해당 소스만이 그런건지 정확히는 현재 알 수 없습니다.

지금까지 저는 DLL을 안 쓰다가 이번에 새로운 일이 생겼는데 DLL을 호출해서 사용해야 할 일이 생겨서 이것 저것 테스트 하다가 이런 문서도 만들게 되었습니다.

(기존 Delphi만 이용시에는 dcu파일로 배포등을 하여 DLL의 필요성을 알지 못했습니다. ^^;;)

정확한 개념이 잡힌 소스인지… 저도 장담을 못하지만 여러가지로 도움이 되었으면 좋겠습니다.

또한 DLL 생성 및 Delphi 기초에 대하여서는 기타 유용한 사이트 및 책을 이용하시기 바랍니다.


아래 방법으로 공부하시기 바랍니다.(저도 이걸로 공부 중)

  1. UPCallTypeDLLTest.dll 을 만든다
  2. UPCallTypeDLLTestApp.exe에서 상기 DLL을 호출한다.
  3. DLL과 APP를 서로 콜방식을 변경하여 가면서 오류 사항 및 반영내용을 스스로 공부한다.

아래 소스는 Delphi 2010으로 만들었습니다.(Delphi 7로 하려다가 그냥~)


Import 해 올 DLL 파일을 반드시 아래 경로에 존재 하여야 한다.
  • [%SystemRoot%] (Windows 디렉토리)
  • [%SystemRoot%]\system32\ 경로 (Microsoft Windows XP 일 경우)
  • 실행파일(현재 작업) 디렉토리에 같이 위치
  • 환경변수 PATH 상의 경로(비추천)

  • UPCallTypeDLLTest.dll
  1: library UPCallTypeDLLTest;
  2: 
  3: uses
  4:   SysUtils,
  5:   Classes,
  6:   Dialogs;
  7: 
  8: {$R *.res}
  9: 
 10: function DLLCallTypePascal(AStr : string) : PChar; pascal;
 11: var
 12:   S : string;
 13: begin
 14:   S := AStr;
 15:   S := 'DLL 함수 테스트 : ' + S + ' - pascal';
 16:   ShowMessage(S);
 17:   Result := PChar(S);
 18: end;
 19: 
 20: function DLLCallTypeCdecl(AStr : string) : PChar; cdecl;
 21: var
 22:   S : string;
 23: begin
 24:   S := AStr;
 25:   S := 'DLL 함수 테스트 : ' + S + ' - cdecl';
 26:   ShowMessage(S);
 27:   Result := PChar(S);
 28: end;
 29: 
 30: function DLLCallTypeStdcall(AStr : string) : PChar; stdcall;
 31: var
 32:   S : string;
 33: begin
 34:   S := AStr;
 35:   S := 'DLL 함수 테스트 : ' + S + ' - stdcall';
 36:   ShowMessage(S);
 37:   Result := PChar(S);
 38: end;
 39: 
 40: exports
 41:   DLLCallTypePascal
 42:   ,DLLCallTypeCdecl
 43:   ,DLLCallTypeStdcall
 44:   ;
 45: 
 46: begin
 47: end.

다음은 정적(Static) DLL로 구현 되어져 있다.

  • 정적(Static) DLL 이란? 본래의 DLL이라기 보다는 코드의 큰 함수들을 따로 모듈별로 분리 했다가 실행 시 함께 처리한다.
  • 동적(Dynamic) DLL(런타임 로딩) 이란 ? DLL은 GetProcAddress라는 API를 사용하여 필요에 따라 첨가하고 필요에 따라 해제시킬 수 있다.
  • UPCallTypeDLLTestApp.exe
      - UB_Main.pas
  1: unit UB_Main;
  2: 
  3: interface
  4: 
  5: uses
  6:   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7:   Dialogs, StdCtrls;
  8: 
  9: type
 10:   TfrmUBMain = class(TForm)
 11:     btnPascal: TButton;
 12:     edtPascal: TEdit;
 13:     btnCdecl: TButton;
 14:     edtCdecl: TEdit;
 15:     btnStdcall: TButton;
 16:     edtStdcall: TEdit;
 17:     procedure btnPascalClick(Sender: TObject);
 18:     procedure btnCdeclClick(Sender: TObject);
 19:     procedure btnStdcallClick(Sender: TObject);
 20:   private
 21:     { Private declarations }
 22:   public
 23:     { Public declarations }
 24:   end;
 25: 
 26: var
 27:   frmUBMain: TfrmUBMain;
 28: 
 29: const
 30:   ImportDLLFile = 'UPCallTypeDLLTest.dll';
 31:   Msg = '안녕! 세계 (Hellow World!)';   // Hellow World! 국산화 버전 ㅎㅎ
 32: 
 33: function DLLCallTypePascal(AStr : string)   : PChar;  pascal;   external ImportDLLFile;
 34: function DLLCallTypeCdecl(AStr : string)    : PChar;  cdecl;    external ImportDLLFile;
 35: function DLLCallTypeStdcall(AStr : string)  : PChar;  stdcall;  external ImportDLLFile;
 36: function DLLCallTypeStdcallNickName(AStr : string)  : PChar;  stdcall;  external ImportDLLFile name 'DLLCallTypeStdcall';
 37: 
 38: implementation
 39: 
 40: {$R *.dfm}
 41: 
 42: procedure TfrmUBMain.btnCdeclClick(Sender: TObject);
 43: var
 44:   S : PChar;
 45: begin
 46:   S := DLLCallTypeCdecl(Msg);
 47:   edtCdecl.Text := S;
 48: end;
 49: 
 50: procedure TfrmUBMain.btnPascalClick(Sender: TObject);
 51: var
 52:   S : PChar;
 53: begin
 54:   S := DLLCallTypePascal(Msg);
 55:   edtPascal.Text := S;
 56: end;
 57: 
 58: procedure TfrmUBMain.btnStdcallClick(Sender: TObject);
 59: var
 60:   S : PChar;
 61: begin
 62:   S := DLLCallTypeStdcall(Msg);
 63:   edtStdcall.Text := S;
 64: end;
 65: 
 66: end.

 출처 : 자작(http://userpark.net)


PS) 본 소스를 바탕으로 .NET C#과 Visual Basic에서 호출하여 사용하는 방법을 추후 올리겠습니다.

      (대부분 C++에서 DLL을 만드는데 전 C++이 약한 관계로 ^^;;)

UPCallTypeDLLTestForDelphi2010.7z

UPCallTypeDLLTestAppForDelphi2010.7z


UPCallTypeDLLTestGroupForDelphi2010(All).7z


 

델마당 코딩 표준

델파이 코딩 가이드 for 델마당 ( version 1.0 )

 

요약

 

본 문서는 델파이 코드 형식에 대한 Borland 표준 스타일 문서(링크)를 바탕으로 만들어졌다.

델마당 표준의 원칙은 소스에 포함된 논리를 보다 명확하게 표현하기 위함이다.

따라서 볼랜드 표준과는 다르게 스타일이 강요되지는 않으며,

누구나 코드를 이해하기 쉽고, 코드에 표현된 논리가 명확한 범위내에서 개인적인 취향에 따라 변경할 수 있음을 명시한다.

 

변경내역

 

최종작성: 2001년 09월 24일 godrm@netsgo.com

초고작성: 2001년 09월 05일 godrm@netsgo.com

 

목적

 

델파이의 오브젝트 파스칼 언어는 아름다울 정도로 잘 디자인된 언어이며, 가장 큰 장점중에 하나가 읽기 쉽다는 점이다.

본 표준의 목적은 이러한 델파이 - 오브젝트 파스칼 코드의 장점을 더욱 극대화시키는 데 있다.

많은 개발자들이 사용하는 방식을 종합단 간단한 표준 방식을 따른다면, 좀 더 보기 좋고 쉬운 코드가 생길 것이며

디버깅 주기나 유지보수 기간을 줄일 수 있고, 소스 코드의 값어치를 높일 수 있을 것이다.

 

물론 코딩 방식이나 개발 작업 스타일은 개발자 자신의 입맛에 따라 다른 문제이다.

그럼에도 불구하고 이렇게 코딩 표준 스타일을 준비하는 것은 나름의 방식이 옳고-그름을 따지자는 것이 아니라,

대부분의 개발자들이 사용하는 표준을 만들어 효율성을 높이자는 것이다.

인간은 표준을 따라 사용하면서 툴이 더 친숙해지며, 잘 쓰는 패턴들을 보다 빠르고 정확하게 인식하는 습성이 있다.

 

아마도 이러한 표준 방식이 낯설더라도 표준에 따라서 사용하다보면 편리함을 느끼게 될 것이다.

그래도 자신의 방식을 지키고자 하는 사람들은, 적어도 이 곳 델마당나 공유 자료로 올릴 경우에는

다른 사람들과의 공유 차원에서 범용적인 표준 방식을 사용했으면 한다.

 

라이센스

 

코딩 표준에 대한 라이센스 같은 것은 당연히 없다.

다만 본 문서 자체를 무단 배포하거나 복제해서 사용하면 안되고, 반드시 델마당에서 만든 표준 문서임을 밝혀야 한다.

 

차례

 

 

 

1. 기본구성

1.1 들여쓰기

블럭/레벨간의 확인가능하고 일정하게 지켜진다면, 들여쓰기에 대한 제약은 전혀 두지 않기로 한다.

단, 볼랜드 방식인 레벨마다 2칸의 탭간격을 추천한다.

 

특히 조건문이나 출력문의 내용이 길어져서 옆줄로 길어진 경우, 다음줄로 내려쓰고 들여쓰기하여 구분할 수 있도록 한다.

 

1.2 주석

기본적인 주석은 중괄호 { } 로 한다.

부수적으로 (* *) 방식은 개발중에 임시로 사용되는 주석 용도로만 사용한다.

// 방식 주석은 한 줄만 주석처리 할 때 사용하도록 한다.

 

유닛 파일 가장 위에는 다음과 같은 파일 헤더를 붙인다.

{***************************************************************}
{                                                               }
{  This line describes the purpose of the unit                  }
{                                                               }
{  Copyright (c) 2001 godrm@netsgo.com                          }
{                                                               }
{     All rights reserved.                                      }
{                                                               }
{***************************************************************}

 

1.3 컨디션 설정

오브젝트 파스칼 컴파일러 지시자에 사용되는 것과 마찬가지로 { } 로 컨티션 설정을 한다.

  if ... then
  begin
    {$IFDEF VER90}
      raise Exception.CreateRes(SError);
    {$ELSE}
      raise Exception.Create(SError);
    {$ENDIF VER90}
  end;

 

1.4 빈공간

한줄 띄우기(Blank Lines)는 저작권 주석이나, 패키지 선언, 클래스 선언, 메소드 선언들 사이에 한다.

다음의 경우에는 빈공간을 주지 않는다.

(1) 메소드 이름과 여는 괄호 사이

(2) .(점) 연산자 앞뒤

(3) 단항연사자와 연산값 사이

(4) 형변환을 위한 형과 변수

(5) 여는 소괄호 '(' 다음과 닫는 소괄호 ')' 앞

   단, ()안에서 함수가 들어갈 경우나 강조할 경우는 띄어써도 무방하다.

(6) 여는 대괄호 '[' 다음과 닫는 소괄호 ']' 앞

(7) 세미콜론 앞

 

  //CORRECT
  function TMyClass.MyFunc(var Value: Integer);
  MyPointer := @MyRecord;
  MyClass := TMyClass(MyPointer);
  MyInteger := MyIntegerArray[5];
  ShowMessage( IntToStr(MyInteger) );

 

  //INCORRECT
  function TMyClass.MyFunc( var Value: Integer ) ;
  MyPointer := @ MyRecord;
  MyClass := TMyClass ( MyPointer ) ;
  MyInteger := MyIntegerArray [ 5 ] ;

 

1.5 기타( 토큰 분리자, 연산자, begin-end )

대부분의 토큰 분리자나 연산자는 붙여쓰는 것을 원칙으로 한다.

단, 사칙연산( +, -, *, /, div, mod )와 부등호( >, <, = ) 그리고 대입연산자( := )는 띄어쓴다.

 

begin-end 는 같은 레벨에 맞춰 쓴다.

단, if-else 문과 사용되는 경우에는 예외를 둔다. (3.5장 (1)if문 참조)

  for I := 0 to 10 do begin // Incorrect, begin on same line as for
  for I := 0 to 10 do       // Correct, begin appears on a separate line
  begin

 

블럭문내의 마지막 명령줄의 생력가능한 세미콜론도 찍어주는 것을 원칙으로 한다.

begin
  MyStatement;
  MyNextStatement;
  MyLastStatement;   // semicolon optional
end;

 

2. 파일이름

파일이름에는 InfixCaps 혹은 Camel Caps 방식인 단어 첫 알파벳만 대문자를 쓰는 방식으로 한다.

단, 확장자는 소문자로 한다.

 

2.1 프로젝트 파일

프로젝트명은 될 수 있으면 프로젝트의 내용을 설명하도록 만들며,

정해진 프로젝트 코드명이 있을 경우에는 코드명을 사용한다.

 

2.2 폼 파일

폼 파일명은 기능별 혹은 구성별로 붙일 수 있는 기능성이름과 Form이라는 postfix를 사용한다.

( 실제로 폼의 .dfm 파일은 유닛 파일명을 저장할 때, 같은 이름으로 그대로 저장된다. )

유의사항: 폼 파일명은 디자인한 폼 클래스의 인스턴스명이 아니다.

폼의 인스턴스는 TForm 클래스명인 Form이라는 prefix를 붙인다. (3.8 인스턴스명 참조)

폼 설명

폼 파일명

About Form

AboutForm.dfm

Main Form

MainForm.dfm

 

2.3 유닛 파일

델파이 폼의 유닛 이름은 자동적으로 폼 파일과 같은 이름을 사용한다. (2.2 폼 파일이름 참조),

반면에 일반 유닛일 경우에는 Unit이라는 postfix를 사용한다.

단, C/C++의 헤더파일을 변환하는 경우에는 확장자를 제외한 파일명을 그대로 사용한다.

유닛 설명

유닛 파일명

About Form Unit

AboutForm.pas

Service Unit

ServiceUnit.pas

Windows.c

Windows.pas

 

2.4 데이터모듈 파일

데이터 모듈의 파일명에는 DM이라는 postfix를 사용한다.

DM 설명

DM 파일명

Client Data Module

ClientDM.dfm

Customer Data Module

CustomerDM.dfm

 

2.5 패키지 파일

패키지 파일명에는 구분할 수 있는 prefix에

디자인타임패키기와 런타임패키지를 구분할 수 있는 infix와

지원하는 델파이버전을 나타내기 위한 D4, D5, D6와 같은 postfix로 구성한다.

"iiilibvv.pkg" - design package

"iiistdvv.pkg" - runtime package

 

3. 오브젝트파스칼

3.1 예약어

모든 오브젝트파스칼 예약어는 소문자로 쓰도록 한다.

 

3.2 함수명

함수명은 동사(+목적어) 형태로 사용하며, 값을 가져오는 경우 Get, 값을 설정하는 경우 Set을 쓴다.

InfixCaps 방식을 사용한다.

  procedure ThisIsMuchMoreReadableRoutineName;

 

  procedure FormatHardDrive;

 

  procedure SetUserName;

 

  function GetUserName: string;

 

3.3 변수명

변수명은 명사 형태로 사용하며, InfixCaps 방식을 사용한다.

변수선언을 할 때는 같은 형끼리는 복수선언하며, 다른 형끼리는 단수선언만 한다.

델파이에서는 WIN32 형식인 헝가리언 표기법을 권장하지 않는다.

하지만, WIN32 API를 사용할 경우나, VisualStudio와 같은 다른 툴과의 연동을 위해서는 사용해도 무방하다.

  var
    nLoop, MyNumber: Integer; // Correct
    lpstrMyString: String; // Incorrect

 

클래스의 멤버 변수일 경우, F(Field) prefix를 주로 사용한다.

필요에 따라서 P(Pointer-포인터형변수), G(Global-전역변수), L(Local-지역변수), X(temp-임시변수), A(argument-함수파라미터)등의 prefix를 붙일 수 있다.

 

3.4 데이터타입

내부 테이터형은 소문자로 표기하며, WIN32 API 데이터형은 대문자로 표기한다.

  var
    MyString: string;  // reserved word
    WindowHandle: HWND; // Win32 API type
    I: Integer;         // type identifier introduced in System unit

 

열거형은 선언할 때는 T(Type) prefix를 붙이며, 열거형 내부 목록에는 열거형에 대한 구분자(혹은 약자)를 2-3글자 prefix로 붙인다. 

  TSongType = (stRock, stClassical, stCountry);

 

배열형의 경우에는 T prefix, Array postfix를 붙이며, 

또한 데이터의 포인터형은 P(Pointer) prefix를 덧붙인다.

  type
    PCycleArray = ^TCycleArray;
    TCycleArray = array[1..100] of Integer;

 

레코드의 경우에도 T prefix를 사용하며, 레코드 내부 변수에는 붙이지 않는다. 

  type
    PEmployee = ^TEmployee;
    TEmployee = record
      Name: string;
      Rate: Double;
    end;

 

3.5 구문

(1) if문

if문은 적어도 두 줄로 내려쓴다.

다만 수행문이 짧으면 한 줄로 써도 무방하다.

  // CORRECT
  if A < B then DoSomething; 
  
  // CORRECT
  if A < B then 
    DoSomething;

 

if-else문의 경우 소스의 논리 구조를 표현하는 수단이다.

각 논리 블록간의 관계가 명확하게 구분된다면, 자유로운 레벨간의 들여쓰기와 begin-end 표시가 허용된다.

그리고 특히 if문이 반복되서 길 게 사용될 경우 begin-end를 표시하여 범위를 명확하게 한다.

가능하면 if-else를 반복해서 사용하지 않도록 하며, 될 수 있으면 case문으로 구성한다.

  // INCORRECT
  if A < B then     
  if C < B then 
    DoSomething
  else if D < B then 
    DoSomething;
  // CORRECT
  if A < B then     
  begin 
    if C < B then 
      DoSomething;
  end
  else if D < B then 
    DoSomething;

 

if문안에 if문의 구조가 5단계이상 들어가지 않도록 코드를 간결화한다.

여러 조건들은 나열할 때는 왼쪽부터 빈도가 높고, 가능성이 높은 것을 선택한다.

  if Condition1 and Condition2 and Condition3 then

 

(2) case문

case문은 순서가 있는 데이터형에만 사용할 수 있다.

case-else문도 if-else와 같이 논리 블록간이 명확하게 구분되는 범위에서 들여쓰기가 허용된다.

 

if문과 마찬가지로 중요도와 빈도가 높은 것이 윗쪽에 있도록 한다.

각 case마다 4-5줄을 넘어가지 않도록 하며, 길어질 경우 따로 함수를 작성하도록 한다.

  // 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;
  
  // 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;  

  

(3) while문 (repeat문)

while문에서는 가능하면 루프중에 빠지지않고, loop조건으로만 종료되도록 구성한다.

 // INCORRECT
  while x < j  do begin
    DoSomething; 
    DoSomethingElse;
  end;
  // CORRECT
  while x < j do 
  begin
    DoSomething; 
    DoSomethingElse;
  end;
  
  // CORRECT
  repeat
    x := j;
    j := UpdateValue;
  until j > 25;
  

 

(4) for문

만약 1씩 증가가 아닌 경우라면, while문을 이용해서 마지막값부터 거꾸로 루프를 돌도록 한다.

  // INCORRECT
  for i := 0 to 10 do begin
    DoSomething; 
    DoSomethingElse;
  end;
  
  // CORRECT
  for i := 0 to 10 do 
  begin
    DoSomething; 
    DoSomethingElse;
  end;
  
  // CORRECT
  i := AList.Count-1;
  while i => 0 do
    i := i - 2;

 

(5) with문

with문을 사용할 경우에는 복수객체나 구조체를 참조하지 않도록 주의하며,

같은 이름의 다른 객체의 프로퍼티나 메소드를 참조하지 않는지 확인해야 한다.

  with Record1, Record2 do

 

3.6 에러처리구문

에러처리 (Exception Handling)는 에러 복구와 리소스 보호의 역할을 한다.

 

(1) try..finally

되도록 각 동적할당마다 try..finally 구문을 사용하여 예외사항에 대비한다.

다음의 예제는 동적할당된 클래스를 참조할 때, 예외가 발생할 수 있는 숨겨진 버그가 있다.

  SomeClass1 := TSomeClass.Create
  SomeClass2 := TSomeClass.Create;
  try
    { do some code }
  finally
    SomeClass1.Free;
    SomeClass2.Free;
  end;

 

다음의 예제는 숨겨진 버그를 없애는 올바른 방법이다.

  SomeClass1 := TSomeClass.Create
  try
    SomeClass2 := TSomeClass.Create;
    try
      { do some code }
    finally
      SomeClass2.Free;
    end;
  finally
    SomeClass1.Free;
  end;

 

(2) try..except

특정 예외 사항이 발생했을 때의 행동을 위해 사용한다.

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

 

(3) try..except..else

혹시 처리되지 않는 에러을 위해서는 else 구문을 사용한다.

 

3.7 클래스명

클래스의 Access Level은 Private, Protected, Public, Published 순으로 낮으며,

데이터는 될 수 있으면 Public 레벨을 사용하지 않고, Private 레벨을 사용하면서 Access Method를 활용한다.

클래스명은 T(Type) prefix를 붙이고 기능/목적상의 이름을 붙인다.

 

3.8 인스턴스명

클래스의 인스턴스명은 클래스명을 앞에 붙이고, 기능/목적상의 이름을 붙인다.

  예) FormMain, FormAbout, ButtonShowList , ButtonLoadImage

단, 유사한 기능의 클래스는 같은 클래스로 묶어도 무방하다

  예) TButton과 TSpeedButton의 예

강조를 위해서나, 뒤에 붙는 이름과 특별히 구분이 필요할 경우에는 '_' 를 넣어도 된다.

  예) FormMain, Form_About, Button_SaveToFile , Button_LoadFromFile

 

3.9 인터페이스

클래스와 같은 방식으로 선언하도록 한다.

 

자료정리 : 김정(고드름)

 

출처 : http://www.delmadang.com/community/bbs_view.asp?bbsNo=23&amp;bbsCat=50&amp;indx=399176

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts