|
스마트클라이언트 정보 |
[1] |
|
등록일:2008-03-28 09:13:37 (0%) 작성자: 제목:IE에서 닷넷 스마트 클라이언트 개발2-인터넷 익스플로러와 연동하기3 |
|
|
DWebBrowserEvents 이벤트 연결 결
국 우여곡절 끝에 IWebBrowser2 인터페이스까지 얻게 되었다. 필자가 C#으로 새롭게 정의한 IWebBrowser2
인터페이스로 형변환된 개체는 SHDocVw.IWebBrowser2로 형변환한 것과 동일하게 사용할 수 있다.
SHDocVw.dll을 사용하지 않은 관계로 우리가 직접 구현한 C# IWebBrowser2 인터페이스에는 한 가지 문제를
지니고 있는데, 웹 브라우저에 이벤트를 연결할 수 있는 방법이 모호하다는 것이다. SHDocVw.dll 참조에서는 적절한 RCW
개체가 tlbimp.exe에 의해 ‘Interop.SHDocVw.dll’로 제공되므로 그걸 사용하면 문제가 없었지만, 스마트
클라이언트에서만큼은 SHDocVw.dll을 참조하여 구현하게 되면 오류가 발생하므로 그런 서비스는 받을 수가 없는 상태이다. 여
기서 예상할 수 있겠지만 tlbimp.exe가 산출해 준 ‘Interop. SHDocVw.dll’대로 구현을 한다면 자연스럽게
이벤트를 delegate로 연결할 수 있을 것이다. 하지만 아쉽게도 필자 나름대로 잠시 시간을 내어
‘Interop.SHDocVw.dll’과 맞추려는 시도를 했지만 성공하진 못했다. 독자들 중에서 이에 대해 시도할 계획이 있다면
참고자료 ③을 참고하기 바란다. 필자 역시 언젠가는 재도전을 염두에 두고, 중간 단계의 시도를 TreeEvent.cs에 실어
놓았는데 지면 제약상 ‘이달의 디스켓’으로 제공하니 그 코드로부터 시작한다면 수고가 줄어들 것이다. 그건 그렇고 닷넷에서
제공해 주는 RCW를 사용할 수 없다고 해서 구현이 불가능한 것은 아니다. 역시 unmanaged 시절에 익힌 것처럼 COM
이벤트 방식으로 얼마든지 구현이 가능하다. 잠시 COM에 낯선 독자들을 위해 COM 이벤트 모델을 살펴보고 지나가겠다.
<그림 1>을 보면서 다음의 설명을 이해하기 바란다.
<그림1>COM에서 이벤트 구현
보
는 바와 같이 COM 개체는 이벤트를 발생하는 인터페이스를 구현한 다음 그 이벤트 인터페이스를 나열할 수 있는
IConnectionPoint Container를 구현해야 한다. 클라이언트 측에서는 바로 그
IConnectionPointContainer 인터페이스를 QueryInterface로 조회하게 되고,
FindConnectionPoint 메쏘드를 통해 연결하고자 하는 이벤트 인터페이스에 해당하는 GUID를 넘겨주어 그 이벤트
인터페이스에 대한 연결 지점을 담당하는 IConnectionPoint 인터페이스를 또 다시 구해 올 수 있다. 클라이언트
측에서는 이벤트 인터페이스를 상속받은 클래스를 정의하고 그 클래스의 인스턴스를 만든 다음
IConnectionPoint::Advise에 인스턴스 포인터를 넘겨주면 이른바 ‘이벤트를 거는(sink)’ 작업이 끝나게
된다. 이후로는 COM 서버에서 이벤트가 발생하면 Advise에 전달되었던 클라이언트 측에 구현된 클래스의 포인터를 통해 해당
메쏘드를 호출해 주는 것이 바로 COM 이벤트 구조이다. 한마디로 COM 이벤트는 ‘양방향 통신’을 하게 된다. 앞의 예를
스마트 클라이언트 예제와 비교해 보자. <그림 1>에서 ‘클라이언트’는 우리가 구현한 TreeControl이 될
것이고, ‘Connectable Object’는 웹 브라우저가 될 것이다. 그러면 웹 브라우저로부터
IConnectionPointContainer 인터페이스를 조회한 후 그 인터페이스에서 제공해 주는
FindConnectionPoint 메쏘드를 사용해 웹 브라우저가 구현한 ‘DWebBrowserEvents2’ 인터페이스에 대한
IConnectionPoint 인터페이스를 구할 수 있다. 이후 이벤트를 걸고 싶을 때는
IConnectionPoint::Advise 메쏘드를 호출하면 되고, 이벤트 해제를 하고자 할 때는
IConnectionPoint::Unadvise 메쏘드를 호출해 주면 되는 것이다. 이를 C# 코드로 표현하면 다음과
같은데, 보는 것처럼 간단하게 이벤트를 연결할 수가 있다. 참고로 IConnectionPointContainer 인터페이스는
IServiceProvider와는 달리 닷넷 BCL(Base Class Library) 차원에서
UCOMIConnectionPointContainer라는 인터페이스로 제공되고 있으며, IConnectionPoint는
UCOMIConnection Point라는 이름으로 동일한 구조의 메쏘드까지 포함해 제공하기 때문에
IServiceProvider처럼 개발자가 구현해 줄 필요가 없다.
// DWebBrowserEvents에 대한 GUID 값 Guid DEventsGuid = new Guid( “34A715A0-6587-11D0-924A-0020AFC7AC4D” ); // WebBrowser 개체를 IConnecitonPointContainer로 형변환 UCOMIConnectionPointContainer ICpc = (UCOMIConnectionPointContainer)WBObject;
// DWebBrowserEvents2 인터페이스에 대한 IConnectionPoint 인터페이스 포인터를 반환 ICpc.FindConnectionPoint( ref DEventsGuid, out _ICp );
// TreeControl에서 DWebBrowserEvents2 인터페이스를 구현하고 있기 때문에 // 자신의 this 포인터를 전달하고, 이후 이벤트 연결 해제를 위해 쿠키 값을 반환 _ICp.Advise( this, out _dwCookie );
앞
의 코드에서는 지면상 생략했지만 TreeControl 개체는 이미 DWebBrowser2 인터페이스를 상속받아서 그에 대한 멤버
함수를 모두 구현해 놓았기 때문에 마지막 부분의 _ICp.Advise 메쏘드에서 자신의 this 포인터를 전달하는 것이
가능하다. 이렇게 이벤트를 걸어주고 나면 이후로 웹 브라우저로부터 이벤트가 발생할 때마다 DWebBrowserEvents2
인터페이스를 상속받아 구현해 두었던 TreeControl 클래스의 멤버 메쏘드가 실행된다. 우리는 그저 필요한 이벤트에 한해
해당 메쏘드에 코드를 추가해 주기만 하면 된다. 이제 웬만큼 구현이 끝난 것 같다. 여기서 잠시 COM을 하지 않은
독자라면 간과하고 지나갈 수 있을 문제를 짚고 넘어가겠다. 앞에서 QueryInterface로 구한 인터페이스 포인터 값은
알려진 대로 내부적으로 IUnknown::AddRef 가 호출되므로 증가된 참조수를 줄여주기 위해 반드시
Marshal.Release를 호출해 줘야만 하고, 걸어 놓은 이벤트에 대해서도 Unadvise로 해제를 해줘야 한다. 스마트
클라이언트에서 자원 해제를 위한 가장 적절한 위치는 IDisposable.Dispose 메쏘드 내부이다. 그곳에서 _ICp,
_htmlDocument, _webBr 개체에 대한 해제 코드를 잊지 말고 넣어주고, 해제와 관련된 코드도 ‘이달의 디스켓’으로
제공하니 확인하기 바란다. 여기서는 스마트 클라이언트를 호스트하고 있는 HTML 문서에 대한 인터페이스 포인터,
WebBrowser에 대한 인터페이스 포인터, 그리고 그 WebBrowser에 이벤트를 연결하는 방법을 구현해 보았다.
Microsoft.mshtml 개체로의 형변환을 Full Trust 보안에서만 제공해 준다는 것이 다소 원칙에 맞지 않는 듯
싶은데 애석하게도 이 문제는 닷넷 프레임워크 1.1에서만 발생하는 것은 아니다. 필자가 테스트하고 있는 SQL 서버 차기 버전인
‘유콘’과 함께 설치되는 ‘닷넷 프레임워크 2.0’ 버전에서도 앞의 문제는 동일하게 발생하고 있는 것을 확인할 수 있었다. 물론
닷넷 프레임워크 2.0도 아직 정식 릴리즈가 된 것은 아니기 때문에 확정지을 수는 없겠지만 현재로서는 기대할 수 없는 상황이다. | | |
[본문링크] IE에서 닷넷 스마트 클라이언트 개발2-인터넷 익스플로러와 연동하기3
|
[1]
|
|
|
|
|
코멘트(이글의 트랙백 주소:/cafe/tb_receive.php?no=3181 |
|
|
|
|
|
|
|
|
|
Copyright byCopyright ⓒ2005, SSISO Community All Rights Reserved.
|
|
|