C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[104] [강좌] C++Builder 메시지 핸들링 (메시지맵 사용)
박지훈.임프 [cbuilder] 17627 읽음    2001-07-26 14:16
아래 글은 제가 98년 10월 18일에 천리안 프로그래머포럼에 올렸던 내용입니다.

-----------------------------------------------------------
안녕하세요. 천리안 프로그래머 포럼 C++Builder 담당자 임펠리테리입니다.

그동안 많은 분들이 관심을 갖고 계시는 C++Builder 의 메시지 핸들링에 대하여 강좌를 하려고 생각을 해왔습니다만, 바쁜 일정 탓에 준비를 못해왔던 차에, C++Builder Developer's Journal에 실렸던 Kent Reisdorph의 강좌를 우연히 발견하고, 이것을 번역하여 강좌로 올릴 생각을 하게 되었습니다. 평소 영어공부에 등한히 하여 여기저기 조금씩 어색하거나 앞뒤가 맞지 않는 점이 발견될 지도 모르겠습니다만, 성의를 어여삐(?!) 여기셔서 좋게 보아주시기 바랍니다.

이 강좌에서는 일반적인 방법으로서 메시지맵을 작성하여 메시지를 처리하는 방법이 언급되었구요, 다른 방법들에 대해서는 이번 번역 강좌를 마친 후에 짬짬이 시간을 내어 작성하여 올리도록 하겠습니다.

