MSHTML Programming by yrs83496

VIEWS: 1,195 PAGES: 28

									                           MSHTML Programming
                                                                       2003년 2월 한주영
                                                                  jooyunghan@hotmail.com


C++를 이용하여 MSHTML을 프로그래밍하는 데 필요한 기본적인 내용들을 정리한다.
MSHTML은 Rendering(Layout) Engine과 HTML Parsing Engine의 구성으로 볼 수 있으며,
4.0부터는 Editing Component까지 포함하여 많은 경우 웹브라우저 컨트롤을 재사용하므로써
노력을 아낄 수 있다.


목차
    Prerequisites and Requirements
    Introduction
    MSHTML Editing Platform
    MFC - CHtmlView/CHtmlEditView
    MSHTML Event Sink
    IHTMLEditDesigner
    Element Behavior
    기타
    References


Prerequisites and Requirements

C++, MFC, ATL 및 COM에 대한 기본적인 이해를 바탕으로 코드를 설명하고 있다. 대부분의
경우 Internet Explorer 5.5 이상을 요구하며, Internet Explorer 6.0 이상이 필요한 경우도 있다.


Introduction

간단히 용어부터 살펴보면 다음과 같다.
    MSHTML: The Microsoft HTML parsing and rendering engine, implemented in mshtml.dll
    웹브라우저 컨트롤: MSHTML을 이용해 웹브라우저 기능을 갖는 컨트롤
    MSHTML Editor: MSHTML에 포함된 확장 기능으로 편집기능 제공하는 부분을 말함


여기서 MSHTML Editor와 MSHTML이 좀 헷갈리는데, MSHTML Editor는 Editing 기능을 언급
할 때 이를 처리해주는 MSHTML의 한부분을 부각시켜 말하는 것이라고 생각하면 좋을 것



                                             1
같다.


MSHTML Editing Platform

MSHTML Editor의 기본 기능들


1:   Text formatting
           A.     Font face (for example, Times Roman, Arial, Courier)
           B.     Font size
           C.     Text style and decoration (Italic, Bold, Underline, Strikethrough, Superscript,
                  Subscript)
           D.     Text color
           E.     Background color
2:   Block formatting
           A.     Indenting
           B.     Outdenting
           C.     Left, right, and center, and full justification
           D.     Text direction (right-to-left or left-to-right)
3:   List editing
           A.     Ordered (numbered) lists
           B.     Unordered (bulleted) lists
           C.     Nesting to any level
4:   Selection services
           A.     Range selection by dragging the mouse
           B.     Word selection by double-clicking
           C.     Paragraph selection by triple-clicking
           D.     Keyboard-based selection (Shift + arrow, Home, and End keys)
5:   Automatic detection of hyperlinks and bookmarks
           A.     Unlimited levels of undo and redo
           B.     Text entry mode
           C.     Insert
           D.     Overwrite
6:   Support for standard keyboard accelerators:
Cut (Ctrl + X)                 Copy (Ctrl + C)            Paste (Ctrl + V)

Bold (Ctrl + B)                Italic (Ctrl + I)          Underline (Ctrl + U)

Undo (Ctrl + Z)                Redo (Ctrl + Y)            Hyperlink (Ctrl + K)




                                                         2
Find (Ctrl + F)               Select all (Ctrl + A)   Select block (Ctrl + Left-click)

기본 기능 사용하기


IOleCommandTarget 인터페이스를 통해 설정가능하다.


7: IOleCommandTarget* pCmdTarget;
8:
9: m_pIDoc->QueryInterface( IID_IOleCommandTarget, pCmdTarget );
10: pCmdTarget->Exec( &CGID_MSHTML, IDM_BOLD, MSOCMDEXECOPT_DODEFAULT, NULL, NULL );



Command ID는 MSDN의 "MSHTML Command Identifiers"를 참고한다. VBScript및 JavaScript
에서 사용가능한 IHTMLDocument2의 execCommand를 C++에서 사용할 수도 있지만 위의
방법에 비해 비효율적이다.


// C++
m_pIDoc->execCommand( L"Bold" );
// javascript
document.execCommand( "Bold" );



IE 5.5에서 새롭게 제공되는 기능들


위의 기능외에 IE 5.5부터 새로 제공되는 기능들은 다음과 같다. 이를 통해 세부적인 편집
기능에 대한 처리가 가능하다. 특히 Batch Undo/Redo의 경우 여러 편집 명령을 하나로 묶
어 Undo할 수 있도록 해주는 것으로 Undo 구현에 효과적이다.


IMarkupServicesPtr markupServices;
//..
markupServices->BeginUndoUnit( L"custom editing command" );
//.. editing commands
markupServices->EndUndoUnit();



1:    Batch undo and redo
2:    Auto-detection undo
3:    Format preservation during cut, copy, and paste operations
4:    Format preservation on empty lines
5:    Tri-state format information
6:    Atomic selection
7:    Vertical text editing
8:    Bidirectional editing
9:    IME reconversion




                                                      3
MSHTML Editor 사용하기


크게 3가지 방법이 있으며, 주로 Document 수준에서의 활성화를 통해 Editor를 사용하게 된
다.


웹브라우저 컨트롤에 대해 설정
IOleControl::OnAmbientPropertyChange( DISPID_AMBIENT_USERMODE );


Document에 대해 설정
IHTMLDocument2의 designMode property를 "On" / "Off" 로 설정
IHTMLDocument2Ptr htmldoc = GetHtmlDocument();
htmldoc->PutdesignMode( L"On" );



각 Element별로 설정
contentEditable 속성값을 "true" / "false" 로 설정. IHTMLElement3의 contentEditable property
IHTMLElement3Ptr elem = aCertainElement;
elem->PutcontentEditable( L"True" );



참고1) Document의 designMode = "On" 과 body element의 contentEditable = "true"
거의 동일한 효과를 가지지만, 몇가지 틀린 동작이 있는 것으로 보임. Document의
designMode를 설정하는 것이 더 적절한 것으로 판단됨.


참고2) contentEditable의 특징
contentEditable을 "true"로 설정한 element는 layout 설정이 변경되어 content selectable하게
된다. 따라서 contentEditable element 내에 또 다른 contentEditable element가 있을 경우, 문
제가 될 수 있다. (의도적으로 사용하는 경우는 가능) contentEditable element 외에도 control
selectable 요소는, ui control, iframe, image, marquee, hr, table이 있다.


참고3)
MFC 7.0의 CHtmlEditView는 Document의 designMode를 "On"으로 설정한다.


void CHtmlEditView::OnNavigateComplete2(LPCTSTR strURL)
{
        SetDesignMode(TRUE);
}

