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

📄 wtl for mfc programmers, part vi.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
      src=3D"http://www.codeproject.com/wtl/WTL4MFC6/appwiz.png" =
width=3D477=20
      align=3Dbottom border=3D0></P>
      <P>Checking that box makes our main dialog derive from=20
      <CODE>CAxDialogImpl</CODE> so it can host ActiveX controls. There =
is=20
      another checkbox on page 2 labeled <I>Host ActiveX Controls</I>, =
however=20
      checking that seems to have no effect on the resulting code, so =
you can=20
      click Finish from page 1.</P>
      <H3><A name=3Dappwizcode></A>The generated code</H3>
      <P>In this section, I'll cover some new pieces of code that we =
haven't=20
      seen before from the AppWizard. In the next section, I'll cover =
the=20
      ActiveX hosting classes in detail.</P>
      <P>The first file to check out is stdafx.h, which has these =
includes:</P><PRE><SPAN class=3Dcpp-preprocessor>#include =
&lt;atlbase.h&gt;</SPAN>
<SPAN class=3Dcpp-preprocessor>#include &lt;atlapp.h&gt;</SPAN>
=20
<SPAN class=3Dcpp-keyword>extern</SPAN> CAppModule _Module;
=20
<SPAN class=3Dcpp-preprocessor>#include &lt;atlcom.h&gt;</SPAN>
<SPAN class=3Dcpp-preprocessor>#include &lt;atlhost.h&gt;</SPAN>
<SPAN class=3Dcpp-preprocessor>#include &lt;atlwin.h&gt;</SPAN>
<SPAN class=3Dcpp-preprocessor>#include &lt;atlctl.h&gt;</SPAN>
<SPAN class=3Dcpp-comment>// .. other WTL headers ...</SPAN></PRE>
      <P>atlcom.h and atlhost.h are the important ones. They contain the =

      definitions of some COM-related classes (like the smart pointer=20
      <CODE>CComPtr</CODE>), and the window class used to actually host=20
      controls.</P>
      <P>Next, look at the declaration of <CODE>CMainDlg</CODE> in=20
maindlg.h:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg : =
<SPAN class=3Dcpp-keyword>public</SPAN> CAxDialogImpl&lt;CMainDlg&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> =
CUpdateUI&lt;CMainDlg&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> CMessageFilter, =
<SPAN class=3Dcpp-keyword>public</SPAN> CIdleHandler</PRE>
      <P><CODE>CMainDlg</CODE> is now derived from =
<CODE>CAxDialogImpl</CODE>,=20
      which is the first step in enabling the dialog to host ActiveX=20
      controls.</P>
      <P>Finally, there's one new line in =
<CODE>WinMain()</CODE>:</P><PRE><SPAN class=3Dcpp-keyword>int</SPAN> =
WINAPI _tWinMain(...)
{
<SPAN class=3Dcpp-comment>//...</SPAN>
    _Module.Init(NULL, hInstance);
=20
    <B>AtlAxWinInit();</B>
=20
    <SPAN class=3Dcpp-keyword>int</SPAN> nRet =3D Run(lpstrCmdLine, =
nCmdShow);
=20
    _Module.Term();
    <SPAN class=3Dcpp-keyword>return</SPAN> nRet;
}</PRE>
      <P><CODE>AtlAxWinInit()</CODE> registers a window class called=20
      <CODE>AtlAxWin</CODE>. This is used by ATL when it creates the =
host window=20
      for an ActiveX control.</P>
      <H2><A name=3Daddreseditor></A>Adding Controls with the Resource =
Editor</H2>
      <P>ATL lets you add ActiveX controls to a dialog using the =
resource=20
      editor, just as you can in an MFC app. First, right-click in the =
dialog=20
      editor and select <I>Insert ActiveX control</I>:</P>
      <P><IMG height=3D345 alt=3D" [Insert menu - 8K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC6/insertmenu.png" =
width=3D355=20
      align=3Dbottom border=3D0></P>
      <P>VC will show a list of the controls installed on your system. =