Kent Reisdorph의 원문(http://www.zdjournals.com/cpb/9706/cpb9761.htm)은 상당히 간결하고 잘 정돈되어 있었습니다만 저의 번역 미숙으로 많은 부분이 오역 혹은 잘못 전달될 수 있습니다. 혹 의문나는 사항에 대해서는 주저없이 메일로 질문을 해주시면 되구요, 아래 글에서 설명이 모자라는 부분에 대해서도 최대한 답변을 해드리도록 하겠습니다. 그럼, 엉터리 번역 나갑니다.


=============================================================================
                      Incorporate custom message-handling in your applications
                      --------------------------------------------------------

                                                             by Kent Reisdorph

운영체제 레벨에서는, 윈도우즈는 항상 메시지와 관련된다. 윈도우즈에서 일어나는 많은 일들은 윈도우즈가 메시지들을 처리하기 때문에 생기는 것이다. VCL은 가장 많이 사용되는 윈도우즈 메시지들에 대해 이벤트를 제공하며, 이 이벤트들을 통해 사용자들은 대단히 많은 메시지들을 쉽게 다룰 수 있다. OnKeyDown 이벤트는 WM_KEYDOWN 메시지에 반응하는 메카니즘을 제공하며, OnMouseDown이벤트는 WM_LBUTTONDOWN과 WM_RBUTTONDOWN 메시지에 반응할 수 있게 해주며 그외에도 수없이 많은 예를 들 수 있다. 이처럼 사용자의 C++Builder 프로그램들은 이벤트들을 통해 대부분의 윈도우즈 메시지들을 핸들하게 된다.

그러나, 메시지는 너무나도 많아서, VCL은 모든 윈도우즈 메시지들을 위한 이벤트를 제공하지 못한다. 만약 사용자가 VCL에 포함되지 않은 윈도우즈 메시지를 다루자 한다면, 또 사용자가 사용자정의 메시지를 구현하려고 한다면, 혹은 윈도우즈 메시지에 대한 별도의 처리가 필요하다면, 사용자는 팔뚝을 걷어붙이고 약간의 작업을 더 해야 한다. 이 강좌에서는, VCL 이벤트 메카니즘의 바깥에서 작업할 필요가 있을 때 사용자가 사용자의 어플리케이션에서 어떻게 메시지를 다룰것인가 하는 것을 설명하려고 한다.

메시지와 메시지 크래킹

윈도우즈의 메시지 시스템이 어떻게 작동하는지 간단히 살펴보자. 가장 먼저, 대부분의 독자가 아마도 알고 있겠지만, 윈도우즈는 메시지에 의해 운영된다. 많은 다양한 이유로, 일반적으론 프로그램(실제로는, 특정 윈도우)에 어떤 작업을 지시하기 위해 윈도우즈는 한 윈도우에 메시지를 보낸다. 예를 들면, 윈도우즈는 특정 윈도우에 WM_PAINT 메시지를 보냄으로서 스스로 다시 그리도록 지시할 수 있다. 이것은 윈도우즈가 어플리케이션에게 특정 작업을 수행할 것을 기대하는 것이므로 사용자는 이것을 명령 메시지로 생각할 수 있다.

또한 윈도우즈는 어플리케이션에 특정 사건이 발생했음을 알리기 위해 메시지를 보내기도 한다. 어플리케이션이 알아야 할 어떤 사건(WM_SIZE 나 WM_MOVE)이 어떤 윈도우 내에서 발생했을 경우나, 윈도우즈 자체 내에서 어떤 일(예를 들면 WM_SYSCOLORCHANGE 나 WM_WININICHANGE 등)이 생겼을 경우 등이다.

컨트롤들이 윈도우이기 때문에, 어떤 사건이 컨트롤 내에서 발생했을 때 윈도우즈는 통지(notification) 메시지를 보낸다. 예로서 에디트 컨트롤 내에서의 텍스트의 변경했을 경우(EN_UPDATE)이나 사용자가 리스트박스의 아이템을 선택했을 경우(LBN_SELCHANGE) 등을 들 수 있다. 이러한 메시지에 응하는 거나 응하지 않는 것은 애플리케이션 자체에 달려있다.

메시지 파라미터

윈도우즈 메시지는 그 메시지에 관한 특정 정보를 포함하고 있는 두개의 파라미터를 갖고 있다(WPARAM 과 LPARAM). WPARAM (word parameter)은 16비트 윈도우즈에서는 16비트 값을 가지고 있었으나 32비트 윈도우즈로 오면서 32비트로 확장되었다. LPARAM (long parameter)은 16비트와 32비트 윈도우즈 양쪽다에서 32비트 값을 가진다.

윈도우즈는 보내어진 각 메시지에 대한 정보를 전달하기 위해 이 두개의 파라미터를 처리한다. 예를 들어 WM_SIZE 메시지는 다음과 같은 세 부분의 정보를 포함한다. 발생한 사이징의 종류(미니마이즈, 맥시마이즈, 리스토어), 윈도우의 새 width, 윈도우의 새 height. 이 경우, WPARAM은 사이징의 타입을 포함하며, LPARAM은 새로운 width와 height 정보를 포함한다. LPARAM의 low word에는 width가, high word에는 height가 저장된다.

대부분의 윈도우즈 메시지는 이와같은 방식으로 정보를 저장한다. 메시지 파라미터를 분석하여 윈도우즈가 보낸 정보를 얻어내는 것은 어플리케이션의 책임이다. 메시지 파라미터에 아주 많은 정보가 포함되는 경우도 있다. (윈도우즈는 때때로 LPARAM 파라미터의 일부로서 구조체의 포인터를 보낸다.)

VCL shield

VCL과 같은 프레임워크의 작업중 일부는 메시지를 처리하는 번잡한 일에서 프로그래머를 보호(shield)해 주는 것이다. 예를 들어, WM_KEYDOWN 메시지를 처리하는 OnKeyDown 이벤트는 프로그래머를 위해 메시지 파라미터를 분석해준다. C++Builder가 OnKeyDown 이벤트에 대해 생성하는 메시지 핸들러는 다음과 같다.
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
    ...
}