template <class T>
class CHtmlEditCtrlBase
{
public:
        BOOL SetDesignMode(BOOL bMode) const
        {
            const T* pT = static_cast<const T*>(this);
            CComPtr<IHTMLDocument2> spDoc;



                                           4
             pT->GetDHtmlDocument(&spDoc);
             if (spDoc)
             {
                 if (bMode)
                         return S_OK == spDoc->put_designMode(L"On") ? TRUE : FALSE;
                 else
                         return S_OK == spDoc->put_designMode(L"Off") ? TRUE : FALSE;
             }
             return FALSE;
         }



MSHTML Editor 기능 확장 인터페이스


IHTMLEditHost
5.5에서 제공되며, 6.0에는 추가적으로 IHTMLEditHost2 인터페이스가 제공된다. 메서드는
SnapRect() 하나이며, 이는 control selectable 요소의 absolute position 배치시에 grid snap
기능을 구현하거나 혹은 특정 alignment를 구현하기 위해 사용한다. IHTMLEditHost2에서 제
공하는 PreDrag() 는 HTML element의 drag & drop 과정을 intercept하여 추가적인 처리를 하
고자 하는 경우 사용된다.




IHTMLEditDesigner
Edit Designer는 편집모드의 MSHTML에 대한 low-level 컨트롤을 가능하게 하는 인터페이스
이며, 이를 구현하여 연결할 경우 강력한 사용자 입력 컨트롤이 가능하게 된다.


사용자 입력에 대해 첫번째로 HTML 상에 event handler로 정의된 내용이 실행되며, 그 뒤
에 MSHTML Editor와 MSHTML이 event 처리를 하게된다. IHTMLEditDesigner를 통해
MSHTML Editor 및 MSHTML 의 기본 동작 대신 다른 동작을 처리할 수 있다. 예를 들어,
버튼에서의 클릭에 대한 MSHTML 의 기본동작은 버튼의 눌려진 모양을 그리는 것이지만,
Edit Designer의 PreHandleEvent에서 이를 가로채어 취소하거나 다른 동작을 취할 수 있다.


IHTMLEditDesigner 인터페이스는 모두 4개의 메소드를 가지며, 각각은 다음과 같다.


1:   TranslateAccelerator(키보드 조합에 대한 처리, Designer에서 사용하는 키조합도 여기서
     처리할 수 있다.)
2:   PreHandlerEvent
3:   PostHandleEvent
4:   PostEditorEventNotify


사용자의 입력이 발생하면, 위 네개의 메소드가 시점을 달리하여 호출된다. Low-level 처리
가 가능하며 MSHTML Editor의 기본기능을 Override하여 강력한 편집기능을 구현할 때 사용


                                            5
된다.


여러 개의 Edit Designer가 연결될 수 있으며, MSHTML은 각 Designer를 순차적으로 호출하
게 된다.


MSHTML Edit Service 인터페이스


Services 인터페이스는 Edit Service, Selection Service, Highlight Rendering Service, Display
Service, Markup Service의 5개가 있으며 각 Service 인터페이스는 Document 개체로부터 얻
을 수 있다(Document는 IServiceProvider를 구현하고있음). Services 인터페이스는 MSHTML
Editor의 세부적인 기능을 제어하기 위해 제공되며, Edit Designer에서 Custom Feature의 구
현시에 주로 사용하게 된다.


IHTMLEditServices
Edit Service는 MSHTML Editor에 Edit Designer를 연결시키기 위한 기본적인 서비스이다.
Add/RemoveDesigner() 메소드를 통해 Custom Edit Designer를 MSHTML Editor에 연결할 수
있다.


그 밖에 Markup Pointer 및 Display Pointer 를 사용하기 위한 MoveToSelectionAnchor(Ex),
및 MoveToSelectionEnd(Ex) 메소드를 제공한다. (-Ex 붙은 메소드는 IHTMLEditServices2에
서 제공된다.) 각각의 메소드는 Pointer를 현재 Editor의 Selection에 위치시키는 것이다.
Anchor는 Selection의 시작, End는 Selection의 끝인데, Selection의 방향에 따라 End가 앞에
나올 수 있다.


ISelectionServices
IHTMLEditServices::GetSelectionServices()로 얻을 수 있다.


Editor의 Seleciton은 하나만 존재하며 화면상에 항상 반전되어 나타나게 된다. 이와는 별도
로 Edit Designer에서 사용할 목적으로 Logical Selection을 구현하기 위한 서비스가
Selection Service이다. 관련 인터페이스는 ISelectionServices, ISelectionServiceListener,
ISegment, ISegmentList, ISegmentListIterator, IElementSegment이다.


두 개의 Markup Pointer로 Selection Segment를 추가하고,
ISegment* ISelectionServices::AddSegment( IMarkupPointer *start, IMarkupPointer *end );



Selection Services로부터 ISegmentList를 구하고, Iterator를 생성하여,
5:   ISegmentListPtr segmentList = selectionServices; // QueryInterface




                                            6
6:   ISegmentListIteratorPtr iterator = segmentList->CreateIterator();



각 Segment로부터 다시 Markup Pointer를 구할 수 있다.
7:   ISegment::GetPointers( IMarkupPointer *start, IMarkupPointer *end );



Table Editing Designer를 구현하는 경우, Table의 Column Selection은 실제 HTML Document
Tree 상에서 연속되지 않은 여러 개의 Selection 집합에 해당한다. 이러한 Logical한
Selection을 구현할 때 Selection Service를 이용할 수 있다.


IHighlightRenderingServices
HTML Document의 Source를 건드리지 않고 Highlight 효과를 주기위한 인터페이스이다.
Selection Service와 비슷하며, 각 Segment에 대해 Rendering Style을 지정할 수 있다. 관련
인터페이스는             IHighlightRenderingServices,    IHighlighSegment(ISegment와   동일),
IHTMLRenderStyle 이다.


HRESULT IHighlightRenderingServices::AddSegment(
    IDisplayPointer* pDispPointerStart,
    IDisplayPointer* pDispPointerEnd,
    IHTMLRenderStyle* pIRenderStyle,
    IHighlightSegment** ppISegment
);



Spell Checking Designer 구현시에, Misspelled word에 빨간 밑줄 긎는 것과 같은 처리를 할
때 사용할 수 있다.


IDisplayServices
Rendering 된 화면상의 정보를 처리하기 위한 서비스로 Display Pointer를 생성하고, Caret
위치를 얻는 등의 기능을 제공한다. Display Pointer로부터 얻을 수 있는 ILineInfo를 통해서
는 현재 화면상에서 특정 줄의 Metrics를 얻을 수있다.


또한 GetComputedStyle() 을 통해 얻는 IHTMLComputedStyle은 특정 위치의 완전한 스타일
정보를 얻을 수 있다.(상속받은 스타일도 모두 처리되어 실제 화면상에 보여지는 스타일 정
보)


IMarkupServices
HTML Document의 처리는 기본적으로 Editor의 Selection단위 혹은 Range단위에서 가능하
다. 또한 Document Tree의 DOM operation이나 DHTML operator을 통해서도 가능하다.
Markup Service는 이와 다른 접근으로서, 소스코드 수준에서의 처리를 위해 제공되는 것이
다.




