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

📄 atl under the hood - part 5.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
lParam)
    {
        <SPAN class=3Dcpp-keyword>switch</SPAN> (uMsg)
        {
        <SPAN class=3Dcpp-keyword>case</SPAN> WM_DESTROY:
            PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
            <SPAN class=3Dcpp-keyword>break</SPAN>;
        }

        <SPAN class=3Dcpp-keyword>return</SPAN> ::DefWindowProc(hWnd, =
uMsg, wParam, lParam);
    }
};
</PRE>
      <P>You have to give the address of callback function in one field =
of=20
      <CODE>WNDCLASS</CODE> or <CODE>WNDCLASSEX</CODE> structure. And =
you give=20
      it something like this after creating the object of =
<CODE>ZWindow</CODE>=20
      class. </P><PRE>    ZWindow zwnd;
    WNDCLASS wnd;

    wnd.lpfnWndProc =3D wnd.WndProc;
</PRE>
      <P>But when you compile this program this will give error =
something like=20
      this. </P><PRE>cannot convert from '<SPAN =
class=3Dcpp-keyword>long</SPAN> (__stdcall ZWindow::*)(<SPAN =
class=3Dcpp-keyword>struct</SPAN> HWND__ *,
   <SPAN class=3Dcpp-keyword>unsigned</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN>,<SPAN class=3Dcpp-keyword>unsigned</SPAN> =
<SPAN class=3Dcpp-keyword>int</SPAN>,<SPAN =
class=3Dcpp-keyword>long</SPAN>)' to '<SPAN =
class=3Dcpp-keyword>long</SPAN> (__stdcall *)(<SPAN =
class=3Dcpp-keyword>struct</SPAN> HWND__ *,
   <SPAN class=3Dcpp-keyword>unsigned</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN>, <SPAN =
class=3Dcpp-keyword>unsigned</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN>,<SPAN class=3Dcpp-keyword>long</SPAN>)
</PRE>
      <P>The reason is you can not pass member function as a call back =
function.=20
      Why? Because in case of member function compiler automatically =
passes one=20
      parameter to the function and that parameter is the pointer of =
that class=20
      or in other words this pointer. So it means when you pass n =
parameters in=20
      the member function then compiler will pass n+1 parameters and the =

      additional parameter is this pointer. The error message from the =
compiler=20
      shows this too that compiler can't convert member function to =
global=20
      function. </P>
      <P>So what should we do if we want to use member function as a =
call back=20
      function? If we tell the compiler to not pass first parameter to =
the=20
      function some how then we can use the member function as a call =
back=20
      function. In C++ if we declare member function as a static then =
compiler=20
      doesn't pass this pointer, this is in fact the difference between =
static=20
      and non static member function. </P>
      <P>So we made <CODE>WndProc</CODE> static in ZWindow class. This =
technique=20
      is also use in case of threading where you want to use member =
function as=20
      a thread function then you make static member function as a thread =

      function. </P>
      <P>Here is update program which use ZWindow class. </P><B>Program =
67</B> <PRE><SPAN class=3Dcpp-preprocessor>#include =
&lt;windows.h&gt;</SPAN>

<SPAN class=3Dcpp-keyword>class</SPAN> ZWindow
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    HWND m_hWnd;

    ZWindow(HWND hWnd =3D <SPAN class=3Dcpp-literal>0</SPAN>) : =
m_hWnd(hWnd) { }

    <SPAN class=3Dcpp-keyword>inline</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> Attach(HWND hWnd)
    { m_hWnd =3D hWnd; }

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL ShowWindow(<SPAN =
class=3Dcpp-keyword>int</SPAN> nCmdShow)
    { <SPAN class=3Dcpp-keyword>return</SPAN> ::ShowWindow(m_hWnd, =
nCmdShow); }

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL UpdateWindow()
    {  <SPAN class=3Dcpp-keyword>return</SPAN> ::UpdateWindow(m_hWnd); }

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM =
lParam)
    {
        <SPAN class=3Dcpp-keyword>switch</SPAN> (uMsg)
        {
        <SPAN class=3Dcpp-keyword>case</SPAN> WM_DESTROY:
            PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
            <SPAN class=3Dcpp-keyword>break</SPAN>;
        }

        <SPAN class=3Dcpp-keyword>return</SPAN> ::DefWindowProc(hWnd, =
uMsg, wParam, lParam);
    }
};

