본문 바로가기

프로그래밍(TA, AA)/델파이

[delphi] 일반적인 프로그래밍 작업

이 장에서는 Delphi의 다음과 같은 일반적인 프로그래밍 작업을 수행하는 방법에 대해 설명합니다.

 

  • 클래스 이해
  • 클래스 정의
  • 예외 처리
  • 인터페이스 사용
  • 사용자 지정 가변 정의 문자열 작업
  • 파일 작업
  • 측정 변환

 

클래스 이해


클래스는 속성, 메소드, 이벤트, 클래스에 대한 지역 변수와 같은 클래스 멤버에 대한 추상적인 정의입니다. 클래스의 인스턴스를 만들면 이 인스턴스를 객체라고 합니다. 객체라는 용어는 Delphi 설명서에서 가끔 부정확하게 사용되고 클래스와 클래스의 인스턴스 간의 구별이 중요하지 않은 곳에서 "객체"가 클래스를 가리키기도 합니다.

 

Delphi는 자체의 객체 계층에 많은 클래스를 포함하지만 객체 지향 프로그램을 작성하는 경우에는 추가의 클래스를 만들어야 합니다. 사용자가 작성하는 클래스는 TObject의 자손이거나 그 자손 중 하나여야 합니다. 클래스 타입 선언에는 클래스의 필드와 메소드 액세스를 제어하는 다음과 같은 세가지의 이용 가능한 섹션이 있습니다.

 

Type
	TClassName = Class(TObject)
		public
			{ public field }
			{ public methods }
		protected
			{ protected fields }
			{ protected methods }
		private
			{ private fields }
			{ private methods }
	end;
  • public 섹션은 액세스 제한이 없는 필드와 메소드를 선언하고, 클래스 인스턴스와 자손 클래스는 이러한 필드와 메소드에 액세스할 수 있습니다.
  • protected 섹션은 일부 액세스 제한이 있는 필드와 메소드를 포함하고, 자손 클래스는 이러한 필드와 메소드에 액세스할 수 있습니다.
  • private 섹션은 액세스가 엄격하게 제한된 필드와 메소드를 선언하고, 클래스 인스턴스와 자손 클래스는 이러한 필드와 메소드에 액세스할 수 없습니다.

클래스를 사용하면 새 클래스를 기존 클래스의 자손으로 생성할 수 있다는 이점이 있습니다. 각 자손 클래스는 그 부모 및 조상 클래스의 필드와 메소드를 상속합니다. 또한 상속된 클래스를 오버라이드하는 새 클래스에서 메소드를 선언하여 좀 더 특별한 새로운 동작을 도입할 수 있습니다.

 

자손 클래스의 일반 구문은 다음과 같습니다.

 

Type
	TClassName = Class {TParentClass}
		public
			{public fields}
			{public methods}
		protected
			{protected fields}
			{protected methods}
		private
			{private fields}
			{private methods}
	end;

부모 클래스 이름이 지정되지 않은 경우 클래스는 TObject로부터 직접 상속합니다. TObject는 기본 생성자와 소멸자를 포함한 몇 가지 메소드만 정의합니다.

 

클래스의 구문, 랭귀지 정의, 규칙에 대한 자세한 내용은 오브젝트 파스칼 랭귀지 안내서 온라인 도움말의 Class types를 참조하면 됩니다.

 

 

클래스 정의


Delphi에서는 클래스를 선언하여 애플리케이션에서 사용해야 하는 프로그래밍 기능을 구현할 수 있습니다. Delphi의 일부 버전에는 클래스 완성(class completion)이라는 기능이 있는데 이 기능은 사용자가 선언하는 클래스 멤버에 대한 뼈대 코드를 생성하여 새 클래스를 정의하고 구현하는 작업을 간단하게 합니다.

 

다음과 같이 클래스를 정의합니다.

 

  1. IDE에서 프로젝트를 열고 File|New|Unit을 선택하여 새 클래스를 정의할 수 있는 새 유닛을 만듭니다.
  2. interface 섹션에 uses 절과 type 섹션을 추가합니다.
  3. type 섹션에 클래스 선언을 작성합니다. 모든 멤버 변수, 속성, 메소드 및 이벤트를 선언해야 합니다.

 

TMyClass = class; { This implicitly descends from TObject }
public
	.
	.
	.
private
	.
	.
	.
published { If descended from TPersistnet or below }
	.
	.
	.

