고급 COM 기술의활용 (II) (Using Advanced COM Techniques II.) 이번장에서는액티브 X 를이용하여여러가지객체나어플리케이션을개발할때부딪힐수있는문제점들과이들에대한해결책을제시할것이다. 그렇게방대한내용은아니지만, 소프트웨어를개발하다보면실제로아주간단한문제로골머리를싸맬때가매우많다. 이번장에서는이런문제들에대해서알아본다. 여기에서소개하는많은팁들은 Inprise 의뉴스그룹에서참고하였음을미리밝혀둔다. 참고로델파이로액티브 X 기술을구현할때의여러가지팁과 FAQ 에대한정보는 Conrad Herrman 이제공하는홈페이지에서많이얻을수있으므로이를참고하기바란다. 이홈페이지의 URL 은 Inprise 홈페이지의개발자정보에서찾을수있을것이다. Out of Process 논비주얼 COM 서버 여러가지 COM 서버를작성하면서지금까지작성한방법을곰곰히생각해보면, 결국에는 in-proc DLL 형태의액티브 X 라이브러리로만들거나현재의어플리케이션에 OLE 자동화객체를추가하는형태로만들었다. 이런식으로어플리케이션프로젝트에자동화객체위저드를이용해서추가한경우에는어떤방식으로든어플리케이션의윈도우가생성되고, 메시지루프가윈도우에의해사용된다. 예를들어, out-of-process COM 서버를만들면언제나좋든싫든폼이하나생성되어버린다. 이럴때에물론 OnCreate 이벤트핸들러에서폼을숨겨버리면그만이지만, 불필요한낭비임에는틀림이없다. 이런경우에윈도우가생성되지않고, in-proc 서버가아닌 out-of-process 서버를작성해서사용하고싶은경우에는어떻게해야할까? 이런경우에는 Forms 유닛의 Application 객체를변경해서사용하되비주얼인터페이스를사용하지않게하는방법이있다. 이를위해서는다음의유닛을사용하면되는데, 이유닛은 Inprise 의뉴스그룹에서공개된유닛인데, 작성자에대한정보를기록해두지않은탓에밝히지못했음을미리말해둔다. 이유닛으로교체한다음에프로젝트파일의 Application.Initialize 와 Application.Run 구문을 ServerApp.Initialize 와 ServerApp.Run 으로대치하면된다. 또한, 어플리케이션에서 Application.ProcessMessage 루틴이사용되는부분이있다면 ServerApp 에대한내용으로변경해야하는것은물론이다. unit ServApp;
interface type TServerApp = class(tobject ) protected procedure DoTerminate(var Shutdown: Boolean); public function ProcessMessages: Boolean; procedure Initialize; procedure Run; var ServerApp: TServerApp; implementation uses ComServ; function TServerApp.ProcessMessages: Boolean; var Msg: TMsg; Result := true; while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do if (Msg.Message = WM_QUIT) then Result := false else TranslateMessage(Msg); DispatchMessage(Msg);
procedure TServerApp.DoTerminate(var Shutdown: Boolean); if Shutdown and not CallTerminateProcs then Shutdown := False; CallTerminateProcs 루틴은델파이의 COM 시스템을종료하는역할을한다. procedure TServerApp.Initialize; if (ComServer.StartMode = smstandalone) then Halt; if (InitProc <> nil) then TProcedure(InitProc); ComServer.OnLastRelease := ServerApp.DoTerminate; InitProc 은 COM 서버시스템을초기화하기위해서필요하다. 즉, 이부분이핵심이라고할수있는데, COM 서버가 stand-alone 으로시작하지못하도록하고마지막 OnLastRelease 이벤트에 DoTerminate 메소드를실행하도록대입하여 COM 서버가종료할때실행되도록한다. procedure TServerApp.Run; while ProcessMessages do; Run 메소드는간단히 ProcessMessage 루틴을반복하도록하면폼이필요없이 out-ofprocess COM 서버를쉽게구현할수있다. initialization ServerApp := TServerApp.Create; finalization ServerApp.Free; end.
구현한내용을보면무척간단하다는것을알수있을것이다. 별거아닌것같지만, 필요에의해서이런유닛을찾아다녀보면막상쓸만한것이없는경우가많고, 그렇다고직접작성하려하면막막한경우가많다. 이주제역시해결방법을보면별것아니지만, 막상만들어보려고하면쉽지않은것이다. 의외로많이사용할가능성이있는해결방법이므로꼭기억했다가사용하기바란다. 가변형변수와스트림간통신 액티브 X 기술을이용하여클라이언트 / 서버어플리케이션을제작하다보면, 간혹스트림을통해바이너리파일을전송할필요가있을때가있다. 이럴때에는 DCOM 에서지원하는데이터형에 TStream 클래스가호환되지않기때문에가변형변수를사용하여전송을해야한다. 즉, 다시말하면서버측에서는파일을메모리스트림에읽어오고, 이를가변형변수로형변환을한뒤에클라이언트로전송하고, 클라이언트에서는이렇게넘어온가변형변수를메모리스트림으로변경하면된다. 다음에스트림과가변형간의형변환을담당하는루틴을소개한다. function StreamToVariant(Stream:TMemoryStream): Variant; var Data: Pointer; Result := VarArrayCreate([0, Stream.Size - 1], varbyte); Data := VarArrayLock(Result); try Move(Stream.Memory^, Data^, Stream.Size); finally VarArrayUnlock(Result); function VariantToStream(V: Variant): TMemoryStream; var Data: Pointer; Result := TMemoryStream.Create; Data := VarArrayLock(V);
try Result.WriteBuffer(Data^, VarArrayHighBound(V, 1) + 1); finally VarArrayUnlock(V); Result.Seek(0, sofrombeginning); IOleClientSite 인터페이스의활용 IOleClientSite 인터페이스를이용하면컨테이너에임베드된객체의정보를얻을수있다. 이인터페이스를얻기위한함수를다음과같이구현할수있다. function ClientSite(obj: IUnknown): IOleClientSite; var Site: IOleClientSite; OleObj: IOleObject; if (obj.queryinterface(ioleobject, OleObj) = S_OK) and (OleObj.GetClientSite(Site) = S_OK) then Result := Site else Result := nil; obj 파라미터는액티브 X 컨트롤을지정한다. 예를들어, 다음과같이사용할수있다. type TButtonX = class(tactivexcontrol)...... ( 중략 ) procedure TButtonX.Click; var
Site: IOleClientSite; Site := ClientSite(Self); 액티브 X 컨트롤을개발한뒤에이를실제로사용하게되면, 실행되는모드가런타임인지아니면디자인타임인지를구별할필요가있을때가있다. 이를파악하기위해서는컨트롤의컨테이너의 UserMode 앰비언트프로퍼티를이용해야한다. 이때에도앞의 ClientSite 함수를이용하면컨테이너의모드를쉽게알수있다. 다음함수는컨테이너가디자인모드이면 True 를반환한다. function IsControlInDesignMode(obj: IUnknown): Boolean; var Mode: Boolean; try Mode := not ((ClientSite(obj) as IAmbientDispatch).UserMode); except Mode := False; Result := Mode; Safe for scripting/safe for initializing 의지원 safe for scripting 과 safe for initializing 이란코드사인을통한기본적인보안과함께사용될수있는 Object Safety 라는 2 차보안을나타내는용어이다. 컨트롤을 HTML 페이지에서다운로드하면페이지가자바스크립트나 VB 스크립트등을이용할수도있고, 컨트롤에대한프로퍼티값들이포함된다. 이때제작한컨트롤의일부메소드나프로퍼티를잘못사용할때클라이언트컴퓨터에나쁜영향을미칠수있다면이러한메소드나프로퍼티가잘못사용되지않도록해야할것이다. 컨트롤이 safe for scripting 으로표시된다는의미는객체가 OLE 자동화를통해안전하게자동화될수있다는의미이다. 즉, 객체를자동화하는각종스크립트에대해서클라이언트컴퓨터에나쁜영향을주지않는다는의미이다. 그리고, safe for initializing 으로표시된다는의미는객체의프로퍼티나데이터가어떤지속성저장소 (persistent storage) 에서도저장되었다가복원될수있다는의미이다. 이들자체에대한보다자세한사항은마이크로소프
트에서제공하는자료들을참고하기바란다. 그렇다면컨트롤에 safe for scripting/initializing 을표시하는방법에대해서알아보도록하자. 여기에는크게 2 가지방법이존재하는데첫번째방법은컨트롤이언제나스크립팅과초기화에안전하다고표시하는것이고, 다른하나는컨트롤이 safe mode 와 unsafe 모드를전환할수있도록표시하는방법이다. 1. 컨트롤에대한적절한레지스트리키를설치한다. 컨트롤이설치될때레지스트리를변경하는방법에대해서는클래스팩토리를오버라이드하여구현한다는것을이미앞에서설명한바있다. 그러므로, 해당되는액티브 X 컨트롤의클래스팩토리클래스를오버라이드하여 safe for scripting/safe for initialization 을표시하도록구현하면된다. 다음의유닛에서이들클래스팩토리를상속하여구현하였다. 이유닛은 Conrad Herrman 이 DAX FAQ 를통해서공개한유닛임을미리밝혀두며, 소스코드에대한설명은이미 29 장에서 UpdateRegistry 메소드를오버라이드하여구현하는방법에대해설명한바있기때문에생략하겠다. unit SafeFactory; interface uses ComObj, ActiveX, AXCtrls; const CATID_SafeForScripting: TGUID = '{7DD95801-9882-11CF-9FA9-00AA006C42C4}'; CATID_SafeForInitializing: TGUID = '{7DD95802-9882-11CF-9FA9-00AA006C42C4}'; type TSafeActiveFormFactory = class(tactiveformfactory) procedure UpdateRegistry(Register: Boolean); override; TSafeActiveXControlFactory = class(tactivexcontrolfactory) procedure UpdateRegistry(Register: Boolean); override; implementation
procedure AddSafetyKeys(const ClassID: TGUID); var ClassKey: string; ClassKey := 'CLSID\' + GUIDToString(ClassID); CreateRegKey(ClassKey + '\Implemented Categories', '', ''); CreateRegKey(ClassKey + '\Implemented Categories\' + GUIDToString( CATID_SafeForScripting), '', ''); CreateRegKey(ClassKey + '\Implemented Categories\' + GUIDToString( CATID_SafeForInitializing), '', ''); procedure RemoveSafetyKeys(const ClassID: TGUID); var ClassKey: string; ClassKey := 'CLSID\' + GUIDToString(ClassID); DeleteRegKey(ClassKey + '\Implemented Categories\' + GUIDToString( CATID_SafeForInitializing)); DeleteRegKey(ClassKey + '\Implemented Categories\' + GUIDToString( CATID_SafeForScripting)); DeleteRegKey(ClassKey + '\Implemented Categories'); {TSafeActiveFormFactory} procedure TSafeActiveFormFactory.UpdateRegistry(Register: Boolean); if Register then AddSafetyKeys(ClassID); inherited UpdateRegistry(Register); end else RemoveSafetyKeys(ClassID); inherited UpdateRegistry(Register);
{TSafeActiveXControlFactory} procedure TSafeActiveXControlFactory.UpdateRegistry(Register: Boolean); if Register then AddSafetyKeys(ClassID); inherited UpdateRegistry(Register); end else RemoveSafetyKeys(ClassID); inherited UpdateRegistry(Register); end. 이클래스팩토리를이용하기위해서는액티브 X 라이브러리의유닛의 uses 절에 SafeFactory.pas 유닛을추가하고, initialization 섹션을다음과같이클래스의이름만변경해주면된다. initialization TSafeActiveXControlFactory.Create(ComServer, TSampleActiveX, TSampleControl, Class_SampleActiveX, 1, '', 0, tmapartment); end. 2. 컨트롤에서 IObjectSafety 인터페이스를구현하는방법 IObjectSafety 인터페이스를구현하면컨트롤이 safety 를요구하지않는컨테이너에서동작할때에는 unsafe 메소드나프로퍼티를사용할수있게할수있다. 그렇지만, IE 와같이보안을요구하는컨테이너에서는 IObjectSafety 인터페이스를이용하여컨트롤이 safe mode 로전환하도록요구하고, 모든 unsafe 메소드와프로퍼티를사용불가능하게만들수있다.
델파이폼을액티브폼으로전환하기 델파이폼을액티브폼으로변경하는요령에대해서설명하고자한다. 많은경우에있어서처음부터액티브폼으로개발하는경우도있겠지만, 이미완성된어플리케이션을액티브폼으로변경하는작업을하고자하는경우도많을것이다. 이럴때에는다음과같은방법을이용하여액티브폼으로변경할수있다. 폼에있는모든컴포넌트를선택하고이를복사했다가액티브폼에붙여넣는방법 이방법은컴포넌트를폼에옮기는데에는큰문제가없지만, 컨트롤과연결된코드는복사 되지않기때문에이들을적절하게설정하는것이가장중요한작업이된다. 컴포넌트템플릿을활용하는방법 폼에있는모든컴포넌트를메뉴를선택하고 Component Create Component Template 메뉴를선택하여템플릿을생성하면 VCL 컴포넌트팔레트에 Template 탭이생성되면서컴포넌트로등록될것이다. 액티브폼을열고이컴포넌트를폼에떨어뜨리면된다. 이방법의장점은컨트롤과함께연결된코드가같이복사된다는점이다. 직접 TForm 클래스를액티브폼으로변경시키는방법 앞서설명한방법과같이컨트롤을복사하지않고, 코드를수정함으로써액티브폼으로변경하는방법이다. 이방법의장점은표준델파이어플리케이션으로일단개발과테스트를마치고간단히액티브폼버전으로변경하여사용할수있다는점이다. 변경원칙은다음과같다. 이방법은 Conrad Herrman 이공개한것으로꽤유용하게적용할수있다. 1. 표준폼어플리케이션을디렉토리에저장한다. 2. 액티브폼을저장할서브디렉토리를생성하고, 새로운액티브폼프로젝트를생성하여저장한다. 3. 액티브폼프로젝트에서프로젝트관리자를선택하고표준폼어플리케이션프로젝트가저장된디렉토리에서모든폼과데이터모듈을프로젝트에추가하도록한다. 4. 액티브폼의 OnCreate 이벤트핸들러를다음과같이작성한다. procedure TActiveForm1.FormCreate(Sender: TObject);
// 이코드는정상적인델파이 TForm 인자식폼을생성한다. ChildForm := TForm1.Create(Self); ChildForm.Parent := Self; ChildForm.Align := alclient; ChildForm.BorderStyle := bsnone; ChildForm.Visible := True; 5. uses 절에서폼의유닛파일을추가하고, 자식폼을 public 섹션에추가한다. type TActiveForm1 = class...... public ChildForm: TForm1;... 폼을컴파일하고테스트한다. 액티브폼과 IE 4.0 델파이의액티브폼은일종의액티브 X 컨트롤이지만, 의외로 IE 4.0 과충돌하는경우가많다. 이문제는델파이의액티브폼위저드에도약간의문제가있지만 IE 4.0 자체가표준과는벗어난여러가지문제점을많이안고있기때문이기도하다. 그러므로, 이문제를완전히해결할수는없지만몇가지고려할점들에대해서논의하고자한다. 먼저델파이 3 에서문제가되었던것중에서델파이 4 에서해결된것들에대해서알아보고, 계속해서고려해야할점을알아보도록하자. 1. 쓰레딩모델 델파이 3 는기본적으로단일쓰레드모델만을지원했기때문에, IE 4.0 의여러인스턴스를메모리에띄울때충돌이일어나는경우이다. 이문제는델파이 4 에서쓰레딩모델로 apartment 쓰레딩모델을선택할수있게되면서많이해결되었다. 보통디폴트로이모드를사용하게되지만, IE 4.0 과의충돌이있다면먼저쓰레딩모델을검토하기바란다.
2. 액티브폼내부컨트롤의포커스설정문제 여러개의컨트롤을가지고있는액티브폼에서하나의컨트롤을클릭하여포커스를주고, 다른어플리케이션을활성화시켰다가다시 IE 4.0 을활성화하면이전에포커스를가졌던컨트롤이포커스를잃게된다. 이문제는액티브폼자체가 UI-active 컨트롤이기때문이다. 그러므로, 프레임이활성화되면컨트롤이 IInPlaceActiveObject.OnFrameWindowActivate 메소드가호출되는데델파이 3 의위저드에서는이메소드가단지 InPlaceActivate(True) 메소드만을호출하기때문에, 컨트롤이이미 UI-active 한경우에는아무런영향을미치지못한다. 그러므로앞서설명한문제를해결하기위해서는폼의활성화된자식컨트롤에포커스를설정해야하는데델파이 4 에서이점이수정되었다. 3. 탭 / 백스페이스키가제대로동작하지않을때 IE 4.0 에서액티브폼을띄운뒤에탭 / 백스페이스키를이용할때제대로동작하지않는문제가발생하는경우가있다. 이문제를해결하기위해서는액티브폼의타입라이브러리를동작시키고 TabsOn 이라는새로운메소드를인터페이스에추가한다. 이메소드의선언은 procedure TabsOn 으로특별한파라미터나반환값은지정할필요가없다. 그리고, 이메소드에대한 ID 를부여한다. 그리고나서액티브폼을구현한유닛의 protected 섹션에선언되어있는 TabsOn 선언부를다음과같이 public 섹션으로옮긴다. public procedure TabsOn; safecall; 그리고, TabsOn 프로시저의구현부분을다음과같이수정한다. procedure TActiveFormX.TabsOn; (ComObject As IOleInPlaceActiveObject).OnFrameWindowActivate(True); 그리고, 다소귀찮기는하지만폼에있는모든컨트롤의 OnClick 이벤트에 TabsOn 을호출하도록추가하여액티브폼을클릭할때마다 UI 를활성화시키도록한다. 다른해결방법으로는 Conrad Herrman 이제시한방법이있는데, 그의해결책은폼에 WM_MOUSEACTIVATE 메시지에대한핸들러를설치해서, 이메시지가발생할때마다 UI
를활성화하는것이다. 이렇게하면, 핸들러가설치된자식컨트롤들이클릭될때마다활성화되어제대로포커스를가지게된다. 메시지핸들러는다음과같이구현한다. 먼저다음과같이핸들러를선언하고이를구현하면된다. procedure WMMouseActivate(var msg: TWMMouseActivate); message WM_MOUSEACTIVATE; ( 중략 ) procedure TActiveFormX.WMMouseActivate(var msg: TWMMouseActivate); inherited; if (msg.result = MA_ACTIVATE) or (msg.result = MA_ACTIVATEANDEAT) then DoUIActivate; procedure TActiveFormX.DoUIActivate; if (ComObject <> nil) then (ComObject as IOleObject).DoVerb( OLEIVERB_UIACTIVATE, nil, nil, 0, 0, PRect(nil)^); 이방법은대부분의경우에적용되지만 RichEdit 컨트롤에서는사용할수없다. 이경우에는 OnClick 메소드를이용한방법을사용해야한다. 액티브폼에서탭키를누르면실제로컨트롤에서이동은일어나지만, 이를실제로는제대로보여주지못하기때문이다. 또한, UI 가활성화되어도자신컨트롤에포커스를제대로설정하지못하기때문에이런현상이나타나는것이므로앞서와같은방법으로이문제를해결해야한다. 액티브 X 서버배포에관한문제 몇가지인터페이스를구현한액티브 X 서버를배포할때에는배포할때염두에두어야할
몇가지사항이있다. IStrings, IProvider, IDataBroker 인터페이스를사용하거나델파이폰트, 색상, 문자열, 그림프로퍼티페이지를사용한경우에는볼랜드의표준 VCL 타입라이브러리를같이배포해야한다. 이라이브러리는 STDVCL32.DLL 라이브러리와 STDVCL32.TLB 라고하는타입라이브러리로존재한다. 이들은모두윈도우의시스템디렉토리에위치하며, 모두시스템레지스트리에등록되어야한다. 액티브 X 컨트롤의코드다운로드문제 29 장에서도설명했듯이액티브 X 컨트롤을배포할때 Web Deployment options 대화상자에서적절한정보를설정하고, Web Deploy 명령을선택하면되는데, 막상홈페이지에올려놓고이홈페이지를클라이언트에가서브라우저를띄우고접근하면커다란붉은 X 자만볼수있는경우가많다. 제작한액티브 X 컨트롤을웹브라우저에띄우기위해서 Web Deploy 명령을선택하면 HTML 문장에 <OBJECT> 태그가추가되면서다음과같이액티브 X 컨트롤에대한정보가추가된다. <OBJECT classid="clsid:29d37f03-f02f-11d0-acb2-0080c7316f20" codebase="http://www.samplesite.com/mycontrol.ocx#version=1,0,1,0" width=350 height=250 align=center hspace=0 vspace=0 > </OBJECT> 이태그에서 #version 부분은옵션인데, 이내용이빠지면버전에상관이없다는의미이다. 실제액티브 X 컨트롤을지칭하는것이 ClassID 이다. 그러므로, IE 가지정된 ClassID 의컨트롤이클라이언트에설치되어있으면, 지정된버전과일치하는것인지알아보고로컬버전이일치하면컨트롤을생성하기위해로컬복사본을이용하게된다. 만약 HTML 페이지에서요구하는버전이현재설치된것보다새버전이거나 ClassID 에지정된컨트롤이아직설치되지않은경우에는 IE 가컨트롤을생성하기전에컨트롤을다운로드하고이를설치하게된다. 이때코드베이스는로컬기계의 Windows/OCCache 디렉토리나서브디렉토리에복사하
는데이때 URI 가 HTTP( 디폴트 ) 를이용하거나, FTP, FILE URI 등을이용할수있다. 여기서원격서버를찾을수없거나, 로컬디스크의디스크공간이보족한경우, 그리고 codebase 의이름이잘못설정된경우 ( 서버가대소문자를가리는경우에흔함 ) 에이과정이실패할수있다.. 액티브 X 컨트롤을다운로드하기전에 IE 가코드 signature 를확인하게된다. 여기에서꽤많은브라우저의설정이잘못된경우에액티브 X 컨트롤을볼수없다. 보안레벨을 High 로설정한경우에는 IE 가컨트롤이코드사인되지않았으면설치를하지않는다. 보안레벨이 Medium 으로설정되면설치할것인지물어보는대화상자를보여주고, 컨트롤을다운로드하게된다. 보안레벨이 Low 로설정되면코드사인되지않은컨트롤도바로설치된다. 이런과정을거쳐다운로드된 codebase 는 Windows/OCCache 디렉토리에설치된다. 설최되는 codebase 는 Object 택그의 CODEBASE 태그에의해그종류가결정된다. 만약파일이 DLL 인경우 ( 보통확장자.OCX) 파일하나를가리키며, 파일이.CAB 인경우에는여러파일이포함되어있다. 그리고, codebase 가.INF 파일인경우에는 codebase 를구성하는파일의리스트를설명한다. DLL 인경우에는설치과정에서 DLL 파일을로드한뒤에 DllRegisterServer 함수를호출하여컨트롤을생성하게된다. 이과정에서 DLL 파일이 LoadLibrary 함수에의해로드되지않을수가있는데이것은 DLL 이라이브러리 DLL 이나델파이패키지, 시스템 DLL 과같은다른파일에의존적인데이파일들에접근할수없는경우이다. DLL 이로드되지만초기화에실패하는경우도있는데, 이것은환경설정에도문제가있을수있지만유닛의초기화섹션에서예외가발생하기때문일수도있다. 또다른문제로는컨트롤이제대로등록되지않는경우에발생할수있다. DLL 이등록되지않는원인으로가장흔한것은 NT 클라이언트를사용할경우에사용자권한이레지스트리를변경할수있는권한이없는경우이다. 컨트롤이이런과정을거쳐서설치되고생성되면 IE 는컨트롤의인스턴스를생성하려고시도한다. 이과정에서문제가발생하는이유로는 HTML 파일에서지정된 ClassID 가잘못지정된경우와메모리나리소스가부족한것이원인일수있다. DCOM 환경설정 COM 객체와액티브 X 컨트롤과액티브폼객체를훌륭하게생성하고, 이를이용하여인트라넷이나인터넷을통해서사용하려고할때문제가되는이유중에서가장커다란비중을차지하는것은뜻밖에도 DCOM 의환경설정을제대로하지못했기때문인경우가많다. 그러면, DCOM 클라이언트 / 서버의환경설정에대해서중요한사항을알아보도록하자. 서버의환경설정
DCOM 의서버는사용자레벨 (user level) 과공유레벨 (share level) 접근이가능하도록환 경설정을할수있다. 이설정을변경하기위해서는제어판의네트워크애플릿을실행하고, 다음과같이엑세스제어페이지에서설정을변경할수있다. 만약윈도우 NT 서버를이용한사용자인증이가능하다면, 사용자엑세스제어를선택하고, 적절한 NT 서버를지정하여사용자와그룹을이용하도록하면된다. NT 서버와관계없이 DCOM 을이용하기위해서는공유엑세스제어를선택하도록한다. 윈도우 95 에서 DCOM 을사용하기위해서는반드시 DCOM for Win95 를설치해야하는데이설치파일은 http://www.microsoft.com/com/dcom95/download.htm 에서구할수있다. 그렇지만필자의생각으로 DCOM 을사용하기위해서는윈도우 NT 4.0 SP 3, 윈도우 98 이상에서사용하기를권하고싶다. 사용자엑세스제어를선택한경우에는 DcomCnfg.exe 유틸리티를실행하고, 이유틸리티의기본보안 (Default Security) 페이지를선택하고, 기본값편집 (Edit Default) 버튼을클릭하면다음과같이액세스권한 (Access Permissions) 대화상자가나타날것이다.
이대화상자에서 추가 버튼을클릭하면다음과같이서버에서관리하고있는모든사용 자목록이나타나는데, 서버어플리케이션에접근해야하는모든사용자들에게접근을허 용하도록설정한다. 여기에서 세계 를선택하면모든사용자에게모두사용가능하도록설정하는것이다. 윈도우 NT 의경우에는다소화면이다르게나타날수있는데 세계 에해당되는것은 Everyone 이다. 참고로필자는윈도우 NT 5.0 영문베타를사용하고있는관계로한글 NT 의해당이름을알지못하므로한글 NT 를사용하고있는독자들은한글로해당되는이름을찾아보기바란다. 이런방법을사용하지않고, 서버어플리케이션을설치하고각어플리케이션마다접근허용을다르게설정하는방법도있다.
이럴경우에는 DCOM 구성등록정보윈도우의응용프로그램탭에서어플리케이션을선 택하고 등록정보 버튼을클릭하면다음과같이이어플리케이션에대한정보를변경할수 있는대화상자가나타날것이다. 여기에서 보안 탭을선택하면앞에서전체적으로엑세스권한을설정했던것과동일한대화상자들이나타날것이다. 이를이용하여각어플리케이션별로접근레벨을다르게설정할수있다. 그리고, 이예에서는나타나지않았지만 응용프로그램실행 탭이있는경우에는이탭에서선택할수있는체크박스가 데이터가있는컴퓨터, 현재컴퓨터, 컴퓨터선택 의 3 가지가나타나는데, 여기서 현재컴퓨터 박스는선택하면안된다. 이를선택하면현재컴퓨터에있는서버만실행이가능하므로 DCOM 으로설정한의미가없다. 그리고, 현재컴퓨터 와 컴퓨터선택 이모두선택된경우에는현재컴퓨터가우선한다. 그러므로, DCOM 서버로작성한서버프로그램이서버에서원격으로실행되게하려면 컴퓨터선택 탭을선택하고서버의 DNS 주소, IP 주소, 호스트이름등을지정하면된다. 참고로윈도우 NT 에서 DComConfg.exe 유틸리티를사용할경우에는 Identity, Endpoints, HTTP 탭이더있는데이중에서 Identity 탭을선택하고 The interactive user 로설정하는것이좋다.
기본적인설정이끝났으면 NT 에서사용자관리자 (User Manager) 를실행하여, Guest 계정을선택하고이계정의정보에서 Accound Disabled 체크박스가선택되어있으면이를제거해야한다. 공유엑세스제어를선택한경우에는레지스트리값을변경할필요가있다. HKLM\Software\Microsoft\OLE 키의내용중에서 EnableRemoteConnect = "Y", LegacyAuthenticationLevel = 1 로설정하도록한다. 이작업은사용자엑세스제어를사용할때에는 DcomCnfg.exe 유틸리티를통해서수정이가능하기때문에매뉴얼로키를변경할필요가없다. DcomCnfg.exe 유틸리티에서는기본등록정보탭에서인증수준을 없음 으로선택하고, 기본보안탭에서 원격연결사용 체크박스를선택하면된다 ( 디폴트로선택되어있다 ). 그리고, 델파이를이용하여작성한어플리케이션중에서 MIDAS 와같이필요한파일이더있는경우에는해당파일을 System 또는 System32 디렉토리에복사하도록한다. 대표적인파일로는 DBCLIENT.DLL, STDVCL32.DLL 파일등이있다. 이제서버어플리케이션을적당한로컬드라이브에복사하고, 필요에따라서 BDE 나 SQL Link 등을설치하고필요한앨리어스등을생성한다. 서버어플리케이션을한번실행하면레지스트리에등록되므로쉽게사용할수있고, inprocess 서버는 DCOM 에서사용되지않는다. 만약 DCOM 95 1.0 버전을이용하고있다면, RPCSS.EXE 의단축아이콘을시작폴더에위치시키는것이좋다. 이런환경설정의변경이효력을발생하려면시스템의재시작이필수적이다. 이제서버어플리케이션을실행하면클라이언트와의연결이가능하다. 클라이언트의환경설정 서버에비해클라이언트의환경설정은더간단하다. 먼저, 윈도우 95 를사용하는독자라면앞서소개한사이트에서 DCOM95 를다운로드받아설치하기바란다. 기본적인설정방법은서버와동일하므로앞의내용을참고하기바란다. 공유방법으로공유엑세스제어를사용하는클라이언트인경우에는서버에서와마찬가지로레지스트리의내용을편집할필요가있다. HKLM\Software\Microsoft\OLE 키에서 LegacyAuthenticationLevel = 1 로설정한다. 설정이끝났으면, 클라이언트어플리케이션을설치하고실행하면된다. 델파이로작성한어플리케이션을사용하는경우에는경우에따라서 DBCLIENT.DLL, STDVCL.DLL 파일을윈도우시스템디렉토리에복사하거나, BDE 나 SQL Link 를설치할필요가있다. 인터넷이용을위한 DCOM 설정
DCOM 을인터넷과방화벽 (firewall) 을넘어서사용할수있도록설정하기위해서는다음과 같은사항을고려해야한다. 1. 서버와클라이언트에서모두 DcomCnfg.exe 유틸리티를실행하여인증수준을 없음 으로설정한다. 2. 레지스트리의내용을다음과같이수정한다. HKLM/Software/Microsoft/Rpc/Internet PortsInternetAvailable="Y" UseInternetPorts="Y" Ports="3000-4000" 3. 135 번포트를열고방화벽을넘도록한다. 4. IP 주소번역을 Disable 한다. DCOM 에대한 HTTP 터널링 (tunneling) 은 NT SP4 에서부터사용할수있게되었다. 보다자세한내용은마이크로소프트에서제공하는정보를참고하기바란다. 에러메시지정리 에러메시지 원인 DCOM not installed DCOM 이설치되지않았다. 1) 레지스트리의 EnableRemoteConnect 값이 N 으로설정된경우 2) 서버어플리케이션이실행되지않은경우 Server execution failed 3) 서버가로컬드라이브에존재하지않는다. 4) 서버객체에접근하는사용자의권한이미달된경우 5) 레지스트리의서버패스가지나치게긴경우 6) DCOMCNFG.exe 에서의어플리케이션위치설정이틀린경우 Class not registered 서버어플리케이션이아직등록되지않음 1) RPCSS 가서버에서실행되지않음 RPC server is unavailable 2) 레지스트리의 EnableRemoteConnect 값이 N 으로설정된경우 3) 잘못된 RemoteServer, ComputerName 4) TCP/IP 설정이잘못된경우 1) 사용자접근레벨로설정되지않은경우 Interface not supported 2) Permission 이 Everyone 에게허용되지않은경우 3) 레지스트리의 LegacyAuthenticationLevel 값이설정되지않은경우
4) Guest 계정이 disable 된경우 5) 클라이언트가클라이언트기계에인터페이스를등록하지않고 vtable 바인딩을시도하는경우 Access is denied 1) DCOM 보안설정이적절치못한경우 2) 서버어플리케이션이로컬드라이브에없는경우 정리 (Summary) 이번장에서는액티브 X 기술을이용하여어플리케이션이나객체를개발하면서만날수있는여러가지문제점과그해결책에대해서알아보았다. 여기에나열한여러가지팁들보다실제로구현과정에들어가면예상외로많은난관에부딪히게된다. MS 에서는나름대로분산환경을지원하기위한표준화방안으로 DCOM 을제시한것이지만, 실제로이를활용하여분산환경을구축하는데에는아직도많은어려움이있으며, 개선해야할부분이많은것으로생각된다. 그렇지만, 앞서나가는개발자가되기위해서는이러한문제점들을파악하고나름대로의해결책을찾으려고노력하는자세가필요할것이다.