위에서 보다시피 프로그래머는 WPARAM and LPARAM 그대로가 아니라 이미 해석된 상태로 얻게 된다. 이 경우, WPARAM은 Key라고 이름이 붙여진 형식이며, 프로그래머에게 어떤 키가 눌려졌는지를 알려주게 된다. LPARAM(WM_KEYDOWN 메시지에서는 아주 복잡한 형태이다)은 TShiftState 객체의 형식이며, [Shift], [Alt], [Ctrl] 키중 메시지를 발생시킨 키가 눌려졌을때 눌려져 있던 키들의 조합이다. 윈도우즈 프로그래밍에서, VCL이 해주는 메시지 분석은 메시지 처리 작업을 대단히 단순화시켜준다.

VCL 메시지 구조체

WPARAM 과 LPARAM 값을 분석하는 것은 골치아픈 일이기 쉽다. 다행히도 VCL은 메시지를 분석하기 위해 프로그래머가 해야할 대부분의 작업을 도와주는 구조체를 제공한다. (메시지 구조체들을 직접 살펴보고 싶다면 MESSAGES.HPP을 참고하라.) 프로그래머는 어플리케이션에서 메시지 처리 함수를 작성할 때 이들 구조체를 사용할 수 있다. (방법은 뒤에서 설명한다.)

모든 메시지를 처리할 수 있는 일반적인 메시지 구조체는 다음과 비슷한 형태이다.
struct TMessage
{
    unsigned int Msg;
    long WParam;
    long LParam;
    long Result;
};

('비슷한' 형태라고 말했다.. 실제의 TMessage 구조체는 구조체를 더욱 복잡하게 만드는 union이 포함되어 있어서 구조체를 약간 단순화했다.)

이 경우 WPARAM 과 LPARAM는 그대로 전달되며, 메시지 파라미터는 분석되지 않은 그대로이다. 이 메시지 구조체를 사용한다면, WPARAM 과 LPARAM 멤버로부터 각각의 메시지 값을 추출해 내는 것은 프로그래머에게 달려있다. 이 메시지 구조체는 사용자 정의 메시지나 아무 값도 전달하지 않는 메시지에 사용될 수 있다. 그러나, 대부분의 경우 처리할 메시지에 적당한 메시지 구조체를 사용하게 된다.

모든 메시지 구조체는 공통적으로 Msg 와 Result 두개의 멤버를 가진다. Msg 멤버는 메시지 번호를 가지고 있다. 예를 들어 WM_ERASEBKGND 메시지는 20이란 값을 가진다. 그러므로 WM_ERASEBKGND 메시지를 받으면, TMessage 구조체의 Msg 멤버의 값은 20이 될 것이다. 대부분의 경우 메시지 처리 함수내에서 Msg 멤버를 따질 필요는 없을 것이다.

Result 멤버를 어떻게 사용할 것인가는 보내어진 메시지의 종류에 따라 다르다. 예를 들어 어플리케이션에서 WM_ERASEBKGND 메시지를 처리한다면 이 메시지에 대한 메시지 핸들러는 true를 리턴해야 하며 이 메시지를 처리하지 않았다면 false를 리턴해야 한다. C++Builder 어플리케이션에서는 WM_ERASEBKGND 메시지의 핸들러의 마지막에서 Result 멤버의 값을 세팅함으로서 이러한 처리를 할 수 있다. 어떤 메시지의 경우, 프로그래머는 Result 값을 전혀 수정하지 않는다. 다른 몇몇 경우에서는 Result는 숫자값이 될 수도 있다. 다시 말해서 Result값을 어떻게 처리할 것인가 하는 것은 처리중인 메시지에 달려있다.

Msg 와 Result 멤버외에도 각 메시지 구조체는 많은 멤버를 가지고 있다. 예를 들면 WM_ERASEBKGND 메시지의 메시지 구조체인 TWMEraseBkgnd는 다음과 같다.
struct TWMEraseBkgnd
{
    unsigned int Msg;
    HDC DC;
    long Unused;
    long Result;
};

이 코드는 디바이스 컨텍스트(DC)의 핸들로서 DC 멤버(WPARAM)를 정의하며, LPARAM은 사용되지 않는다. 이 경우 해석할 것이 별로 없다.