사용자 정의 가변 데이터를 갖는 객체는 RTTI로 컴파일해야 합니다. 이는 이 객체를 {$M+} 컴파일러 지시어 또는 TPersistnet나 그 아래의 자손을 사용하여 컴파일해야 함을 의미합니다.

 

특정 클래스의 자손 클래스를 원하는 경우에는 다음과 같이 정의에서 그 클래스를 나타내야 합니다.

 

TMyClass = class{ TParentClass }; { This descends from TParentClass }

type TMyButton = class(TButton)
	property Size:Integer;
	procedure DoSomethig;
end;

Delphi 버전에서 클래스 완성을 포함하는 경우, interface 섹션에 있는 메소드 저으이 안에 커서를 두고 Ctrl+Shift+C를 누르거나 마우스 오른쪽 버튼을 클릭하여 Complete Class at Cursor를 선택합니다. Delphi는 모든 완료되지 않은 속성 선언을 완성하고 implementation 섹션에서 필요한 빈 메소드를 생성합니다. 클래스 완성이 없으면 사용자가 직접 코드를 작성하여 속성 선언을 완성하고 메소드를 작성합니다.

 

위와 같은 예에서 클래스 완성이 있으며 Delpphi는 인터페이스 선언에 read 지정자와 write 지정자를 추가하여 모든 지원 필드나 메소드를 포함시킵니다.

 

type TMyButton = class(TButton)
	property Size:Integer read FSize write SetSize;
	procedure DoSomething;
private
	FSize:Integer;
	procedure SetSize(const Value:Integer);

또한 유닛의 implementation 섹션에 다음 코드를 추가합니다.

 

{ TMyButton }
procedure TMyButton.DoSomething;
begin
end;
procedure TMyButton.SetSize(const Value:Integer);
begin
	FSize := Value;
end;

 

메소드를 채웁니다. 예를 들면, 버튼에서 DoSomething 메소드를 호출할 때 경고음이 울리게 하려면 begin과 end 사이에 Beep를 추가합니다.

 

{ TMyButton }
procedure TMyButton.DoSomething;
begin
	Beep;
end

procedure TMyButton.SetSeize(const Value:Integer);
begin
	if fsize <> value then
	begin
		FSize := Value;
		DoSomething;
	end;
end;

 

버튼의 크기를 변경하기 위해 SetSize를 호출할 때도 경고음이 울린다는 것에 유의하십시오.

 

클래스와 메소드의 구문, 랭귀지 정의, 규칙에 대한 자세한 내용은 오브젝트 파스칼 랭귀지 안내서 온라인 도움말의 Class types와 methods를 참조하십시오.

 

 

예외 처리 


Delphi는 일관된 방식으로 오류를 처리하는 메커니즘을 제공합니다. 예외 처리를 통해서 애플리케이션은 데이터나 리소스를 잃지 않고 복구 가능한 오류를 복구하고 필요한 경우 종료합니다. Delphi의 오류 조건은 예외에 의해 나타납니다. 이 단원에서는 예외를 사용하여 안전한 애플리케이션을 만들 수 있는 다음과 같은 작업들을 설명합니다.

  • 코드 블록 보호
  • 리소스 할당 보호
  • RTL(Run-Time Library) 예외 처리
  • 컴포넌트 예외 처리
  • 외부 소스를 사용한 예외 처리
  • 예외 숨기기(Silent exceptions)
  • 사용자 고유의 예외 정의


코드 블록 보호


안정적인 애플리케이션을 만들려면 예외가 발생할 때 코드에서 예외를 인식하고 이에 대해 응답해야 합니다. 응답을 지정하지 않으면 애플리케이션은 오류를 설명하는 메시지 상자를 보여줍니다. 이 때 오류가 발생할 수 있는 곳을 알아내고 오류로 인해 데이터나 시스템 리소스의 손실을 가져올 수 있는 곳에 대해 반드시 응답을 정의해야 합니다.


예외에 대한 응답을 만들 때는 코드의 블록에서도 응답을 만듭니다. 일련의 문장들이 모두 오류에 대한 동일한 종류의 응답이 필요한 경우에는 그 문장들을 블록으로 그룹화한 다음 전체 블록에 적용되는 오류 응답을 정의할 수 있습니다.


예외에 대해 특정한 응답을 가진 블록을 protected 블록이라고 하는데 그 이유는 이 블록이 애플리케이션을 종료시키거나 데이터를 손상시키는 오류를 막을 수 있기 때문입니다.


