⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtl for mfc programmers, part vi - hosting activex controls - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<PRE><font color="#0033FF">CAxWindow wndIE = GetDlgItem(IDC_IE);</font></PRE>
      
<P>然后声明一个IWebBrowser2的接口指针并查询浏览器控件的这个接口,使用CAxWindow::QueryControl():</P>
<PRE><font color="#0033FF">CComPtr&lt;IWebBrowser2&gt; pWB2;
HRESULT hr;
hr = wndIE.QueryControl ( &amp;pWB2 );</font></PRE>
      
<P>QueryControl()调用浏览器控件的QueryInterface()方法,如果成功就会返回IWebBrowser2接口,我们可以调用Navigate():</P>
<PRE>    <font color="#0033FF"><SPAN class=cpp-keyword>if</SPAN> ( pWB2 )
        {
        CComVariant v;  <SPAN class=cpp-comment>// empty variant</SPAN>
 
        pWB2-&gt;Navigate ( CComBSTR(<SPAN class=cpp-string>"http://www.codeproject.com/"</SPAN>), 
                         &amp;v, &amp;v, &amp;v, &amp;v );
        }</font></PRE>
<H2><A name=sinkevents></A><font color="#FFFF66">响应控件触发的事件</font></H2>
      
<P>从浏览器控件得到接口非常简单,通过它可以单向的与控件通信。通常控件也会以事件的形式与外界通信,ATL有专用的类包装连接点和事件相应,所以我们可以从控件接收到这些事件。为使用对事件的支持需要做四件事:</P>
 <OL>
  <LI>将CMainDlg变成COM对象
  <LI>添加IDispEventSimpleImpl到CMainDlg的继承列表
  <LI>填写事件映射链,它指示哪些事件需要处理
  <LI>编写事件响应函数</LI>
</OL>
      
<H3><A name=changemaindlg></A><font color="#FFFF66">CMainDlg的修改</font> </H3>
      
<P>将CMainDlg转变成COM对象的原因是事件相应是基于IDispatch的,为了让CMainDlg暴露这个接口,它必须是个COM对象。IDispEventSimpleImpl提供了IDispatch接口的实现和建立连接点所需的处理函数,当事件发生时IDispEventSimpleImpl还调用我们想要接收的事件的处理函数。</P>
      
<P>以下的类需要添加到CMainDlg的集成列表中,同时COM_MAP列出了CMainDlg暴露的接口:</P>
<PRE><B><font color="#0033FF">#include &lt;exdisp.h&gt;    <SPAN class=cpp-comment>// browser control definitions</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;exdispid.h&gt;  // browser event dispatch IDs</SPAN>
</font></B> 
<font color="#0033FF"><SPAN class=cpp-keyword>class</SPAN> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> CAxDialogImpl&lt;CMainDlg&gt;,
                 <SPAN class=cpp-keyword>public</SPAN> CUpdateUI&lt;CMainDlg&gt;,
                 <SPAN class=cpp-keyword>public</SPAN> CMessageFilter, <SPAN class=cpp-keyword>public</SPAN> CIdleHandler,
                 <B><SPAN class=cpp-keyword>public</SPAN> CComObjectRootEx&lt;CComSingleThreadModel&gt;,
                 <SPAN class=cpp-keyword>public</SPAN> CComCoClass&lt;CMainDlg&gt;,
                 <SPAN class=cpp-keyword>public</SPAN> IDispEventSimpleImpl&lt;<SPAN class=cpp-literal>37</SPAN>, CMainDlg, &amp;DIID_DWebBrowserEvents2&gt;
</B>{
...<B>
  BEGIN_COM_MAP(CMainDlg)
    COM_INTERFACE_ENTRY2(IDispatch, IDispEventSimpleImpl)
  END_COM_MAP()
</B>};</font></PRE>
      
<P>CComObjectRootEx类CComCoClass共同使CMainDlg成为一个COM对象,IDispEventSimpleImpl的模板参数是事件的ID,我们的类名和连接点接口的IID。事件ID可以是任意正数,连接点对象的IID是DIID_DWebBrowserEvents2,可以在浏览器控件的相关文档中找到这些参数,也可以查看exdisp.h。</P>
      
<H3><A name=writesinkmap></A><font color="#FFFF66">填写事件映射链</font></H3>
      
<P>下一步是给CMainDlg添加事件映射链,这个映射链将我们感兴趣的事件和我们的处理函数联系起来。我们要看的第一个事件是DownloadBegin,当浏览器开始下载一个页面时就会触发这个事件,我们响应这个事件显示“please 
  wait”信息给用户,让用户知道浏览器正在忙。在MSDN中可以查到DWebBrowserEvents2::DownloadBegin事件的原型</P>
<PRE>  <font color="#0033FF"><SPAN class=cpp-keyword>void</SPAN> DownloadBegin();</font></PRE>
      
<P>这个事件没有参数,也不需要返回值。为了将这个事件的原型转换成事件响应链,我们需要写一个_ATL_FUNC_INFO结构,它包含返回值,参数的个数和参数类型。由于事件是基于IDispatch的,所以所有的参数都用VARIANT表示,这个数据结构的描述相当长(支持很多个数据类型),以下是常用的几个:</P>
      <BLOCKQUOTE>
        <P>VT_EMPTY: <SPAN 
        class=cpp-keyword>void</SPAN><BR>VT_BSTR: BSTR 格式的字符串<BR>
    VT_I4: 4字节有符号整数,用于long类型的参数<BR>
    VT_DISPATCH: 
        IDispatch*<BR>VT_VARIANT>: 
        VARIANT<BR>
    VT_BOOL: VARIANT_BOOL (允许的取值是VARIANT_TRUE和VARIANT_FALSE)</P>
