使用VC++和COM API
尽管使用VC不像Vb中那么容易自动化IE,但是也不太难,尤其是你理解了CON和COM API。无论你使用MFC, ATL, 或者标准 C++自动化IE,方法都是一样—你使用COM API来实现.
VC++中创建一个Internet Explorer实例包括要调用COM API CoCreateInstance ,指定第一个参数为 CLSID_InternetExplorer 。创建IE自动化实例不像创建包含webbrowser的Activex控件困难。你不需要实现容器或者site对象的必要接口。
来看看如何容易的使用CoCreateInstance 创建IE实例吧。启动Visual C++, 新建MFC AppWizard (exe) 应用程序命名为 MfcAutoIE.选择dialog-based option, 认可其他缺省选项.
现在加入如VbAutoIE中的控件到表单.对话框看起来如 6-21. 分派ID到对话框的各个控件。 确信控件TAB次序如 Figure 6-22. (tab 次序影响到radio按钮的工作)
Figure 6-21. MfcAutoIE dialog.
Figure 6-22. MfcAutoIE dialog tab order.
现在用右键菜单设置每一个隐藏radio按钮的Group ,属性设置如表 6-9.
Table 6-9. Member Variables for MfcAutoIE Dialog Controls
Control | Type | Member Variable |
Hide radio button for AddressBar | int | m_nAddressBar |
Edit box | CString | m_strStatusText |
Hide radio button for MenuBar | int | m_nMenuBar |
Hide radio button for StatusBar | int | m_nStatusBar |
Hide radio button for ToolBar | int | m_nToolBar |
我们使用ClassWizard 为表 6-9 中的控件建立变量时,他们自动加入到 CMfcAutoIEDlg. 成员变量设置为-1.
编译MfcAutoIE Example之前我们设置编译的Directory次序 属性
编译之前,你需要处理一些重要任务:
1. 确信你已经从MSDN中下载IE5的头文件和库文件。
2. 在Tools/Options 菜单的Directories页, 确信lib路径中包含Internet Explorer 5 和Windows 2000库文件.载列表中。
3. 配置Include: 略
现在我们加入代码使之工作。 首先你应当包含ExDisp.h到你的对话框头文件—MfcAutoIEDlg.h. ExDisp.h 是包含了WebBrowser接口和类ID的头文件.确信你已经从MSDN下载了最新的版本。
建立一个private 或者protected 的数据类型,指向IWebBrowser2 的指针, 命名为m_pInetExplorer. 如下
protected: IWebBrowser2* m_pInetExplorer; |
现在在构造函数中初始化m_pInetExplorer 为 NULL 。你必须也初始化COM. 放置一个CoInitialize 的COM API调用在构造函数。构造函数看起来应当如下:
CMfcAutoIEDlg::CMfcAutoIEDlg(CWnd* pParent /*=NULL*/) : CDialog(CMfcAutoIEDlg::IDD, pParent), m_pInetExplorer(NULL) { //{{AFX_DATA_INIT(CMfcAutoIEDlg) m_strStatusText = _T(""); m_nAddressBar = -1; m_nMenuBar = -1; m_nStatusBar = -1; m_nToolBar = -1; //}}AFX_DATA_INIT //Note that LoadIcon does not require a subsequent DestroyIcon //in Win32. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // Initialize COM CoInitialize(NULL); } |
建立一个析构函数,以便调用CoUninitialize API 函数用以反初始化 COM. 此处的析构函数:
CMfcAutoIEDlg::~CMfcAutoIEDlg() { // Uninitialize COM. // CoUninitialize(); } |
在预备工作之后, 让我们开始实现具体的控制。首先为Start IE5 按钮建立一个消息循环. 通常,你可以使用ClassWizard建立消息循环处理句柄. 在此消息句柄, 采用 CoCreateInstance API 建立一个IE实例。 此处初建的Internet Explorer实例初始化为隐藏, 所以你必须使用Visible属性使他可见。为了导航到用户的主页,使用GoHome 方法。此处为消息处理句柄代码:
void CMfcAutoIEDlg::OnStartIE5() { // If an instance of Internet Explorer has // not already been created, create one. // This instance will initially be hidden, // so make it visible by using the Visible // property. Also, navigate to the user's // home page by using the GoHome method. // if (m_pInetExplorer) MessageBox (_T("Only one instance of Internet Explorer is allowed.")); else { HRESULT hr; hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER, IID_IWebBrowser2, (LPVOID*)&m_pInetExplorer); if (SUCCEEDED(hr)) { // Set the radio buttons to their correct values. SetRadioButtons(); m_pInetExplorer->put_Visible(VARIANT_TRUE); m_pInetExplorer->GoHome(); } } } |
在此代码中,我们首先检查是否IE的上一个实例已经建立。如果已经建立,将会显示一个错误消息框。(你仅仅能够启动一个IE的实例,随后你将可以看到如何检测IE窗口被关闭以便重置IE的数据成员。)如果一个IE的实例还未创建, CoCreateInstance 将 CLSID_InternetExplorer 作为第一个参数被调用. (此类 ID 定义于ExDisp.h ,为Internet Explorer的唯一标示符.)
第二个参数我们设定为NULL ,因为我们不希望此COM对象被聚合(be aggregated). 我们希望IE运行在一个单独的进程空间,所以我们指定第三个参数为特殊值 CLSCTX_SERVER .我们利用第四个参数指示哪一个接口我们将通过CoCreateInstance 调用创建一个COM对象后被创建。在此例中,我们将一直希望获得IWebBrowser2, 所以我们指定IID_IWebBrowser2 为第四个参数值。最后我们传送存储接口指针的变量. 对于此参数,你必须采用void类型传递一个指针的地址 (确信你传送的指针指向一个接口类型。)
如果一个IE实例成功创建,名为SetRadioButtons 的成员变量被创建。这是一个protected 成员函数,检查当前地址栏、菜单条、工具条和状态条等的状态 ,用来设置radio 按钮组的状态。.为检查每一个的状态我们简单的获取属性关联的当前值 。
C++ 应用中使用COM 没有包装类, 属性被引用为使用 get_ and put_ 方法.为检取每一个用户问题的状态,我们简单的调用每一个关联的(UI)项目的get_ 方法 .除了 get_ToolBar外其他get_方法返回指向VARIANT_BOOL 数据类型,返回值指示用户接口是否可见或者隐藏。如果用户接口元素可见,将返回VARIANT_TRUE 。如果该项目是隐藏的,将返回VARIANT_FALSE 。这些值区别于TRUE和 FALSE 的用法.
提醒
当在Visual C++涉及 VARIANT_BOOL , 你必须使用VARIANT_TRUE 或者VARIANT_FALSE 代替 TRUE or FALSE. VARIANT_TRUE定义值 0xffff, 而 TRUE 定义为1. 如果你比较 VARIANT_TRUE 和 TRUE, 你将发现在Vb中不匹配,你可以在涉及到VARIANT_BOOL. 使用true和false是由于VB替你实现了转换。
get_ToolBar 方法不同于其他属性,因为它指向一个整型指针,所以我们如果发现返回非0,工具条可见。如果整型值是0,工具条将隐藏:
提醒
如果一个属性只读, put_ 将不会出现。同样,如果一个属性只写,将不会出现get_ 方法。
此处为 SetRadioButtons 方法的代码:
void CMfcAutoIEDlg::SetRadioButtons() { VARIANT_BOOL vtBool = VARIANT_TRUE; // Get the current state of the AddressBar. // m_pInetExplorer->get_AddressBar(&vtBool); m_nAddressBar = (vtBool == VARIANT_TRUE) ? 1 : 0; // Get the current state of the MenuBar. // m_pInetExplorer->get_MenuBar(&vtBool); m_nMenuBar = (vtBool == VARIANT_TRUE) ? 1 : 0; // Get the current state of the StatusBar. // m_pInetExplorer->get_StatusBar(&vtBool); m_nStatusBar = (vtBool == VARIANT_TRUE) ? 1 : 0; // Get the current state of the ToolBar. // Unlike the other get methods, get_ToolBar // takes a pointer to an integer. // m_pInetExplorer->get_ToolBar(&m_nToolBar); UpdateData(FALSE); // Initializes dialog box with changed values. } |
:
void CMfcAutoIEDlg::OnAddrBarShowHide() { UpdateData(TRUE); if (m_pInetExplorer) { VARIANT_BOOL vtShow = m_nAddressBar ? VARIANT_TRUE : VARIANT_FALSE; m_pInetExplorer->put_AddressBar(vtShow); } } void CMfcAutoIEDlg::OnMenuBarShowHide() { UpdateData(TRUE); if (m_pInetExplorer) { VARIANT_BOOL vtShow = m_nMenuBar ? VARIANT_TRUE : VARIANT_FALSE; m_pInetExplorer->put_MenuBar(vtShow); } } void CMfcAutoIEDlg::OnStatusBarShowHide() { UpdateData(TRUE); if (m_pInetExplorer) { VARIANT_BOOL vtShow = m_nStatusBar ? VARIANT_TRUE : VARIANT_FALSE; m_pInetExplorer->put_StatusBar(vtShow); } } void CMfcAutoIEDlg::OnToolBarShowHide() { UpdateData(TRUE); if (m_pInetExplorer) m_pInetExplorer->put_ToolBar(m_nToolBar); } |
注意到OnToolBarShowHide 方法中我们将m_nToolBar 数据成员传递给put_ToolBar 方法替代了VARIANT_BOOL. 我们暂时不解释为什么,就像get_ToolBar, put_ToolBar 传递一个整型而不是VARIANT_BOOL.
现在利用ClassWizard 建立一个Change 按钮的消息循环处理句柄 。此消息的句柄将在任何时候设定set Internet Explorer 的状态条为edit 输入框内容。 代码看起来如下:
void CMfcAutoIEDlg::OnChangeStatusText() { UpdateData(TRUE); if (m_pInetExplorer) { _bstr_t bstrStatusText = m_strStatusText.AllocSysString(); m_pInetExplorer->put_StatusText(bstrStatusText); } } |
确信你在第一个任务就是调用传递TRUE的 UpdateData and .这样的目的是更新对阿框中所有相关的控件, 包括 m_strStatusText. 如果m_pInetExplorer 不是NULL—那意味着 Internet Explorer一个实例已经被创建— StatusText 被设定为用户输入的文字。 StatusText 同样事采用put_ 设定Visible 属性。 该函数需要一个BSTR的入口参数,所以调用 AllocSysString 方法使得m_strStatusText 数据成员变量分派为BSTR 可以传递给put_StatusText. AllocSysString 是CString 的方法,返回一个Cstring对象中值的 BSTR 类型。BSTR 返回自 AllocSysString 存储于_bstr_t类型的变量, 一个 COM 编译器支持的Visual C++类。为了使用此类,你必须包含comdef.h 头文件,置于对话框实现文件CMfcAutoIEDlg—MfcAutoIEDlg.cpp. 该类将小心处理BSTR离开当前范围的状况,所以你不需要调用SysFreeString的 Win32 API 以释放调用put_StatusText.之后的BSTR.
至此,我们基本上完成了。为了使用户输入Enter时不关闭对话框,重写基类对话框的OnOK方法。在此方法中,简单的不做任何事。确信你没有调用基类的CDialog::OnOK 方法,否则,对话框会关闭。
现在来重写OnCancel 的基类方法, 该方法调用于用户按下ESC或者点击对话框的右键菜单的关闭或者对话框的X按钮。在 OnCancel中,如果一个Internet Explorer 实例已经被创建, 在调用Quit 方法时关闭InternetExplorer 对象。 Quit 甚至可以在用户默认关掉Internet Explorer. 如果出现此情形, Quit 方法将返回 RPC_S_SERVER_UNAVAILABLE, 标示Internet Explorer 不再可用.你可以简单忽略此错误消息。以下为OnCancel的代码:
void CMfcAutoIEDlg::OnCancel() { if (m_pInetExplorer) m_pInetExplorer->Quit(); CDialog::OnCancel(); } |
最后, 你必须释放掉指向IE的IWebBrowser2 接口指针。你可以在对话框的析构函数中处理。此处为更型后的析构函数:
CMfcAutoIEDlg::~CMfcAutoIEDlg() { // Release the WebBrowser interface pointer // if (m_pInetExplorer) { m_pInetExplorer->Release(); m_pInetExplorer = NULL; } // Uninitialize COM // CoUninitialize(); } |
现在,通常我们可以编译运行对话框应用程序。启动IE实例,测试。