<SPAN class=3Dcpp-keyword>int</SPAN> WINAPI WinMain(HINSTANCE hInstance, =
HINSTANCE hPrevInstance, LPSTR lpCmdLine, =20
                   <SPAN class=3Dcpp-keyword>int</SPAN> nCmdShow)
{
    <SPAN class=3Dcpp-keyword>char</SPAN> szAppName[] =3D <SPAN =
class=3Dcpp-string>"Hello world"</SPAN>;
    HWND hWnd;
    MSG msg;
    WNDCLASS wnd;
    ZWindow zwnd;
   =20
    wnd.cbClsExtra    =3D NULL;
    wnd.cbWndExtra    =3D NULL;
    wnd.hbrBackground    =3D (HBRUSH)GetStockObject(WHITE_BRUSH);
    wnd.hCursor        =3D LoadCursor(NULL, IDC_ARROW);
    wnd.hIcon        =3D LoadIcon(NULL, IDI_APPLICATION);
    wnd.hInstance        =3D hInstance;
    wnd.lpfnWndProc    =3D ZWindow::WndProc;
    wnd.lpszClassName    =3D szAppName;
    wnd.lpszMenuName    =3D NULL;
    wnd.style        =3D CS_HREDRAW | CS_VREDRAW;
   =20
    <SPAN class=3Dcpp-keyword>if</SPAN> (!RegisterClass(&amp;wnd))
    {
        MessageBox(NULL, <SPAN class=3Dcpp-string>"Can not register =
window class"</SPAN>, <SPAN class=3Dcpp-string>"Error"</SPAN>,=20
                   MB_OK | MB_ICONINFORMATION);
        <SPAN class=3Dcpp-keyword>return</SPAN> -<SPAN =
class=3Dcpp-literal>1</SPAN>;
    }
   =20
    hWnd =3D CreateWindow(szAppName, <SPAN class=3Dcpp-string>"Hello =
world"</SPAN>, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,=20
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, =
hInstance, NULL);

    zwnd.Attach(hWnd);
   =20
    zwnd.ShowWindow(nCmdShow);
    zwnd.UpdateWindow();

    <SPAN class=3Dcpp-keyword>while</SPAN> (GetMessage(&amp;msg, NULL, =
<SPAN class=3Dcpp-literal>0</SPAN>, <SPAN class=3Dcpp-literal>0</SPAN>))
    {
        DispatchMessage(&amp;msg);
    }
   =20
    <SPAN class=3Dcpp-keyword>return</SPAN> msg.wParam;
}
</PRE>
      <P>This program just shows the usage of <CODE>ZWindow</CODE>. And =
to be=20
      very honest this class do nothing special. It is just wrapper on =
Window=20
      API, the only advantage you get from this is that now you don't =
need to=20
      pass <CODE>HWND</CODE> as a parameter, but instead of this now you =
have to=20
      type the object name when calling member function. </P>
      <P>Like before this you call function like this </P><PRE>    =
ShowWindow(hWnd, nCmdShow);
</PRE>
      <P>And now you call something like this </P><PRE>    =
zwnd.ShowWindow(nCmdShow);
</PRE>
      <P>Not a big advantage till now. </P>
      <P>Let's see how we can handle window message in the =
<CODE>WndProc</CODE>.=20
      In the previous program we handle only one function i.e.=20
      <CODE>WM_DESTROY</CODE>. If we want to handle more messages then =
add more=20
      case in the switch statement. Let's modify the =
<CODE>WndProc</CODE> to=20
      handle <CODE>WM_PAINT</CODE>. It would be something like this. =
</P><PRE><SPAN class=3Dcpp-keyword>switch</SPAN> (uMsg)
{
<SPAN class=3Dcpp-keyword>case</SPAN> WM_PAINT:
    hDC =3D ::BeginPaint(hWnd, &amp;ps);
    ::GetClientRect(hWnd, &amp;rect);
    ::DrawText(hDC, <SPAN class=3Dcpp-string>"Hello world"</SPAN>, =
-<SPAN class=3Dcpp-literal>1</SPAN>, &amp;rect, DT_CENTER | DT_VCENTER  =
DT_SINGLELINE);
    ::EndPaint(hWnd, &amp;ps);
    <SPAN class=3Dcpp-keyword>break</SPAN>;

<SPAN class=3Dcpp-keyword>case</SPAN> WM_DESTROY:
    ::PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
    <SPAN class=3Dcpp-keyword>break</SPAN>;
}
</PRE>
      <P>This code is perfectly valid and print "Hello World" in center =
of=20
      Window. But why use API's <CODE>BeginPaint</CODE>,=20
      <CODE>GetClientRect</CODE> and <CODE>EndPaint</CODE> when it all =
should be=20
      a member function of ZWindow class according to our criteria, =
because all=20
      of these have <CODE>HWND</CODE> as a first parameter. </P>
      <P>Because all those function are not static. And you can't call =
non=20
      static member function from static member function. Why? Because =
the=20
      difference is this pointer, non static member function has this =
pointer=20
      and static function doesn't have it. If we somehow pass this =
pointer to=20
      static member function then we can call the non static member =
function=20
      from static member function. Let's take a look at the following =
program.=20
      </P><B>Program 68</B> <PRE><SPAN class=3Dcpp-preprocessor>#include =
&lt;iostream&gt;</SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;

