천객만래 [千客萬來] (It has an interminable succession of visitors)

[개발/VC++] WebBrowser Control 이벤트 연결 - C++



WebBrowser Control
IDispatch 
IWebBrowser2
    .ReadyState
        READYSTATE_COMPLETE

    .Navigate2()
    .get_Document() // IDispatch -> IHTMLDocument2
    .get_StatusText()

    on DownloadBegin
    on DocumentComplete
    on DownloadComplete

IOleObject

 

IHTMLWindow2

IHTMLDocument2
    .get_all()
    .get_parentWindow() // IHTMLWindow2

IHTMLElementCollection
    .item()
    .tags // IHTMLElementCollection

IHTMLElement

a connectable object
    IConnectionPointContainer
        .FindConnectionPoint() // DHTMLElementEvents2

DHTMLElementEvents2
    .Advise()

outgoing HTMLElementEvents2 interface // event sink object // the client event sink 
    IDispatch
        .Invoke()

----------------------------------------------------------------------------------------


class CTryDlg : public CDialog
{
// Construction
public:
    CTryDlg(CWnd* pParent = NULL);    // standard constructor

// Dialog Data
    //{{AFX_DATA(CTryDlg)
    enum { IDD = IDD_TRY_081209_DIALOG };
    CWebBrowser2    m_webBrowser;
    //}}AFX_DATA
...
    // Generated message map functions
    //{{AFX_MSG(CTryDlg)
    ...
    afx_msg void OnDocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT FAR* URL);
    DECLARE_EVENTSINK_MAP()
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

BOOL CTryDlg::OnInitDialog()
{
    ...
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here
// {
    COleVariant     szURL       = "http://www.google.com";
    m_webBrowser.Navigate2(szURL, NULL, NULL, NULL, NULL);
// }    
    return TRUE;  // return TRUE  unless you set the focus to a control
}
...
BEGIN_EVENTSINK_MAP(CTryDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CTryDlg)
    ON_EVENT(CTryDlg, IDC_EXPLORER1, 259 /* DocumentComplete */, OnDocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

void CTryDlg::OnDocumentCompleteExplorer1(LPDISPATCH lpDisp, VARIANT FAR* URL) 
{
    // TODO: Add your control notification handler code here
   IUnknown*  pUnk;
   LPDISPATCH lpWBDisp;
   HRESULT    hr;

   pUnk = m_webBrowser.GetControlUnknown();
   ASSERT(pUnk);

   hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);
   ASSERT(SUCCEEDED(hr));

   if (lpDisp == lpWBDisp )
   {
      // Top-level Window object, so document has been loaded
      TRACE("Web document is finished downloading\n");
   }

  lpWBDisp->Release();
}
----------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------
m_pBrowser // IWebBrowser2

// DWebBrowserEvents2::DocumentComplete
void CMyClass::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL)
{
    HRESULT hr;
    IUnknown* pUnkBrowser = NULL;
    IUnknown* pUnkDisp = NULL;
    IDispatch* pDocDisp = NULL;
    IHTMLDocument2* pDoc = NULL;

    // Is this the DocumentComplete event for the top frame window?
    // Check COM identity: compare IUnknown interface pointers.
    hr = m_pBrowser->QueryInterface(IID_IUnknown, (void**)&pUnkBrowser);

    if (SUCCEEDED(hr))
    {
        hr = pDisp->QueryInterface(IID_IUnknown, (void**)&pUnkDisp);

        if (SUCCEEDED(hr))
        {
            if (pUnkBrowser == pUnkDisp)
            {
                // This is the DocumentComplete event for the top frame.
                // This page is loaded, so we can access the DHTML Object Model.
                hr = m_pBrowser->get_Document(&pDocDisp);

                if (SUCCEEDED(hr))
                {
                    // Obtained the document object.
                    pDocDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDoc);
                    if (SUCCEEDED(hr))
                    {
                        // Obtained the IHTMLDocument2 interface for the document object
                        ProcessDocument(pDoc);
                    }

                    pDocDisp->Release();
                }
            }

            pUnkDisp->Release();
        }

        pUnkBrowser->Release();
    }
}

