寄宿WebBrowser 控件
我们现在开始在VB和VC中创建一些程序来寄宿(Host)WebBrowser控件。在你完成本部分的样本,你将对如何创建寄宿一个WebBrowser控件的应用程序又一个基本的了解。当你看到如此容易的加入Web浏览功能加入到你的应用程序,我相信你会立即开始实践的。
使用VB
在VB中,你可以在5分钟内开发一个全功能的自己的web浏览 。以下步骤为建立一个web浏览器程序:
1. 启动VB.
2. 选择“Standard EXE“ ,进入设计模式。
3. WebBrowser 控件未自动化包含到控件工具箱(Control Toolbox)。 要增加 WebBrowser 控件到 控件工具箱,选择 Project 菜单下的Components. ,如下对话将显示:
Figure 6-3. 组件对话框.
4. 如果Controls TAB页未显示,点击 Controls TAB页 。然后勾选中列表中的“ Microsoft Internet Controls”,点击OK关闭对话框。Vb将会增加WebBrowser 控件到控件工具箱,如图所示:
Figure 6-4. Visual Basic 控件工具条在增加了WebBrowser 控件后的图标
5. 为增加 WebBrowser 控件至窗体,点击WebBrowser 控件,然后确定在窗体中的大小。一旦你增加了一个控件到表单,Visual Basic 将指派其名称为 WebBrowser1.
6. 调整表单的尺寸一边导航时候可看到更多的web内容。预留一些空间给地址栏。表单看起来如 Figure 6-5.
7. 双击空区域以增加Load 事件。为了能够使WebBrowser 导航到一个web页,你仅需要调用如GoHome, GoSearch, Navigate, 或者 Navigate2.等导航方法。
8. 调用GoHome 方法到用户主页。代码如下:
Private Sub Form_Load() WebBrowser1.GoHome End Sub |
Figure 6-5. Visual Basic form after adding the WebBrowser control.
如此就完成了! 你已经创建了一个全功能的web浏览器. 照我的时间,仅仅不好过分钟。为确信它可工作,你可启动进行测试。你的应用程序将装入webbrowser控件兵导航到主页。保存工程为VbWebHost.
尽管你已经拥有一个可工作的Internet应用程序,你仍需要做些工作视你的应用程序更像一个真实的web浏览器。为了可导航增加一些控件到表单。为输入URL增加一个 label, 一个文字输入框, Go 按钮, Back 按钮, Forward 按钮, 以及Stop 按钮. 表单应该看起来如Figure 6-6.
如 Table 6-7 分派给你的控件属性。
Figure 6-6. Visual Basic form after adding controls.
Table 6-7. 控件属性
控件 | 属性 |
Label | Caption = "Address:" |
TextBox | Name = txtAddress; Text = "" (In other words, remove the default text.) |
Go Button | Name = btnGo; Caption = "Go" |
Back Button | Name = btnBack; Caption = "< Back" |
Forward Button | Name = btnFwd; Caption = "Forward >" |
Stop Button | Name = btnStop; Caption = "Stop" |
增加一些代码,调用WebBrowser 控件的方法使得工作正常。 举例来说,当用户输入文字到文字输入框且点击Go 按钮,使用 Navigate 方法处理导航。 当然,你必须缺新用户真实输入了一些文字到文字输入框。
同样, 你也可以使用GoBack, GoForward, 以及 Stop 方法以实现Back, Forward, 和 Stop 按钮。记住 GoBack 和 GoForward 方法当前状态下无效。Visual Basic 代码看起来类似如下:
Option Explicit Private Sub btnBack_Click() On Error Resume Next WebBrowser1.GoBack End Sub Private Sub btnFwd_Click() On Error Resume Next WebBrowser1.GoForward End Sub Private Sub btnGo_Click() WebBrowser1.Navigate txtAddress.Text End Sub Private Sub btnStop_Click() WebBrowser1.Stop End Sub Private Sub Form_Load() WebBrowser1.GoHome End Sub |
注意 On Error Resume Next 特别用于Back 和Forward 按钮的click事件处理. 当当前URL前后无历史列表,这些方法将返回错误。Visual Basic错误捕获用于处理他们。
现在测试程序,在浏览器完成导航到主页,输入URL 到文字框点击Go 按钮。你将有两个 URLs 在历史列表中。点击 Back按钮退回到主页, 接着点击 Forward 按钮前移。在web页转载时候点击 Stop 按钮确信Stop 按钮工作正常。
打印web页
用为用户经常想打印在web浏览器中的页面,你可能细想加入打印功能到你的应用程序。过去打印在VB中笨重难以实现(使用sendkey),现在可以使用ExecWB方法来轻松实现,且非常可靠。
哟增加打印功能,首先加入Print 按钮到表单。 (如前面) 命名按钮为 btnPrint, 改变标题为Print. 看起来如Figure 6-7.
Figure 6-7. Visual Basic form after adding a Print button.
下一步, 双击 Print 按钮以增加Click事件处理代码.事件处理过程中, 调用 ExecWB 方法, 传递打印需要的命令ID: OLECMDID_PRINT.如果你想打印前提醒用户, 指定OLECMDEXECOPT_PROMPTUSER; 其他情形指定OLECMDEXECOPT_DONTPROMPTUSER。 本例中,我们打印前提示 。打印命令没有输入输出,所以你指定第三个和第四个参数 Null 。代码应当如下:
Private Sub btnPrint_Click() On Error Resume Next WebBrowser1.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, _ Null, Null End Sub |
使用 Visual C++
Vc中创建浏览器应用程序毕vb中稍微困难。如果白手起家创建米的宿应用程序 (无MFC 或 ATL), 需要实现大量的COM接口来寄宿WebBrowser 控件。你必须还要利用COM的API CoCreateInstance 创建WebBrowser 控件的实例,指定 CLSID_WebBrowser a作为你想创建的对象的CLSID 。并且还要 将控件"site"于你的应用程序.
因为建立ActiveX 控件容器费本文讨论主题,所以着重讨论简单途径寄宿webbrowser控件。
使用 MFC
你可以创建3种类型的MFC应用程序: 单文档接口 (SDI), 多文档接口 (MDI), 以及基于对话框的应用程序。因为对话框MFC类似VB,所以本处将讨论采用SDI来寄宿webbrowser控件。一旦你知道如何采用SDI 应用来寄宿webbrowser控件,转为MDI 将会容易些。
在演示SDI的例子中,我将使用WebBrowser (CWebBrowser2) 包装类MFC的内置CHtmlView 类将帮助你理解如何在MFC中寄宿WebBrowser 。
CHtmlView 类无需太多解释。要使用它,必须在MFC AppWizard第6步中选择你的应用程序的基类为ChtmlView, 如 Figure 6-8. 在完成 wizard后, 你的应用程序的视图类奖派生自 CHtmlView. 然后你可以直接调用IWebBrowser2 接口的不同方法.
Figure 6-8. MFC AppWizard - Step 6 of 6 dialog box.
为创建MFC 单文档接口应用程序,启动Visual C++ 新建菜单。新的对话框展示如 Figure 6-9.
Figure 6-9. Visual C++ New dialog box.
在 Projects 页, 选择 MFC AppWizard (exe) 项, 输入一个项目名称 (譬如 MfcWebHost之类), 点击OK. MFC AppWizard is 步骤一显示. (看 Figure 6-10.)
Figure 6-10. Step 1 of the MFC AppWizard.
选择 Single Document 。然后认可缺省选项,点击完成. 要增加WebBrowser 到你的工程,选择菜单Project/Add To Project/Components,如下图Figure 6-11所示:
Figure 6-11. Selecting Components And Controls.
Visual C++ 收集所有的你的系统中的组件和控件信息展示在Components 和Controls 陈列对话框,如图Figure 6-12所示.
Figure 6-12. Components And Controls Gallery dialog box.
双击 Registered ActiveX Controls , 定位到并选择Microsoft Web Browser, 点击插入按钮,提示你是否想加组件, 点击 OK。wizard 显示确认对话框如 Figure 6-13.
Figure 6-13. Confirm Classes dialog box.
缺省情况下, CWebBrowser2 将被选择。CWebBrowser2 类是VC为你创建的WebBrowser 控件的包装类。 因为该类特定实现于MFC, 所以你仅可在MFC项目中使用。点击OK 按钮增加CWebBrowser2 到项目中. 然后关闭陈列对话框
包含 WebBrowser2.h 在你的view 类的头文件—MfcWebHostView.h中:
创建private 或者 protected 数据成员,命名为 m_webBrowser. 声明如下:
protected: CWebBrowser2 m_webBrowser; |
为WM_CREATE 消息建立消息处理句柄. 在此事件处理中, 使用m_webBrowser的 Create 方法加入创建一个webbrowser控件的新实例。 (Create 方法是包装类为你创建的.) OnCreate 消息处理代码看起来如下:
int CMfcWebHostView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // Create WebBrowser control // if (!m_webBrowser.Create(NULL, WS_CHILD|WS_VISIBLE, CRect(), this, NULL)) { return -1; } return 0; } |
现在为WM_SIZE 消息创建消息处理. 当应用程序改变大小时候修改WebBrowser 控件的大小。如果你不包含以下代码,你的View窗口永远也不会显示webbrowser控件。 此处展示该消息处理代码:
void CMfcWebHostView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // Resize WebBrowser control // m_webBrowser.MoveWindow( 0, 0, cx, cy ); m_webBrowser.UpdateWindow(); } |
覆盖OnInitialUpdate m基类的代码在应用程序首次创建时导航到用户主页。此处展示OnInitialUpdate 消息处理代码:
void CMfcWebHostView::OnInitialUpdate() { CView::OnInitialUpdate(); // Navigate to the user's home page. // m_webBrowser.GoHome(); } |
编译且运行程序.将导航到用户的主页,如Figure 6-14.
Figure 6-14. MfcWebHost application.
现在加入一些访问internet的功能。 增加 Navigate 包含一些Go Back, Go Forward, Go Home, Go Search, Go To A Web Page、Stop等子菜单, 你的菜单看起来类似Figure 6-15.
Figure 6-15. Navigate menu.
现在你可以加入快捷健到你的菜单,例如Alt-Left 组合键给Go Back. 你可以使用你习惯的组合健
为每一个菜单项建立实现句柄。增加菜单消息处理句柄代码是较为容易的。举例, GoBack 方法实现Go Back 菜单项代码看起来如下:
void CMfcWebHostView::OnNavigateGoBack() { m_webBrowser.GoBack(); } void CMfcWebHostView::OnNavigateGoForward() { m_webBrowser.GoForward(); } void CMfcWebHostView::OnNavigateGoHome() { m_webBrowser.GoHome(); } void CMfcWebHostView::OnNavigateGoSearch() { m_webBrowser.GoSearch(); } void CMfcWebHostView::OnNavigateStop() { m_webBrowser.Stop(); } |
如上面提到,如果history列表不存在前项或者后项而用户点击Go Back 或者 Go Forward ,将会发生错误.
Go To A Web Page 菜单项是特别情形. 对此菜单项, 一个对话框将显示询问用户想去的URL. (见 Figure 6-16.)
Figure 6-16. Enter A URL For Navigation dialog box.
另外的选择,你可在工具条建立编辑框 用于导航. 在本例子中, 我选择了对话框。当建立对话框,你可以使用ClassWizard 建立新的对话框类.命名为CAddressDlg. 对话框类应当包含名为m_strAddress 的CString ,它将控制用户输入的地址。如果你的ClassWizard 创建此类成员,该成员将会是public的. 改变数据成员为protected, 且建立如下的访问存取方法:
public: const CString& GetAddress() const { return m_strAddress; } protected: CString m_strAddress; |
现在建立Go To A Web Page 菜单项的消息处理句柄.该菜单句柄将建立显示CAddressDlg 对话框. (确信 CAddressDlg 的头文件包含在 MfcWebHostView.cpp中.) 在用户输入URL 且点击OK后, 应用程序将利用webbrowser的Navigate 方法导航到URL 。 代码如下:
void CMfcWebHostView::OnNavigateGoToAWebPage() { CAddressDlg dlgAddr; // Show the dialog box. If the user clicks OK, // make sure a URL was entered. If one was entered, // navigate to that URL by using the Navigate method. // if (dlgAddr.DoModal() == IDOK) { CString strAddress = dlgAddr.GetAddress(); if (!strAddress.IsEmpty()) { COleVariant vtEmpty; m_webBrowser.Navigate(strAddress, &vtEmpty, &vtEmpty, &vtEmpty, &vtEmpty); } } } |
在以上代码中, 一个CAddressDlg 类的实例被创建。DoModal 用于显示对话框。如果用户点击OK 按钮,应用程序应当检查 URL是否合法。
使用 ATL
在过去,寄宿WebBrowser控件的ATL应用程序项比较标准的C++没有任何优势。但是现在,新的ATL3的ActiveX控件容器类允许你较容易创建宿主WebBrowser 控件的。
因为实现ATL用户界面特征如菜单和工具条还是使用Win32实现,本例我将展示其本质上灵活的一面。我只想展示如何使用新的容器类寄宿webbrowser控件。我不准备实现任何用户界面。本例子仅仅实现一个容纳WebBrowser的框架。
用ATL建立一个WebBrowser 宿主应用程序, 启动0 Visual C++, 执行以下及个步骤:
1. 新建.
2. 选择ATL COM AppWizard, 输入 AtlWebHost 作为工程名
3. 点击 OK, 选择 Executable (EXE),完成。
4. 在新建工程信息对话框点击OK, wizard 将建立ATL可执行文件工程的基本代码。
5. 向工程中加入宿主WebBrowser 的控件A。具体操作,在ClassView面板中右击 AtlWebHost类
6. 从上下文菜单中选择New ATL Object. ATL Object Wizard 对话框将显示
7. 从面板中选择HTML Control,如 Figure 6-17所示:
Figure 6-17. ATL Object Wizard with HTML Control selected.
8. 点击Next ,为控件输入一个短小名,例如 AtlWbHost.。wizard 自动填写其它部分
9. 保持推荐值直到OK.
wizard 将建立CAtlWbHost 类, 包含样本代码寄宿WebBrowser 控件.实例化WebBrowser控件的关键代码在OnCreate 方法的实现代码中, 当 WM_CREATE 消息被发送到关联此类的windows窗体时被调用。wizard 为 OnCreate 插入的代码如下:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { CAxWindow wnd(m_hWnd); HRESULT hr = wnd.CreateControl(IDH_ATLWBHOST); if (SUCCEEDED(hr)) hr = wnd.SetExternalDispatch(static_cast<IAtlWbHostUI*>(this)); if (SUCCEEDED(hr)) hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser); return SUCCEEDED(hr) ? 0 : -1; } |
在这段代码中, 类型微CAxWindow 的windows对象被首先创建,该对象提供ActiveX 控件容器支持. 下一步, 用CAxWindow 类的CreateControl方法创建WebBrowser控件。注意传递给CreateControl 的是HTML页的资源ID,所以当WebBrowser控件被创建时候HTML页被显示。然后SetExternalDispatch 方法被调用。该方法实现于IDocHostUIHandler 接口。
如果任何一个步骤都没有错误发生, 代码将用CAxWindow 的QueryControl 方法查询 IWebBrowser2接口.如果一切顺利, QueryControl 返回IWebBrowser2 接口的指针,存储于m_spBrowser 成员变量. 缺省情况下, wizard 将其标记为public.
提醒
作为我所认为的良好的面向对象编程习惯, 我习惯改变m_spBrowser 成员为 protected .当然你可以决定是否也如此做
如果现在就编译执行代码, 什么事情也不会发生。你必须加入创建和显示窗体的代码。要实现,你必须首先在CAtlWbHost 类中实现Run方法. (该名字无关痛痒。 你可选择任何你感兴趣的名字.) 示例代码如下:
STDMETHODIMP Run() { // // Create and show the window. // RECT rcClient = { CW_USEDEFAULT, 0, 0, 0 }; if (Create(GetDesktopWindow(), rcClient, _T("ATL Browser"), WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, (UINT)NULL) == NULL) { return E_FAIL; } ShowWindow(SW_SHOWNORMAL); return S_OK; } |
当 Create 方法被调用, WM_CREATE 消息发送到窗口; 因此, OnCreate 方法被调用,OnCreate中包含之前讨论的寄宿WebBrowser 控件的代码。
提醒
Create 方法属于CWindowImpl 类,而该类是CcomControl 的基础类。. CAtlWbHost 派生于CComControl, 这意味着你不如直接调用CWindowImpl 的方法。
下一步必须调用Run 方法以创建和显示窗体。 此调用将被生成于AtlWebHost.cpp 文件直接存在于你的应用程序消息循环之上。但在Run 被调用之前, CAtlWbHost 类的实例必须被创建。你不可以简单的象其他C++对象一样简单采用New操作符创建一个实例 。你必须采用CComObject 的CreateInstance 方法建立该类的实例。 在你的应用程序的消息泵处(CAtlWebHost.cpp中), 插入如下代码实例化CAtlWbHost 类, 然后调用 Run 方法:
CComObject<CAtlWbHost>* pWbHost; HRESULT hr = CComObject<CAtlWbHost>::CreateInstance(&pWbHost); if (SUCCEEDED(hr)) pWbHost->Run(); // Message pump MSG msg; while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg); |
如果现在编译执行, 它将可以工作了。它装入WebBrowser 控件, 导航到wizard automatically 插入到你的应用程序的HTML资源页. 你可以导航到某些有实际意义的地方. 你可在 OnCreate 函数中调用GoHome 。 在你加入调用 GoHome 之后, OnCreate 函数看起来如下:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { CAxWindow wnd(m_hWnd); HRESULT hr = wnd.CreateControl(IDH_ATLWBHOST); if (SUCCEEDED(hr)) hr = wnd.SetExternalDispatch(static_cast<IAtlWbHostUI*>(this)); if (SUCCEEDED(hr)) hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser); if (SUCCEEDED(hr)) m_spBrowser->GoHome(); return SUCCEEDED(hr) ? 0 : -1; } |
当你编译执行,你的应用程序看起来类似图Figure 6-18.
Figure 6-18. AtlWebHost application.
打印 Web 页
所有打印只需要调用传递OLECMDID_PRINT的 ExecWB 方法。
MfcWebHost 要支持打印, 应当建立一个ID_FILE_PRINT菜单的菜单句柄,在菜单句柄中调webbrowser的ExecWB ,以及传递 OLECMDID_PRINT. 你也可打印前提醒用户, 仅需要我们多做少量代码. 尽管如此,如果你想知道用户是否按下OK按钮或者取消按钮, 检查 ExecWB的返回值。针对打印命令, 如果用户点几OK以初始化打印, ExecWB 将返回S_OK。 如果用户点击取消, ExecWB 将返回 S_OK以外的值. (说 " S_OK以外的值" 是因为取消按钮的返回值不具有典型代表性) 以下代码为当用户选择文件菜单中打印命令时的调用情况。
void CMfcWebHostView::OnFilePrint() { m_webBrowser.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } |
作为打印的附加功能, WebBrowser control 试图提供打印页设置功能.采用打印页设置, 用户可以改变例如页头页脚等设置。要实现业设置功能,代码调用 ExecWB 并且传递 OLECMDID_PAGESETUP. 代码如下:
void CMfcWebHostView::OnFilePageSetup() { m_webBrowser.ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } |
使用 Visual C++
Vc中创建浏览器应用程序毕vb中稍微困难。如果白手起家创建米的宿应用程序 (无MFC 或 ATL), 需要实现大量的COM接口来寄宿WebBrowser 控件。你必须还要利用COM的API CoCreateInstance 创建WebBrowser 控件的实例,指定 CLSID_WebBrowser a作为你想创建的对象的CLSID 。并且还要 将控件"site"于你的应用程序.
因为建立ActiveX 控件容器费本文讨论主题,所以着重讨论简单途径寄宿webbrowser控件。
使用 MFC
你可以创建3种类型的MFC应用程序: 单文档接口 (SDI), 多文档接口 (MDI), 以及基于对话框的应用程序。因为对话框MFC类似VB,所以本处将讨论采用SDI来寄宿webbrowser控件。一旦你知道如何采用SDI 应用来寄宿webbrowser控件,转为MDI 将会容易些。
在演示SDI的例子中,我将使用WebBrowser (CWebBrowser2) 包装类MFC的内置CHtmlView 类将帮助你理解如何在MFC中寄宿WebBrowser 。
CHtmlView 类无需太多解释。要使用它,必须在MFC AppWizard第6步中选择你的应用程序的基类为ChtmlView,如 Figure 6-8. 在完成 wizard后, 你的应用程序的视图类奖派生自 CHtmlView. 然后你可以直接调用IWebBrowser2接口的不同方法.
Figure 6-8. MFC AppWizard - Step 6 of 6 dialog box.
为创建MFC 单文档接口应用程序,启动Visual C++ 新建菜单。新的对话框展示如 Figure 6-9.
Figure 6-9. Visual C++ New dialog box.
在 Projects 页, 选择 MFC AppWizard (exe) 项, 输入一个项目名称 (譬如 MfcWebHost之类), 点击OK. MFC AppWizard is 步骤一显示. (看 Figure 6-10.)
Figure 6-10. Step 1 of the MFC AppWizard.
选择 Single Document 。然后认可缺省选项,点击完成. 要增加WebBrowser 到你的工程,选择菜单Project/Add To Project/Components,如下图Figure 6-11所示:
Figure 6-11. Selecting Components And Controls.
Visual C++ 收集所有的你的系统中的组件和控件信息展示在Components 和Controls 陈列对话框,如图Figure 6-12所示.
Figure 6-12. Components And Controls Gallery dialog box.
双击 Registered ActiveX Controls , 定位到并选择Microsoft Web Browser, 点击插入按钮,提示你是否想加组件, 点击 OK。wizard 显示确认对话框如 Figure 6-13.
Figure 6-13. Confirm Classes dialog box.
缺省情况下, CWebBrowser2 将被选择。CWebBrowser2 类是VC为你创建的WebBrowser 控件的包装类。 因为该类特定实现于MFC, 所以你仅可在MFC项目中使用。点击OK 按钮增加CWebBrowser2 到项目中. 然后关闭陈列对话框
包含 WebBrowser2.h 在你的view 类的头文件—MfcWebHostView.h中:
创建private 或者 protected 数据成员,命名为 m_webBrowser. 声明如下:
protected: CWebBrowser2 m_webBrowser; |
为WM_CREATE 消息建立消息处理句柄. 在此事件处理中, 使用m_webBrowser的 Create 方法加入创建一个webbrowser控件的新实例。 (Create 方法是包装类为你创建的.) OnCreate 消息处理代码看起来如下:
int CMfcWebHostView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // Create WebBrowser control // if (!m_webBrowser.Create(NULL, WS_CHILD|WS_VISIBLE, CRect(), this, NULL)) { return -1; } return 0; } |
现在为WM_SIZE 消息创建消息处理. 当应用程序改变大小时候修改WebBrowser 控件的大小。如果你不包含以下代码,你的View窗口永远也不会显示webbrowser控件。 此处展示该消息处理代码:
void CMfcWebHostView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // Resize WebBrowser control // m_webBrowser.MoveWindow( 0, 0, cx, cy ); m_webBrowser.UpdateWindow(); } |
覆盖OnInitialUpdate m基类的代码在应用程序首次创建时导航到用户主页。此处展示 OnInitialUpdate 消息处理代码:
void CMfcWebHostView::OnInitialUpdate() { CView::OnInitialUpdate(); // Navigate to the user's home page. // m_webBrowser.GoHome(); } |
编译且运行程序.将导航到用户的主页,如Figure 6-14.
Figure 6-14. MfcWebHost application.
现在加入一些访问internet的功能。 增加 Navigate 包含一些Go Back, Go Forward, Go Home, Go Search, Go To A Web Page、Stop等子菜单, 你的菜单看起来类似Figure 6-15.
Figure 6-15. Navigate menu.
现在你可以加入快捷健到你的菜单,例如Alt-Left 组合键给Go Back. 你可以使用你习惯的组合健
为每一个菜单项建立实现句柄。增加菜单消息处理句柄代码是较为容易的。举例, GoBack 方法实现Go Back 菜单项代码看起来如下:
void CMfcWebHostView::OnNavigateGoBack() { m_webBrowser.GoBack(); } void CMfcWebHostView::OnNavigateGoForward() { m_webBrowser.GoForward(); } void CMfcWebHostView::OnNavigateGoHome() { m_webBrowser.GoHome(); } void CMfcWebHostView::OnNavigateGoSearch() { m_webBrowser.GoSearch(); } void CMfcWebHostView::OnNavigateStop() { m_webBrowser.Stop(); } |
如上面提到,如果history列表不存在前项或者后项而用户点击Go Back 或者 Go Forward ,将会发生错误.
Go To A Web Page 菜单项是特别情形. 对此菜单项, 一个对话框将显示询问用户想去的URL. (见 Figure 6-16.)
Figure 6-16. Enter A URL For Navigation dialog box.
另外的选择,你可在工具条建立编辑框 用于导航. 在本例子中, 我选择了对话框。当建立对话框,你可以使用ClassWizard 建立新的对话框类.命名为CAddressDlg. 对话框类应当包含名为m_strAddress 的CString ,它将控制用户输入的地址。如果你的ClassWizard 创建此类成员,该成员将会是public的. 改变数据成员为protected, 且建立如下的访问存取方法:
public: const CString& GetAddress() const { return m_strAddress; } protected: CString m_strAddress; |
现在建立Go To A Web Page 菜单项的消息处理句柄.该菜单句柄将建立显示CAddressDlg 对话框. (确信CAddressDlg 的头文件包含在 MfcWebHostView.cpp中.) 在用户输入URL 且点击OK后, 应用程序将利用webbrowser的Navigate 方法导航到URL 。 代码如下:
void CMfcWebHostView::OnNavigateGoToAWebPage() { CAddressDlg dlgAddr; // Show the dialog box. If the user clicks OK, // make sure a URL was entered. If one was entered, // navigate to that URL by using the Navigate method. // if (dlgAddr.DoModal() == IDOK) { CString strAddress = dlgAddr.GetAddress(); if (!strAddress.IsEmpty()) { COleVariant vtEmpty; m_webBrowser.Navigate(strAddress, &vtEmpty, &vtEmpty, &vtEmpty, &vtEmpty); } } } |
在以上代码中, 一个CAddressDlg 类的实例被创建。DoModal 用于显示对话框。如果用户点击OK 按钮,应用程序应当检查 URL是否合法。
使用 ATL
在过去,寄宿WebBrowser控件的ATL应用程序项比较标准的C++没有任何优势。但是现在,新的ATL3的ActiveX控件容器类允许你较容易创建宿主WebBrowser 控件的。
因为实现ATL用户界面特征如菜单和工具条还是使用Win32实现,本例我将展示其本质上灵活的一面。我只想展示如何使用新的容器类寄宿webbrowser控件。我不准备实现任何用户界面。本例子仅仅实现一个容纳WebBrowser的框架。
用ATL建立一个WebBrowser 宿主应用程序, 启动0 Visual C++, 执行以下及个步骤:
1. 新建.
2. 选择ATL COM AppWizard, 输入 AtlWebHost 作为工程名
3. 点击 OK, 选择 Executable (EXE),完成。
4. 在新建工程信息对话框点击OK, wizard 将建立ATL可执行文件工程的基本代码。
5. 向工程中加入宿主WebBrowser 的控件A。具体操作,在ClassView面板中右击 AtlWebHost 类
6. 从上下文菜单中选择New ATL Object. ATL Object Wizard 对话框将显示
7. 从面板中选择HTML Control,如 Figure 6-17所示:
Figure 6-17. ATL Object Wizard with HTML Control selected.
8. 点击Next ,为控件输入一个短小名,例如 AtlWbHost.。wizard 自动填写其它部分
9. 保持推荐值直到OK.
wizard 将建立CAtlWbHost 类, 包含样本代码寄宿WebBrowser 控件.实例化WebBrowser控件的关键代码在OnCreate 方法的实现代码中, 当 WM_CREATE 消息被发送到关联此类的windows窗体时被调用。wizard 为OnCreate 插入的代码如下:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { CAxWindow wnd(m_hWnd); HRESULT hr = wnd.CreateControl(IDH_ATLWBHOST); if (SUCCEEDED(hr)) hr = wnd.SetExternalDispatch(static_cast<IAtlWbHostUI*>(this)); if (SUCCEEDED(hr)) hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser); return SUCCEEDED(hr) ? 0 : -1; } |
在这段代码中, 类型微CAxWindow 的windows对象被首先创建,该对象提供ActiveX 控件容器支持. 下一步, 用CAxWindow 类的CreateControl方法创建WebBrowser控件。注意传递给CreateControl 的是HTML页的资源ID,所以当WebBrowser控件被创建时候HTML页被显示。然后SetExternalDispatch 方法被调用。该方法实现于IDocHostUIHandler 接口。
如果任何一个步骤都没有错误发生, 代码将用CAxWindow 的QueryControl 方法查询 IWebBrowser2 接口.如果一切顺利, QueryControl 返回IWebBrowser2 接口的指针,存储于m_spBrowser 成员变量. 缺省情况下, wizard 将其标记为public.
提醒
作为我所认为的良好的面向对象编程习惯, 我习惯改变m_spBrowser 成员为 protected . 当然你可以决定是否也如此做
如果现在就编译执行代码, 什么事情也不会发生。你必须加入创建和显示窗体的代码。要实现,你必须首先在CAtlWbHost 类中实现Run方法. (该名字无关痛痒。 你可选择任何你感兴趣的名字.) 示例代码如下:
STDMETHODIMP Run() { // // Create and show the window. // RECT rcClient = { CW_USEDEFAULT, 0, 0, 0 }; if (Create(GetDesktopWindow(), rcClient, _T("ATL Browser"), WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, (UINT)NULL) == NULL) { return E_FAIL; } ShowWindow(SW_SHOWNORMAL); return S_OK; } |
当 Create 方法被调用, WM_CREATE 消息发送到窗口; 因此, OnCreate 方法被调用,OnCreate中包含之前讨论的寄宿WebBrowser 控件的代码。
提醒
Create 方法属于CWindowImpl 类,而该类是CcomControl 的基础类。. CAtlWbHost 派生于CComControl, 这意味着你不如直接调用CWindowImpl 的方法。
下一步必须调用Run 方法以创建和显示窗体。 此调用将被生成于AtlWebHost.cpp 文件直接存在于你的应用程序消息循环之上。但在Run 被调用之前, CAtlWbHost 类的实例必须被创建。你不可以简单的象其他C++对象一样简单采用New操作符创建一个实例 。你必须采用CComObject 的CreateInstance 方法建立该类的实例。 在你的应用程序的消息泵处(CAtlWebHost.cpp中), 插入如下代码实例化CAtlWbHost 类, 然后调用 Run 方法:
CComObject<CAtlWbHost>* pWbHost; HRESULT hr = CComObject<CAtlWbHost>::CreateInstance(&pWbHost); if (SUCCEEDED(hr)) pWbHost->Run(); // Message pump MSG msg; while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg); |
如果现在编译执行, 它将可以工作了。它装入WebBrowser 控件, 导航到wizard automatically 插入到你的应用程序的HTML资源页. 你可以导航到某些有实际意义的地方. 你可在 OnCreate 函数中调用GoHome 。 在你加入调用GoHome 之后, OnCreate 函数看起来如下:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { CAxWindow wnd(m_hWnd); HRESULT hr = wnd.CreateControl(IDH_ATLWBHOST); if (SUCCEEDED(hr)) hr = wnd.SetExternalDispatch(static_cast<IAtlWbHostUI*>(this)); if (SUCCEEDED(hr)) hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser); if (SUCCEEDED(hr)) m_spBrowser->GoHome(); return SUCCEEDED(hr) ? 0 : -1; } |
当你编译执行,你的应用程序看起来类似图Figure 6-18.
Figure 6-18. AtlWebHost application.
打印 Web 页
所有打印只需要调用传递OLECMDID_PRINT的 ExecWB 方法。
MfcWebHost 要支持打印, 应当建立一个ID_FILE_PRINT菜单的菜单句柄,在菜单句柄中调webbrowser的ExecWB ,以及传递 OLECMDID_PRINT. 你也可打印前提醒用户, 仅需要我们多做少量代码. 尽管如此,如果你想知道用户是否按下OK按钮或者取消按钮, 检查 ExecWB的返回值。针对打印命令, 如果用户点几OK以初始化打印, ExecWB 将返回S_OK。 如果用户点击取消, ExecWB 将返回 S_OK以外的值. (说 " S_OK以外的值" 是因为取消按钮的返回值不具有典型代表性) 以下代码为当用户选择文件菜单中打印命令时的调用情况。
void CMfcWebHostView::OnFilePrint() { m_webBrowser.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } |
作为打印的附加功能, WebBrowser control 试图提供打印页设置功能.采用打印页设置, 用户可以改变例如页头页脚等设置。要实现业设置功能,代码调用 ExecWB 并且传递 OLECMDID_PAGESETUP. 代码如下:
void CMfcWebHostView::OnFilePageSetup() { m_webBrowser.ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); } |