나의 COM(Component Object Model) 경험담 #3 벌써 #3 까지왔습니다. 고맙게도점수를주시는분들도계셨습니다. 그리고저의협박아닌협박때문인지아무도질문은하지않더군요. ^^; 네좋습니다. 물론대부분의사람들이그럴가치를느끼지못해서그러셨겠지만, 전역시나제맘대로대부분경청태도가좋군이렇게생각할랍니다. 그뒤는이제말안해도다아시리라생각합니다. 그럼시작하겠습니다. 자이제정리할겸생각좀해보자. 난아직 COM에대한정의는내리지않았다. #1과 #2에서대충이런것이라고말한것은모두조금씩잘못된내용이다.( 속았다고생각하진마라. 인생이원래그런거다. 앞으로몇번은더속아야할것이다.) 그것들은단지 COM의이해를돕기위한쉬운그림그리기에지나지않는다. 그럼 COM 이도대체뭘까? 이것도 Microsoft 홈페이지에서죽어라찾아봐도감을잡을수있을지모르겠다. 역시마이크로소프트이다. ( 이연막작전은누구도당할수없다.) 3년쯤전이었던걸로기억한다. 난친구랑나름대로공부한것을가지고얘기를한적이있었다.( 아주드문경우다. 보통은여자얘기, 술이야기가대부분이다.) 그러다가 COM 얘기가나왔고 COM에대한정의를가지고한참을싸웠다. 친구는 COM을 Component 개념으로우겼다. 마치 ActiveX에가깝게말이다. 그리고난일종의라이브러리라고우겼다. DLL에가깝게말이다.( 결국비슷한말이었지만, 자존심문제였다. 거짓임이감이오더라도그자리에서는양보할수없다.) 지금이글을읽는당신은무엇이라고우기겠나? 어쨌든, 친구와난둘다틀렸다. 그것도완전히틀린것이다. 이것은모두마이크로소프트의잘못이다. 그냥 COM은이것이다라고정의만하면되는데왜하지않는지모르겠다.
자그럼마이크로소프트에서말하는 COM은무엇인가? 답은이렇다. 오브젝트와시스템이개방적이고변화가능한방식으로상호동작할수있는방법을정의하는다수의기술에대한바이너리사양이다. 오 ~ 훌륭한정의가아닌가? 우리의마이크로소프트에서 COM을정의해주셨다. 그것도정확하게말이다. 이글을읽자마자바로 COM이뇌속깊이와닿지않는가? ( 정막이흐른다 ) 정말그런사람이있다면그사람은프로그래밍이아닌소프트웨어공학쪽으로추천하고싶다. 대부분의사람은이막연한말에응그렇구나하고아무생각없이넘어간다. 좀어렵네하고말이다. 하지만그러면안된다. 더이상진도가나갈수없는것이다. 개념도잡지않은상태에서무슨 COM을하겠다는말인가? 이부분을확실히집고넘어가야만발전할수있다. 자그러면자세히살펴보자. 오브젝트란말은무엇인가? 여기서오브젝트는하나의프로세스가될수도있고컴포넌트가될수도있다. 결국이것도애매하게정의해놓았다.( 쥑일 ~) 그리고시스템역시마찬가지다여러가지의미로해석될수있다. 그래좋다. 프로세스간또는스래드간또는컴포넌트간또는기타어플리케이션과컴포넌트간, 수도없이많은경우의수가생긴다.(MS 너희가원하는것이이것이냐?) 이들간에상호동작할수있는방법을정의하는다수 (?) 여기서또나왔다. 다수 ( 적당히많은 ) 란말도애매하다. 결국 COM 은여러가지기술들또는규약을복합적으로부르는말이다. 이런떠그럴 ~ 더어렵잖아. 결국괜히해석했다. 그렇다. 우리는이정의를외울필요가없다. 그러면우리가해야할일은무엇인가? 우리는프로그래머다. 따라서기술만알면된다. 따라서프로그래머입장에서 COM은 Componet와인터페이스, ActiveX, ATL, 오토메이션, COM 스래딩모델등등 COM에서사용되는기술들을알면되는것이다. 이모든것이다 COM이다. 이제이해가되었는가? COM은틀을제공할뿐이다. 이런규칙만지키면너희는다 COM에포함될수있다. 휴 ~~ 한숨돌리자. 자어렵게 COM의정의를내렸다. 여기서불만인사람도있을것이다. 불만가져도좋다. 자신이확실히 COM을알고있고이것에대한정의내릴수있다면이번한번만답글을허용하겠다. 대신질문은여전히금지다. 간단히 COM에대한정의만내려라. 그리고생각해보자. 모두머리를맞대고말이다. 그럼이제 #2에이은프로그래밍을해보자. #2에서 CoInitialize 와 CoCreateInstance를했다. 그리고부가적으로따라오는두함수도했다. 이것들은언급하지않겠다. 여기서개체를생성하고이용한다고할때이개체는 COM 컴포넌트이다. 그리고이모든것이 COM의범주에속하는기술인것이다. ( 지겹다이제 COM에대한정의와관련된것은
그만하자.) 앞으로내가언급할내용의대부분은 COM 컴포넌트가될것이다. 그냥컴포넌트라고해도문맥상 COM 컴포넌트라고생각하면된다. 이컴포넌트는인터페이스를가진다. 그리고이인터페이스는모든컴포넌트들이가지고있는기본인터페이스인 IUnknown 인터페이스에서상속받는다. 점점재미가떨어지고있다. 공부하고싶은마음이이걸보는순간없어지려고할것이다. 하지만걱정하지말자상속에대해두려움을갖고있다면이것도해결할수있다. 모든두려움은실제내부까지깊숙히들어가보려고하기때문에생기는것이다. 겉에서둘러보면서 너상속이구나 하고알아보기만하면된다. C++ 에서개체상속은많이들어봤고실제로해본사람도많다. 앞에서본 CPrettyButton역시 CButton에서상속받지않았나? 그럼개체상속과인터페이스상속은어떻게다른가? 간단한예로이해하자. 앞에서난우주정거장을컴포넌트로예를들었다. 이렇게생각할때개체상속은기본서비스를가지고있는우주정거장을가져와서화려한네온간판을달고내부인테리어를하고필요한음식과팔수있는연료를준비하는과정이라고생각하면된다. 그럼인터페이스상속은무엇인가? 인터페이스를다른우주선들과의도킹장치라고예를들었으니이것도거기에맞춰서생각해보자. 처음우주정거장은서비스는가지고있지만이것들을어디로통해제공해야하는지는모른다. 따라서연료서비스를위해연료공급호스도추가해야하고음식서비스를위해출입구도만들어야한다. 즉우주선의도킹장치를만들어야한다는것이다. 만약이것이없다면서비스는존재하지만우주선들은그서비스를사용하지못하게된다는것이다. 그런데여기서중요한것이있다이부분에서는실제도킹장치를만드는것은우주정거장에서해야한다. 바로인터페이스상속이라는말은도킹장치의설계도를얻어왔다는것이다. 지구인우주선의도킹장치의규격과외계인우주선의도킹장치규격을알아왔다는것이다. 그럼최소한한군데라도팔아서이윤을남기려면외계인용은만들지못하더라도지구인용은만들어야하지않겠나. 최소한굶어죽지않으려면말이다. 돈을더벌고싶다면외계인용도만들면금상첨화일것이다. 그리고컴포넌트는최소한 IUnknown 인터페이스만이라도가지고있어야한다. 이것은정거장을운영하기위한최소한의필수조건이라고생각하면되겠다. 그렇다고해서이것만가지고할수있는것은아무것도없다. 돈은벌수가없다는말이다. 따라서지구인용도킹장치하나는최소한만들어놔야한다. 도킹장치가없는정거장은정거장이아니다. 왜냐하면그것은우주를둥둥떠다니는고철덩어리에불과하기때문이
다. 자그럼이제정거장을만들어보자. COM의기본적인문법을모두무시하겠다. 이걸지키면코드가복잡해지고이해하는것조차도힘들어진다. 괜히사서고생을하지말자. 물론나중에다이해가되면당연히완전한문법으로만들것이다. 인터페이스의이름을붙일때우리는잠정적으로앞에 I 를붙인다. IUnknown, IClassFactory 등등이렇게된다. 이제아래의코드를함자세히살펴보자. 이게바로정거장이다. 하지만, 이코드가실제로돌아갈것이라생각하면큰일이다. 절대돌아가지않는다. 그냥 이해를돕기위해뺄건다뺀부분이다. Class C정거장 : public I지구인, public I외계인 public: C정거장 (); ~C정거장 () //IUnknown 메서드 HRESULT stdcall QueryInterface(REFIID riid, LPVOID* ppv); ULONG strcall AddRef(void) ULONG strcall Release(void) //I 지구인메서드 HRESULT stdcall 휘발류연료팔기 (short 금액 ); HRESULT stdcall 비빔밥팔기 (short 금액 ); //I 외계인메서드 HRESULT stdcall 미네랄연료팔기 (short 금액 ); HRESULT stdcall 미네랄식료품팔기 (short 금액 ); private short 매출 ; short 순익 ; DWORD m_cref; // 현재도킹하고있는우주선수
그런데자세히보면 IUnknown 에서는상속받지않았는데내부에선언되어있다. 그것은 I 지구인과 I외계인모두가 IUnknown에서상속받았기때문이다. 모든인터페이스는 IUnknown 에서상속받는다는것을잊지말자. 앞의코드에서처럼 IUnknown 인터페이스는 3개의메서드로구성되어있다. QueryInterface(REFIID riid, LPVOID* ppv); AddRef(void) Release(void) 이세가지다. 이걸보면인터페이스란것이그냥메서드선언의집합이아닌가하는생각도든다. 하지만, 이것은위험한생각이다. 이해는쉬울지몰라도그렇게해놓은이유가있는것이다. 설명은다음코드를보면알수있을것이다. 자세한설명은하지않겠다. 왠만한책에보면정말장황한설명이많이있으니참조하면좋을듯싶다. 이제남은것은각각의메서드들의실제구현이다. 이것을우리는 C++ 에서오버라이드라고 한다. 재정의라고우리말로번역해서말하는사람도있다. 그럼실제구현부분을보자. //IUnknown 메서드 HRESULT stdcall C정거장 ::QueryInterface(REFIID riid, LPVOID* ppv) I지구인과 I외계인인터페이스중하나를 ppv에넘겨준다 ; // 여기서는원하는인터페이스를돌려주면된다. // 성공유무를리턴한다. ULONG strcall C정거장 ::AddRef(void) 여기서는도킹해있는우주선수를하나증가시킨다 ; ULONG strcall C 정거장 ::Release(void) 여기서는도킹해있는우주선수를하나감소시킨다 ;
//I지구인메서드 HRESULT stdcall C정거장 :: 휘발류연료팔기 (short 금액 ) 매출을금액만큼증가시킨다 ; 순익을금액 /10 만큼증가시킨다 ; return S_OK; HRESULT stdcall C정거장 :: 비빔밥팔기 (short 금액 ) 매출을금액만큼증가시킨다 ; 순익을금액 /10 만큼증가시킨다 ; return S_OK; //I외계인메서드 HRESULT stdcall C정거장 :: 미네랄연료팔기 (short 금액 ) 매출을금액만큼증가시킨다 ; 순익을금액 /20 만큼증가시킨다 ; return S_OK; HRESULT stdcall C정거장 :: 미네랄식료품팔기 (short 금액 ) 매출을금액만큼증가시킨다 ; 순익을금액 /20 만큼증가시킨다 ; return S_OK; 자대충이해가갈것이다. 주석은필요가없을것같다. 코드내용자체가주석이아닌가?( 아니라고생각해도어쩔수없다. 더이상은내능력이상이다.) 인터페이스정의에는어떠한내부구현코드도없다. 실제구현은 C정거장에서한다. 왜그럴까? 정거장마다그내부사정에따라다르게구현되기때문이다. 원가를많이낮춘곳은순익이많이남을테고그렇지않은곳은그반대일것이다. 결국내부구현은정거장에서알아서할일이다.
여기서 IUnknown이왜중요한걸까? 잘생각해보자. 정거장은최대한많은돈을벌어야한다. 그런데만약우주선이한대도도킹해있지않은상태라고가정해보자. 괜히전기세낭비하면서내부를풀로가동해야할까? 전기를아껴야돈도그만큼더벌린다. 즉우주선이한대도없다면그때전기를아끼기위해꺼야한다. 기억이가물가물한사람을위해다시한번말하면우주선은어플리케이션에비교된다. 즉어플리케이션이 COM 컴포넌트를참조하고있는지확인하면서 COM 컴포넌트는스스로언제사라져야할지아는것이다. 그럼여기서쿼리인터페이스는무엇인가? 모든인터페이스가 IUnknown 에서상속받는다고했으니 I지구인인터페이스에도쿼리인터페이스메서드가있다. 이것은어디다쓰는걸까? 외계인이지구인출입구로왔다. 근데자신이쓰려는미네랄연료와미네랄식료품이없는것이다그래서묻는것이다. 외계인도킹장치는어디있냐고. 그럼지구인출입구는쿼리인터페이스메서드를사용하여외계인출입구위치를알아와서외계인에게가르쳐주는것이다. IUnknown 얼마나쉬운가? 왜있어야하는지의문도풀렸다. 책으로공부하면 IUnknown 며 칠을잡고있어도이놈이뭐하는놈인지잘모른다. 적어도난그랬다. 오늘가장중요한 IUnknown 에대해서알아봤다. 오늘은여기까지하자. 대부분소스를보는순간보기싫은마음이굴뚝같았을것이다. 이해한다. 나도그렇다. 담은것은또언제일지나도잘모르겠다. 아직까지는하루하루가지만내성격상언제또퍼질지모른다. 한번퍼지면 1주일은그냥잠수탄다. 기다리지마라. 그냥나오면나왔구나하고생각하면된다. 이글을읽었다는자체가마지막까지다읽었다는가정하에말한다. 내말을 100% 그대로받아들이면큰일난다는것이다. 언제또오늘처럼말을뒤집을지모른다. 모든것은이해하기위한과정일뿐이다. 잠온다.
e mail : icoddy@hotmail.com msn id : icoddy@hotmail.com 박성규