<SPAN class=3Dcpp-keyword>class</SPAN> C=20
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    <SPAN class=3Dcpp-keyword>void</SPAN> NonStaticFunc()=20
    {   =20
        cout &lt;&lt; <SPAN class=3Dcpp-string>"NonStaticFun"</SPAN> =
&lt;&lt; endl;
    }

    <SPAN class=3Dcpp-keyword>static</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> StaticFun(C* pC)=20
    {
        cout &lt;&lt; <SPAN class=3Dcpp-string>"StaticFun"</SPAN> =
&lt;&lt; endl;
        pC-&gt;NonStaticFunc();
    }
};

<SPAN class=3Dcpp-keyword>int</SPAN> main()
{
    C objC;
    C::StaticFun(&amp;objC);
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
      <P>The output of this program is </P><PRE>StaticFun
NonStaticFun
</PRE>
      <P>So we can use the same technique here i.e. store the address of =
ZWindow=20
      object in a global variable and then call non static member =
function from=20
      that pointer. Here is update version of the previous program in =
which we=20
      are not calling windowing API directly. </P><B>Program 69</B> =
<PRE><SPAN class=3Dcpp-preprocessor>#include &lt;windows.h&gt;</SPAN>

<SPAN class=3Dcpp-keyword>class</SPAN> ZWindow;

ZWindow* g_pWnd =3D NULL;

<SPAN class=3Dcpp-keyword>class</SPAN> ZWindow
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    HWND m_hWnd;

    ZWindow(HWND hWnd =3D <SPAN class=3Dcpp-literal>0</SPAN>) : =
m_hWnd(hWnd) { }

    <SPAN class=3Dcpp-keyword>inline</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> Attach(HWND hWnd)
    { m_hWnd =3D hWnd; }

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL ShowWindow(<SPAN =
class=3Dcpp-keyword>int</SPAN> nCmdShow)
    { <SPAN class=3Dcpp-keyword>return</SPAN> ::ShowWindow(m_hWnd, =
nCmdShow); }

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL UpdateWindow()
    {  <SPAN class=3Dcpp-keyword>return</SPAN> ::UpdateWindow(m_hWnd); }

    <SPAN class=3Dcpp-keyword>inline</SPAN> HDC BeginPaint(LPPAINTSTRUCT =
ps)
    {  <SPAN class=3Dcpp-keyword>return</SPAN> ::BeginPaint(m_hWnd, ps); =
}

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL EndPaint(LPPAINTSTRUCT =
ps)
    {  <SPAN class=3Dcpp-keyword>return</SPAN> ::EndPaint(m_hWnd, ps); }

    <SPAN class=3Dcpp-keyword>inline</SPAN> BOOL GetClientRect(LPRECT =
rect)
    {  <SPAN class=3Dcpp-keyword>return</SPAN> ::GetClientRect(m_hWnd, =
rect); }

    BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE =
hInstance,=20
                HWND hWndParent =3D <SPAN class=3Dcpp-literal>0</SPAN>,  =
  DWORD dwStyle =3D WS_OVERLAPPEDWINDOW,=20
                DWORD dwExStyle =3D <SPAN class=3Dcpp-literal>0</SPAN>, =
HMENU hMenu =3D <SPAN class=3Dcpp-literal>0</SPAN>)
    {
        m_hWnd =3D ::CreateWindowEx(dwExStyle, szClassName, szTitle, =
dwStyle,=20
                                  CW_USEDEFAULT, CW_USEDEFAULT, =
CW_USEDEFAULT,=20
                                  CW_USEDEFAULT, hWndParent, hMenu, =
hInstance, NULL);

        <SPAN class=3Dcpp-keyword>return</SPAN> m_hWnd !=3D NULL;
    }

    <SPAN class=3Dcpp-keyword>static</SPAN> LRESULT CALLBACK =
WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        ZWindow* pThis =3D g_pWnd;
        HDC hDC;
        PAINTSTRUCT ps;
        RECT rect;

        <SPAN class=3Dcpp-keyword>switch</SPAN> (uMsg)
        {
        <SPAN class=3Dcpp-keyword>case</SPAN> WM_PAINT:
            hDC =3D pThis-&gt;BeginPaint(&amp;ps);
            pThis-&gt;GetClientRect(&amp;rect);
            ::DrawText(hDC, <SPAN class=3Dcpp-string>"Hello =
world"</SPAN>, -<SPAN class=3Dcpp-literal>1</SPAN>, &amp;rect,=20
                       DT_CENTER | DT_VCENTER | DT_SINGLELINE);
            pThis-&gt;EndPaint(&amp;ps);
            <SPAN class=3Dcpp-keyword>break</SPAN>;

        <SPAN class=3Dcpp-keyword>case</SPAN> WM_DESTROY:
            ::PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
            <SPAN class=3Dcpp-keyword>break</SPAN>;
        }

⌨️ 快捷键说明

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