                                              7
Markup Pointer는 HTML 소스코드 상에서의 정확한 위치를 지정할 수 있고, 이를 이용해 편
집기능의 수행도 가능하다. (Element 추가 삭제, Text 추가 삭제)


MFC - CHtmlView/CHtmlEditView

CHtmlView의 개요


CHtmlView는 웹브라우저 컨트롤을 호스팅하는 컨트롤 View이다. 대부분의 구현은 웹브라우
저 컨트롤에서 발생하는 Event에 대한 Handler정의와 Method에 대한 Wrapper Method로 구
성되며, Load/Save/Source와 같은 Help Method를 구현하고 있다. 또한 CHtmlView는
IDocHostUIHandler 인터페이스의 구현을 Indirect로 제공하고 있다. (CHtmlControlSite가
IDocHostUIHandler를 구현하고, 이는 CHtmlView에 구현된 Handler를 호출하는 식이다.)


MFC 4.x의 CHtmlView는 Wrapper Method까지만 구현되어 있어, Event Sink를 직접해주어야
했으며, Copy/Paste 와 같은 Window Message에 대한 Handler를 웹브라우저 컨트롤에 연결
되어 있지도 않았다.


Web Browser Control Hosting
BOOL CHtmlView::CreateControlSite(COleControlContainer* pContainer,
  COleControlSite** ppSite, UINT /* nID */, REFCLSID /* clsid */)
{
        ASSERT(ppSite != NULL);
        *ppSite = new CHtmlControlSite(pContainer);
        return TRUE;
}


BOOL CHtmlView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                     DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
                     UINT nID, CCreateContext* pContext)
{
        // create the view window itself
        m_pCreateContext = pContext;
        if (!CView::Create(lpszClassName, lpszWindowName,
             dwStyle, rect, pParentWnd, nID, pContext))
        {
         return FALSE;
        }

       // assure that control containment is on
       AfxEnableControlContainer();

       RECT rectClient;
       GetClientRect(&rectClient);

       // create the control window
       // AFX_IDW_PANE_FIRST is a safe but arbitrary ID
       if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, lpszWindowName,
            WS_VISIBLE | WS_CHILD, rectClient, this, AFX_IDW_PANE_FIRST))
       {
        DestroyWindow();



                                           8
        return FALSE;
       }

       // cache the dispinterface
       LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown();
       HRESULT hr = lpUnk->QueryInterface(IID_IWebBrowser2, (void**) &m_pBrowserApp);
       if (!SUCCEEDED(hr))
       {
        m_pBrowserApp = NULL;
        m_wndBrowser.DestroyWindow();
        DestroyWindow();
        return FALSE;
       }

       return TRUE;
}



Event Sink Map
// .h
DECLARE_EVENTSINK_MAP()

// .cpp
BEGIN_EVENTSINK_MAP(CHtmlView, CFormView)
        ON_EVENT(CHtmlView, AFX_IDW_PANE_FIRST, DISPID_STATUSTEXTCHANGE,
OnStatusTextChange, VTS_BSTR)
        ON_EVENT(CHtmlView, AFX_IDW_PANE_FIRST, DISPID_PROGRESSCHANGE, OnProgressChange,
VTS_I4 VTS_I4)
...
END_EVENTSINK_MAP()



Wrapper Methods
void CHtmlView::Navigate2(LPITEMIDLIST pIDL, DWORD dwFlags /* = 0 */,
        LPCTSTR lpszTargetFrameName /* = NULL */)
{
        ASSERT(m_pBrowserApp != NULL);

        COleVariant vPIDL(pIDL);
        COleVariant empty;

        m_pBrowserApp->Navigate2(vPIDL,
            COleVariant((long) dwFlags, VT_I4),
            COleVariant(lpszTargetFrameName, VT_BSTR),
            empty, empty);
}



CHtmlControlSite
CHtmlControlSite는     COleControlSite(IOleControlSite의 MFC구현)에서         상속받은 클래스로
IDocHostUIHandler 인터페이스를 구현하고 있다. IDocHostUIHandler는 웹브라우저 컨트롤에
서 발생하는 UI 이벤트를 처리하도록 하는 COM 인터페이스이며 CHtmlControlSite의 기본
구현은 해당 이벤트에 대한 핸들링을 CHtmlView로 포워딩하는 것이다. CHtmlView는 각 핸
들러를 virtual로 구현하고 있으며 아무런 동작도 하지 않는 것을 기본으로 구현하고 있다.
실제 구현시에는 CHtmlView 상속 클래스에서 이를 Override하여 구현한다.


예를 들어, OnGetHostInfo()를 Override하여 HTML화면의 기본설정을 할 수 있다.



                                           9
HRESULT CHtmlView::OnGetHostInfo(DOCHOSTUIINFO *pInfo)
{
   WCHAR* szCSS = L"BODY {background-color:#ffcccc}";
   WCHAR* szNS = L"IE;MyTags;MyTags2='www.microsoft.com'";
   OLECHAR* pCSSBuffer = (OLECHAR*)CoTaskMemAlloc((wcslen(szCSS) + 1) *
sizeof(OLECHAR));
   OLECHAR* pNSBuffer = (OLECHAR*)CoTaskMemAlloc((wcslen(szNS) + 1) * sizeof(OLECHAR));
   wcscpy(pCSSBuffer, szCSS);
   wcscpy(pNSBuffer, szNS);

     pInfo->cbSize = sizeof(DOCHOSTUIINFO);
     pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_SCROLL_NO;
     pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
     pInfo->pchHostCss = pCSSBuffer;
     pInfo->pchHostNS = pNSBuffer;

     return S_OK;
}



CHtmlControlSite는 제공되지 않는 클래스로, MFC 내부적으로 사용된다. 따라서 특정 경우
에는 직접 CHtmlControlSite와 같은 기능을 구현할 필요가 있다. (Custom Element를 사용하
고자 하는 경우에는 IOleControlSite구현 개체에서 IHostBehaviorInit인터페이스를 구현해야
한다.) 이때는 위와 같은 OnGetHostInfo()등을 사용할 수 없게되며, 사용하고자 한다면, MFC
의 소스코드로부터 CHtmlControlSite를 복사해와서 기본기능은 그대로 두고, 추가적인 기능
을 구현하도록 한다.


CHtmlEditView의 개요


MFC 7.0부터 제공되는 CHtmlEditView는 MSHTML Editing 기능을 제공하는 MFC 클래스로
서 CHtmlView의 기본기능 외에 다양한 HTML 편집 기능을 제공한다.


1:   HTML Edit Command Handler 추가
2:   MSHTML UI Handler 인터페이스 구현


이를 위해 MSHTML의 IOleCommandTarget 인터페이스 및 MSHTML Editing 커맨드 부분을
담당하는 CHtmlEditCtrlBase라는 템플릿 클래스가 제공되며 CHtmlEditView는 CHtmlView와
CHtmlEditCtrlBase를 복수 상속한 형태를 가지고 있다.




                                           (CFormView - CHtmlView - CHtmlEditView)



                                            10
