api handle?

공부/c++ 2014.05.16 11:38
설명의 편의를 위해 경어는 생략하겠습니다.)
(저도 여기저기서 주워들은 것이라서 틀린점이 있을 수 있습니다. 지적해 주시면 정말 도움이 될 것입니다.)

정확한 통계가 있을리는 만무하지만.. 많은 사람들이 윈도우 개발을 처음 접하면 몇가지 의문점이 (실제로는 산더미같이!!!) 생기게 된다.

제일 먼저 메인함수를 접하게 되는데, 콘솔에서의 메인이라 해봐야 짧으면 "void main()" 뿐이니 몇자 되지도 않고 간단하다.

그런데.. 처음 접하게 되는 윈도우 메인함수는..


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ... )

아닛! 메인부터 벌써 가드가 철저하다!

대체!! APIENTRY는 무엇이며 HINSTANCE는 또 무엇이란 말인가???

놀란 가슴을 부여잡고 도움말을 찾기 위해 HINSTANCE 위에서 F1을 누르거나..

자립심이 약간 결여된 사람들은 브라우저를 열고 이름은 밝힐 수 없지만 X이버 지식X에 가서 검색을 한다...


MSDN -> 인스턴스의 "핸들" 입니다. (설명 참 짧다. 이런 뻔한걸 왜 물어보냐는 투다.. ㅇㅅㅇ);;

지식X -> HINSTANCE란 프로그램의 모듈을 담고 있는 "핸들"로서..


핸들..?? 아니 대체 핸들은 또 뭐야~(산넘어 산이다) 하며 다시 검색해본다.

MSDN -> 핸들은 오브젝트여요~
( 앞산이 어디에 있냐? 뒷산 앞에 있어~ 그럼 뒷산은 어딨는데? 앞산 뒤에 있지~ 라는것 같다)

지식X -> "06년식 트라제 사제오디오 설치시 핸들리모컨 사용이.."
(헉!! 깜짝 놀라며 api 핸들로 다시 검색해본다..;;)


(다시 검색된 지식X 결과)
-> 윈도우에서 다루는 자원번호로... 주민등록번호와 같은 어쩌고 저쩌고..
-> 말그대로 핸들입니다.. 운전하는 사람이 자동차 구조를 알필요가.. 어쩌고 저쩌고.. (결론은 알필요 없는 소리)
-> (일단 영어의 뜻을 살펴보자며 사전을 복사해다 긁어놓고..) 이뜻에서 유추해보건데.. 이러쿵 저러쿵.. 핸들을 통해서 컨트롤의 속성을 조절.. 어쩌고 저쩌고.. 일종의 메모리 번지값에 대한 주소..
(결론은 틀린소리...;;)


아니.. 그러니까 대체 뭐라는 거야.. ㅇ_ㅇ);;;


역시나 이름은 밝힐 수 없지만 이곳 홈주인이신 김모상형님이 쓰신 책의 내용을 요약해 보자면..

(1) 운영체제가 발급해 주는 것을 받아서 쓸 뿐, 직접 만들 수는 없다.

(2) 대상을 빠르게 구분하기 위해 정수형을 사용하며 중복되지 않는다.

(3) 파일, 브러쉬, 펜, 폰트 등을 모두 핸들을 붙여 번호로 관리한다.

음.. 그럼 이 내용을 정리해보자면..


"내가 파일이나 폰트를 만들어달라고 OS에게 요청을 하면, OS는 이것들을 만든 후에 중복되지 않는 핸들이라는 고유 ID를 만들어 붙이고, 만든 파일이나 폰트를 직접 주는 것이 아니라, 핸들만 건내주는 것이구나" 라는 것을 알 수 있다.

(우선 여기까지의 내용이 기억나지 않으면 옆 API강좌의 1-3-나. 핸들에 대한 이해를 읽고오자)
자.. 이제 핸들이라는 것은 "파일이나 폰트, DC, 브러쉬, 펜 등등의 각종 [!]오브젝트 에 대한 일종의 참조 번호"라는 것은 이해할 수 있을 것이다.

어라? 그러고 보니 MSDN의 "핸들은 오브젝트여요" 라는 소리가 틀린말만은 아니다.


그렇다면 왜 파일이나, 폰트, 펜등의 오브젝트를 직접 주지않고 이렇게 복잡한 방식을 취했는지 생각해보자.

( 아니.. 생각해보자고 했는데 생각하지 않고 스크롤 내린사람은 반성하자 ㅡㅅㅡ);;