Scroll=20
      down to <I>Microsoft Web Browser</I> and click <I>OK</I> to insert =
the=20
      control into the dialog. View the properties of the new control =
and set=20
      its ID to IDC_IE. The dialog should now look like this, with the =
control=20
      visible in the editor:</P>
      <P><IMG height=3D244 alt=3D" [ IE control in editor - 6K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC6/iectrl.png" =
width=3D350=20
      align=3Dbottom border=3D0></P>
      <P>If you compile and run the app now, you'll see the web browser =
control=20
      in the dialog. It will show a blank page however, since we haven't =
told it=20
      to navigate anywhere.</P>
      <P>In the next section, I'll cover the ATL classes involved in =
creating=20
      and hosting ActiveX controls, and then we'll see how to use those =
classes=20
      to communicate with the browser.</P>
      <H2><A name=3Datlhostclasses></A>ATL Classes for Control =
Hosting</H2>
      <P>When hosting ActiveX controls in a dialog, there are two =
classes that=20
      work together: <CODE>CAxDialogImpl</CODE> and =
<CODE>CAxWindow</CODE>. They=20
      handle all the interfaces that control containers have to =
implement, and=20
      provide some utility functions for common actions such as querying =
the=20
      control for a particular COM interface.</P>
      <H3><A name=3DCAxDialogImpl></A>CAxDialogImpl</H3>
      <P>The first class is <CODE>CAxDialogImpl</CODE>. When you write =
your=20
      dialog class, you derive from <CODE>CAxDialogImpl</CODE>, instead =
of=20
      <CODE>CDialogImpl</CODE>, to enable control hosting.=20
      <CODE>CAxDialogImpl</CODE> has overrides for <CODE>Create()</CODE> =
and=20
      <CODE>DoModal()</CODE>, which call through to the global functions =

      <CODE>AtlAxCreateDialog()</CODE> and <CODE>AtlAxDialogBox()</CODE> =

      respectively. Since the IEHoster dialog is created with=20
      <CODE>Create()</CODE>, we'll take a closer look at=20
      <CODE>AtlAxCreateDialog()</CODE>.</P>
      <P><CODE>AtlAxCreateDialog()</CODE> loads the dialog resource and =
uses the=20
      helper class <CODE>_DialogSplitHelper</CODE> to iterate through =
the=20
      controls and look for special entries created by the resource =
editor that=20
      indicate an ActiveX control needs to be created. For example, here =
is the=20
      entry in the IEHoster.rc file for the web browser =
control:</P><PRE>CONTROL <SPAN class=3Dcpp-string>""</SPAN>,IDC_IE,<SPAN =
class=3Dcpp-string>"{8856F961-340A-11D0-A96B-00C04FD705A2}"</SPAN>,
        WS_TABSTOP,<SPAN class=3Dcpp-literal>7</SPAN>,<SPAN =
class=3Dcpp-literal>7</SPAN>,<SPAN class=3Dcpp-literal>116</SPAN>,<SPAN =
class=3Dcpp-literal>85</SPAN></PRE>
      <P>The first parameter is the window text (an empty string), the =
second is=20
      the control ID, and the third is the window class name.=20
      <CODE>_DialogSplitHelper::SplitDialogTemplate()</CODE> sees that =
the=20
      window class begins with <CODE>'{'</CODE> and knows it's an =
ActiveX=20
      control entry. It creates a new dialog template in memory that has =
those=20
      special <CODE>CONTROL</CODE> entries replaced by ones that create=20
      <CODE>AtlAxWin</CODE> windows instead. The new entry is the =
in-memory=20
      equivalent of:</P><PRE>CONTROL <SPAN =
class=3Dcpp-string>"{8856F961-340A-11D0-A96B-00C04FD705A2}"</SPAN>,IDC_IE=
,<SPAN class=3Dcpp-string>"AtlAxWin"</SPAN>,
        WS_TABSTOP,<SPAN class=3Dcpp-literal>7</SPAN>,<SPAN =