// IHTMLDocument2
void CMyClass::ProcessDocument(IHTMLDocument2* pDoc)
{
    IHTMLElementCollection* pElemColl = NULL;

    hr = pDoc->get_all(&pElemColl);
    if (SUCCEEDED(hr))
    {
        // Obtained element collection.
        ProcessElementCollection(pElemColl);
        pElemColl->Release();
    }
}

void CMyClass::ProcessElementCollection(IHTMLElementCollection* pElemColl)
{
    IDispatch* pElemDisp = NULL;
    IHTMLElement* pElem = NULL;
    _variant_t varID("myID", VT_BSTR);
    _variant_t varIdx(0, VT_I4);

    hr = pElemColl->item(varID, varIdx, &pElemDisp);

    if (SUCCEEDED(hr))
    {
        hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);

        if (SUCCEEDED(hr))
        {
            // Obtained element with ID of "myID".
            ConnectEvents(pElem);
            pElem->Release();
        }

        pElemDisp->Release();
    }
}


void CMyClass::ConnectEvents(IHTMLElement* pElem)
{
    HRESULT hr;
    IConnectionPointContainer* pCPC = NULL;
    IConnectionPoint* pCP = NULL;
    DWORD dwCookie;

    // Check that this is a connectable object.
    hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);

    if (SUCCEEDED(hr))
    {
        // Find the connection point.
        hr = pCPC->FindConnectionPoint(DIID_HTMLElementEvents2, &pCP);

        if (SUCCEEDED(hr))
        {
            // Advise the connection point.
            // pUnk is the IUnknown interface pointer for your event sink
            hr = pCP->Advise(pUnk, &dwCookie);

            if (SUCCEEDED(hr))
            {
                // Successfully advised
            }

            pCP->Release();
        }

        pCPC->Release();
    }
}


STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
                                REFIID riid,
                                LCID lcid,
                                WORD wFlags,
                                DISPPARAMS* pdispparams,
                                VARIANT* pvarResult,
                                EXCEPINFO* pexcepinfo,
                                UINT* puArgErr)
{
    switch (dispidMember)
    {
        case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
        OnClick();
        break;

        default:
        break;
    }

    return S_OK;
}

----------------------------------------------------------------------------------------

IOleInPlaceFrame
IOleClientSite
IOleInPlaceSite

EmbedBrowserObject()
    window handle
        _IOleClientSiteEx    // USERDATA
            IOleInPlaceFrame
            IOleClientSite
            IOleInPlaceSite
            IDocHostUIHandler

    CoCreateInstance()
        CLSID_WebBrowser
        IWebBrowser2
            .put_Left()
            .put_Top()
            .put_Width()
            .put_Height()
            .Navigate2()

        IOleObject
            .Close()
            .SetClientSite() // IOleClientSite
            .SetHostNames()
            .DoVerb()

UnEmbedBrowserObject()

ResizeBrowser()

DisplayHTMLPage()

DoPageAction()

GetWebPtrs()
    IHTMLDocument2

IHTMLElementCollection

GetWebElement()
    IHTMLElement

CreateWebEvtHandler()

FreeWebEvtHandler()

WaitOnReadyState()

더보기


extern "C" {

HINSTANCE        cwebdll;

long WINAPI EmbedBrowserObject(HWND hwnd);
void WINAPI UnEmbedBrowserObject(HWND hwnd);
long WINAPI DisplayHTMLPage(HWND hWnd, const char *url);
void WINAPI ResizeBrowser(HWND hWnd, DWORD x, DWORD y);

}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
     // TODO: Place code here.
// {
    // Load our DLL containing the OLE/COM code. We do this once-only. It's named "cwebpage.dll"
    if (!(cwebdll = LoadLibrary("cwebpage.dll")))
    {
        MessageBox(0, "Can't open cwebpage.dll!", "ERROR", MB_OK);
        return(-1);
    }