</BLOCKQUOTE>
      
<P>另外,标志VT_BYREF表示将一个参数转换成相应的指针。例如,VT_VARIANT|VT_BYREF表示VARIANT*类型。下面是_ATL_FUNC_INFO的定义:</P>
<PRE><SPAN class=cpp-preprocessor><font color="#0033FF">#define _ATL_MAX_VARTYPES 8</font></SPAN>
 
<font color="#0033FF"><SPAN class=cpp-keyword>struct</SPAN> _ATL_FUNC_INFO
{
  &nbsp; CALLCONV cc;
    VARTYPE  vtReturn;
    SHORT &nbsp;  nParams;
    VARTYPE  pVarTypes[_ATL_MAX_VARTYPES];
};</font></PRE>
      
<P>参数:</P>
      
<DL> 
  <DT>cc
  <DD>我们的事件响应函数的调用方式约定,这个参数必须是CC_STDCALL,表示是__stdcall方式
  <DT>vtReturn
  <DD>事件响应函数的返回值类型
  <DT>nParams
  <DD>事件带的参数个数
  <DT>pVarTypes
  <DD>相应的参数类型,按从左到右的顺序</DD>
</DL>
      
<P>了解这些之后,我们就可以填写DownloadBegin事件处理的_ATL_FUNC_INFO结构:</P>
<PRE><font color="#0033FF">_ATL_FUNC_INFO DownloadInfo = { CC_STDCALL, VT_EMPTY, <SPAN class=cpp-literal>0</SPAN> };</font></PRE>
      
<P>现在,回到事件响应链,我们为每一个我们想要处理的事件添加一个SINK_ENTRY_INFO宏,下面是处理DownloadBegin事件的宏:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> ...
{
...
<B>  BEGIN_SINK_MAP(CMainDlg)
    SINK_ENTRY_INFO(<SPAN class=cpp-literal>37</SPAN>, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN,
                    OnDownloadBegin, &amp;DownloadInfo)
  END_SINK_MAP()
</B>};</font></PRE>
      
<P>这个宏的参数是事件的ID(37,与我们在IDispEventSimpleImpl的继承列表中使用的ID一样),事件接口的IID,事件的dispatch 
  ID(可以在MSDN或exdispid.h头文件中查到),事件处理函数的名字和指向描述这个事件处理的_ATL_FUNC_INFO结构的指针。</P>
      
<H3><A name=writehandler></A><font color="#FFFF66">编写事件处理函数</font></H3>
      
<P>好了,等了这么长时间(吹个口哨!),我们可以写事件处理函数了:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> __stdcall CMainDlg::OnDownloadBegin()
{
  <SPAN class=cpp-comment>// show "Please wait" here...</SPAN>
}</font></PRE>
      
<P>现在来看一个复杂一点的事件,比如BeforeNavigate2,这个事件的原型是:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> BeforeNavigate2 ( 
    IDispatch* pDisp, VARIANT* URL, VARIANT* Flags,
    VARIANT* TargetFrameName, VARIANT* PostData,
    VARIANT* Headers, VARIANT_BOOL* Cancel );</font></PRE>
      
<P>此方法有7个参数,对于VARIANT类型参数可以从MSDN查到它到底传递的是什么类型的数据,我们感兴趣的是URL,是一个BSTR类型的字符串。</P>
      
<P>描述BeforeNavigate2事件的_ATL_FUNC_INFO结构是这样的:</P>
<PRE><font color="#0033FF">_ATL_FUNC_INFO BeforeNavigate2Info =
    { CC_STDCALL, VT_EMPTY, <SPAN class=cpp-literal>7</SPAN>,
        { VT_DISPATCH, VT_VARIANT|VT_BYREF, VT_VARIANT|VT_BYREF,
          VT_VARIANT|VT_BYREF, VT_VARIANT|VT_BYREF, VT_VARIANT|VT_BYREF,
          VT_BOOL|VT_BYREF }
};</font></PRE>
      
<P>和前面一样,返回值类型是VT_EMPTY表示没有返回值,nParams是7,表示有7个参数。接着是参数类型数组,这些类型前面介绍过了,例如VT_DISPATCH表示IDispatch*。</P>
<p>事件响应链的入口与前面的例子很相似:</p>
<PRE>  <font color="#0033FF">BEGIN_SINK_MAP(CMainDlg)
    SINK_ENTRY_INFO(<SPAN class=cpp-literal>37</SPAN>, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN,
                    OnDownloadBegin, &amp;DownloadInfo)
    <B>SINK_ENTRY_INFO(<SPAN class=cpp-literal>37</SPAN>, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2,
                    OnBeforeNavigate2, &amp;BeforeNavigate2Info)</B>
  END_SINK_MAP()</font></PRE>
      
<P>事件处理函数是这个样子:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> __stdcall CMainDlg::OnBeforeNavigate2 (
    IDispatch* pDisp, VARIANT* URL, VARIANT* Flags, 
    VARIANT* TargetFrameName, VARIANT* PostData, 
    VARIANT* Headers, VARIANT_BOOL* Cancel )
{
CString sURL = URL-&gt;bstrVal;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -