Library Zone Articles
External Articles
Byte Size

Discovery Zone Catalogue
Diary
Links
Bookstore
Interactive Zone Ask the Gurus
Discussion Groups
Newsletters
Feedback
Etc Cartoons
Humour
COMpetition
Advertising
Site Builder ASP Web Ring ASP Web Ring

Click here
The Developer's Resource & Community Site
COM XML ASP Java & Misc. NEW: VS.NET
International This Week Forums Author Central Find a Job

How to use DDX with WTL?

Download print article

This has been asked a few times in the ATL newsgroups. (For the uninitiated, WTL is Window Template Library). There is an excellent article by Dr. Richard Grimes about how to use WTL. So, I will not go there.

Adding DDX support to your WTL application

WTL comes with a neat class called CWinDataExchange which allows you to do data exchange between member variables and dialog items. In order to use that, you have to do the following things:

Assuming that you have already generated a WTL application from the wizard,

1) Add #include <atlddx.h> to stdafx.h (or any other convenient place). If you want to use CString available from WTL in the data exchange code, you have to #include <atlmisc.h> before including atlddx.h.


#include <atlbase.h>
#include <atlapp.h> 

extern CAppModule _Module;

#include <atlwin.h>
//Add following lines

#include <atlmisc.h> 
#include <atlddx.h>

2) If you want to use float arguments to be exchanged, you have to define a compile time directive _ATL_USE_DDX_FLOAT. Note that if you use this, you cannot use _ATL_MIN_CRT since floats are exchanged using the CRT functions. In particular, it uses <float.h> to do that.

3) Derive the class which requires the data exchange from CWinDataExchange.


class CMainDlg : public CDialogImpl<CMainDlg>,
                           public CWinDataExchange<CMainDlg> //Add this
{
public:
       enum { IDD = IDD_MAINDLG };

4) Add DDX map to the class


       BEGIN_DDX_MAP(CMainDlg)
              DDX_TEXT(IDC_STRING,m_edit1)
              DDX_INT(IDC_INT,m_int)
              DDX_INT_RANGE(IDC_INT_RANGE,m_int_range,-10,100)
              DDX_TEXT_LEN(IDC_STRING_RANGE,m_string_range, 8)
              DDX_FLOAT(IDC_FLOAT, m_float)
              DDX_FLOAT_RANGE(IDC_FLOAT_RANGE,m_float_range,-1.00,2500.24)
              DDX_CHECK(IDC_CHECK_BOX,m_check)
              DDX_RADIO(IDC_RADIO1, m_radio)
//DDX_CONTROL() is just a simple wrapper to do subclassing of a given window.
       END_DDX_MAP() 

Explanations on each macro and the functions are provided later.

5) Provide default implementation for OnDataValidateError() and OnDataExchangeError() functions. Those functions are called by the framework (CWinDataExchange) when it encounters an error either during validation or while exchanging. If you do not provide any implementation, the default implementation will give a Beep() and sets the focus on the offending control. OnDataValidateError() occurs only when you have set the limits for the corresponding control, i.e., length of the string, min or max value for an int etc


	void OnDataValidateError(UINT id, BOOL bSave,_XData& data)
		{
		CString str;
 
		switch (data.nDataType)
			{
			case ddxDataNull:
				str = "Data is NULL.";
				break;
			case ddxDataText:
				str.Format("Type text, length of data :%i, allowed; %i\n",
				data.textData.nLength, data.textData.nMaxLength);
 				break;
			case ddxDataInt:
				str.Format("Type int, value:%i, allowed min:%i, max:%i\n",
						data.intData.nVal,data.intData.nMin,
						data.intData.nMax);
				break;
#ifdef _ATL_USE_DDX_FLOAT
			case ddxDataFloat:
			case ddxDataDouble:
				{
					char buf[1024];
					sprintf(buf,"Type float: value:%f, min:%f, max:%f",
						data.floatData.nVal,data.floatData.nMin,
						data.floatData.nMax);
					str = buf;
				}
				break;
#endif
			}
				MessageBox (str);
			}
 
	void OnDataExchangeError(UINT id, BOOL bSave)
	{
		MessageBox ("DataExchange Error");
	}

