接收事件的途徑
依靠開發工具你創建客戶應用程序,你可以接收事件通過不同的途徑. 顯然, 在Vb中接收事件同在VC中接收事件相比是如此不同和容易.在 C++ 應用中,你可以用不同的技術,通過使用 ATL, MFC, 或者標準C++.
Visual Basic 中接收事件
Visual Basic是創建大多數類型應用的最輕松的工具, 所以我告訴你VB是處理事件最溶的工具時也不要驚奇. ATL 和 Visual Basic 示例我們同樣的工作,但是ATL花費了我4個小時, 而 Visual Basic 例子僅僅只花20 分鐘.別說我錯了—我是ATL, 和 MFC, C++的忠實信徒, 尤其是你建立一個接口的時候.但是 Visual Basic當建立客戶應用程序從類似IE這樣的服務器接收事件時是偉大的工具.
OK,如何從Visual Basic 應用程序中接收事件?當宿主WebBrowser 控件,你不必做任何特別的事. Visual Basic 在form上為WebBrowser 控件接收事件.你所需要做的全部事情就是未你要接收的任何事件創建一個事件處理句柄.
你象創建其他事件句柄一樣創建句柄 (例如Form_Load event). 從Procedure下拉列表框中選擇你象控制的句柄, 在事件句柄中,加入任何你型在事件激發時執行的任何代碼.
當自動化服務器時候接收事件, 例如在VB應用中的Internet Explorer,過程直截了當.首先設置對服務器的類型庫的引用, 你可以訪問Project/References 菜單.之后,采用WithEvents 關鍵字聲明服務器對象的變量.舉例, 如果你自動化Internet Explorer, 你將聲明變量如下:
Dim WithEvents InternetExplorer1 As InternetExplorer |
下一步,采用new或者其他 關鍵字創建實例變量 ,如下::
Set InternetExplorer1 = CreateObject("InternetExplorer.Application.1") |
或者:
Set InternetExplorer1 = New InternetExplorer |
當你采用以上途徑生成實例接收事件, Visual Basic 自動為你初始化和管理事件接收.你不必擔心連接點問題,VB為你處理它們.
在你輸入建立服務器的代碼之后,你插入符合服務器事件的方法調用. 舉例來說, 如果你想控制由IE激活的DownloadBegin event, 你應當聲明類似如下的方法聲明:
Private Sub InternetExplorer1_DownloadBegin() ' Insert your best Visual Basic code here. End Sub |
當你不再想接收來自服務器的事件,簡單設置變量為Nothing:
Set InternetExplorer1 = Nothing |
C++中接收事件
C++ 應用程序中接收事件比Vb中多一些工作.但如果你在MFC對話框程序中宿主過WebBrowser控件, 你可以在classwizard中選擇你想控制的事件.使用C++的其他應用程序宿主WebBrowser 或者自動化Internet Explorer 需要多一點的工作,但是仍然不需要更多的工作.在C++客戶接收事件,僅僅需要以下5個步驟:
1. 獲取連接點容器的指針 (IConnectionPointContainer).
2. 調用IconnectionPointContainer 的方法 FindConnectionPoint 找出你想接收的事件。對 Internet Explorer來講, 你應當為DWebBrowserEvents2 連接點接口實現事件. (作為可選, 你可以調用EnumConnectionPoints 以枚舉服務器支持的全部連接點)
3. 實現接入你想接收事件的連接點的通報(Advise)。 當實現通告時,傳遞一個事件接收槽的Iunknown接口的指針。 記住,事件接收槽必須實現 IDispatch 接口以接收來自WebBrowser的事件。 Advise 方法將返回一個cookie ,該Cookie在你調用Unadvise 方法的時候攜帶上。
4. 實現 IDispatch::Invoke 以控制任何激發的事件。. (開發工具如 MFC 及 ATL 能夠容易為你做到.)
5. 當你不再接受事件,調用Unadvise, 并且傳遞cookie.
以上步驟如果采用VB和MFC /ATL等可能不很明顯,但是當你采用標準C++創建應用程序的時候就應當很明顯了.
以下 C++ 代碼允許你在自動化IE的時候接收事件. 留意注釋代碼實現了哪一個步驟. 假定當你想連接事件時ConnectEvents 方法被調用,且當應用程序退出時候Exit 方法被調用. 同樣的,類CSomeClass 繼承自IDispatch, 且m_pIE 數據成員為通過CoCreateInstance 方法創建的IE的實例
void CSomeClass::ConnectEvents() { IConnectionPointContainer* pCPContainer; // Step 1: 獲取連接點的指針. // HRESULT hr = m_pIE->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer); if (SUCCEEDED(hr)) { // m_pConnectionPoint is defined like this: // IConnectionPoint* m_pConnectionPoint; // Step 2: 選找連接點. // hr = pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &m_pConnectionPoint); if (SUCCEEDED(hr)) { // Step 3: 實現連接點地事件接收 // hr = m_pConnectionPoint->Advise(this, &m_dwCookie); if (FAILED(hr)) { ::MessageBox(NULL, "Failed to Advise", "C++ Event Sink", MB_OK); } } pCPContainer->Release(); } } void CSomeClass::Exit() { // Step 5: Unadvise. 注意m_pConnectionPoint 應當在CSomeClass的析構函數中釋放 // if (m_pConnectionPoint) { HRESULT hr = m_pConnectionPoint->Unadvise(m_dwCookie); if (FAILED(hr)) { ::MessageBox(NULL, "Failed to Unadvise", "C++ Event Sink", MB_OK); } } } |
注意此處少了step4:客戶端的 IDispatch::Invoke 方法實現. 我將很快討論此點. 每一次服務器激發事件會調用此. 當事件被激發,服務器傳遞事件的DISPID 到Invoke. 對于 Internet Explorer 5, 以下DISPIDs 定義于ExDispID.h 頭文件.
· DISPID_BEFORENAVIGATE2
- DISPID_COMMANDSTATECHANGE
- DISPID_DOCUMENTCOMPLETE
- DISPID_DOWNLOADBEGIN
- DISPID_DOWNLOADCOMPLETE
- DISPID_NAVIGATECOMPLETE2
- DISPID_NEWWINDOW2
- DISPID_ONFULLSCREEN
- DISPID_ONMENUBAR
- DISPID_ONQUIT
- DISPID_ONSTATUSBAR
- DISPID_ONTHEATERMODE
- DISPID_ONTOOLBAR
- DISPID_ONVISIBLE
- DISPID_PROGRESSCHANGE
- DISPID_PROPERTYCHANGE
- DISPID_STATUSTEXTCHANGE
- DISPID_TITLECHANGE
現在我們返回討論Invoke. 該方法有8個參數, 但我們將僅僅討論其中的兩個: dispidMember和pDispParams. (其余的參見MSDN中的IDispatch::Invoke.)
dispidMember 參數將告訴你哪一個事件被激發.如果客戶應用程序接收來自Internet Explorer的事件, dispidMember 參數的值應當是DISPIDs 列表中的某個.
pDispParams 輸入參數是指向容器結構的指針, 存儲事件激發時的其他項. 傳遞到事件句柄的參數存儲在pDispParams->rgvarg ,逆序存放. 舉例來說, Internet Explorer 激發NavigateComplete2 事件如下所示:
NavigateComplete2(pDisp, URL) |
當 Invoke 被調用, pDispParams->cArgs 將包含兩個值, URL 參數在 pDispParams->rgvarg[0]以及pDisp 參數存儲在 pDispParams->rgvarg[1]. 這些就是COM次序傳遞參數給Invoke 方法的方式.
以下為 NavigateComplete2 事件的處理.注意采用ATL的CComVariant 處理從 VARIANT到 BSTR包裝.
#include <strstrea.h> STDMETHODIMP CSomeClass::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { USES_CONVERSION; strstream strEventInfo; if (!pDispParams) return E_INVALIDARG; switch (dispidMember) { // The parameters for this DISPID: // [0]: URL navigated to - VT_BYREF|VT_VARIANT // [1]: An object that evaluates to the top-level or frame // WebBrowser object corresponding to the event. // case DISPID_NAVIGATECOMPLETE2: // Check the argument's type. if (pDispParams->rgvarg[0].vt == (VT_BYREF|VT_VARIANT)) { CComVariant varURL(*pDispParams->rgvarg[0].pvarVal); varURL.ChangeType(VT_BSTR); // strEventInfo is an object of type strstream. // strEventInfo << "NavigateComplete2: " << OLE2T(vtURL.bstrVal) << ends; ::MessageBox(NULL, strEventInfo.str(), "Invoke", MB_OK); } break; default: break; } return S_OK; } |
在ATL中接收事件
連同實現了缺省的COM 接口實現, ATL提供了兩個函數—AtlAdvise 和 AtlUnadvise—使得任何課連接對象的事件接收簡單化.
AtlAdvise 函數告訴一個可連接對象客戶想從此可連接對象接收事件.該函數封裝實現接收事件的步驟1到3. AtlAdvise 理所當然省了大量的時間.就像IConnectionPoint::Advise 方法,AtlAdvise 返回一個cookie供你稍后調用 AtlUnadvise. AtlUnadvise 告訴可連接對象客戶不再接收事件.
讓我們行說吧, 舉個例子, ATL應用程序自動化Internet Explorer, 所以你想知道任何IE激發的事件. 為了告知Internet Explorer客戶想接收事件,發出對AtlAdvise的以下調用:
HRESULT hr = AtlAdvise(m_spInetExplorer, GetUnknown(), DIID_DWebBrowserEvents2, &m_dwCookie); |
四個參數傳遞給AtlAdvise. 第一個參數是指向可連接對象的IUnknown 接口的指針.m_spInetExplorer 數據成員是一個經過我們自動化當前運行的Internet Explorer實例的指針. 因為m_spInetExplorer 指向的對象直接或者間接繼承自IUnknown, 編譯器自動轉換m_spInetExplorer 為當前運行的 IE實例的IUnknown 接口指針.
AtlAdvise 第二個參數必須指向提供事件的對象的IUnknown 接口. GetUnknown 函數返回此接口.記住,提供事件的類必須通過某種途徑實現 IDispatch in.在此例子中,該類繼承自 IDispatch.
第三個參數為你象接收的事件的IID, Internet Explorer 事件的可連接對象的IIS是DIID_DWebBrowserEvents2.
最后一個參數指向DWORD的指針,該DWORD接收返回的Cookie. 該 cookie 將用于調用AtlUnadvise.
客戶必須實現 IDispatch::Invoke 以控制Internet Explorer 激發的事件. 當你的應用程序完成從IE接收事件, 只需要調用 call AtlUnadvise, 如下:
HRESULT hr = AtlUnadvise(m_spInetExplorer, DIID_DWebBrowserEvents2, m_dwCookie); |

Figure 7-3. ATLIEEvtSpy.
以下展示如何自動化IE:
hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_spInetExplorer); if (SUCCEEDED(hr)) { m_spInetExplorer->put_Visible(TRUE); m_spInetExplorer->GoHome(); |
接下來, AtlAdvise 調用以接收事件, 如下:
hr = AtlAdvise(m_spInetExplorer, GetUnknown(), DIID_DWebBrowserEvents2, &m_dwCookie); |
CIEEvtObj 類繼承自IDispatch, 所以 CIEEvtObj 類可以作為事件接收對象. Invoke 實現控制事件. 每當Internet Explorer 激發一個事件, 在listBox中顯示一個消息.以西為invoke的代碼:
STDMETHODIMP CIEEvtObj::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { _ASSERT(m_spInetExplorer); USES_CONVERSION; strstream strEventInfo; if (!pDispParams) return E_INVALIDARG; switch (dispidMember) { // // The parameters for this DISPID are as follows: // [0]: Cancel flag - VT_BYREF|VT_BOOL // [1]: HTTP headers - VT_BYREF|VT_VARIANT // [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT // [3]: Target frame name - VT_BYREF|VT_VARIANT // [4]: Option flags - VT_BYREF|VT_VARIANT // [5]: URL to navigate to - VT_BYREF|VT_VARIANT // [6]: An object that evaluates to the top-level or frame // WebBrowser object corresponding to the event // case DISPID_BEFORENAVIGATE2: strEventInfo << "BeforeNavigate2: "; if (pDispParams->cArgs >= 5 && pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT)) { CComVariant vtURL(*pDispParams->rgvarg[5].pvarVal); vtURL.ChangeType(VT_BSTR); strEventInfo << OLE2T(vtURL.bstrVal); } else strEventInfo << "NULL"; strEventInfo << ends; break; // // The parameters for this DISPID: // [0]: Enabled state - VT_BOOL // [1]: Command identifier - VT_I4 // case DISPID_COMMANDSTATECHANGE: strEventInfo << "CommandStateChange: "; if (pDispParams->cArgs == 0) strEventInfo << "NULL"; else { if (pDispParams->cArgs > 1 && pDispParams->rgvarg[1].vt == VT_I4) { strEventInfo << "Command = " << pDispParams->rgvarg[1].lVal; } if (pDispParams->rgvarg[0].vt == VT_BOOL) { strEventInfo << ", Enabled = " << ((pDispParams->rgvarg[0].boolVal == VARIANT_TRUE) ? "True" : "False"); } } strEventInfo << ends; break; case DISPID_DOCUMENTCOMPLETE: strEventInfo << "DocumentComplete" << ends; break; case DISPID_DOWNLOADBEGIN: strEventInfo << "DownloadBegin" << ends; break; case DISPID_DOWNLOADCOMPLETE: strEventInfo << "DownloadComplete" << ends; break; // // The parameters for this DISPID: // [0]: URL navigated to - VT_BYREF|VT_VARIANT // [1]: An object that evaluates to the top-level or frame // WebBrowser object corresponding to the event // case DISPID_NAVIGATECOMPLETE2: if (pDispParams->rgvarg[0].vt == (VT_BYREF|VT_VARIANT)) { CComVariant vtURL(*pDispParams->rgvarg[0].pvarVal); vtURL.ChangeType(VT_BSTR); strEventInfo << "NavigateComplete2: " << OLE2T(vtURL.bstrVal) << ends; } break; // // The parameters for this DISPID: // [0]: Maximum progress - VT_I4 // [1]: Amount of total progress - VT_I4 // case DISPID_PROGRESSCHANGE: strEventInfo << "ProgressChange: "; if (pDispParams->cArgs == 0) strEventInfo << "NULL"; else { if (pDispParams->cArgs > 1 && pDispParams->rgvarg[1].vt == VT_I4) { strEventInfo << "Progress = " << pDispParams->rgvarg[1].lVal; } if (pDispParams->rgvarg[0].vt == VT_I4) strEventInfo << ", ProgressMax = " << pDispParams->rgvarg[0].lVal; } strEventInfo << ends; break; // // The parameter for this DISPID: // [0]: Name of property that changed - VT_BSTR // case DISPID_PROPERTYCHANGE: strEventInfo << "PropertyChange: "; if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_BSTR) { strEventInfo << OLE2T(pDispParams->rgvarg[0].bstrVal); } else { strEventInfo << "NULL"; } strEventInfo << ends; break; // // The parameters for this DISPID: // [0]: New status bar text - VT_BSTR // case DISPID_STATUSTEXTCHANGE: LPOLESTR lpStatusText; m_spInetExplorer->get_StatusText(&lpStatusText); strEventInfo << "StatusTextChange: "; if (!strcmp(OLE2T(lpStatusText), "")) strEventInfo << "NULL"; else strEventInfo << OLE2T(lpStatusText); strEventInfo << ends; break; case DISPID_NEWWINDOW2: strEventInfo << "NewWindow2" << ends; break; // // The parameter for this DISPID: // [0]: Document title - VT_BSTR // case DISPID_TITLECHANGE: strEventInfo << "TitleChange: "; if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_BSTR) { strEventInfo << OLE2T(pDispParams->rgvarg[0].bstrVal); } else { strEventInfo << "NULL"; } strEventInfo << ends; break; // The user has told Internet Explorer to close. // case DISPID_ONQUIT: return Stop(); default: // Note: This class acts only as an event sink, so // there's no reason to call the base class version of Invoke. strEventInfo << "Unknown Event" << dispidMember << ends; break; } AddEventToList(strEventInfo.str()); return S_OK; } |
請注意此使用了標準C++ 庫的 strstream 類來建立字符串.這么做是因為ATL 不提供像Cstring的類. 每一次從IE接收到事件,建立一個包含事件的名稱和參數的字符串. 然后顯示在列表框中.
退出時候調用AtlUnadvise:
STDMETHODIMP CIEEvtObj::Stop() { if (m_spInetExplorer) { HRESULT hr = AtlUnadvise(m_spInetExplorer, DIID_DWebBrowserEvents2, m_dwCookie); if (FAILED(hr)) ATLTRACE("Failed to Unadvise/n"); } PostQuitMessage(0); return S_OK; } |
在 MFC中接收事件
MFC提供了數個宏使得你可以接收從自動化的對象或者宿主的控件的事件。在兩種情況中, 接收事件的類必須直接或者間接繼承自CCmdTarget. CCmdTarget 實現接收事件的IDispatch 接口. 另外, 你必須在你的應用中調用EnableAutomation 初始化包含在CCmdTarget 中的IDispatch.
在MFC中自動化一個COM 對象時接收事件
在mfc中接收事件很容易.全部要做的就是在代碼中調用AfxConnectionAdvise 函數以通告連接點客戶需要接收事件.當客戶不許要接收事件,調用AfxConnectionUnadvise. AfxConnectionAdvise 和AfxConnectionUnadvise 函數定義于afxctl.h 頭文件。
AfxConnectionAdvise 函數查詢連接點容器, 尋找可連接點,并且通告連接點. 函數的5個參數如下:
Table 7-3 Parameters of the AfxConnectionAdvise Function
Parameter | Description |
pUnkSrc | 指向激發事件的com對象的IUnknown 接口的指針. pUnkSrc 是由CoCreateInstance.建立的對象的指針 |
pUnkSink | 指向事件接收的 IUnknown 接口 |
iid | 連接點的IID. 例如對IE來說,是DIID_DWebBrowserEvents2. |
bRefCount | 傳遞 TRUE 表示建立連接點將導致pUnkSink 的引用將增加。FALSE 表示不會增加. |
pdwCookie | 表示此連接。由AfxConnectionAdvise 將傳遞給 AfxConnectionUnadvise |
處理事件也很容易。記住MFC事件接收類必須繼承自CCmdTarget. CCmdTarget 使用派遣映射檢測當接收到事件時調用處理函數.你必須首先在頭文件中聲明派遣映射 然后再實現文件中 (.cpp) 實現. 幸運地, MFC提供了宏來幫助聲明和處理派遣映射。.
為了定義派遣映射, 首先在聲明接收事件類的頭文件中簡單定義DECLARE_DISPATCH_MAP. 這些宏聲明派遣映射和CCmdTarget 訪問的函數. 一旦你定義了派遣映射,你應當在實現文件中實現宏. 第一個宏放在BEGIN_DISPATCH_MAP 宏.它指定事件接收類的基礎類.舉例來說,如果事件類是CEventSink 繼承自 CCmdTarget, BEGIN_DISPATCH_MAP 將看起來如下:
BEGIN_DISPATCH_MAP(CEventSink, CCmdTarget) |
接下來用DISP_FUNCTION_ID來聲明派遣ID。此宏的六個參數:
Table 7-4 Parameters of the DISP_FUNCTION_ID Macro
Parameter | Description |
theClass | 事件類的名稱 |
szExternalName | 函數的名字. |
dispid | 事件的DISPID |
pfnMember | 指向處理事件的成員函數. |
vtRetval | 成員函數的返回值類型,是VARENUM 的每局類型,定義于wtypes.h 頭文件 |
vtsParams | 空格分隔的參數類型的列表. |
假設你想控制DownloadComplete 事件. 告訴CCmdTarget 你將控制處理DownloadComplete, 如下使用:
DISP_FUNCTION_ID(CIE5Events, "DownloadComplete", DISPID_DOWNLOADCOMPLETE, OnDownloadComplete, VT_EMPTY, VTS_NONE) |
最終采用 END_DISPATCH_MAP宏關閉.完整如下:
BEGIN_DISPATCH_MAP(CEventSink, CCmdTarget) DISP_FUNCTION_ID(CIE5Events, "DownloadComplete", DISPID_DOWNLOADCOMPLETE, OnDownloadComplete, VT_EMPTY, VTS_NONE) END_DISPATCH_MAP() |
在MFC中寄宿 ActiveX 控件時處理事件
這類似于處理COM對象的事件.主要區別在于你不需要通告或者解除通告連接點. CCmdTarget 未你控制了他.
在寄宿一個Activex控件情形中, CCmdTarget 使用事件接收宏代理派遣宏.就像你猜想的一樣, MFC 提供初始化事件接收通告映射. 聲明此宏類似聲明派遣宏—派 DECLARE_EVENTSINK_MAP 宏存放在頭文件中.另外的聲明映射, DECLARE_EVENTSINK_MAP 聲明 CCmdTarget 訪問映射的類
接下來在類中實現事件接收.開始于EGIN_EVENTSINK_MAP 宏.指定事件接收類的 和它的基類。舉例,此處為實例:
BEGIN_EVENTSINK_MAP(CMyDlg, CDialog) |
現在實用ON_EVENT*宏來處理是按接收.。大多數情形,你將使用帶有5個參數的ON_EVENT.攜帶的參數如下:
ON_EVENT(CMyDlg, IDC_WEBBROWSER, DISPID_DOWNLOADCOMPLETE, OnDownloadComplete, VTS_NONE) |
如果你象多個成員函數處理此事件, 使用ON _EVENT_RANGE宏.
Table 7-5 Parameters of the ON_EVENT Macro
Parameter | Description |
theClass | 在那個類中接收事件 |
id | 控件的資源ID號 |
dispid | 有控件激活的事件的 ID. |
pfnHandler | 事件的成員函數,用來處理事件句柄. 此函數應當有BOOL來型的返回值以及匹配事件的參數。當事件函數被處理則返回TRUE |
vtsParams | VTS_ constants 的類型 |
你引剛才用 END_EVENTSINK_MAP 宏.完整的定義如下:
BEGIN_EVENTSINK_MAP(CMyDlg, CDialog) ON_EVENT(CMyDlg, IDC_WEBBROWSER, DISPID_DOWNLOADCOMPLETE, OnDownloadComplete, VTS_NONE) END_EVENTSINK_MAP() |
對于 DocumentComplete 事件,你應當如下聲明:
// Declare the event sink map. This declaration goes // in the class declaration of CMFCIEEvtSpyDlg in the // MFCIEEvtSpyDlg.h header file. // DECLARE_EVENTSINK_MAP() // Initialize the event sink map. These macros // go in the implementation file _ MFCIEEvtSpyDlg.cpp. // BEGIN_EVENTSINK_MAP(CMFCIEEvtSpyDlg, CDialog) ON_EVENT(CMFCIEEvtSpyDlg, IDC_WEBBROWSER, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT) END_EVENTSINK_MAP() |
Figure 7-4. MFCIEEvtSpy.
當WebBrowser 控件基于對話框應用,你通常不需要插入默認的宏, 因為 ClassWizard 可為你做這一切.而在SDI或者MDI工程中,需要加上此宏。
現在事件接收映射已經聲明, 每當WebBrowser 控件激發了DocumentComplete 事件,OnDocumentComplete 方法將被調用.在CMFCIEEvtSpyDlg的 OnDocumentComplete 方法中, 包含URL和事件名稱的字符串被創建。之后字符串加入到列表框中展示WebBrowser 控件的事件.
以下代碼解釋如何接收處理DocumentComplete 事件.:
void CMFCIEEvtSpyDlg::OnDocumentComplete(LPDISPATCH pDisp, VARIANT* URL) { USES_CONVERSION; CString strEvt("DocumentComplete: "); strEvt += OLE2T(URL->bstrVal); AddEventToList(WBListBox, strEvt); } |
當啟動后,采用CoCreateInstance 創建的ie實例傳遞LSID_InternetExplorer接口..
以下為代碼:
void CMFCIEEvtSpyDlg::OnStartIE() { if (m_pInetExplorer == NULL) // Can start only one instance { // Create an instance of Internet Explorer. // HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pInetExplorer); if (SUCCEEDED(hr)) { // Set up the event sink. // BOOL bAdvised = AfxConnectionAdvise(m_pInetExplorer, DIID_DWebBrowserEvents2, m_pIE5Events->GetInterface(&IID_IUnknown), TRUE, &m_dwCookie); // Disable the Start IE5 button so that the // user knows that only one instance of // Internet Explorer can be started at a time. // m_btnStartIE.EnableWindow(FALSE); // Make Internet Explorer visible and go home. // m_pInetExplorer->put_Visible(VARIANT_TRUE); m_pInetExplorer->GoHome(); } } } |
為接收Internet Explorer 的事件,你應當聲明派遣接口且在實現文中:
// Declare the dispatch map. This // declaration is placed in the class declaration // for the CIE5Events class, which is in the // CIE5Events.h header file. // DECLARE_DISPATCH_MAP() // Initialize the dispatch map in the // implementation file for CIE5Events _ CIE5Events.cpp. // BEGIN_DISPATCH_MAP(CIE5Events, CCmdTarget) DISP_FUNCTION_ID(CIE5Events, "DocumentComplete", DISPID_DOCUMENTCOMPLETE, OnDocumentComplete, VT_EMPTY, VTS_DISPATCH VTS_PVARIANT) END_DISPATCH_MAP() |
現在無論如何接收到的自動化 Internet Explorer 的事件 DocumentComplete,OnDocumentComplete方法將被調用. OnDocumentComplete 方法創建一個包含事件名稱和URL的字符串,且加入到列表框通告Internet Explorer事件發生.同樣期它事件發生也會如此處理.此處為CIE5Events 類的OnDocumentComplete 方法代碼:
void CIE5Events::OnDocumentComplete(LPDISPATCH pDisp, VARIANT* URL) { USES_CONVERSION; CString strEvt("DocumentComplete: "); strEvt += OLE2T(URL->bstrVal); m_pParent->AddEventToList(CMFCIEEvtSpyDlg::IE5ListBox, strEvt); } |