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

📄 wtl for mfc programmers, part ii.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
<SPAN class=3Dcpp-preprocessor>#include &lt;atlcrack.h&gt;      // WTL =
enhanced msg map macros</SPAN></PRE>
      <P><EM>atlapp.h</EM> is the first WTL header you include. It =
contains=20
      classes for message handling and <CODE>CAppModule</CODE>, a class =
derived=20
      from <CODE>CComModule</CODE>. You should also define=20
      <CODE>_WTL_USE_CSTRING</CODE> if you plan on using =
<CODE>CString</CODE>,=20
      because <CODE>CString</CODE> is defined in atlmisc.h yet there are =
other=20
      headers that come before atlmisc.h which have features that use=20
      <CODE>CString</CODE>. Defining <CODE>_WTL_USE_CSTRING</CODE> makes =

      atlapp.h forward-declare the <CODE>CString</CODE> class so those =
other=20
      headers know what a <CODE>CString</CODE> is.</P>
      <P>Next let's define our frame window. SDI windows like ours are =
derived=20
      from <CODE>CFrameWindowImpl</CODE>. The window class is defined =
with=20
      <CODE>DECLARE_FRAME_WND_CLASS</CODE> instead of=20
      <CODE>DECLARE_WND_CLASS</CODE>. Here's the beginning of our window =

      definition in MyWindow.h:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_FRAME_WND_CLASS(_T(<SPAN class=3Dcpp-string>"First WTL =
window"</SPAN>), IDR_MAINFRAME);

    BEGIN_MSG_MAP(CMyWindow)
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
};</PRE>
      <P><CODE>DECLARE_FRAME_WND_CLASS</CODE> takes two parameters, the =
window=20
      class name (which can be <CODE>NULL</CODE> to have ATL generate a =
name for=20
      you), and a resource ID. WTL will look for an icon, menu, and =
accelerator=20
      table with that ID, and load them when the window is created. It =
will also=20
      look for a string with that ID and use it as the window title. We =
also=20
      chain messages to <CODE>CFrameWindowImpl</CODE> as it has some =
message=20
      handlers of its own (most notably <CODE>WM_SIZE</CODE> and=20
      <CODE>WM_DESTROY</CODE>).</P>
      <P>Now let's look at <CODE>WinMain()</CODE>. It is pretty similar =
to the=20
      <CODE>WinMain()</CODE> we had in Part I, the difference is in the =
call to=20
      create the main window.</P><PRE><SPAN class=3Dcpp-comment>// =
main.cpp:</SPAN>
<SPAN class=3Dcpp-preprocessor>#include "stdafx.h"</SPAN>
<SPAN class=3Dcpp-preprocessor>#include "MyWindow.h"</SPAN>
=20
CAppModule _Module;
=20
<SPAN class=3Dcpp-keyword>int</SPAN> APIENTRY WinMain ( HINSTANCE =
hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine, <SPAN =
class=3Dcpp-keyword>int</SPAN> nCmdShow )
{
    _Module.Init ( NULL, hInstance );
=20
CMyWindow wndMain;
MSG msg;
=20
    <SPAN class=3Dcpp-comment>// Create the main window</SPAN>
    <SPAN class=3Dcpp-keyword>if</SPAN> ( NULL =3D=3D wndMain.CreateEx() =
)
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>1</SPAN>;       <SPAN class=3Dcpp-comment>// Window =
creation failed</SPAN>
=20
    <SPAN class=3Dcpp-comment>// Show the window</SPAN>
    wndMain.ShowWindow ( nCmdShow );
    wndMain.UpdateWindow();
=20
    <SPAN class=3Dcpp-comment>// Standard Win32 message loop</SPAN>
    <SPAN class=3Dcpp-keyword>while</SPAN> ( GetMessage ( &amp;msg, =
NULL, <SPAN class=3Dcpp-literal>0</SPAN>, <SPAN =
class=3Dcpp-literal>0</SPAN> ) &gt; <SPAN class=3Dcpp-literal>0</SPAN> )
        {
        TranslateMessage ( &amp;msg );
        DispatchMessage ( &amp;msg );
        }
=20
    _Module.Term();
    <SPAN class=3Dcpp-keyword>return</SPAN> msg.wParam;
}</PRE>
      <P><CODE>CFrameWindowImpl</CODE> has a <CODE>CreateEx()</CODE> =
method that=20
      has the most common default values, so we don't need to specify =
any=20
      parameters. <CODE>CFrameWindowImpl</CODE> will also handle loading =

      resources as explained earlier, so you should make some dummy =
resources=20
      now with IDs of <CODE>IDR_MAINFRAME</CODE>, or check out the =
sample code=20
      accompanying the article.</P>
      <P>If you run this now, you'll see the main frame window, but of =
course it=20
      doesn't actually <I>do</I> anything yet. We'll need to add some =
message=20
      handlers to do stuff, so now is a good time to cover the WTL =
message map=20
      macros.</P>
      <H2><A name=3Dwtlmsgmap></A>WTL Message Map Enhancements</H2>
      <P>One of the cumbersome and error-prone things when using the =
Win32 API=20
      is unpacking parameters from the <CODE>WPARAM</CODE> and=20
      <CODE>LPARAM</CODE> data sent with a message. Unfortunately, ATL =
doesn't=20
      help much, and we still have to unpack data from all messages =
aside from=20
      <CODE>WM_COMMAND</CODE> and <CODE>WM_NOTIFY</CODE>. But WTL comes =
to the=20
      rescue here!</P>
      <P>WTL's enhanced message map macros are in <EM>atlcrack.h</EM>. =
(The name=20
      comes from "message cracker", a term used for similar macros in=20
      <EM>windowsx.h</EM>.) To start, change <CODE>BEGIN_MSG_MAP</CODE> =
to=20
      <CODE>BEGIN_MSG_MAP_EX</CODE>. The <CODE>_EX</CODE> version =
generates some=20
      code that the message crackers use.</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    <FONT color=3Dred>BEGIN_MSG_MAP_EX(CMyWindow)</FONT>
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
};</PRE>
      <P>For our clock program, we'll need to handle =