이제, WM_SIZE 메시지의 메시지 구조체를 살펴보자.
struct TWMSize
{
    unsigned int Msg;
    long SizeType;
    unsigned short Width;
    unsigned short Height;
    long Result;
};

여기서 WPARAM은 size type (SizeType)이며, LPARAM은 Width 와 Height로 나누어진다. 다음에 어떻게 프로그래머가 C++Builder 어플리케이션에서 메시지 구조체를 사용할 수 있는지 보여주도록 하겠다.

VCL 이벤트 처리

이벤트 핸들링은 C++Builder 프로그래밍의 기본적인 부분이므로 VCL 이벤트를 다루는 데 대하여 그리 깊이 들어가지는 않겠다.(시간이 지나면 차차 익숙해질 것이다) 대신에 좀더 높은 부분을 다루어보자.

이전에 말했듯이, VCL은 자주 사용되는 윈도우즈 메시지에 대해 많은 이벤트를 제공한다. 이러한 VCL의 특징은 이벤트에 이벤트 핸들링 함수를 달 수 있게 해준다. 이벤트가 발생할 때, 작성한 함수는 자동으로 호출된다. 이벤트 핸들링 함수내에서 그 함수에 해당하는 특정 작업을 수행하게 된다. VCL은 자주 사용되는 윈도우즈 메시지의 핸들링을 너무도 쉽게 만들어서 전통적인 윈도우즈 프로그래밍에서 메시지 핸들링이 얼마나 지겨운 일이었는지를 종종 잊게 만든다.

다른 메시지들의 처리

종종 프로그래머는 VCL이 이벤트를 제공하지 않는 메시지를 처리할 필요가 생기게 된다. 프로그래머가 어플리케이션에서 다루어야 할 메시지로서 WM_ERASEBKGND 와 WM_SETCURSOR 메시지 등이 있다. 일반적인 VCL 이벤트 모델 바깥의 메시지들을 처리하기 위해서는, 다음과 같은 일들을 해야 한다.

1. 메시지를 처리할 윈도우의 클래스 선언내에 메시지맵 작성
2. 처리할 메시지의 항목을 메시지맵에 추가
3. 메시지 핸들링 함수를 작성
 
메시지맵의 작성

VCL 이벤트가 없는 메시지(사용자 정의 메시지를 포함하여)를 처리하기 위해서는 메시지맵을 작성해야 한다. 일반적인 메시지맵은 다음과 같다.
BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(MYMESSAGE, TMessage, OnMyMessage)
    MESSAGE_HANDLER(WM_ERASEBKGND, TWMEraseBkgnd, WmEraseBkgnd)
END_MESSAGE_MAP(TForm)

만약 OWL(Borland's Object Windows Library)에 익숙하다면, 이 코드가 OWL의 response table와 유사하다는 것을 알 수 있을 것이다. 그러나 C++Builder 메시지맵의 요소들은 약간 재 배열되었다.

OWL의 response table과 마찬가지로 C++Builder의 메시지맵도 매크로로 구성되어 있다. 첫번째 메크로인 BEGIN_MESSAGE_MAP는 메시지맵은 메시지맵의 처음임을 알린다. 이 매크로는 파라미터를 갖지 않는다. 다음으로, 처리하고자 하는 각 메시지에 대해 MESSAGE_HANDLER 매크로가 필요하다. MESSAGE_HANDLER 매크로는 첫 파라미터로서 메시지의 이름을 가지며, 메시지구조체의 이름을 두번째 파라미터로, 메시지 핸들링 함수의 이름을 마지막 인자로서 가진다. 마지막으로, END_MESSAGE_MAP 매크로가 매시지맵의 끝임을 표시한다.

메시지를 핸들할 클래스의 헤더에 메시지맵을 위치시킨다. 메시지맵은 클래스 선언의 public 섹션에 위치해야 한다(보통은 마지막에 한다). 예를 들어서 메인폼에서 WM_ERASEBKGND 메시지를 핸들한다면 TForm1 클래스의 선언은 다음과 비슷하게 될 것이다.
//---------------------------------------------
#ifndef MyMainH
#define MyMainH
//---------------------------------------------
#include 
#include 
#include 
#include 
#include 
//---------------------------------------------
 
class TForm1 : public
TForm
{
__published: // IDE-managed Components
private: // User declarations
// Message handler  declaration
void __fastcall WmEraseBkgnd(TWMEraseBkgnd& Message);
 
public: // User declarations
    virtual __fastcall TForm1(TComponent* Owner);
 
// The message-map table.
BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_ERASEBKGND, TWMEraseBkgnd, WmEraseBkgnd)
END_MESSAGE_MAP(TForm)
};
 