6) Call DoDataExchange() with TRUE to save and FALSE to load. You can use the second argument of DoDataExchange normally –1, to do the data exchange only on a particular control. DoDataExchange returns TRUE if it successfully exchanged the data else will return FALSE.


void SetupDlg()
	{
		m_edit1 = "Hello there";
		m_string_range = "abcdefgh";
		m_int = 1;
		m_int_range = 12;
#ifdef _ATL_USE_DDX_FLOAT
		m_float = -23.45;
		m_float_range =1212.23232;
#endif
 
		m_check = 1;
		m_radio = 0;
		DoDataExchange(FALSE);
	}
 
	void ShowSels()
	{
		if (DoDataExchange(TRUE))
		{
			char buf[1024];
#ifdef _ATL_USE_DDX_FLOAT
			sprintf(buf,"%s\n%i\n%f\n%s\n%i\n%f\n%i\n%i\n",
				m_edit1,m_int,m_float, m_string_range,
				m_int_range,m_float_range,
 				m_check,m_radio);
#else
			sprintf(buf,"%s\n%i\n%s\n%i\n%i\n%i\n",
				m_edit1,m_int,m_string_range,m_int_range,
				m_check,m_radio);
#endif
			MessageBox(buf);
		}
	}

Structures used by CWinDataExchange


// Helpers for validation error reporting
	enum _XDataType
	{
		ddxDataNull = 0,
		ddxDataText = 1,
		ddxDataInt = 2,
		ddxDataFloat = 3,
		ddxDataDouble = 4
	};
 
	struct _XTextData
	{
		int nLength;
		int nMaxLength;
	};
 
	struct _XIntData
	{
		long nVal;
		long nMin;
		long nMax;
	};
 
	struct _XFloatData
	{
		double nVal;
		double nMin;
		double nMax;
	};
 
	struct _XData
	{
		 _XDataType nDataType;
		union
		{
			_XTextData textData;
			_XIntData intData;
			_XFloatData floatData;
		};

	};

All these are used only during error reporting and otherwise, not used. Since, these are self-explanatory, I won't get into explaining each of them. You can use this in validation error handler as:


	void OnDataValidateError(UINT id, BOOL bSave,_XData& data)
	{
		CString str;
 
		switch (data.nDataType)
		{
		case ddxDataNull:
			str = "Data is NULL.";
			break;
		case ddxDataText:
			str.Format("Type text, length of data :%i,
				allowed; %i\n", data.textData.nLength,
				data.textData.nMaxLength);
			break;
		case ddxDataInt:
			str.Format("Type int, value:%i,
				allowed min:%i, max:%i\n",data.intData.nVal,
				data.intData.nMin,data.intData.nMax);
			break;
#ifdef _ATL_USE_DDX_FLOAT
		case ddxDataFloat:
		case ddxDataDouble:
			{
				char buf[1024];
				sprintf(buf,"Type float: value:%f,
					min:%f, max:%f",data.floatData.nVal,
					data.floatData.nMin,data.floatData.nMax);
				str = buf;
			}
			break;
#endif
		}
		MessageBox (str);
	}

MACROS in CWinDataExchange

CWinDataExchange has several macro helpers to do the data exchange. Following is the listing of those macros that you can use in BEGIN_DDX_MAP()/END_DDX_MAP().


DDX_TEXT(<Id of the control> , <variable name>)
DDX_TEXT_LEN(<id of the control>, <variable name>,
			<length allowed>)
 
DDX_INT(<id of the control>, <variable name>)
DDX_INT_RANGE(<id of the control>, <variable name>,
			<minimum value>, <maximum>)
DDX_UINT(<id of the control>,<variable name>)
DDX_UINT_RANGE(<id of the control>, <variable name>,
			<min>, <max>)
DDX_FLOAT(<id of the control>, <variable name>)
DDX_FLOAT_RANGE(<id of the control>, <variable name>,
			<min>, <max>)