코드의 블록을 보호하려면 다음을 이해해야 합니다.

  • 예외에 대한 응답
  • 예외와 제어 흐름
  • 예외 응답 중첩


예외에 대한 응답

오류 조건이 발생하면 애플리케이션은 예외를 발생시키는데 이것은 애플리케이션이 예외 객체를 만든다는 것을 의미합니다. 예외가 일단 발생하면 애플리케이션은 클린업 코드를 실행하거나 예외를 처리하거나 아니면 둘 다 수행합니다.


클린업 코드 실행

예외에 응답하는 가장 간단한 방법은 일부 클린업 코드가 실행되는 것을 보장하는 것입니다. 이러한 종류의 응답은 오류를 일으키는 조건을 고쳐주니느 않지만 애플리케이션이 불안정한 상태의 환경에 머무르지 않도록 해줍니다. 보통 이러한 종류의 응답을 사용하여 오류 발생 여부와 상관없이 애플리케이션이 할당된 리소스를 확실히 해제하도록 합니다.


예외 처리

이것은 특정한 예외에 대한 특정한 응답입니다. 예외를 처리하면 오류 조건을 없애고 예외 객체를 소멸시키며 이를 통해 애플리케이션을 계속 실행할 수 있습니다. 보통 애플리케이션이 오류를 복구하고 계속 실행할 수 있도록 하기 위해 예외 핸들러를 정의합니다. 처리해야 할 예외의 종류에는 존재하지 않는 파일 열기 시도, 용량이 꽉 찬 디스크에 쓰기, 허용 한도를 초과하는 계산 등이 있습니다. 이러한 예외 중에서 "File not found"와 같은 예외는 고치고 재시도하기가 쉽지만 메모리 부족과 같은 예외는 애플리케이션이나 사용자가 고치기가 더 어렵습니다.


예외를 효과적으로 처리하려면 다음을 이해해야 합니다.

  • 예외 핸들러 작성
  • 예외 처리 문장
  • 예외 인스턴스 사용
  • 예외 핸들러의 범위
  • 기본 예외 핸들러 제공
  • 예외 클래스 다루기
  • 예외 재발생


예외와 제어 흐름

예외는 코드의 정상적인 흐름을 방해하지 않으므로 오브젝트 파스칼을 사용하여 애플리케이션에 오류 처리 기능을 통합하기가 쉽습니다. 사실, 알고리즘의 주요 과정에 오류확인과 오류 처리를 두지 않으면 예외는 사용자가 작성하는 코드를 단순화해 줄 것입니다.


보호 블록을 선언할 때 블록 안에서 발생할 수 있는 예외에 대한 특정 응답을 정의하게 됩니다. 그 블록에서 예외가 발생하면 즉시 사용자가 정의한 응답으로 건너서 실행된 다음 그 블록을 벗어납니다.


다음 코드는 보호 블록을 포함하고 있습니다. 예외가 protected 블록에서 발생하면 예외 처리 부분으로 건너뛰어 실행되면서 경고음이 울립니다. 블록 밖에서 실행이 재개됩니다.


try
  AssignFile(F, FileName);
  Reset(F);
  .
  .
  .
except
  on Exception do Beep;
end;
  { execution resumes here, outside the protected block }


예외 응답 중첩

사용자 코드는 블록 내에서 발생하는 예외에 대한 응답을 정의합니다. 파스칼에서는 다른 블록 내에 코드의 블록을 중첩할 수 있기 때문에 사용자 지정된 응답을 이미 포함하고 있는 블록 내에서도 응답을 사용자 지정할 수 있습니다.


가장 간단한 경우를 예로 들면, 리소스 할당을 보호할 수 있고 그 보호된 블록 내에 다른 리소스를 할당하고 보호하는 블록을 정의할 수 있습니다. 개념적으로 보면 다음과 같습니다.



또한 주변 블록 안에서의 예외 처리를 오버라이드하는 특정 예외에 대한 지역 처리를 정의하기 위해서 중첩 블록을 사용할 수 있습니다. 개념적으로 보면 다음과 같습니다.



또한 예외 처리 블록 내에 리소스 보호를 중첩시키면서 다른 종류의 예외 응답 블록을 혼합할 수 있으며 그 반대로도 할 수 있습니다.



리소스 할당 보호


