浙林龙哥

   :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
ATL Windowing by examples : A Simple tutorial 
Submitted by date of submission user level
Mahesh Chand July 01, 2000 intermediate

This article is divided into two parts. In first part, I will explain details about Windows classes in ATL, and second part covers real world example of how to create  windows and dialog boxes using ATL Windowing.

ATL Window Classes

You must be familiar with CWnd class of MFC. CWnd class provides base functionality for manipulating a window in MFC and is a base class for all kind of windows including dialog boxes, controls, views etc. ATL provides almost ( not exactly ) similar class for windows. This class is CWindow. Here is an UML diagram for ATL Window classes.

CWindow This class provides the base functionality for manipulating a window in ATL. CWindow is just a wrapper of Windows APIs and HWND. Here is implementation of some of its functions. As you can see that this class's functions calls Win APIs.

class CWindow
{
public:
static RECT rcDefault;
HWND m_hWnd;

CWindow(HWND hWnd = NULL)
{
m_hWnd = hWnd;
}


// Window Text Functions

BOOL SetWindowText(LPCTSTR lpszString)
{
ATLASSERT(::IsWindow(m_hWnd));
return ::SetWindowText(m_hWnd, lpszString);
}

int GetWindowText(LPTSTR lpszStringBuf, int nMaxCount) const
{
ATLASSERT(::IsWindow(m_hWnd));
return ::GetWindowText(m_hWnd, lpszStringBuf, nMaxCount);
}
BOOL MoveWindow(LPCRECT lpRect, BOOL bRepaint = TRUE)
{
ATLASSERT(::IsWindow(m_hWnd));
return ::MoveWindow(m_hWnd, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, bRepaint);
}

................

..................

}

CWindow class provides most of the functionality provided by CWnd. Here is comparison between Windows programming and ATL CWindow:

Windows programming :
HWND hWnd = ::CreateWindow( "button", "Click me", 
   WS_CHILD, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
   CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
::ShowWindow( hWnd, nCmdShow );
::UpdateWindow( hWnd );

The equivalent code using ATL's CWindow class is

CWindow win;
win.Create( "button", NULL, CWindow::rcDefault, "Click me",
   WS_CHILD );
win.ShowWindow( nCmdShow );
win.UpdateWindow();

 

CWindowImpl 

CWindowImpl is derived from CWindow and CMessageMap. CMessageMap class handles messaging of a window. This class provides two additional features: window class registration and message handling. 

/////////////////////////////////////////////////////////////////////////////
// CWindowImpl - Implements a window

template <class TBase = CWindow>
class ATL_NO_VTABLE CWindowImplRoot : public TBase, public CMessageMap
{

............

.....................
// Message reflection support
LRESULT ReflectNotifications(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
static BOOL DefaultReflectionHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult);
};

CWindowImpl is used to create a new window. It takes three template parameters. Second and third parameters are optional. 

template < class T, class TBase = CWindow, class TWinTraits = CControlWinTraits > where class T is your class derived from CWindowImpl, TBase is base class derived from CWindow.  

The TWinTraits = CControlWinTraits template parameter is a class that encapsulates window styles. This class must implement GetWndStyle and GetWndStyleEx member functions. Here is typedef ATL provides for traits 

typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0> CControlWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CFrameWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD> CMDIChildWinTraits;

CWindow implements Create function to create a window. Here is how to use CWindowImpl in your program:

First, derive your class from CWindowImpl, like this:
class CMcbWindow : public CWindowImpl<CMcbWindow >
{

Note that your new class's name must be passed as an argument to the CWindowImpl template.

Within the class definition, define the message map:

BEGIN_MSG_MAP(CMcbWindow)
   MESSAGE_HANDLER(WM_PAINT,OnPaint)
   MESSAGE_HANDLER(WM_CREATE,OnCreate)
   MESSAGE_HANDLER(WM_DESTROY,OnDestroy)
END_MSG_MAP()

The following line:

MESSAGE_HANDLER(WM_PAINT,OnPaint)

means "When the window receives a WM_PAINT message, invoke member function CMyWindow::OnPaint."

Define the member functions that handle the messages:

LRESULT OnPaint(
   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{ ... 
}
LRESULT OnCreate(
   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{ ...
}
LRESULT OnDestroy(
   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{ ... 
}
}; // CMyWindow

Now Invoke Create member function to create a CWindowImpl window.

CMcbWindow wnd;      
wnd.Create( NULL, CWindow::rcDefault, _T("Mahesh test"),
   WS_OVERLAPPEDWINDOW|WS_VISIBLE );

CAxWindow 

CAxWindow is used to host an ActiveX control. Here are its methods. 

Method Description
CAxWindow Constructs a CAxWindow object.
AttachControl Attaches an existing ActiveX control to the CAxWindow object.
CreateControl Creates an ActiveX control, initializes it, and hosts it in the CAxWindow window.
CreateControlEx Creates an ActiveX control and retrieves an interface pointer (or pointers) from the control.
GetWndClassName Retrieves the predefined class name of the CAxWindow object.
QueryControl Retrieves the IUnknown of the hosted ActiveX control.
QueryHost Retrieves the IUnknown pointer of the CAxWindow object.
SetExternalDispatch Sets the external dispatch interface used by the CAxWindow object.
SetExternalUIHandler Sets the external IDocHostUIHandler interface used by the CAxWindow object.

Its easy to use CAxWindow. Just instantiate it and call Create. To host a control, call CreateControl method. Suppose you want to use calendar control. Here is the example:

CAxWindow wnd;
wnd.Create(hParent, .. );

CComPtr<IAxWinHostWindow> spHost;
wnd.QueryHost(&spHost);
hr = spHost->CreateControl(L"MSCal.Calendar", wnd, NULL);
}

Here is one other code snippet. 

CAxWindow wnd(m_hWnd);
HRESULT hr = wnd.CreateControl(IDH_CHTM);

if (SUCCEEDED(hr))
{
hr = wnd.SetExternalDispatch(static_cast<ICHTMUI*>(this));
long dwStyle = wnd.GetWindowLong(GWL_STYLE);
wnd.SetWindowLong(GWL_STYLE,dwStyle | WS_HSCROLL | WS_VSCROLL);
}

I will use this code in my sample example, How to host a web browser control inside an Explorer Bar later in this section.

CAxHostWindow I am not a big fan of this class. This class hosts an ActiveX control. In my previous example, I have used one interface IAxWinHostWindow. This is same class's interface. But I like using CAxWindow. QueryHost of CAxWindow returns IAxWinHostWindow.

 

ATL Dialog classes  

There are three dialog classes supported by ATL. All three classes fall in the category of ATL Windowing. 

CDialogImpl  This class is a base class for implementing modal or modeless dialog boxes. This class provides a procedure that routes messages to the default message map. ActiveX controls are not supported in this class.

CAxDialogImpl This class supports ActiveX controls. Rest is same as CDialogImpl.

CSimpleDialog This class implements modal dialog boxes and is used for simple dialog boxes such as About Box. It provides command handlers for OK and Cancel buttons. Here is how to display a Help About message box.

BEGIN_MESSAGE_MAP (CMyWindow)
     COMMAND_ID_HANDLER( ID_HELP_ABOUT, OnHelpAbout )
     .........

END_MESSAGE_MAP

LRESULT OnHelpAbout( WORD, WORD, HWND, BOOL& )
{
    CSimpleDialog<IDD_DIALOG1> dlg;
    int res = dlg.DoModal();
    return 0;
}

CSimpleDialog provides handlers for IDOK, IDCANCEL, IDABORT, IDRETRY, IDIGNORE, IDYES, and IDNO.

 

How to create a Window using CWindowImpl class?

In this sample example, I am using CWindowImpl class to create a simple window.

Step 1: Start new Win32 Application project. 

Step 2: Include these lines in your stdafx.h file.      

#include <atlbase.h>
extern CComModule _Module;
#include <atlwin.h>

The atlbase.h class is basic ATL support. ATL Windowing classes are defined in atlwin.h. CComModule is a global class similar to CWinApp in MFC. The _comModule is a global variable represents the application.

Step 3: Now write this code into your WinMain function. You WinMain should look like this:      

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
{
_Module.Init( NULL, hInstance );

// Create an instance of CMcbWindow
CMcbWindow atlWnd;
atlWnd.Create( NULL, CWindow::rcDefault, _T("Mahesh's ATL Window"),
WS_OVERLAPPEDWINDOW|WS_VISIBLE );

MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}

_Module.Term();
return msg.wParam;
}

Step 4: Derive CMcbWindow class from CWindowImpl and write OnPaint and OnDestroy functions.

// NOTE: See the template parameter. Its CMcbWindow
class CMcbWindow : public CWindowImpl<CMcbWindow> 
{
// START MESSAGE_MAP
BEGIN_MSG_MAP( CMcbWindow )
MESSAGE_HANDLER( WM_PAINT, OnPaint )
MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
END_MSG_MAP()
// END MESSAGE_MAP

// This function will paint a Hello mindcracker string 
LRESULT OnPaint( UINT, WPARAM, LPARAM, BOOL& )
{
PAINTSTRUCT ps;
HDC hDC = GetDC();
BeginPaint( &ps );
TextOut( hDC, 0, 0, _T("Hello mindcracker"), 17 );
EndPaint( &ps );
return 0;
}

LRESULT OnDestroy( UINT, WPARAM, LPARAM, BOOL& ){
PostQuitMessage( 0 );
return 0;
}
};

Step 5: Define CComModule _Module extern variable. 

// ATLWnd.cpp : Defines the entry point for the application.
#include "stdafx.h"
CComModule _Module;

Step 5: Compile and Run your program.

Here is the output. You can download the attached project. AtlWnd.zip 

 

Implementing a dialog box using ATL Object Wizard

There are two ways to add a dialog box. If you are developing an ATL/COM dll then you can use ATL Object Wizard to add a dialog. Here are the steps:

Step 1: Go to Insert ATL Object, Select Category - Miscellaneous and double click on Dialog.

Step 2: Insert MyDlg as Short Name. And click Ok.

This wizard adds a class CMyDlg into your project. This class is derived from CAxDialogImpl. 

class CMyDlg : public CAxDialogImpl<CMyDlg>  

This class has OnInitDialog and handlers for Ok and Cancel buttons. You can modify this dialog according to your needs.

Now you can create this dialog box modal or modeless. For modal dialog box :

// Include mydlg.h in the file where you want to call your Dialog.

#include "mydlg.h" 

// Create an instance of CMyDlg and call DoModal(). 

CMyDlg dlg;
Dlg.DoModal();

for Modeless, call Create member function.

// Include mydlg.h in the file where you want to call your Dialog.

#include "mydlg.h" 

// Create an instance of CMyDlg and Call ::Create method.

CMyDlg dlg;
Dlg.Create( ::GetDestopWindow()); 

dlg.ShowWindow( SW_SHOWNORMAL);

 

Cheers,

Mahesh

posted on 2004-09-10 10:55  浙林龙哥  阅读(2050)  评论(0)    收藏  举报