DDX_CONTROL(<id of the control>, <variable name>)
DDX_CHECK (<id of the control>, <variable name>)
DDX_RADIO(<id of the control>, <variable name>)

DDX_TEXT and DDX_TEXT_LEN can take LPSTR, BSTR, CComBSTR or WTL::CString as arguments.

For DDX_UINT , DDX_UINT_RANGE, DDX_INT and DDX_INT_RANGE argument type is an int.

For DDX_FLOAT and DDX_FLOAT_RANGE, the variable type is to be a double. Note that this is wrapped with _ATL_USE_DDX_FLOAT directive. So, if you don’t want to use CRT you have to avoid floats. (or is it the otherway around?)

The difference between DDX_UINT and DDX_INT is that the former does does exchange with unsigned integers and the latter takes the signs into consideration.

DDX_CONTROL is just a simple wrapper to do SubclassWindow() on a given dialog item. Note that it needs the second argument to be a CContainedWindow or CCindow.


template <class TControl>
DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
{
       T* pT = static_cast<T*>(this);
       if(!bSave && ctrl.m_hWnd == NULL)
              ctrl.SubclassWindow(pT->GetDlgItem(nID));
}

Both DDX_RADIO and DDX_CHECK take int as the variable.

To Setup the radio buttons, you need to create a group of radio buttons with the first in the zorder with WS_GROUP style. The rest of them should not have that. Note that DDX_CHECK gives 0, 1 or 2 based on the selection (0 – unselected, 1- selected and 2 – indeterminate).


Mail a question to the author!!

As part of the IDevResource commitment to Open Publishing, all of our authors are available to answer all of your trickiest questions at Author Central. For information about the authors, or to mail a question, visit them at Author Central.

Did you like this article?

If you liked this article, tell us about it. You can email your remarks to us at [email protected]

Have your say about the article. You can make your point about the article by mailing [email protected] (If you haven't allready joined, you can join by going to onelist.com/community/dev-com).

More ByteSize articles:

'ILoveYou' By Richard Grimes, 200500
Richard Grimes discusses the release of the Microsoft patch for the 'ILoveYou' virus. Go To Article.

COM+ 2.0 - First Announcement of Microsoft's New Technology By Richard Grimes, 100500
Richard Grimes reports on the recent news about COM+ 2. Go To Article.

How to use DDX with WTL? By Girish Bharadwaj, 270300
Go To Article.

ATL Server By Richard Grimes, 220200
Richard's report from European Devweek 2000, and VCDC Bonn 2000 gives an insight into the new ATL Server technology.
Go To Article.

COM Threading Models By Gopalan Suresh Raj, 070200
Gopalan explains the differences in COM and Win 32 threading models.
Go To Article.

ActiveX & COM By Gopalan Suresh Raj, 270100
Gopalan explains the basics of ActiveX / COM as a truly distributed Object Oriented Architecture.
Go To Article.

Type Library Info, XML and a bit of XSL for fun! by Richard Anderson 121199
This article assumes you understand COM, Type Libraries, XML and enough about VB that you can either use the code as a starting point, or, translate it into another language.
Go To Article.
This article can be downloaded: Zip File (76kb).

COM and Apartments By Richard Grimes, 070100
A discussion on the creation and use of "Apartments" in Win32.
Go To Article.

What is WTL? By Richard Grimes, 070100
Richard gives a basic introduction to WTL.
Go To Article.

An Introduction to Interface Programming By Richard Grimes, 070100
Richard describes the background to interfaces.
Go To Article.


Click here

Contribute to IDR:

To contribute an article to IDR, a click here.

To contact us at IDevResource.com, use our feedback form, or email us.

To comment on the site contact our webmaster.

Promoted by CyberSavvy UK - website promotion experts

All content © Copyright 2000 IDevResource.com, Disclaimer notice

WTL Architecture by Richard Grimes

Java COM integration

Visit the IDR Forums

Visit our NEW WTL Section

Join the Developers Webring