2009. 8. 19. 16:33ㆍ언어/C++ Builder
시삽 : 원래 이학균님께서 Q/A에 올리신 글입니다만... Q/A에 두셔서 다른 질문/답변에 파묻히기에는
아깝고, 또 성격상 강좌에 가까워서 Tip 게시판으로 옮깁니다.
------------------------------------------------------------------------
제 목: C++ 빌더로 채팅서버를 만들어보자.
작성자: 이학균
U R L : http://explore.kwangwoon.ac.kr/~k98el560 (야후에서 '학균'검색)
작성일: 2001. 07. 28일
연락처: (HP)016-411-8187 (버디버디)lobin2 (e-mail)lobin2@hanmir.com
------------------------------------------------------------------------
비주얼 개발 툴의 장점은 이미 만들어진 컴포넌트를 등록해서 몇가지 속성을 지정해
제공되는 메소드를 불러 쓰는 것만으로도 멋진 프로그램이 완성됩니다. 하지만, 이
컴포넌트가 종류가 많고 기능도 다양하다지만, 모든 기능을 할 수는 없는 것이고 이에
따라 우리는 제공되는 Win32 API를 이용하여 자신이 원하는 기능을 구현하기도 합니다.
차후에 똑같은 기능을 구현하기 위해 저수준의 API함수를 써서 만들기 보다, 컴포넌트를
만들어 불러쓰면 훨씬 편하게 프로그램을 짤 수 있습니다.
회사에서 RS-232C 시리얼 통신하는 프로그램을 짰는데, 요구에 따라 컴포넌트 화하였습니다.
회사에서 쓰는 프로그램을 올릴 순 없고, 그 프로그램의 가장 기본적인 기능만을
올리도록 하겠습니다.
다음은, 컴포넌트를 만드는 방법에 대해 알아보겠습니다.
1. 컴포넌트에 제공되는 기능
컴포넌트에는 크게 세가지로 나누어 지원을 해 줍니다. 하나는 속성 Property,
또 하나는 Method, 마지막으로 Event가 있습니다. 씨 빌더를 사용해 보신 분들을 기준으로
설명하기 때문에 다들 아시리라 믿고 넘어갑니다.
2. 컴포넌트 만들기
File - New 에서 Component를 선택하시면, 상속받을 컴포넌트를 선택하고 이름을 적으시면
간단한 코딩이 완성됩니다.
3. 상속
만약 해당 컴포넌트가 TServerSocket을 상속 받으시면 TServerSocket의 모든 기능을
다 사용하실 수가 있습니다. 특별히 상속받을게 없으시면 TComponent를 상속받으십시요.
4. 프로퍼티, 메소드, 이벤트의 구현
아래의 간단한 헤더 파일의 예를 보며 설명을 하겠습니다.
//---------------------------------------------------------------------------
#ifndef NewSerialComponentH
#define NewSerialComponentH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#define WM_COMM_READ WM_USER + 1
//---------------------------------------------------------------------------
typedef void __fastcall (__closure *TCommReadEvent)(System::TObject* Sender, String InBuf, int Length );
enum TBaudRate {BAUD1200=0, BAUD2400=1, BAUD4800=2, BAUD9600=3, BAUD19200=4, BAUD38400=5};
class PACKAGE TSerialComponent : public TComponent
{
friend class TReceiveSerialThread;
private:
int LengthValue;
void SetLength(int LengthValue);
void __fastcall SetBaudRate(TComPort FBaudRate);
Classes::TNotifyEvent FOnCommRead;
TCommReadEvent FOnCommRead;
protected:
TBaudRate FBaudRate;
public:
int __fastcall Open(void); // 메소드 지정은 여기에
__fastcall TSerialComponent(TComponent* Owner);
__fastcall ~TSerialComponent(void);
// 감지 메시지를 받아 이벤트와 연결한다.
MESSAGE void __fastcall OnCommReadFunc(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COMM_READ,TMessage,OnCommReadFunc)
END_MESSAGE_MAP(TSerialComponent)
__published: // 프로퍼티 표시되는 부분
__property int Length = {read=LengthValue, write=SetLength, default=3};
__property TBaudRate BaudRate = {read=FBaudRate, write=SetBaudRate, default=BAUD9600};
__property TCommReadEvent OnCommRead = {read=FOnCommRead, write=FOnCommRead}; // 이벤트
};
//----------------------------------------------------------------------------------
먼저 메소드 지정은 public란에 일반 함수 생성하듯이 선언하고 cpp에 구현해 주면됩니다.
property는 크게 두가지 종류가 있습니다. 하나는 정수형 입력하는 방식이고 또 다른 하나는 여러개 중에
선택하는 것입니다.
첫번째 정수형 입력 방식은 __published란에
_property int Length = {read=LengthValue, write=SetLength, default=3}; 라고 선언을 합니다.
여기서 저장되는 변수는 LengthValue라는 변수고 이는 private에 int형으로 선언되었습니다. 바뀌었을 때
저장되는 함수는 SetLength라는 함수로 이도 역시 private에 선언 되었습니다 cpp본체에 이 함수는
넘어온 인자값을 LengthValue에 대입만 시켜 주는 것이 끝입니다.
다른 방법으로 여러개 중에 고르는 방법이 있는데, enum을 사용하는 것입니다.
enum TBaudRate {BAUD1200=0, BAUD2400=1, BAUD4800=2, BAUD9600=3, BAUD19200=4, BAUD38400=5};
클래스 외부에 TBaudRate라는 값으로 선언을 해 주고 protected에 TBaudRate FBaudRate라고 선언합니다.
__published에 다음과 같이 선언을 하고 물론 SetBaudRate 본체에도 FBaudRate값을 대입시켜 주는 것으로 끝입니다.
__property TBaudRate BaudRate = {read=FBaudRate, write=SetBaudRate, default=BAUD9600};
마지막으로 이벤트가 있는데, 간단한 예로 COM포트에 데이타가 수신이 되면은 읽어들인 String 문자열과
길이를 반환하는 이벤트를 만들려면...
typedef void __fastcall (__closure *TCommReadEvent)(System::TObject* Sender, String InBuf, int Length );
이렇게 사용자 정의형으로 선언을 하고 private에 TCommReadEvent FOnCommRead; 라고 선언을 합니다.
그리고 __published에 __property TCommReadEvent OnCommRead = {read=FOnCommRead, write=FOnCommRead};이렇게
선언을 하면 됩니다. 실재로 쓰레드를 돌려 Com포트에 데이타가 들어왔다는걸 감지하는 루틴에서
FOnCommRead(this, ResultBuf, length);라는 식으로 인자를 넘겨주면 해당 컴포넌트 이벤트에 위의 인자를
사용할 수 있게끔 해 줍니다.
부가적으로 메시지 핸들링도 같이 설명하겠습니다. 윈도우에서 제공하는 각종 메시지나 사용자 정의
메시지를 감지하기 위해 메시지 핸들링하는 기법을 빌더에서도 제공하는데, 간단히 아래와 같이 하면 됩니다.
// 감지 메시지를 받아 이벤트와 연결한다.
MESSAGE void __fastcall OnCommReadFunc(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COMM_READ,TMessage,OnCommReadFunc)
END_MESSAGE_MAP(TSerialComponent)
여기서 WM_COMM_READ는 사용자 정의 메시지고, 여기에 윈도우 자체 메시지를 넣으면 그것이 감지가 됩니다.
위의 소스를 보시면 간단히 이해가 가실 겁니다.
사용자 정의 메시지일 경우 cpp 본체에서 메시지를 뿌려줘야 되는데, 이를 수행하는 함수가 Perform() 함수입니다.
해당 시점에서 메시지를 발생시키면 OnCommReadFunc라는 함수가 수행 될 것입니다. 참고적으로 알아 두세요
다음으로 cpp 파일을 보겠습니다. 보기 편하게 간략한 구조만 올리도록 하겠습니다.
//-----------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "NewSerialComponent.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
void __fastcall TSerialComponent::SetBaudRate(TBaudRate Value)
{
FBaudRate=Value;
return;
}
//----------------------------------------------------------------------
// 메소드
int __fastcall TSerialComponent::Open(void)
{
// 함수 내용
}
void __fastcall TSerialComponent::Close(void)
//---------------------------------------------------------------------------
// 컴포넌트 부분
static inline void ValidCtrCheck(TSerialComponent *)
{
new TSerialComponent(NULL);
}
__fastcall TSerialComponent::TSerialComponent(TComponent* Owner)
: TComponent(Owner)
{
}
__fastcall TSerialComponent::~TSerialComponent(void)
{
}
namespace Newserialcomponent
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSerialComponent)};
RegisterComponents("Samples", classes, 0);
}
}
//---------------------------------------------------------------------------------
이게 끝입니다. 눈여겨 봐야 될게 SetBaudRate라는 것인데, 넘어온 값을 FBaudRate에 저장함으로써
프로퍼티 설정은 끝이고.. 메소드 설정은 일반 함수 구현하듯이 하면 됩니다.
그리고 이벤트 호출하는 부분은 앞서 설명 드렸고요. 이 cpp에는 회사 프로그램 내용이 들어가기
때문에 호출하는 부분을 생략했습니다. 이벤트 발생은 감지되는 루틴에서 FOnCommRead(this, String, Length);라는
식으로 인자를 전달하면 끝입니다.
이상으로 간략한 컴포넌트 만들기는 끝났습니다. 차후에 시리얼 통신 강좌가 끝난 후
회사 프로그램을 수정하여 기본적인 기능만 넣어서 자료실에 소스를 올리겠습니다.
발췌 : 볼랜드 포럼
'언어 > C++ Builder' 카테고리의 다른 글
쓰레드를 이용한 채팅 서버 만들기. (0) | 2009.09.04 |
---|---|
C++ Builder Component 설치 하기. (0) | 2009.09.01 |
Tcp/Ip Socket Programming (0) | 2009.08.31 |
C++ Builder 의 C++언어 확장 (0) | 2009.08.19 |
C++ Builder 기초 (0) | 2009.08.19 |