강력한 애플리케이션을 만드는 한 가지 중요한 요소는 예외가 발생하더라도 할당한 리소스를 확실히 해제하도록 하는 것입니다. 예를 들어, 애플리케이션이 메모리를 할당할 경우 반드시 메모리도 해제하도록 해야 합니다. 애플리케이션이 파일을 열 경우 나중에 파일도 반드시 닫도록 해야 합니다.


예외는 코드에서만 발생하는 것이 아니라는 점을 명심하십시오. 예를 들면, RTL 루틴 호출이나 애플리케이션의 다른 컴포넌트가 예외를 발생시킬 수 있습니다. 개발자가 작성한 코드는 이러한 조건이 발생했을 경우 할당된 리소스를 확실히 해제하도록 해야 합니다.


리소스를 효과적으로 보호하기 위해서는 다음 사항을 이해해야 합니다.

  • 보호가 필요한 리소스 종류
  • 리소스 보호 블록 만들기

 

보호가 필요한 리소스 종류

일반적인 환경에서는 애플리케이션이 할당과 해제에 대한 코드를 포함하여 할당된 리소스를 해제하도록 할 수 있습니다. 그러나 예외가 발생할 때에도 애플리케이션이 리소스 해제 코드를 실행하게 해야 합니다.


항상 해제를 염두에 두어야 하는 몇 가지 일반적인 리소스는 다음과 같습니다.

  • 파일
  • 메모리
  • Windows 리소스(VCL 전용)
  • 객체


다음 이벤트 핸들러는 메모리를 할당한 다음 오류를 생성하므로 메모리를 해제하는 코드를 절대 실행하지 않습니다.


procedure TForm1.Button1Click(Sender:TComponent);
var
  APointer:Pointer;
  AnInteger, ADividend:Integer;
begin
  ADividend := 0;
  GetMem(APoint, 1024);{ allocate 1K of memory }
  AnInteger := 10 div ADividend;{ this generates an error }
  FreeMem(APointer, 1024);{ it never gets here }
end;


대개의 오류가 이렇게 명백한 것은 아니지만 위의 예제는 중요한 점을 보여줍니다. 0으로 나누는 오류가 발생하면 블록 밖으로 건너뛰어 실행되므로 FreeMem 문장이 절대로 메모리를 해제하지 못합니다.


FreeMem이 GetMem에 의해 할당된 메모리를 확실히 해제하도록 하려면 코드를 리소스 보호 블록에 넣어야 합니다.



리소스 보호 블록 만들기

예외인 경우에도 할당된 리소스를 확실히 해제하려면 보호된 블록 안에 리소스 사용 코드를 포함시키고 이 블록의 특별한 부분에 리소스 해제 코드를 추가해야 합니다. 전형적인 보호된 리소스 할당 형태는 다음과 같습니다.

{ allocate the resource }
try
  { statements that use the resource }
finally
  { free the resource }
end;

try..finally 블록의 주요 특징은 protected 블록에서 예외가 발생하더라도 애플리케이션이 블록의 finally 부분에 있는 모든 문장을 항상 실행한다는 것입니다. 블록의 try 부분의 코드 또는 try 부분의 코드에 의해 호출된 루틴이 예외를 발생시키면 그 시점에서 실행이 중지됩니다. 예외 핸들러가 일단 발견되면 클린업 코드라는 finally 부분으로 건너뛰어 실행됩니다. finally 부분이 실행되고 나면 예외 핸들러가 호출됩니다. 예외가 발생하지 않으면 클린업 코드가 정상적인 순서로 try 부분의 모든 문장 뒤에서 실행됩니다.


다음 코드에서는 메모리를 할당하고 오류를 생성하면서 할당된 메모리를 해제하는 이벤트 핸들러의 예를 보여줍니다.


procedure TForm1.Button1Click(Sender:TComponent);
var
  APointer:Pointer;
  AnInteger, ADividend:Integer;
begin
  ADividend := 0;
  GetMem(APointer, 1024);{ allocate 1K of memory }
  try
    AnInteger := 10 div ADividend;{ this generates an error }
  finally
    FreeMem(APointer, 1024);{ execution resumes here, despite the error }
  end;
end;

finally 블록의 문장은 예외 발생에 영향을 받지 않습니다. try 부분의 문장에서 예외가 발생하지 않으면 finally 블록을 거쳐 계속 실행됩니다.



RTL(Run-Time Library) 예외 처리


수학 함수나 파일 처리 프로시저와 같은 런타임 라이브러리(RTL)의 루틴을 호출하는 코드를 작성할 경우, RTL은 예외의 형태로 애플리케이션에 오류를 보고합니다. 기본적으로 RTL 예외는 애플리케이션이 사용자에게 보여 주는 메시지를 생성합니다. RTL 예외를 다른 방법으로 처리하는 자신만의 예외 핸들러를 정의할 수 있습니다.


기본적으로 메시지를 보여 주지 않는 예외 숨기기(silent exceptions)도 있습니다.


RTL 예외는 다른 모든 예외처럼 처리됩니다. RTL 예외를 효과적으로 처리하려면 다음 사항을 이해해야 합니다.

  • RTL 예외
  • 예외 핸들러 작성
  • 예외 처리 문장
  • 예외 인스턴스 사용
  • 예외 핸들러의 범위
  • 기본 예외 핸들러 제공
  • 예외 클래스 다루기
  • 예외 재발생


RTL 예외

런타임 라이브러리의 예외는 SysUtils 유닛에서 정의되며 이 예외는 모두 Exception이라는 일반적인 예외 객체 타입의 자손입니다. Exception은 RTL 예외가 기본적으로 보여 주는 메시지에 대한 문자열을 제공합니다.


다음 표에서 설명한 대로 여러 종류의 예외가 RTL에 의해 발생합니다.


 오류 타입

 원인

 의미

 I/O

 파일 또는 I/O 장치 액세스 오류

 대부분의 I/O 예외는 파일에 액세스할 때 반환된 오류 코드와 관련이 있습니다.

 힙

 동적 메모리 사용 오류

 사용 가능한 메모리가 불충분하거나 애플리케이션이 힙 외부를 가리키는 포인터를 처리할 때 힙 오류가 발생할 수 있습니다.

 정수 함수

 정수 타입 표현식의 부적합한 연산

 오류에는 0으로 나누기, 범위 밖의 숫자나 표현식, 오버플로 등이 있습니다.

 부동 소수점 수학

 실수 타입 표현식의 부적합한 연산

 부동 소수점 오류는 하드웨어 보조프로세서 또는 소프트웨어 에뮬레이터가 원인입니다. 오류에는 잘못된 명령, 0으로 나누기, 오버플로 또는 언더플로 등이 있습니다.

 타입 변환
 (Typecast)

 as 연산자를 사용하는 잘못된 타입 변환

 객체는 호환 가능한 타입으로만 타입 변환할 수 있습니다.

 변환

 잘못된 타입변환

 IntToStr, StrToInt, StrToFloat 등과 같은 타입 변환 함수는 매개변수를 원하는 타입으로 변환할 수 없을 때 변환 예외를 발생시킵니다.

 하드웨어

 시스템 상태

 하드웨어 예외는 프로세서 또는 사용자가 액세스 위반, 스택 오버플로 또는 키보드 인터럽트 등과 같은 어떤 오류 조건이나 인터럽트를 생성했음을 나타냅니다.

 가변

 부적합한 타입 강제 변환

 가변(variant)을 호환 가능한 타입으로 강제 변환할 수 없는 표현식에서 가변을 차조하면 오류가 발생합니다.


RTL 예외 타입 목록은 SysUtils 유닛의 코드를 참조하십시오.


예외 핸들러 작성

예외 핸들러는 특정 예외 또는 코드의 protected 블록 안에서 발생하는 예외를 처리하는 코드입니다. 크로스 플랫폼 프로그래밍에서는 예외 핸들러를 작성해야 하는 경우가 거의 드뭅니다. 대부분의 예외는 4-4 페이지의 "코드 블록 보호"와 4-7 페이지의 "리소스 할당 보호"에서 설명한 대로 try...finally 블록을 사용하여 처리할 수 있습니다.


예외 핸들러를 정의하려면 보호하려는 코드를 예외 처리 블록안에 포함시키고 블록의 except 부분에 예외 처리 문장을 지정합니다. 

try
  { statements you want to protect }
except
  { exception-handling statements }
end;


애플리케이션은 예외가 try 부분의 문장이 실행되는 동안에 발생하는 경우에만 except 부분의 문장을 실행합니다. try 부분 문장의 실행에는 try 부분의 코드에 의해 호출되는 루틴이 포함됩니다. 즉, try 부분의 코드가 자체 예외 핸들러를 정의하지 않는 루틴을 호출하면 예외 처리 블록으로 돌아와서 실행됩니다.


