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
[584] C++에서 델파이의 initialization/finalization 따라하기
박지훈.임프 [cbuilder] 9489 읽음    2006-03-21 18:52
델파이로 개발해보신 분이면, 이따금씩 오브젝트 파스칼의 initialization/finalization 문법이 얼마나 편리한지 아실 겁니다.
initialization/finalization은 오브젝트 파스칼에서 interface/implementation 과 마찬가지로 소스상의 섹션인데요.
initialization은 해당 소스를 포함한 모듈이 로딩될 때(exe든 dll/bpl이든) 무조건 호출되는 루틴들을 지정할 수 있고,
finalization은 반대로 해당 모듈이 언로딩될 때 무조건 호출되는 루틴들을 지정합니다.

어쩌면 이해를 못하실 수도 있는데..
이해가 잘 안되시는 분들은 이런 문법에 대해 필요성을 느끼지 못한 것이니 그다지 신경쓸 필요가 없을 듯. ^^

VCL의 소스를 보신 분들은 볼랜드의 개발자들이 VCL에서 이 initialization/finalization 문법을 얼마나 요긴하게 잘 활용
했는지 아실 겁니다. dll이나 bpl을 개발하는 경우 초기에 무조건 실행될 루틴을 지정하려면 C++에서는 DllEntryPoint를
이용할 수 있기는 하지만 반대로 언로딩될 때 호출될 루틴은 지정할 방법이 마땅치 않습니다.

마침 제가 C++빌더와 델파이 양쪽 모두에서 사용 가능한 이런 문법이 필요해서 여기저기 뒤져봤습니다.
그랬더니 두가지 방법이 나오더군요.

첫번째 방법은 #pragma startup과 #pragma exit를 이용하는 것입니다.

void Initialize(void)
{
  ShowMessage("Initialize");
}

void Finalize(void)
{
  ShowMessage("Finalize");
}

#pragma startup Initialize
#pragma exit Finalize

이걸로 끝입니다. 이 소스를 포함한 모듈이 로딩될 때 먼저 Initialize() 함수가 실행되고, 언로딩될 때는 Finalize() 함수가
실행됩니다. [#pragma startup 함수이름] 다음에 우선순위(priority)를 지정할 수도 있습니다.

이 문법에 대해서는 포럼에 예전에 올렸던 담비님의 다음 글에도 설명되어 있더군요.
(구글링을 해서 해외 사이트에서 찾고 나니 역시 구글에 포럼의 글도 검색되어 나오더군요.)
http://www.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=106

또다른 한가지 방법은 전역 클래스 객체의 생성자/파괴자에서 처리하는 방식입니다.
VCL 기반이 아닌 C++ 클래스를 하나 만들고 생성자/파괴자를 만듭니다. 그리고 해당 클래스의 객체를 (포인터가 아니라)
객체 자체를 정적으로 생성하면 됩니다. 해당 모듈이 로딩될 때 정적으로 선언된 해당 클래스 객체가 생성되고 따라서
생성자가 호출되므로 여기서 초기화 루틴을 호출하면 됩니다. 또한 역시 해당 모듈이 언로딩될 때 해당 객체가 파괴되므로
파괴자에서 종료 루틴을 호출하면 되지요.

class TInit 
{ 
public: 
    TInit() 
    { 
        Initialization(); 
    } 

    ~TInit() 
    { 
        Finalization(); 
    } 

    static void Initialization(); 
    static void Finalization(); 
} Init; 


// YOUR UNIT BODY 
void TInit::Initialization() 
{ 
    // Enter your initialization code here 
} 

void TInit::Finalization() 
{ 
    // Enter your finalization code here 
} 

(위 코드는 Gabriel Kamenov이라는 분이 뉴스그룹에 올린 예제 코드입니다)

참고로, 저는 첫번째 방법, 그러니까 #pragma startup / #pragma exit 방식을 선택했습니다.
초기화/종료 루틴만을 위해 정적 객체를 하나 생성한다는 것이 왠지 맘에 안들고 또 첫번째 방식이 좀 더 코드가 간소해서요.
하지만 하는 역할은 동일하므로 원하시는 대로 방법을 선택해서 쓰시면 되겠습니다.

그럼...
WARSHIP [warship]   2006-03-22 10:33 X
정말 좋은 팁이네요 ^^; 
좋은 정보 감사합니다~
김상면 [windyboy]   2006-03-24 08:37 X
임프님 제가 알기로는 다음 상수르 이용하면 된다고 알고 있는데...

A process loads the DLL (DLL_PROCESS_ATTACH).
The current process creates a new thread (DLL_THREAD_ATTACH).
A thread exits normally (DLL_THREAD_DETACH).
A process unloads the DLL (DLL_PROCESS_DETACH).

제가 잘못아는 건가요?
김태선 [jsdkts]   2006-04-03 10:19 X
김상면님 말씀이 맞습니다만
박지훈님 팁이 상당히 가치가 있어 보이는군요.
김태선 [jsdkts]   2006-05-16 16:53 X
#pragma startup Initialize
#pragma exit Finalize
은 DLL 뿐만 아니라 EXE 형태에서도 사용할 수 있으나
유닛별로 적용되는 것이 아니라 실행 프로그램 전체에 대해 동일함수로 적용됩니다.
그러므로 한번만 사용할 수 있습니다.
박지훈.임프 [cbuilder]   2006-10-21 06:50 X
둘 이상의 소스에서 같은 이름의 함수를 #pragma startup으로 호출할 경우, 같은 이름의 함수는 첫번째 하나만 실행된다는 보고가 있습니다. 아마도 제 생각에는 당연한 것 같습니다만...
http://www.hadihariri.com/techblog/atozed/2006_10_19.html

지금 제가 시간이 없어서 해보진 않았습니다.
물론, 함수 이름 뒤에 소스 유닛 이름을 붙여준다든지 하는 식으로 다 다르게 만들어버리면 간단히 해결되겠지요. ㅎㅎ
장성호 [nasilso]   2009-02-05 03:15 X
Dll의 경우
DLL_PROCESS_ATTACH / DLL_THREAD_ATTACH / DLL_THREAD_DETACH / DLL_PROCESS_DETACH 경우는
Loader에서 Dll을 LoadLibrary하면서 DllMain(BCB의 경우 DllEntryPoint) 을 호출해주는데

#pragma startup  은 LoadLibrary가 끝난후 즉 DllMain(혹은 DllEntryPoint) 가 return된후에 호출됩니다.
DllMain(혹은 DllEntryPoint)에서 무슨 작업을 하는것은 매우 위험하다고 합니다.
그 이유는 다음문서를 보시면 잘 나와있습니다.

http://download.microsoft.com/download/a/f/7/af7777e5-7dcd-4800-8a0a-b18336565f5b/DLL_bestprac.doc


+ -

관련 글 리스트
584 C++에서 델파이의 initialization/finalization 따라하기 박지훈.임프 9489 2006/03/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.