// }
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    ...
}
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
// {
        case WM_CREATE:
            // Embed the browser object into our host window. We need do this only
            // once. Note that the browser object will start calling some of our
            // IOleInPlaceFrame and IOleClientSite functions as soon as we start
            // calling browser object functions in EmbedBrowserObject().
            if (EmbedBrowserObject(hWnd)) return(-1);
            DisplayHTMLPage(hWnd, "http://www.microsoft.com");
            break;
// }
        case WM_DESTROY:
// {
            // Detach the browser object from this window, and free resources.
            UnEmbedBrowserObject(hWnd);
// }
            PostQuitMessage(0);
            break;
        case WM_COMMAND:
            ...
            break;
        case WM_SIZE:
            // Resize the browser object to fit the window
            ResizeBrowser(hWnd, LOWORD(lParam), HIWORD(lParam));
            break;
        ...
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}


참조 사이트:

http://support.microsoft.com/kb/315617/en-us/
http://msdn.microsoft.com/en-us/library/bb508508(VS.85).aspx
http://support.microsoft.com/kb/194179/en-us/
http://www.codeproject.com/KB/shell/dlgdhtmlevents.aspx?display=Print
http://msdn.microsoft.com/en-us/library/aa293017(VS.71).aspx
http://urassa.tistory.com/entry/Web-Browser-Control-FAQ

http://www.codeproject.com/KB/COM/cwebpage.aspx?display=Print
http://jjjryu.tistory.com/entry/IE-1
http://support.microsoft.com/kb/196339/en-us/
http://jjjryu.tistory.com/entry/ActiveX-%EC%BB%A8%ED%8A%B8%EB%A1%A4-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8
http://www.codeproject.com/KB/shell/AutomateShellWindow.aspx?display=Print
http://www.codeproject.com/KB/shell/iehelper.aspx?display=Print


출처 : http://jjjryu.tistory.com/333

Posted by SB패밀리



[개발/VC++] WebBrowser Control 이벤트 연결 - C++


WebBrowser Control
IDispatch
IWebBrowser2
    .ReadyState
        READYSTATE_COMPLETE

    .Navigate2()
    .get_Document() // IDispatch -> IHTMLDocument2
    .get_StatusText()

    on DownloadBegin
    on DocumentComplete
    on DownloadComplete

IOleObject

 

IHTMLWindow2

IHTMLDocument2
    .get_all()
    .get_parentWindow() // IHTMLWindow2

IHTMLElementCollection
    .item()
    .tags // IHTMLElementCollection

IHTMLElement

a connectable object
    IConnectionPointContainer
        .FindConnectionPoint() // DHTMLElementEvents2

DHTMLElementEvents2
    .Advise()

outgoing HTMLElementEvents2 interface // event sink object // the client event sink
    IDispatch
        .Invoke()

----------------------------------------------------------------------------------------


class CTryDlg : public CDialog
{
// Construction
public:
    CTryDlg(CWnd* pParent = NULL);    // standard constructor

// Dialog Data
    //{{AFX_DATA(CTryDlg)
    enum { IDD = IDD_TRY_081209_DIALOG };
    CWebBrowser2    m_webBrowser;
    //}}AFX_DATA
...
    // Generated message map functions
    //{{AFX_MSG(CTryDlg)
    ...
    afx_msg void OnDocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT FAR* URL);
    DECLARE_EVENTSINK_MAP()
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