//---------------------------------------------
extern TForm1
*MainForm;
//---------------------------------------------
#endif

메시지맵 매크로는 오버라이딩된 Dispatch() 함수로 해석되므로 메시지맵은 클래스의 선언부에 와야 한다. Dispatch() VCL 함수는 윈도우즈 메시지를 처리하고 그 메시지를 적절한 이벤트 핸들링 함수에 보낸다. (만약 이 주제에 대해 좀더 깊이 공부할 생각이 있다면 SYSDEFS.H 헤더에서 이들 매시지맵 매크로의 프로토타입을 찾아 볼 수 있다.) Dispatch() 함수는 윈도우즈로부터 메시지를 받았을때 해당 메시지 핸들링 함수를 호출한다. 메시지에 해당 메시지 핸들러가 없으면 그 메시지는 처리를 위해 베이스 클래스의 Dispatch() 함수로 전달된다.

메시지맵에 항목 추가

메시지맵 코드를 작성한 후에, 핸들할 각 메시지의 항목들을 메시지맵에 추가해야 한다. 실제 항목은 MESSAGE_HANDLER 매크로가 된다. WM_ERASEBKND 메시지에 대한 항목은 다음과 같이 될 것이다.
MESSAGE_HANDLER(WM_ERASEBKGND, TWMEraseBkgnd, WmEraseBkgnd)

앞에서 언급했듯이, 처리할 메시지에 대한 메시지맵 항목은 처리할 메시지의 이름과 그 메시지에 해당하는 메시지 구조체의 이름, 그리고 메시지 핸들링 함수의 이름을 포함하게 된다. 사용자 메시지에 대해서는 TMessage or TWMNoParams 구조체를 사용하거나 새로운 메시지 구조체를 작성할 수도 있다.

메시지 핸들링 함수를 작성

마지막으로, 메시지를 처리하기 위하여 메시지 핸들링 함수를 작성한다. 이 함수는 특정한 signature에 따라야 한다. (역주: 시그니처를 뭐라고 번역해야 할지 모르겠는데, C++ 개념에서 시그니처는 함수의 인자리스트, 리턴형, calling convention 등으로 나타내어지는 함수 식별방법을 말합니다. ^^) 이 함수는 단 하나의 파라미터를 가지며, void형 리턴값을 가지고, __fastcall modifier를 가진다. 하나의 파라미터는 메시지 구조체에 대한 레퍼런스이다. (레퍼런스는 아시죠? & 쓰는 참조 연산자...)

먼저 메시지를 핸들링할 클래스의 private 섹션에 메시지핸들러 함수를 선언하자. WM_ERASEBKGND 메시지의 경우 선언은 다음과 비슷할 것이다.
void __fastcall WmEraseBkgnd(TWMEraseBkgnd& Message);

함수의 이름이 중요한 것은 아니지만, 프로그래머는 습관적으로 핸들하려는 메시지와 같은 이름을 붙이길 바랄것이다.
  다음으로, 메시지를 처리할 클래스의 소스 유닛에 메시지 핸들링 함수를 정의(구현)하자. 예로서 다음 WM_ERASEBKGND 메시지 핸들러는 폼의 배경에 해치(역주: XXX 무늬)를 그린다.