그렇다.. 다들 짐작했겠지만 모 CF의 광고처럼 "오브젝트는 소중하니까요~" 일 것이다.

약간은 맞지 않는 측면이 있지만 다음의 예를 통해 알아보자.


자, 당신은 공무원이고 도로공사에 필요한 공금 수백억이 정부로부터 당신에게 "직접" 주어졌다면 어떻게 할것인가?

"공금은 투명하고 안전하게 관리되어야 하니 지금 당장 쓸돈이 아니면 은행에 보관한 후에 공개입찰을 통해서 건설사를 선정하고 비용을 사용할때마다 영수증을 받고 출금내역을 기록할 것이다."
( 우와! 이런분이 있다면 정말 존경스럽다. ㅇ_ㅇ);; 법없이도 살 분이다!!)


나라면(다른 분들도 비슷하겠지만.. ㅡㅅㅡ);; 다른 직원들 몰래 공금을 몽땅 들고 해외로 튄다거나..

하루이틀에 걸쳐 사용할 금액이 아니니, 일정 금액을 몰래 빼돌려 CMA 계좌라도 개설해서 거기다 넣고 이자를 받아 챙기거나

입찰시에 건설사와 짜고 공사비를 부풀린 후에 부풀린 금액을 리베이트로 받을 것이다.

또한 이렇게 공금을 달라는 대로 담당자에게 직접 이사람 저사람 주다보면 누구에게 얼마를 주었는지, 얼마를 받아야 되는지 정부에서는 관리도 되지 않는다.


여기서 비유한 공금은 오브젝트(파일, 펜, 폰트 등등) 이고, 정부는 OS라고 생각하면 된다.

사방 팔방에 흑심품은 사람 천지니 어디 믿고 공금을 전부 맡기겠는가? 그럴수는 없다.

공공계좌를 개설한 후에 입금을 시키고, 계좌를 통해서만 입출금이 가능하게 하고, 입출금 내역은 정기적인 감사를 통해 투명성을 확보한다.


이러한 방식을 취함으로서 공금(오브젝트)의 안전성과 투명성, 그리고 정부(OS)에서는 공금(오브젝트)이 어떻게 사용되고 있는지 관리하기가 편하다.

이제 오브젝트를 직접 주지 않는 대략적인 이유가 이해가 되었을 것이다.

"파일이나 폰트등의 오브젝트(공금)는 안전한 관리를 위해 직접 넘기지 않고, 핸들ID(계좌)를 통한 참조만 가능하게 해놨구나" 라는 것을 알 수 있다.


여기까지의 내용을 정리하자면.

"OS는 오브젝트를 생성한 후에 중복되지 않는 정수형의 ID를 핸들값으로서 부여한 후 프로세서에 넘김으로서 오브젝트의 안정성을 확보하고, 프로세서는 이 핸들을 받아 생성된 오브젝트를 자유롭게 [!]참조 할 수 있다. "
이번에는 핸들의 특성에 대해 알아보자.

역시나 이번에도 이름은 밝힐 수 없지만, 김모상형님이 쓰신 책의 내용중에 다음과 같은 내용이 있다.
(이거 무단으로 전제하는건데.. 잡혀가는거 아닌지 모르겠다.. ㅠ.ㅠ);;;

----------------------------------------------------------------------------------------
26-1-가. 파일 핸들도 메모리를 차지하고..(중략) 사용하고 난 후에 해제하는 것이 원칙이다. 파일을 닫지 않았더라도 프로그램이 종료될 때 열려진 모든 파일은 [!]자동으로 닫혀지지만...
40-2-나. 프로세스가 종료될 때는 다음 일련의 작업이 이루어진다. (중략) [!]모든 열려진 핸들을 닫는다.
----------------------------------------------------------------------------------------

아니! 이 내용을 보니 "프로세스 종료시에 알아서 핸들이 닫혀진다" 고 한다. 그렇다면 다음 예제들을 한번 살펴보자.

예) 타이머 사용과 제거.
hTimer = (HANDLE)SetTimer(hWnd,1,1000,NULL);
// 타이머 사용후.
// KillTimer(hWnd,1); <- 필요없는 코드 ?