BOOL CTryDlg::OnInitDialog()
{
    ...
    SetIcon(m_hIcon, FALSE);        // Set small icon
   
    // TODO: Add extra initialization here
// {
    COleVariant     szURL       = "http://www.google.com";
    m_webBrowser.Navigate2(szURL, NULL, NULL, NULL, NULL);
// }   
    return TRUE;  // return TRUE  unless you set the focus to a control
}
...
BEGIN_EVENTSINK_MAP(CTryDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CTryDlg)
    ON_EVENT(CTryDlg, IDC_EXPLORER1, 259 /* DocumentComplete */, OnDocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

void CTryDlg::OnDocumentCompleteExplorer1(LPDISPATCH lpDisp, VARIANT FAR* URL)
{
    // TODO: Add your control notification handler code here
   IUnknown*  pUnk;
   LPDISPATCH lpWBDisp;
   HRESULT    hr;

   pUnk = m_webBrowser.GetControlUnknown();
   ASSERT(pUnk);

   hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);
   ASSERT(SUCCEEDED(hr));

   if (lpDisp == lpWBDisp )
   {
      // Top-level Window object, so document has been loaded
      TRACE("Web document is finished downloading\n");
   }

  lpWBDisp->Release();
}
----------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------
m_pBrowser // IWebBrowser2

// DWebBrowserEvents2::DocumentComplete
void CMyClass::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL)
{
    HRESULT hr;
    IUnknown* pUnkBrowser = NULL;
    IUnknown* pUnkDisp = NULL;
    IDispatch* pDocDisp = NULL;
    IHTMLDocument2* pDoc = NULL;

    // Is this the DocumentComplete event for the top frame window?
    // Check COM identity: compare IUnknown interface pointers.
    hr = m_pBrowser->QueryInterface(IID_IUnknown, (void**)&pUnkBrowser);

    if (SUCCEEDED(hr))
    {
        hr = pDisp->QueryInterface(IID_IUnknown, (void**)&pUnkDisp);

        if (SUCCEEDED(hr))
        {
            if (pUnkBrowser == pUnkDisp)
            {
                // This is the DocumentComplete event for the top frame.
                // This page is loaded, so we can access the DHTML Object Model.
                hr = m_pBrowser->get_Document(&pDocDisp);

                if (SUCCEEDED(hr))
                {
                    // Obtained the document object.
                    pDocDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDoc);
                    if (SUCCEEDED(hr))
                    {
                        // Obtained the IHTMLDocument2 interface for the document object
                        ProcessDocument(pDoc);
                    }

                    pDocDisp->Release();
                }
            }

            pUnkDisp->Release();
        }

        pUnkBrowser->Release();
    }
}

// IHTMLDocument2
void CMyClass::ProcessDocument(IHTMLDocument2* pDoc)
{
    IHTMLElementCollection* pElemColl = NULL;

    hr = pDoc->get_all(&pElemColl);
    if (SUCCEEDED(hr))
    {
        // Obtained element collection.
        ProcessElementCollection(pElemColl);
        pElemColl->Release();
    }
}

void CMyClass::ProcessElementCollection(IHTMLElementCollection* pElemColl)
{
    IDispatch* pElemDisp = NULL;
    IHTMLElement* pElem = NULL;
    _variant_t varID("myID", VT_BSTR);
    _variant_t varIdx(0, VT_I4);

    hr = pElemColl->item(varID, varIdx, &pElemDisp);

    if (SUCCEEDED(hr))
    {
        hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);

        if (SUCCEEDED(hr))
        {
            // Obtained element with ID of "myID".
            ConnectEvents(pElem);
            pElem->Release();
        }

        pElemDisp->Release();
    }
}


void CMyClass::ConnectEvents(IHTMLElement* pElem)
{
    HRESULT hr;
    IConnectionPointContainer* pCPC = NULL;
    IConnectionPoint* pCP = NULL;
    DWORD dwCookie;

    // Check that this is a connectable object.
    hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);

    if (SUCCEEDED(hr))
    {
        // Find the connection point.
        hr = pCPC->FindConnectionPoint(DIID_HTMLElementEvents2, &pCP);

        if (SUCCEEDED(hr))
        {
            // Advise the connection point.
            // pUnk is the IUnknown interface pointer for your event sink
            hr = pCP->Advise(pUnk, &dwCookie);

            if (SUCCEEDED(hr))
            {
                // Successfully advised
            }

            pCP->Release();
        }

        pCPC->Release();
    }
}


STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
                                REFIID riid,
                                LCID lcid,
                                WORD wFlags,
                                DISPPARAMS* pdispparams,
                                VARIANT* pvarResult,
                                EXCEPINFO* pexcepinfo,
                                UINT* puArgErr)
{
    switch (dispidMember)
    {
        case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
        OnClick();
        break;

        default:
        break;
    }

    return S_OK;
}

----------------------------------------------------------------------------------------

IOleInPlaceFrame
IOleClientSite
IOleInPlaceSite

EmbedBrowserObject()
    window handle
        _IOleClientSiteEx    // USERDATA
            IOleInPlaceFrame
            IOleClientSite
            IOleInPlaceSite
            IDocHostUIHandler

    CoCreateInstance()
        CLSID_WebBrowser
        IWebBrowser2
            .put_Left()
            .put_Top()
            .put_Width()
            .put_Height()
            .Navigate2()

        IOleObject
            .Close()
            .SetClientSite() // IOleClientSite
            .SetHostNames()
            .DoVerb()

UnEmbedBrowserObject()

ResizeBrowser()

DisplayHTMLPage()

DoPageAction()

GetWebPtrs()
    IHTMLDocument2

IHTMLElementCollection

GetWebElement()
    IHTMLElement

CreateWebEvtHandler()

FreeWebEvtHandler()

WaitOnReadyState()

더보기


extern "C" {

HINSTANCE        cwebdll;

long WINAPI EmbedBrowserObject(HWND hwnd);
void WINAPI UnEmbedBrowserObject(HWND hwnd);
long WINAPI DisplayHTMLPage(HWND hWnd, const char *url);
void WINAPI ResizeBrowser(HWND hWnd, DWORD x, DWORD y);

}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
     // TODO: Place code here.
// {
    // Load our DLL containing the OLE/COM code. We do this once-only. It's named "cwebpage.dll"
    if (!(cwebdll = LoadLibrary("cwebpage.dll")))
    {
        MessageBox(0, "Can't open cwebpage.dll!", "ERROR", MB_OK);
        return(-1);
    }
// }
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    ...
}
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
// {
        case WM_CREATE:
            // Embed the browser object into our host window. We need do this only
            // once. Note that the browser object will start calling some of our
            // IOleInPlaceFrame and IOleClientSite functions as soon as we start
            // calling browser object functions in EmbedBrowserObject().
            if (EmbedBrowserObject(hWnd)) return(-1);
            DisplayHTMLPage(hWnd, "http://www.microsoft.com");
            break;
// }
        case WM_DESTROY:
// {
            // Detach the browser object from this window, and free resources.
            UnEmbedBrowserObject(hWnd);
// }
            PostQuitMessage(0);
            break;
        case WM_COMMAND:
            ...
            break;
        case WM_SIZE:
            // Resize the browser object to fit the window
            ResizeBrowser(hWnd, LOWORD(lParam), HIWORD(lParam));
            break;
        ...
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}


참조 사이트:

http://support.microsoft.com/kb/315617/en-us/
http://msdn.microsoft.com/en-us/library/bb508508(VS.85).aspx
http://support.microsoft.com/kb/194179/en-us/
http://www.codeproject.com/KB/shell/dlgdhtmlevents.aspx?display=Print
http://msdn.microsoft.com/en-us/library/aa293017(VS.71).aspx
http://urassa.tistory.com/entry/Web-Browser-Control-FAQ

http://www.codeproject.com/KB/COM/cwebpage.aspx?display=Print
http://jjjryu.tistory.com/entry/IE-1
http://support.microsoft.com/kb/196339/en-us/
http://jjjryu.tistory.com/entry/ActiveX-%EC%BB%A8%ED%8A%B8%EB%A1%A4-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8
http://www.codeproject.com/KB/shell/AutomateShellWindow.aspx?display=Print
http://www.codeproject.com/KB/shell/iehelper.aspx?display=Print


출처 : http://jjjryu.tistory.com/333

Posted by SB패밀리