class=3Dcpp-literal>7</SPAN>,<SPAN class=3Dcpp-literal>116</SPAN>,<SPAN =
class=3Dcpp-literal>85</SPAN></PRE>
      <P>The result is that an <CODE>AtlAxWin</CODE> window will be =
created with=20
      the same ID, and its window text will be the GUID of the ActiveX =
control.=20
      So if you call <CODE>GetDlgItem(IDC_IE)</CODE>, the return value =
is the=20
      <CODE>HWND</CODE> of the <CODE>AtlAxWin</CODE> window, not the =
ActiveX=20
      control itself.</P>
      <P>Once <CODE>SplitDialogTemplate()</CODE> returns,=20
      <CODE>AtlAxCreateDialog()</CODE> calls=20
      <CODE>CreateDialogIndirectParam()</CODE> to create the dialog =
using the=20
      modified template.</P>
      <H3><A name=3DAtlAxWin></A>AtlAxWin and CAxWindow</H3>
      <P>As mentioned above, an <CODE>AtlAxWin</CODE> is used as the =
host window=20
      for an ActiveX control. There is a special window interface class =
that you=20
      use with an <CODE>AtlAxWin</CODE>: <CODE>CAxWindow</CODE>. When an =

      <CODE>AtlAxWin</CODE> is created from a dialog template, the=20
      <CODE>AtlAxWin</CODE> window procedure, =
<CODE>AtlAxWindowProc()</CODE>,=20
      handles <CODE>WM_CREATE</CODE> and creates the ActiveX control in =
response=20
      to that message. An ActiveX control can also be created at =
runtime,=20
      without being in the dialog template, but we'll cover that case =
later.</P>
      <P>The <CODE>WM_CREATE</CODE> handler calls the global=20
      <CODE>AtlAxCreateControl()</CODE>, passing it the =
<CODE>AtlAxWin</CODE>'s=20
      window text. Recall that this was set to the GUID of the web =
browser=20
      control. <CODE>AtlAxCreateControl()</CODE> calls a couple more =
functions,=20
      but eventually the code reaches =
<CODE>CreateNormalizedObject()</CODE>,=20
      which converts the window text to a GUID, and finally calls=20
      <CODE>CoCreateInstance()</CODE> to create the ActiveX control.</P>
      <P>Since the ActiveX control is a child of the =
<CODE>AtlAxWin</CODE>, the=20
      dialog can't directly access the control. However, =
<CODE>CAxWindow</CODE>=20
      has methods for communicating with the control. The one you'll use =
most=20
      often is <CODE>QueryControl()</CODE>, which calls=20
      <CODE>QueryInterface()</CODE> on the control. For example, you can =
use=20
      <CODE>QueryControl()</CODE> to get an <CODE>IWebBrowser2</CODE> =
interface=20
      from the web browser control, and use that interface to navigate =
the=20
      browser to a URL.</P>
      <H2><A name=3Dcallmethods></A>Calling the Methods of a =
Control</H2>
      <P>Now that our dialog has a web browser in it, we can use its COM =

      interfaces to interact with it. The first thing we'll do is make =
it=20
      navigate to a new URL using its <CODE>IWebBrowser2</CODE> =
interface. In=20
      the <CODE>OnInitDialog()</CODE> handler, we can attach a=20
      <CODE>CAxWindow</CODE> variable to the <CODE>AtlAxWin</CODE> that =
is=20
      hosting the browser.</P><PRE>CAxWindow wndIE =3D =
GetDlgItem(IDC_IE);</PRE>
      <P>Next, we declare an <CODE>IWebBrowser2</CODE> interface pointer =
and=20
      query the browser control for that interface, using=20
      =
<CODE>CAxWindow::QueryControl()</CODE>:</P><PRE>CComPtr&lt;IWebBrowser2&g=
t; pWB2;
HRESULT hr;
=20
    hr =3D wndIE.QueryControl ( &amp;pWB2 );</PRE>
      <P><CODE>QueryControl()</CODE> calls <CODE>QueryInterface()</CODE> =