try 부분의 문장이 예외를 발생시키면 즉시 except 부분으로 건너뛰어 실행되고 여기서 현재 예외에 적용되는 핸들러를 찾을 때까지 특정 예외 처리 문장 또는 예외 핸들러를 통한 단계를 거칩니다.


일단 애플리케이션이 예외를 처리하는 예외 핸들러를 찾게 되면 그 문장을 실행한 후 예외 객체를 자동적으로 소멸시킵니다. 그러면 현재 블록의 끝에서 계속 실행됩니다.



예외 처리 문장

try..except 블록에서 except 부분의 각 on 문장들은 특별한 유형의 예외 처리 코드를 정의합니다. 이러한 예외 처리 문장의 형태는 다음과 같습니다.


on <type of exception> do <statement>;


0으로 나누기에 대한 기본 결과를 제공하는 예외 핸들러를 다음과 같이 정의할 수 있습니다.


function GetAverage(Sum, NumberOfItems:Integer):Integer;
begin
  try
    Result := Sum div NumberOfItems;{ handle the normal case }
  except
    on EDivByZero do Result := 0;{ handle the exception only if needed }
  end;
end;


함수를 호출할 때마다 0에 대한 검사를 하는 것보다는 위와 같이 하는 것이 더 명확합니다. 다음은 예외를 사용하지 않는 동일한 함수입니다.


function GetAverage(Sum, NumberOfItems:Integer):Integer;
begin
  if NumberOfItems <> 0 then{ always test }
    Result := Sum div NumberOfItems{ use normal calculation }
  else Result := 0;{ handle exceptional case }
end;


위의 두 가지 함수의 차이는 예외를 가진 프로그래밍과 갖지 않은 프로그래밍 간의 차이를 정읳바니다. 이러한 예는 매우 간단하지만 수십 개의 입력한 내용 중 하나가 잘못되면 수백 개의 단계 중의 하나가 실패할 수 있는 경우와 같은 더 복잡한 계산을 생각해 볼 수 있습니다.


예외를 사용하면 알고리즘의 "정상적인" 표현식을 모두 작성한 다음 이 알고리즘이 적용되지 않는 예외적인 경우를 만들 수 있습니다. 예외를 사용하지 않으면 프로그램의 매단계를 검사하여 계산의 각 단계를 진행할 수 있는지 확인해야 합니다.



예외 인스턴스 사용

대부분의 경우 예외 핸들러는 타입 이외의 예외에 대한 정보를 필요로 하지 않으므로 다음과 같은 on..do 문장은 예외의 타입에만 한정됩니다. 그러나 어떤 경우에는 예외 인스턴스에 포함된 정보가 다소 필요할 수도 있습니다.


예외 핸들러에서 예외 인스턴스에 대한 특정 정보를 읽으려면 예외 인스턴스에 액세스할 수 있게 해주는 on..do의 특별한 변형을 사용합니다. 이 특별한 폼에는 인슽턴스를 유지하기 위한 임시 변수를 제공해야 합니다.


단일 폼을 포함하는 새 프로젝트를 만들 경우, 스크롤 막대와 명령 버튼을 폼에 추가할 수 있습니다. 버튼을 더블 클릭하고 클릭 이벤트 핸들러에 다음 줄을 추가합니다.


ScrollBar1.Max := ScrollBar1.Min - 1;

스크롤 막대의 최댓값이 최솟값을 항상 초과해야 하기 때문에 이 줄은 예외를 발생시킵니다. 애플리케이션에 대한 기본 예외 핸들러는 예외 객체에 메시지를 포함하는 대화상자를 엽니다. 이 핸들러에서는 예외 처리 오버라이드할 수 있으며 예외 메시지 문자열을 포함하는 자신의 메시지 상자를 만들 수 있습니다.


try
  ScrollBar1.Max := ScrollBar1.Min - 1;
except
  on E:EInvalidOpration do
    MessageDlg('Ignoring exception:' + E.Message, mtInformation, [mbOK], 0);
end;

임시 변수(이 예에서 E)는 콜론 뒤에 지정된 타입입니다(이 예에서 EInvalidOperation). 필요한 경우에 예외를 더 특정한 타입으로 타입 변환하기 위해 as 연산자를 사용할 수 있습니다.


임시 예외 객체를 절대 소멸시키지 마십시오. 예외 처리는 자동으로 예외 객체를 소멸시킵니다. 사용자가 직접 객체를 소멸시키면 애플리케이션이 객체를 다시 소멸하여 액세스 위반을 일으킵니다.