<CODE>WM_CREATE</CODE> and=20
      set a timer. The WTL message handler for a message is called=20
      <CODE>MSG_</CODE> followed by the message name, for example=20
      <CODE>MSG_WM_CREATE</CODE>. These macros take just the name of the =

      handler, so let's add one for =
<CODE>WM_CREATE</CODE>:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CMyWindow : <SPAN class=3Dcpp-keyword>public</SPAN> =
CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)<FONT color=3Dred>
        MSG_WM_CREATE(OnCreate)</FONT>
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
=20
    <SPAN class=3Dcpp-comment>// OnCreate(...) ?</SPAN>
};</PRE>
      <P>WTL message handlers look a lot like MFC's, where each handler =
has a=20
      different prototype depending on what parameters are passed with =
the=20
      message. But since we don't have a wizard to write the handler, =
we'll have=20
      to find the prototype ourselves. Fortunately, VC can help out. Put =
the=20
      cursor on the "MSG_WM_CREATE" text and press F12 to go to the =
definition=20
      of that macro. Since this is the first time we've used this =
feature with=20
      this project, VC will have to rebuild all first to build its =
browse info=20
      database. Once that's done, VC will open atlcrack.h at the =
definition of=20
      <CODE>MSG_WM_CREATE</CODE>:</P><PRE><SPAN =
class=3Dcpp-preprocessor>#define MSG_WM_CREATE(func) \</SPAN>
    <SPAN class=3Dcpp-keyword>if</SPAN> (uMsg =3D=3D WM_CREATE) \
    { \
        SetMsgHandled(TRUE); \
        <FONT color=3Dred>lResult =3D =
(LRESULT)func((LPCREATESTRUCT)lParam); \</FONT>
        <SPAN class=3Dcpp-keyword>if</SPAN>(IsMsgHandled()) \
            <SPAN class=3Dcpp-keyword>return</SPAN> TRUE; \
    }</PRE>
      <P>The line in red is the important one, it's the actual call to =
the=20
      handler, and it tells us the handler returns an =
<CODE>LRESULT</CODE> and=20
      takes one parameter, a <CODE>LPCREATESTRUCT</CODE>. Notice that =
there is=20
      no <CODE>bHandled</CODE> parameter like the ATL macros use. The=20
      <CODE>SetMsgHandled()</CODE> function replaces that parameter; =
I'll=20
      explain this more shortly.</P>
      <P>Now we can add an <CODE>OnCreate()</CODE> handler to our window =

      class:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMyWindow : =
<SPAN class=3Dcpp-keyword>public</SPAN> =
CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)<FONT color=3Dred>
</FONT>        MSG_WM_CREATE(OnCreate)
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
=20
    <FONT color=3Dred>LRESULT OnCreate(LPCREATESTRUCT lpcs)
    {
        SetTimer ( <SPAN class=3Dcpp-literal>1</SPAN>, <SPAN =
class=3Dcpp-literal>1000</SPAN> );
        SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }</FONT>
};</PRE>
      <P><CODE>CFrameWindowImpl</CODE> inherits indirectly from=20
      <CODE>CWindow</CODE>, so it has all the <CODE>CWindow</CODE> =