3:    class CHtmlEditView
4:        : public CHtmlView
5:        , public CHtmlEditCtrlBase< CHtmlEditView >



또한 CHtmlEditView는 대응하는 Document 클래스가 CHtmlEditDoc일 것으로 가정하고 있다.
CHtmlEditDoc은 Open/Save/New 등의 메소드를 CHtmlEditView의 기능을 이용하여 구현한
다.


6: BOOL CHtmlEditDoc::OnOpenDocument(LPCTSTR lpszFileName)
7: {
8:     BOOL bRet = FALSE;
9:     CHtmlEditView* pView = GetView();
10:    if (pView != NULL)
11:    {
12:        pView->Navigate(lpszFileName);
13:        SetTitle(lpszFileName);
14:        bRet = TRUE;
15:    }
16:
17:    return bRet;
18: }



HTML Edit Command 처리


다음과 같은 HTML Editing Command에 대한 Message Mapping 매크로가 제공되어,
MSHTML Edit 상에서 발생하는 명령을 윈도 Message에 매핑시켜 메뉴나 툴바와의 연동이
쉽게 되었다.


1:    // declaration
2:    DECLARE_DHTMLEDITING_CMDMAP(CXmlEditorView)
3:
4:    // definition
5:    BEGIN_DHTMLEDITING_CMDMAP(CXmlEditorView)
6:     DHTMLEDITING_CMD_ENTRY(ID_EDIT_COPY, IDM_COPY)
7:     DHTMLEDITING_CMD_ENTRY(ID_EDIT_CUT, IDM_CUT)
8:     DHTMLEDITING_CMD_ENTRY(ID_EDIT_PASTE, IDM_PASTE)
9:     DHTMLEDITING_CMD_ENTRY(ID_EDIT_UNDO, IDM_UNDO)
10:   END_DHTMLEDITING_CMDMAP()



그 외에 Method에 연결하는 DHTMLEDITING_CMD_ENTRY_FUNC 등의 매크로도 있다.


상속하고 있는 CHtmlEditCtrlBase<>에는 편집기능들에 대한 모든 Editing Command들
(IOleCommandTarget::Exec()로 호출하는)을 Method로 Wrapping하고 있다.


// CHtmlEditCtrlBase
HRESULT OrderList(LPCTSTR szId = NULL) const
{
        return ExecHelperSetVal(IDM_ORDERLIST, szId);
}




                                             11
HRESULT ExecHelperSetVal(UINT nCmdID,
                                          bool bValue,
                                          long nMinSupportLevel =
OLECMDF_SUPPORTED|OLECMDF_ENABLED,
                                          long nExecOpt = OLECMDEXECOPT_DODEFAULT) const
{
        HRESULT hr = E_FAIL;
        long lStatus = QueryStatus(nCmdID);
        if ((lStatus & nMinSupportLevel) == nMinSupportLevel)
        {
            CComVariant vIn(bValue);
            hr = ExecCommand(nCmdID, nExecOpt, &vIn);
        }
        return hr;
}

HRESULT ExecCommand(const GUID *pGuid, long cmdID, long cmdExecOpt, VARIANT* pInVar=NULL,
VARIANT* pOutVar=NULL) const
{
        const T* pT = static_cast<const T*>(this);
        CComPtr<IHTMLDocument2> spDoc;
        HRESULT hr = E_FAIL;
        pT->GetDHtmlDocument(&spDoc);
        if (spDoc)
        {
            CComQIPtr<IOleCommandTarget> spCmdTarg = spDoc;
            if (spCmdTarg)
            {
                 hr = spCmdTarg->Exec(pGuid, cmdID, cmdExecOpt, pInVar , pOutVar);
            }
            else
                 hr = E_NOINTERFACE;
        }
        return hr;
}



CHtmlView와 CHtmlEditView의 차이


결과적으로 CHtmlView와 CHtmlEditView의 차이는 위와 같은 Editing Command를 구현했느
냐, CHtmlEditDoc을 통해 저장루틴을 제공하느냐, Design Mode가 어떠하냐 하는 것 밖에 없
다.


여기서 Editing Command 구현은 CHtmlEditCtrlBase<>로 떼어내어 구현하고 있으나, 이는
IOleCommandTarget::Exec()로 CHtmlView에서도 사용가능하다. 그렇지만 이러한 편집 명령
을 자주 사용한다면 CHtmlEditView를 이용하는 것이 쉬울것이다.


MSHTML Event Sink

Event Sink 개요


HTML의 Event Sink는 MSHTML Editor와 관계없이 MSHTML에서 발생하는 이벤트(유저 입



                                          12
력)에 대한 High level 처리를 가능하게 한다. 예를 들어 Focus-in, Selection Start, Drag&Drop
등이 여기에 해당한다.


주요 이벤트 목록
1:    Copy/Cut/Paste
2:    Drag/Drop
3:    Mouse Move/Click
4:    Focus


MSHTML에서 발생하는 모든 Event는 MSDN의 "MSHTML DispInterfaces"를 참고한다.


Event Sink 구현


Event Sink 클래스는 IDispatch 인터페이스를 구현해야 하며, MFC를 이용하는 경우
CCmdTarget을 상속받아 정의하는 것도 가능하다.


Event Sink 를 사용하기 위해서는 Event Sink 클래스를 구현하고, HTML Document 혹은 각
Element에 대해 Advise하여 연결하고, Unadvise하여 연결을 해제한다.


1:    void CEditorView::SomeMethods {
2:    …
3:        MSHTML::IHTMLDocument2Ptr htmldoc = GetHtmlDocument();
4:        m_editEventSink = new edit::CEditEventSink(htmldoc);
5:        m_editEventSink->Advise();
6:    …
7:    }
8:
9:    void CEditEventSink::Advise()
10:   {
11:       IUnknownPtr htmldocUnknown(m_htmldoc);
12:       IUnknownPtr sinkUnknown(this);
13:       AfxConnectionAdvise(
14:           htmldocUnknown
15:           , DIID_HTMLDocumentEvents2
16:           , sinkUnknown
17:           , TRUE
18:           , &m_eventSinkCookie);
19:   }



이렇게 연결된 Event Sink 개체는 이벤트가 발생할 때 Invoke() 메소드가 호출되며, Dispid로
이벤트를 구분하여 처리할 수 있다.