on the=20
      web browser, and if that succeeds, the <CODE>IWebBrowser2</CODE> =
interface=20
      is returned to us. We can then call =
<CODE>Navigate()</CODE>:</P><PRE>    <SPAN class=3Dcpp-keyword>if</SPAN> =
( pWB2 )
        {
        CComVariant v;  <SPAN class=3Dcpp-comment>// empty =
variant</SPAN>
=20
        pWB2-&gt;Navigate ( CComBSTR(<SPAN =
class=3Dcpp-string>"http://www.codeproject.com/"</SPAN>),=20
                         &amp;v, &amp;v, &amp;v, &amp;v );
        }</PRE>
      <H2><A name=3Dsinkevents></A>Sinking Events Fired by a =
Control</H2>
      <P>Getting an interface from the web browser is pretty simple, and =
it lets=20
      us communicate in one direction - <I>to</I>&nbsp;the control. =
There is=20
      also a lot of communication <I>from</I>&nbsp;the control, in the =
form of=20
      events. ATL has classes that encapsulate connection points and =
event=20
      sinking, so that we can receive the events fired by the browser. =
To use=20
      this support, we do four things:</P>
      <OL>
        <LI>Make <CODE>CMainDlg</CODE> into a COM object=20
        <LI>Add <CODE>IDispEventSimpleImpl</CODE> to =
<CODE>CMainDlg</CODE>'s=20
        inheritance list=20
        <LI>Write an <I>event sink map</I> that indicates which events =
we want=20
        to handle=20
        <LI>Write handlers for those events </LI></OL>
      <H3><A name=3Dchangemaindlg></A>Changes to CMainDlg</H3>
      <P>The reason why we make <CODE>CMainDlg</CODE> a COM object is =
that an=20
      event sink is based on <CODE>IDispatch</CODE>. In order for=20
      <CODE>CMainDlg</CODE> to expose COM interfaces, it has to be a COM =
object.=20
      <CODE>IDispEventSimpleImpl</CODE> provides an implementation of=20
      <CODE>IDispatch</CODE> and handles the calls needed to set up a =
connection=20
      point. <CODE>IDispEventSimpleImpl</CODE> also calls our event =
handlers=20
      when events that we want to handle are received.</P>
      <P>Here are the classes to add to the <CODE>CMainDlg</CODE> =
inheritance=20
      list, along with the <CODE>COM_MAP</CODE> that lists the =
interfaces that=20
      <CODE>CMainDlg</CODE> exposes:</P><PRE><B>#include =
&lt;exdisp.h&gt;    <SPAN class=3Dcpp-comment>// browser control =
definitions</SPAN>
<SPAN class=3Dcpp-preprocessor>#include &lt;exdispid.h&gt;  // browser =
event dispatch IDs</SPAN>
</B>=20
<SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg : <SPAN =
class=3Dcpp-keyword>public</SPAN> CAxDialogImpl&lt;CMainDlg&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> =
CUpdateUI&lt;CMainDlg&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> CMessageFilter, =
<SPAN class=3Dcpp-keyword>public</SPAN> CIdleHandler,
                 <B><SPAN class=3Dcpp-keyword>public</SPAN> =
CComObjectRootEx&lt;CComSingleThreadModel&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> =
CComCoClass&lt;CMainDlg&gt;,
                 <SPAN class=3Dcpp-keyword>public</SPAN> =
IDispEventSimpleImpl&lt;<SPAN class=3Dcpp-literal>37</SPAN>, CMainDlg, =
&amp;DIID_DWebBrowserEvents2&gt;
</B>{
...<B>
  BEGIN_COM_MAP(CMainDlg)
    COM_INTERFACE_ENTRY2(IDispatch, IDispEventSimpleImpl)
  END_COM_MAP()

⌨️ 快捷键说明

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