예) DC를 얻고 펜을 작성한 후에 제거.`
hdc=BeginPaint(hWnd,&ps);
MyPen = CreatePen(PS_SOLID, 5, RGB(0,0,255));
OldPen = (HPEN)SelectObject(hdc, MyPen);
Rectangle(hdc,50,50,300,200);
SelectObject(hdc, OldPen);
//DeleteObject(MyPen); <- 필요없는 코드 ?
//EndPaint(hWnd,&ps); <- 필요없는 코드 ?

(1) 종료시에 알아서 모든 핸들을 자동으로 닫는다면, 열려져 있는 얼마 안되는 핸들의 메모리가 무시할 정도라면 KillTimer나 DeleteObject등은 필요하지 않는것 아닌가?


다른 생각도 한번 해보자. "모니터링 프로그램을 실행시켜주는 실행 프로그램(1개)과 모니터링 프로그램들(n개)"을 작성한다고 가정해보자.

실행프로그램이 먼저 동작하고, 사용자의 입력에 따라 각각의 독립된 프로세스인 모니터링 프로그램들을 실행시킨다.

자~ 당신은 폰트, 브러쉬, 펜등을 작성하여 실행프로그램의 UI를 멋지게 꾸민후 작성을 완료했다.

다음으로 n개의 모니터링 프로그램을 만들려고 생각해보니 이런 생각이 든다.

어차피 모니터링 프로그램들은 실행 프로그램이 먼저 실행되어야 한다.
그렇다면 모니터링 프로그램들에서 제각각 폰트, 브러쉬, 펜을 작성하느니, "실행 프로그램에서 이미 만들어 놓은 폰트, 브러쉬, 펜들의 핸들을 받아 사용"하면 리소스도 절약되고, 코딩도 간결해지지 않겠는가!! 우와! 나이쓰 아이디어!!!!!

(2) 실행프로그램의 폰트, 브러쉬, 펜등의 핸들을 모니터링 프로그램들의 실행인자로 넘겨줘 사용하도록 만들었다.


한김에 가정을 하나 더 해보자. 사용자가 색이나 선굵기를 지정하면 펜과 브러쉬를 만들고 마우스 클릭에 따라 원이나 사각형을 그려주는 초간단 그림판을 만들었다.

그림판을 만들어 사용자에게 보내니, "아니 그린 내용을 저장하고 불러오는 기능도 만들어 주셔야죠" 라고 하기에 다음과 같이 저장하고 로드하도록 만들었다.

(파일 저장을 위한 구조체 선언)
typedef struct {
int nType; //0이면 원 1이면 사각형
HBRUSH hBrush; // 브러쉬 핸들
HPEN hPen; // 펜 핸들
int sx; // 시작점 x
int sy; // 시작점 y
int ex; // 종료점 x
int ey; // 종료점 y
}DrawInfo;

DrawInfo dwInfo;
dwInfo.hBrush = MyBrush;
dwInfo.hPen = MyPen;
(어쩌구저쩌구...)

(파일 저장)
WriteFile(hFile, &dwInfo, sizeof(DrawInfo), &dwWritten, NULL);

우와~! 퍼펙하다. 사용자가 만든 브러쉬와 펜 정보를 저장하고, 시작점과 끝점 도형의 종류까지 저장하니 완벽하다.

WriteFile();로 파일에 저장을 한후 파일을 확인해 보니 브러쉬부터 시작점, 종료점 등등 모든 값들이 제대로 들어가 있다.

자, 이제 로드를 만들어 볼까?

(파일 로드)
ReadFile(hFile, &dwInfo, sizeof(DrawInfo), &dwRead, NULL);

hdc = BeginPaint(hWnd,&ps);
OldBrush = (HBRUSH)SelectObject(hdc, dwInfo.hBrush);
OldPen = (HPEN)SelectObject(hdc, dwInfo.hPen);
if(dwInfo.nType == 0) {
Ellipse(hdc, dwInfo.sx, dwInfo.sy, dwInfo.ex, dwInfo.ey);
} else {
Rectangle(hdc, dwInfo.sx, dwInfo.sy, dwInfo.ex, dwInfo.ey);
}

(3) 우와~! 퍼펙 할까?


(1)번의 경우는 자료 부족 및 능력 부족으로 인해 "확신 할 수는 없지만" 프로세스 종료시 타이머나 파일, 폰트등의 오브젝트는 자동으로 소멸된다고 생각한다.
(혹시 정확한 내용을 아시는 분은 증빙 자료 및 소견서를 200자 원고지 100매 이내로 써서 보내지 않으셔도 되니..ㅠㅠ 알려주시면 감사하겠습니다.. __);

앞서 공사비로 비유했지만, 정부(OS)에서 공사비를(오브젝트) 계좌에 넣어 목록으로 관리하니, 공사가 끝났다면 해당 계좌를 회수 할 것이다.

나중에 나오겠지만 오브젝트에 핸들을 붙여 관리하려면 당연히 "핸들 리스트가" 존재할 것이고, 이 리스트가 존재함으로서 OS는 종료된 프로세스에 관련된 오브젝트는 파괴할 것이다.

물론 자동으로 파괴하니 CloseHandle하지도 말고 DeleteObject() 할것도 없이 편하게 코딩하자! 라는 뜻은 아니다.

이러한 코딩이 좋지 못하다는 것은 누구나가 아는 사실이고, 여기서 말하는 요점은 이런 "특징" 이 있다는 것이지 "옳은 방식"은 아니라는 것을 잊지말자.


(2)번의 경우를 보고 "우와~! 정말 굿아이디어다"라고 생각하신분 설마.. 없으시기를 바란다.. -_ㅡ+

"오브젝트가 소중"하기 때문에 핸들로 관리를 하는건데, 핸들번호만 안다고 해서 개나소나 다 가져다가 오브젝트를 쓴다면 이런짓을 뭐하러 하겠는가?

앞서 나온 공사비로 예를 들자면, "계좌번호"만 안다고 해서 아무나가서 돈을 달라고 하면 돈주는 은행이 있겠는가? 그렇다면 돈을 땅에 파묻어놓고 쓰지 뭐하러 은행에 맡기겠는가?

"핸들은 다른 프로세스에게 넘길 이유도 없고, 넘겨봐야 쓸 수가 없다"


그렇다면 (3)번의 경우는 어떠할까?

다른 프로세스에 넘기는 것이 아니고, 자신의 프로세스에서 생성한 오브젝트의 핸들 ID를 파일에 보관했다가 사용하는 것이니 전혀 문제 될 것이 없어 보이긴 하다.

하지만, 핸들이라는 것은 만들어 놓은 오브젝트를 참조할 번호일뿐 "오브젝트 자체"가 아니라는 것은 우리 모두가 이미 알고 있다.

내가 만든 그림판이 실행중에 브러쉬를 만들어 브러쉬의 핸들을 저장했다면, "브러쉬라는 오브젝트는 이미 만들어져 있기" 때문에 핸들값을 어디에 저장했다 꺼냈는가와 관계 없이 브러쉬라는 오브젝트를 참조 할 수 있다.
(정부로부터 공사비 계좌를 받을때 같이 만든 현금카드를 벽장에 넣어놓았다고 해서 ATM을 이용 못하고, 금고에 넣어놓으면 이용할수 있는가? 이건 말도 안된다~!)

하지만 파일에 핸들값을 저장한 후에 그림판이 종료되면 어떻게 될 것인가? 내가 파괴를 하건 하지 않았건, OS에서 알아서 "브러쉬 오브젝트를 파괴" 할 것이다.

다시 그림판을 실행시킨 후에 파일에 저장했던 핸들값을 읽어들여 봐야 "브러쉬라는 오브젝트는 이미 파괴" 되었으니 핸들값이 의미가 있겠는가?
(앞서 받은 현금카드로 ATM에서 언제든지 편리하게 돈을 뽑아 공사비를 지불했다. 그런데 공사가 끝나 정부에서 계좌를 없애버렸는데도, 현금카드가 있으니 돈은 나오겠는가?)


자.. 이제 요점을 정리해보자.

(1) 특정 프로세스가 오브젝트 생성을 요청하여 받은 핸들은 무언가의 "핸들 리스트"로 관리될 것이다.
(2) OS는 프로세스가 종료되면 "핸들 리스트"를 보고 생성되어 있는 오브젝트를 모두 파괴한다(가정)
(3) 폰트, 펜, 브러쉬를 생성하여 받은 핸들값은 다른 프로세스에 넘겨봐야 의미가 없다. ([!] 모든 핸들이 의미가 없는것은 아니다. 일단은 이렇게만 알아두자)
(4) 핸들은 오브젝트에 대한 참조ID 일 뿐이므로 오브젝트가 파괴된 후, 해당 핸들값은 의미가 없다.

출저 soen.kr


저작자 표시 비영리 동일 조건 변경 허락
신고
Creative Commons License
Creative Commons License

'공부 > c++' 카테고리의 다른 글

메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16
boost access in to all directory  (5) 2014.05.15
boost directory접근  (0) 2014.05.15

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret