MFC程序员WTL指南(7)包容ActiveX控件
2008-01-19 20:26:50 来源:WEB开发网出了使用资源编辑器,还可以在运行其间动态创建ActiveX控件。About对话框演示了这种技术。对话框编辑器预先放置了一个group box用于浏览器控件的定位:
在OnInitDialog()函数中我们使用 CAxWindow创建了一个新AtlAxWin,它定位于我们预先放置好的group box的位置上(这个group box随后被销毁):
LRESULT CAboutDlg::OnInitDialog(...)
{
CWindow wndPlaceholder = GetDlgItem ( IDC_IE_PLACEHOLDER );
CRect rc;
CAxWindow wndIE;
// Get the rect of the placeholder group box, then destroy
// that window because we don''t need it anymore.
wndPlaceholder.GetWindowRect ( rc );
ScreenToClient ( rc );
wndPlaceholder.DestroyWindow();
// Create the AX host window.
wndIE.Create ( *this, rc, _T(""),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN );
接下来我们用CAxWindow方法创建一个ActiveX控件,有两个方法可以选择:CreateControl()和CreateControlEx()。CreateControlEx()用一个额外的参数返回接口指针,这样就不需要再调用QueryControl()函数。我们感兴趣的两个参数是第一个和第四个参数,第一个参数是字符串形式的浏览器控件的GUID,第四个参数是一个IUnknown*类型的指针,这个指针指向ActiveX控件的IUnknown接口。创建控件后就可以查询IWebBrowser2接口,然后就可以像前面一样控制它导航到某个URL。
CComPtr<IUnknown> punkCtrl;
CComQIPtr<IWebBrowser2> pWB2;
CComVariant v;
// Create the browser control using its GUID.
wndIE.CreateControlEx ( L"{8856F961-340A-11D0-A96B-00C04FD705A2}",
NULL, NULL, &punkCtrl );
// Get an IWebBrowser2 interface on the control and navigate to a page.
pWB2 = punkCtrl;
pWB2->Navigate ( CComBSTR("about:mozilla"), &v, &v, &v, &v );
}
对于有ProgID的ActiveX控件可以传递ProgID给CreateControlEx(),代替GUID。例如,我们可以这样创建浏览器控件:
// 使用控件的ProgID: 创建Shell.Explorer:
wndIE.CreateControlEx ( L"Shell.Explorer", NULL,
NULL, &punkCtrl );
CreateControl()和CreateControlEx()还有一些重载函数用于一些使用浏览器的特殊情况,如果你的应用程序使用WEb页面作为HTML资源,你可以将资源ID作为第一个参数,ATL会创建浏览器控件并导航到这个资源。IEHoster包含一个ID为IDR_ABOUTPAGE的WEB页面资源,我们在About对话框中使用这些代码显示这个页面:
wndIE.CreateControl ( IDR_ABOUTPAGE );
这是显示结果:
例子代码对上面提到的三个方法都用到了,你可以查看CAboutDlg::OnInitDialog()中的注释和未注释的代码,看看它们分别是如何工作的。
键盘事件处理最后一个但是非常重要的细节是键盘消息。ActiveX控件的键盘处理非常复杂,因为控件和它的宿主程序必须协同工作以确保控件能够看到它感兴趣的消息。例如,浏览器控件允许你使用TAB键在链接之间切换。MFC自己处理了所有工作,所以你永远不会意识到让键盘完美并正确的工作需要多么大的工作量。
不幸的是向导没有为基于对话框的程序生成键盘处理代码,当然,如果你使用Form View作为视图类的SDI程序,你会看到必要的代码已经被添加到PreTranslateMessage()中。当程序从消息队列中得到鼠标或键盘消息时,就使用ATL的WM_FORWARDMSG消息将此消息传递给当前拥有焦点的控件。它们通常不作什么事情,但是如果是ActiveX控件,WM_FORWARDMSG消息最终被送到包容这个控件的AtlAxWin,AtlAxWin识别WM_FORWARDMSG消息并采取必要的措施看看是否控件需要亲自处理这个消息。
如果拥有焦点的窗口没有识别WM_FORWARDMSG消息,PreTranslateMessage()就会接着调用IsDialogMessage()函数,使得像TAB这样的标准对话框的导航键能正常工作。
例子工程的PreTranslateMessage()函数中含有这些必需的代码,由于PreTranslateMessage()只在无模式对话框中有效,所以如果你想在基于对话框的应用程序中正确使用键盘就必须使用无模式对话框。 继续在下一章,我们将回到框架窗口并介绍如何使用分隔窗口。
修改记录May 20, 2003: 文章第一次发布。
更多精彩
赞助商链接