1:    HRESULT __stdcall CEditEventSink::Invoke(DISPID dispidMember, REFIID riid,
2:            LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
3:            EXCEPINFO* pexcepinfo, UINT* puArgErr)
4:    {
5:        MSHTML::IHTMLWindow2Ptr window = m_htmldoc->GetparentWindow();



                                            13
6:      MSHTML::IHTMLEventObjPtr event = window->Getevent();
7:
8:      switch(dispidMember) {
9:      case DISPID_HTMLDOCUMENTEVENTS_ONCLICK:
10:         {
11:             pvarResult->vt = VT_BOOL;
12:             pvarResult->boolVal = OnClick( event );
13:         }
14:         break;
15:     case DISPID_HTMLELEMENTEVENTS2_ONDBLCLICK:
16:         {
17:             …




IHTMLEditDesigner

IHTMLEditDesigner 개요


Edit Designer는 편집모드의 MSHTML에 대한 low-level 컨트롤을 가능하게 하는 인터페이스
이며, 이를 구현하여 연결할 경우 강력한 사용자 입력 컨트롤이 가능하게 된다.


사용자 입력에 대해 첫번째로 HTML 상에 event handler로 정의된 내용(OM Handlers)이 실
행되며, 그 뒤에 MSHTML Editor와 MSHTML이 event 처리를 하게된다. IHTMLEditDesigner
를 통해 MSHTML Editor 및 MSHTML 의 기본 동작 대신 다른 동작을 처리할 수 있다. 예
를 들어, 버튼에서의 클릭에 대한 MSHTML 의 기본동작은 버튼의 눌려진 모양을 그리는 것
이지만, Edit Designer의 PreHandleEvent에서 이를 가로채어 취소하거나 다른 동작을 취할
수 있다.


IHTMLEditDesigner 인터페이스는 모두 4개의 메소드를 가지며, 각각은 다음과 같다.


18: TranslateAccelerator(키보드 조합에 대한 처리, Designer에서 사용하는 키조합도 여기서
      처리할 수 있다.)
19: PreHandlerEvent
20: PostHandleEvent
21: PostEditorEventNotify


사용자의 입력이 발생하면, 위 네개의 메소드가 시점을 달리하여 호출된다. Low-level 처리
가 가능하며 MSHTML Editor의 기본기능을 Override하여 강력한 편집기능을 구현할 때 사용
된다.


다음은 위의 네 메소드가 호출되는 시점을 나타낸 것이다.




                                          14
IHTMLEditDesigner 구현


MSHTML로부터 얻은 IHTMLEditServices 인터페이스의 AddDesigner()로 연결하여 사용한다.


MSHTML::IHTMLDocument2Ptr htmldoc( GetHtmlDocument() );
IServiceProviderPtr serviceProvider(htmldoc);
MSHTML::IHTMLEditServicesPtr editServices;
if( SUCCEEDED(serviceProvider->QueryService( SID_SHTMLEditServices,
IID_IHTMLEditServices, (void**)&editServices) )) {
        m_editDesigner = new edit::CCursorControlDesigner( htmldoc, this );
        editServices->AddDesigner( m_editDesigner );
}



Edit Designer의 구현 예제


HRESULT CCursorControlDesigner::PreHandleEvent(DISPID inEvtDispId, IHTMLEventObj
*pIEventObj)
{
        HRESULT hr = S_FALSE;
        MSHTML::IHTMLEventObjPtr evtObj( pIEventObj );
        MSHTML::IHTMLElementPtr srcElem( evtObj->GetsrcElement() );
        switch (inEvtDispId) {
             case DISPID_HTMLELEMENTEVENTS2_ONMOUSEDOWN:
                 {
                          tstring name = to_string(srcElem->GettagName());
                          if( name == _T("INPUT" ) || name == _T("SELECT") ) {
                                  MSHTML::IHTMLElement2Ptr(srcElem)->focus();
                          }
                 }
                 break;
...



예제)Table 편집




                                           15
Element Behavior

DHTML Behavior 개요


Internet Explorer 5.0부터 Behavior란 개념이 소개되었다. MSHTML의 확장성과 재사용성을
얻기위해 사용가능한 Behavior는 간단하게는 HTC로 구현되며, 보다 복잡하게는 C++를 이
용해서도 구현가능하다. Behavior는 MSHTML이 구현하고 있는 기본적인 Rendering 방식 및
Event Handling 방식을 별도의 컴포넌트로 정의하여 재사용할 수 있게 한다.


간단하게는 다음과 같은 예제를 들 수 있다.


Hilite.htc
<PUBLIC:COMPONENT>
<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="Hilite()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="Restore()" />
<SCRIPT LANGUAGE="JScript">
  var normalColor, normalSpacing;

   function Hilite()
   {
     // save original values
     normalColor = runtimeStyle.color;
     normalSpacing= runtimeStyle.letterSpacing;

       runtimeStyle.color = "red";
       runtimeStyle.letterSpacing = 2;
   }

  function Restore()
  {
    // restore original values
    runtimeStyle.color = normalColor;
    runtimeStyle.letterSpacing = normalSpacing;
  }
</SCRIPT>
</PUBLIC:COMPONENT>



hilite.html
<HEAD>
<STYLE>
  LI {behavior:url(hilite.htc)}
</STYLE>
</HEAD>
22:
23: <P>Mouse over the two list items below to see this effect.
24: <UL>
25:   <LI>HTML Authoring</LI>
26:   <LI>Dynamic HTML</LI>
27: </UL>



연결하는 방법은 위의 HTML 문서에서 보듯이 CSS 의 Behavior Property를 이용하거나,
DHTML의 addBehavior 메소드를 이용해서 연결하고 이를 해제(removeBehavior)할 수 있다.



                                           16
Element Behavior 개요


Internet Explorer 5.5에서 추가된 것으로 기존의 DHTML Behavior는 이후부터 Attached
Behavior라 부른다. Element Behavior와 Attached Behavior의 차이점은 Attached Behavior가
기존의 Element의 기능을 재정의(overriding)하기 위한 것인 반면, Element Behavior는 새로
운 엘리먼트(Custom Element)에 대한 기능을 정의한다는 것이다. 하지만 이보다 더 큰 차이
점은 Sync/Async라고 볼 수 있는데, Attached Behavior가 URL 혹은 Object 태그를 이용해서
연결되어, Async로 가져오기 때문에 해당 Element가 Parsing이 끝난 뒤에도 Behavior가 아
직 download 되지않은 경우는 처리가 되지 않는다. Element Behavior는 <?import>를 통해
문서 Parsing 단계에서 Behavior가 완전히 Load된다.(이는 처리모델에서 큰 차이점이 있
다!!)




Element Behavior의 또다른 특징은 Attached Behavior에서 할 수 없었던 Rendering까지
Customization하는 거이 가능하다는 것이다. 그밖에도 ViewLink, LiteralContent등 이전의
Attached Behavior로는 구현할 수 없었던 것들이 가능하게 되었다.


관련 인터페이스 및 Enum


(from MSDN)
Interfaces

IElementBehavior           This interface provides a notification mechanism so that MSHTML can communicate

                           with a behavior.


IElementBehaviorCategory   This interface is used to identify a Dynamic HTML (DHTML) behavior by category.


IElementBehaviorFactory    This interface provides a standard mechanism for MSHTML to locate and instantiate

                           a DHTML behavior.


IElementBehaviorFocus      Allows an element behavior to provide its own focus rectangle.


IElementBehaviorLayout     This interface is implemented by a binary element behavior in order to take part in

                           the layout process.


IElementBehaviorLayout2    This interface extends the IElementBehaviorLayout interface, which enables binary

                           behaviors to participate in the layout process.


IElementBehaviorSite       This interface provides communication between MSHTML and a DHTML behavior.




                                                  17
IElementBehaviorSiteCategory   This interface provides DHTML behaviors with a way of identifying other behaviors

                               by category.


IElementBehaviorSiteLayout     Allows behaviors to control the layout process.


ElementBehaviorSiteLayout2     This interface extends the IElementBehaviorSiteLayout interface, which allows

                               behaviors to control the layout process.


IElementBehaviorSiteOM         This interface provides event services to DHTML behaviors.


IElementBehaviorSiteOM2        Enables binary element behaviors to retrieve their default values.


IElementBehaviorSiteRender     Allows an element behavior to receive notification of changes in the rendering

                               environment.


IElementBehaviorSubmit         Allows element behaviors resident in a form to submit data.


IElementNamespace              Provides a standard mechanism for creating an element behavior.


IElementNamespaceFactory       Provides a standard mechanism for creating element behaviors for a namespace.


IElementNamespaceFactory2      This interface extends IElementNamespaceFactory and provides a standard

                               mechanism for creating an element behavior for a specific namespace and

                               implementation.


IElementNamespaceFactoryCall   Provides a standard mechanism for hosts of MSHTML to resolve tagnames.

back


IElementNamespaceTable         Provides a mechanism for a host of MSHTML to add its own namespaces and to

                               create tags for those namespaces.


IHostBehaviorInit              This interface enables the host application to populate the namespace table for the

                               current document.


IHTMLElementDefaults           This interface provides the ability to programmatically set default properties on an

                               element behavior.


IHTMLNamespace                 This interface provides a means to dynamically import an element behavior into a

                               document.


IHTMLNamespaceCollection       This interface is a collection of all namespace objects associated with the document.


IHTMLPainter                   This custom interface provides methods to MSHTML so that it can draw a rendering

                               behavior.


IHTMLPainterOverlay            This custom interface provides a method to MSHTML that enables a rendering

                               behavior to use the Microsoft® DirectDraw® hardware overlay buffer, if the buffer is




                                                      18
                           present.


IHTMLPaintSite             This interface provides methods that enable a rendering behavior to communicate

                           with MSHTML from within the behavior's implementation of the IHTMLPainter::Draw

                           and IHTMLPainter::HitTestPoint methods.


IHTMLSubmitData            Allows element behaviors to add to the form submission data sent to a server.




Enumerations

BEHAVIOR_LAYOUT_INFO        Specifies the type of layout control the layout behavior exhibits.


BEHAVIOR_LAYOUT_MODE        Provides a layout behavior with information about the current state of the layout

                            engine.


ELEMENTDESCRIPTOR_FLAGS     Specifies the type of element behavior to create by the

                            IElementNamespace::AddTag method.


ELEMENTNAMESPACE_FLAGS      Specifies options that MSHTML uses to add namespaces with the

                            IElementNamespaceTable::AddNamespace method.




Element Behavior 구현


Element Behavior를 정의하는 방법은 3가지가 있다.
        HTML Component(HTC)
        Binary Element Behavior(C++ COM Server)
        Windows Scripting Component(WTC)


렌더링까지 직접하는 경우에는 Binary (Element) Behavior를 이용하여야 한다. Binary
Behavior를 만들기 위해서는 아직까지 C++를 이용한 COM개체외에는 방법이 없다. (표 참
고)


Element Behavior가 어떤 방법으로 구현되어도 다음과 같이 Custom Element에 연결할 수
있다.
HTML을 이용
<HTML> 태그에 Custom Namespace 추가
<OBJECT> 태그로 Element Behavior 구현 추가

<?import> PI로 구현 및 Namespace를 연결하고 구현을 로딩




                                                  19
다음과 같이 HTML에서 <object>태그와 <?import?> Processing Instruction을 이용하여
Custom Tag를 사용하고 여기에 Element Behavior를 연결할 수 있다.


1:   <html xmlns:mybb>
2:    <head>
3:     <object id=mytag ... ></object>
4:     <?import namespace=mybb implementation=#mytag >
5:    </head>
6:    <body>
7:     <mybb:mytag></mybb:mytag>
8:    </body>
9:   </html>



1에서 mybb라는 네임 스페이스를 선언하고, 3에서 <object> 태그를 이용하여 Behavior
Factory를 지정한 후, 4에서 <?import> 구문으로 네임스페이스와 비헤비어 팩토리를 연결시
킨 것이다. 이후에는 7과 같이 custom tag를 사용할 수 있다.



Program에서 연결


HTML을 이용하는 방법은 주로 웹 상에서 Element Behavior를 이용할 때 쓰게 되는 방법이
고, 웹브라우저 컨트롤를 호스팅하는 보통의 애플리케이션에는 잘 맞지 않는 방법이다. IE
6.0부터     IHostBehaviorInit이라는    인터페이스가             제공된다.   IHostBehaviorInit를   이용하여
Element Behavior Factory를 등록하는 방법은 다음과 같다.


IOleControlSite 구현 개체에서 IServiceProvider 인터페이스 구현
IServiceProvider::QueryService()호출 시 IHostBehaviorInit 인터페이스 전달
IHostBehaviorInit::PopulateNamespaces()호출        시    Custome    Namespace        추가   및
IElementNamespaceFactory 인터페이스 등록
PopulateNamespaces()에서 MSHTML에 대해 IElementNamespaceTable인터페이스를 쿼리하
고
IElementNamespaceTable::AddNamespace()를 호출하여
Parameter로 Namespace Prefix및 IElementNamespaceFactory 인터페이스 전달
IElementNamespaceFactory 구현개체에서 IElementBehaviorFactory 인터페이스 구현



Element Factory 로딩 및 Namespace 초기화 과정


아래의 그림은 C++을 이용해 직접 Factory를 전달하는 과정을 각 Method 호출에 따라 나
타낸 것이다. Factory가 별도의 모듈(COM DLL)로 개발된 경우에도 Factory 부분은 동일하며
IHostBehaviorInit 부분을 이용해서 IElementNamespaceFactory를 얻는 과정이 MSHTML에
의해 <Object>, <?import>로 대체된다는 점이 다르다.



                                            20
                                                                IServiceProvider
              1. QueryService(SID_SElementBehaviorFactory

                                                                                      HOST App.


                                                                IHostBehaviorInit
          2. PopulateNamespaceTable( IElementNamespaceTable )


                3. AddNamespace( NS, URN, 0, IElementNamespaceFactory )
    MSHTML

                  IElementNamespaceTable


                     4. Create( IElementNamespace )
                                                            IElementNamespaceFactory


                                                                                       Factory
                                    5. Add( Tag, 0 )

                    IElementNamespace                       IElementBehaviorFactory




여기서 1번으로부터 얻은 Factory는 Custom Element에 해당하지 않는다. Attached Behavior)
MSHTML은 IElementNamespaceFactory 인터페이스에 대해 IElementBehaviorFactory를 얻
는다.


<OBJECT>, <?IMPORT> 처리과정
<HTML XMLNS:MYNS>
<HEAD>
...
<OBJECT id="impl" code="clsid:..." />
<?IMPORT namespace="MYNS" implementation="#impl">
...
<MYNS:MYTAG />
...
    1.   IMPORT 를 만나 Namespace 'MYNS'의 Implementation(COM Component or HTC)
         을 로드하고,
    2.   Component로부터 IElementNamespaceFactory를 얻는다.
    3.   이후는 앞의 4번 이후와 동일하다.


HTC로 구현된 경우는 <PUBLIC:COMPONENT tagName=”ABC”> 와 같은 내용을 처리하여
5. AddTag() 가 처리된다.




                                                 21
Element Behavior의 생성 및 파괴


Element Behavior는 IElementBehaviorFactory::FindBehavior() 에 의해 생성되어, 파괴되기 전
에 MSHTML에 의해 Init(), Notify(), Detach() 세 개의 메소드가 호출된다.


생성시점
TAG string parsing할때
HTMLDocument를 이용하여 element 생성할때 or 생성한 Element DOM에 붙여넣을때
파괴시점
DOM 이 없어질때(body.innerHTML = "")
DOM 상에서 Element삭제할 때


Element Behavior 생성 과정



                                       IElementBehavior
                MSHTML                                                    IElementBehavior
                                            Factory


     parse
                         FindBehavior(tag)
    Start tag                                                <<Create>>




                                  Init( IElementBehaviorSite )


                                    Notify( oncontentready )
    End tag

                                   Notify( ondocumentready )
    Document

                                             Detach()




<HTML XMLNS:MYNS>
<HEAD>
...
<OBJECT id="impl" code="clsid:..." />
<IMPORT namespace="MYNS" implementation="#impl">
...
<MYNS:MYTAG />
...



위와 같은 html 문서를 읽어들인다고 하자.




                                                        22
<MYNS:MYTAG />를 만나 Namespace 'MYNS'의 구현으로부터 IElementBehaviorFactory를
얻어오고, MYTAG란 이름으로 IElementBehaviorFactory::FindBehavior( ... ) 를 호출한다.
IElementBehaviorFactory::FindBehavior()에서는 이름을 확인하여(optional), 해당 Element
Behavior를 생성하여 넘겨준다.
MSHTML은 Element Behavior를 찾게되면, 곧바로 IElementBehavior::Init
( IElementBehaviorSite )를 호출하고,
이때 Element Behavior는 얻은 IElementBehaviorSite를 Cache해두고 필요한 Interface를 얻
어 사용한다.(IElementBehaviorSiteOM, IElementBehaviorSiteCategory 등)
           * 조심할 것은 이 시점에서 IElementBehaviorSite::GetElement()로 얻은 엘리먼트
           (Master Element)를 Cache해 두면 안된다는 것이다. (Detach가 호출되지 않는다)
Custom Tag의 내용을 마저 읽게되면 그때 Notify( oncontentready ), document parsing이 끝
나면 Notify( ondocumentready )를 호출한다.
Notify()가 호출될 때 Element Behavior는 Init에서 얻은(Cache해둔) IElementBehaviorSite를
사용할 수 있다. master element의 reference가 필요한 경우 cache해 둔
IElementBehaviorSite로 부터 master element를 얻어오도록 한다.
(IElementBehaviorSite::GetElement )
Event Sink를 구현하고자 하는 경우, content ready 혹은 document ready Notify에서 Advise를
하도록 한다.


Rendering Behavior

Rendering Behavior 개요


Custom   Tag를    이용하여       일반    태그로    표시할     수   없는    Rendering이   필요한   경우,
IElementBehavior 구현 개체에서 IHTMLPainter 및           IElementBehaviorLayout 인터페이스를
추가 구현한다. (IHTMLPainter는 현재는 c++만 이용해서 구현이 가능한 인터페이스이다. 일
반 behavior가 HTML Component 및 Windows Scripting Component를 이용해서 구현가능한
점과 다르다.)


이렇게 Binary Behavior 중에서도 IHTMLPainter를 구현한 것을 Rendering Behavior라고 한
다.   (추가적으로        그림뿐      아니라       MSHTML   Rendering   엔진이   이용할     수    있도록
IElementBehaviorLayout을 구현하는 것이 일반적이다.)


MSHTML은 Element Behavior를 얻고나면 바로 IHTMLPainter 인터페이스를 조사하여, 발견
되면 이후의 Rendering을 IHTMLPainter::Draw()를 이용하여 그리게된다.




                                          23
예제) Tag Image




HTML 내용
<my:tagimage caption=”#maintain” shape=”>” ></my:tagimage>
<my:tagimage caption=”#maintain” shape=”<” ></my:tagimage>
<my:tagimage caption=”collapsed” shape=”()” ></my:tagimage>



Rendering Behavior 관련 인터페이스


IHTMLPainter 인터페이스


아래의 네 메소드를 가지고 있다.


   virtual HRESULT __stdcall Draw(RECT rcBounds, RECT rcUpdate,
            LONG lDrawFlags, HDC hdc, LPVOID pvDrawObject);
   virtual HRESULT __stdcall OnResize(SIZE size);
   virtual HRESULT __stdcall GetPainterInfo(
            HTML_PAINTER_INFO *pInfo);
   virtual HRESULT __stdcall HitTestPoint(POINT pt, BOOL *pbHit,
            LONG *plPartID);



        GetPainterInfo()
여기서 Rendering Option을 지정한다.
Draw()가 처음 호출되기 전에 호출되고, IHTMLPainterSite::InvalidatePainterInfo() 를 호출할
때 호출된다.


typedef struct _HTML_PAINTER_INFO {
   LONG lFlags; // HTML_PAINTER (OPAQUE, TRANSPARENT, HITTEST, … )
   LONG lZOrder; // HTML_PAINT_ZORDER (REPLACE/BELOW/ABOVE_ALL/CONTENT/FLOW …)
   IID iidDrawObject;
   RECT rcExpand;
} HTML_PAINTER_INFO;



        HitTestPoint()
Rendering Behavior의 경우는 OnClick 이벤트가 발생하지 않는다. 화면 상의 좌표와 렌더링
비헤비어가 실제로 차지하는 좌표 영역이 다를 수 있기 때문이다.




                                           24
OnClick이 발생하게 하려면 HitTestPoint()를 구현해야 한다.(Default구현은 원래 사이즈에 대
해 Click 여부를 판단하게 되며, 구현을 통해 영역을 재정의 할 수 있다.)


현재의 좌표 값이 Rendering Behavior의 영역에 포함되는지 아닌지 알려줘야 한다.


HRESULT __stdcall CTagImageBehavior::HitTestPoint(POINT pt, BOOL *pbHit, LONG *plPartID)
{
        MSHTML::IHTMLElement2Ptr elem2 = m_site->GetElement();
        MSHTML::IHTMLRectPtr htmlrect = elem2->getBoundingClientRect();
        CRect rect(htmlrect->Getleft(), htmlrect->Gettop(),
            htmlrect->Getright(), htmlrect->Getbottom());

         if (pt.x > 0 && pt.x < rect.Width() &&
             pt.y > 0 && pt.y < rect.Height()) {
             *pbHit = TRUE;
             *plPartID = 0;
         }
         return S_OK;
}



그러나 실제로는 *pdHit = TRUE; 를 설정해주는 것만으로 구현될 수 있으며, HitTestPoint()
의 주요한 용도는 User Action에 대한 처리를 위해, 특정 region에 대한 click 여부를 판단하
기 위해 사용하며, region에 대한 id는 plPartID로 넘겨주게 된다. plPartID 값은 OnClick
Event에 해한 Event 개체로부터 얻을 수 있다.(IHTMLEventObj3::behaviorPart Property)


         Draw()
    virtual HRESULT __stdcall Draw(RECT rcBounds, RECT rcUpdate,
             LONG lDrawFlags, HDC hdc, LPVOID pvDrawObject);



렌더링할 영역의 크기, 렌더링에 사용할 DC를 받게 된다. 이 영역 안에서 주어진 DC를 가
지고 그림을 그리게 된다. 알파 블렌딩을 하고 그라디에이션을 주는등 다양한 효과를 줄 수
있다.


    IElementBehaviorLayout 인터페이스


엘리먼트의 크기, 위치에 관한 걸 지정할 수 있는 인터페이스이다.


    virtual HRESULT __stdcall GetSize(LONG dwFlags, SIZE sizeContent,
             POINT *pptTranslateBy, POINT *pptTopLeft,
             SIZE *psizeProposed);
    virtual HRESULT __stdcall GetLayoutInfo(LONG *plLayoutInfo);
    virtual HRESULT __stdcall GetPosition(LONG lFlags,
             POINT *pptTopLeft);
    virtual HRESULT __stdcall MapSize(SIZE *psizeIn, RECT *prcOut);



GetLayoutInfo()로 Layout Option을 설정한다.




                                           25
typedef enum _BEHAVIOR_LAYOUT_INFO {
    BEHAVIORLAYOUTINFO_FULLDELEGATION = 1,
    BEHAVIORLAYOUTINFO_MODIFYNATURAL = 2,
    BEHAVIORLAYOUTINFO_MAPSIZE = 4
} BEHAVIOR_LAYOUT_INFO;



대부분 Full Delegate로 등록하게 되며, MSHTML은 GetSize()를 통해 Layout 할때 크기를 정
하게 된다. Modify Natural인경우는 MSHTML이 먼저 크기를 정하고 이를 GetSize()에서 수정
할 수 있도록 한다.


IElementBehaviorSiteLayout::InvalidateLayoutInfo()를 호출하여 GetLayoutInfo()가 다시 호출
되고, IElementBehaviorSiteLayout::InvalidateSize()를 호출하여 GetSize()가 다시 호출된다.



기타


MSHTML 사용을 위한 MSHTML.IDL 수정하기

// in stdafx.h
// MSHTML
#import "../mshtml_ie6_modified.tlb" named_guids
rename("TranslateAccelerator","TranslateAcceleratorX")
//#import <mshtml.tlb> named_guids
rename("TranslateAccelerator","TranslateAcceleratorX")



위와 같이 Import하고 MSHTML 인터페이스 사용시에는 항상 MSHTML을 붙여 사용하는 것
이 편리하다. 이는 Namespace를 명시적으로 사용하지 않는 경우 MSXML과 Name conflict
가 발생하기 때문이다.


앞에서 보면 원본 mshtml.tlb가 아닌 modified version을 사용하고 있는데, 이는 IE 6.0에 추
가된 Markup Service 등과 같은 일부 인터페이스에 대한 IDL이 일부 적절치 못하여, 효과적
인 Com Smart Pointer 클래스를 생성하지 못하는 것을 수정한 것이다.


수정한 것은 mshtml.idl을 수정하여 midl.exe를 이용하여 컴파일 한 것이다.


IMarkupServices::CreateMarkupPointer()의 예를 들어 수정된 내용을 보면 다음과 같다.


//   원본
[]   HRESULT CreateMarkupPointer([out] IMarkupPointer** ppPointer);
//   수정본
[]   HRESULT CreateMarkupPointer([retval, out] IMarkupPointer** ppPointer);




                                             26
즉, retval attribute가 적절히 사용되지 않은 곳에 retval attribute를 붙여준 것이다.


XSLT Output을 WebBrowser Control에 보여주기


이미지 등과 같이 외부 링크에 대해서는 특별한 고려를 해야 한다.


쉬운 방법은 변환 결과(XSLT Transformation 결과)를 파일(HTML)로 저장하고 그 파일을 로
드하는 방법이다. 상대경로처리를 WebBrowser Control이 알아서 해준다. 그러나 이렇게 했
을 때는 불필요한 임시 파일이 남는다.


또다른 방법은 변환 결과 HTML을 파일로 저장하는 것이 아니라 MSHTML이 제공하는
IPersistStreamInit 인터페이스를 이용하여 동적으로 로딩하는 방식이다. HTML 스트림을 바
로 로드하거나, 혹은 MSXML4의 XSLT Processor의 Output으로 HTML Document를 바로 지
정하여 로드할 수있다. 이 경우는 WebBrowser Control이 상대경로 처리에 대한 base url이
없어 외부참조 이미지가 표시되지 않을 수 있다.(상대경로 처리는 Navigate될 때 지정된
base url을 이용한다.)


이에 대해서는 HTML BASE 엘리먼트를 이용하여 처리할 수 있다. XSLT 생성단계에서
BASE 엘리먼트를 추가하고, base URL을 지정하여 WebBrowser Control에서 상대경로를 해
석할 수 있도록 한다.


단, HTML base 태그의 값은 문서가 로딩된 후에는 변경할 수 없으며 변경하더라도 영향을
미치지 않는다.


DHTML Edit Component



References (MSDN Articles)

Reusing the WebBrowser Control
WebBrowser Customization
Reusing MSHTML
Using MSHTML Editing
The MSHTML Editing Platform in Internet Explorer 5.5
MSHTML References
Edit Designers



                                             27
Introduction to DHTML Behaviors
Using DHTML Behaviors
About Element Behaviors
Using Custom Tags in Internet Explorer
Implementing Binary DHTML Behaviors
How to Create a Binary Element Behavior using ATL
Using Rendering Behaviors


MSDN Internet Samples, http://msdn.microsoft.com/downloads/samples/internet/




                                            28

								
To top