« WebBrowser Controlを使う | メイン | どこまで組み込もう? »

2005年12月03日

mixi Alert 開発日誌:: WebBrowser Controlでイベントに反応する

    

IEコンポーネントの使い方でonclick や onmouseover などのイベントをハンドルしたいが出来ないと書いてあったのでリンクを見てやったみたら、すんなり出来た。
具体的には、

DocumentCompleteで次のようにしてオブジェクトのコネクション ポイントとクライアントのシンクとの間に接続を確立。

    hr = pDoc->QueryInterface(&pSrcUnk);
    hr = AtlAdvise(pSrcUnk, pSink, DIID_HTMLDocumentEvents, &dwDocCookie);

pDocは、読み込んだドキュメントのIHTMLDocument2を表している。

BeforeNavigate2で次のようにして、以前のドキュメントに確立された接続を終了。

if( pSrcUnk )
{
    hr = AtlUnadvise(pSrcUnk, DIID_HTMLDocumentEvents, dwDocCookie);
    pSrcUnk.Detach();
}

pSrcUnkはCComPtr<IUnknown> pSrcUnk;と定義している。

シンクのヘッダーは次のようにした。

#ifndef __EVENT_SINK_H__
#define __EVENT_SINK_H__

#include <oaidl.h>

class CEventSink : public IDispatch
{
protected:
    int m_cRef;

public:
    CEventSink() : m_cRef(1) {}
    ~CEventSink() {}

    //Methods of IUnknown
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
    ULONG STDMETHODCALLTYPE AddRef();
    ULONG STDMETHODCALLTYPE Release();

    // Methods of IDispatch
    STDMETHOD (GetTypeInfoCount)(UINT* pctinfo) { return E_NOTIMPL; }
    STDMETHOD (GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
    STDMETHOD (GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }
    STDMETHOD (Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr);
};
#endif

ソースは次のようにした。

#include "CEventSink.h"
#include <olectl.h>
#include <mshtmdid.h>

// {8773DF07-30E6-4f21-9568-2B6D326626D7}
static const GUID IID_ClickEventSink =
{ 0x8773df07, 0x30e6, 0x4f21, { 0x95, 0x68, 0x2b, 0x6d, 0x32, 0x66, 0x26, 0xd7 } };

HRESULT STDMETHODCALLTYPE CEventSink::QueryInterface(REFIID iid, void** ppvObject)
{
    if (iid == IID_IUnknown || iid == IID_IDispatch|| iid == IID_ClickEventSink)
    {
        if( ppvObject == NULL ) return E_POINTER;
        *ppvObject = this;
        AddRef();
        return S_OK;
    } else {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
ULONG STDMETHODCALLTYPE CEventSink::AddRef()
{
    m_cRef++;
    return m_cRef;
}
ULONG STDMETHODCALLTYPE CEventSink::Release()
{
    int ret = --m_cRef;
    if (ret <= 0) {
        delete this;
        ret = 0;
    }
    return ret;
}
HRESULT STDMETHODCALLTYPE CEventSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
    HRESULT hr;
    if( dispid == DISPID_CLICK ) {
        pvarResult->vt = VT_BOOL;
        pvarResult->boolVal = TRUE;
        hr = S_OK;
    } else if( dispid == DISPID_EVMETH_ONCONTEXTMENU ) {
        pvarResult->vt = VT_BOOL;
        pvarResult->boolVal = TRUE;
        hr = S_OK;
    } else {
        hr = DISP_E_MEMBERNOTFOUND;
    }
    return hr;
}

DISPID_CLICKは左クリックされた時のイベントで、DISPID_EVMETH_ONCONTEXTMENUはコンテキスメニュー(右クリックメニュー)が表示され時のイベント。
これらのイベントはmshtmdid.hに定義されている。
上述のようにするとコンテキスメニューは表示されなくなる。
が、良く考えたらテキストが選択されていた場合などで表示するメニューを変えたいので、IDocHostUIHandler を実装して設定してやる方法の方が良さそう。
それはまた今度やろう。



投稿者 Takenori : 2005年12月03日 23:42




comments powered by Disqus
Total : Today : Yesterday : なかのひと