void __fastcall TForm1::WmEraseBkgnd(TWMEraseBkgnd& Message)
{
    TCanvas* canvas = new TCanvas();
 
    canvas->Handle = Message.DC;
    canvas->Brush->Handle = CreateHatchBrush(HS_DIAGCROSS, clBlue);
    canvas->FillRect(ClientRect);
    Message.Result = true;
    delete canvas;
}

먼저 이 코드는 TCanvas 객체를 생성하여 메시지 구조체를 통해 전달된 HDC를 캔바스의 Handle 프로퍼티에 대입한다. 이렇게 함으로서 이 코드는 디바이스 컨텍스트를 얻고 TCanvas의 멤버 함수와 프로퍼티를 이용하여 디바이스 컨텍스트를 조작할 수 있게 해준다. 다음으로 이 코드는 해치 브러시를 생성하여 캔바스의 브러시 프로퍼티에 대입한다. 그런 후에 이 해치 브러시로 폼의 클라이언트 사각 영역을 채운다. 그런후에 윈도우즈에게 메시지를 처리하였고 윈도우즈가 더이상 할 일이 없음을 알리기 위해 메시지 구조체의 Result 멤버를 true로 세팅한다. 마지막으로 메모리 누수를 막기 위해 TCanvas 객체를 삭제한다.  핸들하기를 원하는 각 메시지에 대한 메시지핸들러 함수를 생성하기 위해서는 이
러한 절차를 거쳐야 한다.

메시지의 디폴트 핸들링

윈도우즈 메시지를 처리할 때 자주 새로운 처리 뿐 아니라 그 메시지에 대한 윈도우즈의 기본 처리도 필요하게 된다. 예를 들어 에디트 컨트롤의 모든 글자가 대문자로 나오길 바랄 수 있다. 그러기 위해서는 문자들을 수정하고 처리하기 위해 윈도우즈에 메시지를 보내게 된다. 이 경우 다음과 같이 메시지 구조체의 Key 인자를 수정하고 윈도우즈에게 메시지를 전달하기 위해 베이스 클래스의 Dispatch() 멤버함수를 호출한다.
void __fastcall TForm1::OnKeyDown(TWMKeyDown& Message)
{
    if (Message.CharCode > 96 && Message.CharCode < 123)
        Message.CharCode -= 32;
 
    TForm::Dispatch(&Message);
}

Dispatch() 함수가 TMessage 구조체의 포인터를 요구하므로 구조체를 VCL에 전달할 때 메시지 구조체의 주소를 얻어야 한다. Dispatch() 함수를 메시지 파라미터들을 수정하기 전에 호출할 것인지 혹은 이후에 호출할 것인지는 역시 처리할 메시지의 종류에 따라 다르다.

메시지에 대한 디폴트 핸들링을 하기 위해 DefaultHandler() 함수를 호출할 수도 있다. 이론적으로 Dispatch() 함수를 호출하는 것으로 충분하지만, 어떤 특정 상황에서는 DefaultHandler() 가 Dispatch() 와는 다른 결과를 보이는 것을 발견했다. 이러한 차이점이 내 코드의 실수인지 VCL의 버그인지 모르겠다. 하지만 적어도 메시지를 윈도우즈에 전달하기 위한 방법이 한가지 방법뿐인 것은 아니란것을 알고 있기를 바란다.

예제 : 해칭

리스트 A와 B는 폼의 배경에 해치무늬를 그리기 위한 메시지핸들러를 사용하는 프로그램이다. 이 프로그램은 WmEraseBkgnd 메시지 핸들러에서 WM_ERASEBKGND 메시지를 캐치하여 그린다. 새 프로젝트를 만들어서 C++Builder가 자동생성한 코드를 다음 두 리스트로 바꾸어라. 프로그램을 실행시켜보면, 폼의 배경에 파란색의 해치 무늬가 나타날 것이다.