functions=20
      like <CODE>SetTimer()</CODE>. This makes windowing API calls look =
a lot=20
      like MFC code, where you use the various <CODE>CWnd</CODE> methods =
that=20
      wrap APIs.</P>
      <P>We call <CODE>SetTimer()</CODE> to create a timer that fires =
every=20
      second (1000 ms). Since we want to let =
<CODE>CFrameWindowImpl</CODE>=20
      handle <CODE>WM_CREATE</CODE> as well, we call =
<CODE>SetMsgHandled(<SPAN=20
      class=3Dcpp-keyword>false</SPAN>)</CODE> so that the message gets =
chained to=20
      base classes via the <CODE>CHAIN_MSG_MAP</CODE> macro. This call =
replaces=20
      the <CODE>bHandled</CODE> parameter that the ATL macros use. (Even =
though=20
      <CODE>CFrameWindowImpl</CODE> doesn't handle =
<CODE>WM_CREATE</CODE>,=20
      calling <CODE>SetMsgHandled(<SPAN =
class=3Dcpp-keyword>false</SPAN>)</CODE>=20
      is a good habit to get into when using base classes, so you don't =
have to=20
      remember which messages the base classes handle. This is similar =
to the=20
      code that ClassWizard generates; most handlers start or end with a =
call to=20
      the base class handler.)</P>
      <P>We'll also need a <CODE>WM_DESTROY</CODE> handler so we can =
stop the=20
      timer. Going through the same process as before, we find the=20
      <CODE>MSG_WM_DESTROY</CODE> macro looks like this:</P><PRE><SPAN =
class=3Dcpp-preprocessor>#define MSG_WM_DESTROY(func) \</SPAN>
    <SPAN class=3Dcpp-keyword>if</SPAN> (uMsg =3D=3D WM_DESTROY) \
    { \
        SetMsgHandled(TRUE); \
        <FONT color=3Dred>func(); \</FONT>
        lResult =3D <SPAN class=3Dcpp-literal>0</SPAN>; \
        <SPAN class=3Dcpp-keyword>if</SPAN>(IsMsgHandled()) \
            <SPAN class=3Dcpp-keyword>return</SPAN> TRUE; \
    }</PRE>
      <P>So our <CODE>OnDestroy()</CODE> handler takes no parameters and =
returns=20
      nothing. <CODE>CFrameWindowImpl</CODE> <I>does</I> handle=20
      <CODE>WM_DESTROY</CODE> as well, so in this case we do need to =
call=20
      <CODE>SetMsgHandled(<SPAN =
class=3Dcpp-keyword>false</SPAN>)</CODE>:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)<FONT color=3Dred>
</FONT>        MSG_WM_CREATE(OnCreate)
        <FONT color=3Dred>MSG_WM_DESTROY(OnDestroy)</FONT>
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()<BR><BR><BR>
    <FONT color=3Dred><SPAN class=3Dcpp-keyword>void</SPAN> OnDestroy()
    {
        KillTimer(<SPAN class=3Dcpp-literal>1</SPAN>);
        SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
    }
</FONT>};</PRE>
      <P>Next up is our <CODE>WM_TIMER</CODE> handler, which is called =
every=20
      second. You should have the hang of the F12 trick by now, so I'll =
just=20
      show the handler:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CMyWindow : <SPAN class=3Dcpp-keyword>public</SPAN> =
CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)<FONT color=3Dred>
</FONT>        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)<FONT color=3Dred>
        MSG_WM_TIMER(OnTimer)
</FONT>        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
=20
    <FONT color=3Dred><SPAN class=3Dcpp-keyword>void</SPAN> OnTimer ( =
UINT uTimerID, TIMERPROC pTimerProc )
    {
        <SPAN class=3Dcpp-keyword>if</SPAN> ( <SPAN =
class=3Dcpp-literal>1</SPAN> !=3D uTimerID )
            SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
        <SPAN class=3Dcpp-keyword>else</SPAN>
            RedrawWindow();
    }
</FONT>};</PRE>
      <P>This handler just redraws the window so the new time appears in =
the=20
      client area. Finally, we handle <CODE>WM_ERASEBKGND</CODE> and in =
that=20
      handler, we draw the current time in the upper-left corner of the =

⌨️ 快捷键说明

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