List A (MSGTEST.H)
#include 
 
//---------------------------------------------
 
class TForm1 : public TForm
{
__published: // IDE-managed components
 
private: // User declarations
    void __fastcall WmEraseBkgnd(TWMEraseBkgnd& Message);
public: // User declarations
    virtual __fastcall TForm1(TComponent* Owner);
 
BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_ERASEBKGND, TWMEraseBkgnd, WmEraseBkgnd)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------
extern TForm1 *Form1;
//---------------------------------------------


List B (MSGTEST.CPP)
//--------------------------------------------------
#include 
#pragma hdrstop
 
#include "Unit1.h"
//--------------------------------------------------
#pragma resource "*.dfm"
 
TForm1 * Form1;
//--------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//--------------------------------------------------
 
void __fastcall TForm1::WmEraseBkgnd(TWMEraseBkgnd& Message)
{
    TCanvas* canvas = new TCanvas();
    canvas->Handle = Message.DC;
    canvas->Brush->Handle = CreateHatchBrush(HS_DIAGCROSS, clBlue);
    canvas->FillRect(ClientRect);
    Message.Result = true;
    delete canvas;
}
//--------------------------------------------------


결론

VCL이 내장하고 있는 이벤트들은 프로그래머에게 대부분의 윈도우즈 메시지를 핸들할 수 있도록 해준다. 그러나 VCL 이벤트가 모든 윈도우 메시지를 다 커버하진 못한다. 이 강좌에서 제공한 정보를 이용하여 프로그래머는 VCL이 이벤트를 제공하든 하지 않든가에 관계없이 모든 윈도우 메시지를 핸들할 수 있게 된다.


Kent Reisdorph는 TurboPower Software의 고참 엔지니어이며 TeamB(Borland's volunteer online support group)의 멤버이다. 그는 Teach Yourself C++Builder in 21 Days and Teach Yourself C++Builder in 14 Days의 저자이기도 하다. 그의 이메일 주소는 다음과 같다 : 75300.1417@compuserve.com.

=============================================================================

자... 강좌는 끝났습니다. 번역하느라 읽다보니, 제가 그간 알고 있었던 메시지맵에 대한 거의 모든 것이 다 잘 설명되어있군요. 더이상의 부연은 필요없으리라 생각됩니다만, 위에서 켄트가 말했듯이 메시지맵 매크로의 더 자세한 부분을 알고 싶으신 분은 반드시 include\vcl 디렉토리에 있는 sysdefs.h 화일을 들여다보시기 바랍니다. 메시지맵 매크로가 어떻게 확장되는지 잘 알 수 있을겁니다. (진정한 C/C++ 프로그래머 정신을 갖고 계신 분이라면 반드시 뒤져보실 것을 권합니다.)

위에서 켄트는 메시지맵만이 커스텀 메시지핸들링 루틴을 구현하기 위한 유일한 방법인것처럼 설명했는데, 사실은 그렇지 않습니다. 오히려 저는 WinProc() 함수를 오버라이딩 하는 쪽을 더 선호하는데, 처리할 메시지가 많을 수록 더 유리합니다. 이 방법에 대해서는 시간이 나는대로 강좌를 써보기로 하겠습니다만, 급하시거나 궁금해서 못견디시겠다는 분은 직접 해보셔도 그리 어렵지 않을겁니다.

아무쪼록 미숙한 번역이 C++Builder 프로그래밍에 입문하시는 많은 분들께 도움이 되길 진심으로 바라면서,
그럼 이만...



독립문에서 임펠리테리였습니다.

(cbuilder, skyhi18, cbuilder@thrunet.com)

+ -

관련 글 리스트
104 [강좌] C++Builder 메시지 핸들링 (메시지맵 사용) 박지훈.임프 17627 2001/07/26
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.