| // Windows Template Library - WTL version 8.0 | 
 | // Copyright (C) Microsoft Corporation. All rights reserved. | 
 | // | 
 | // This file is a part of the Windows Template Library. | 
 | // The use and distribution terms for this software are covered by the | 
 | // Microsoft Permissive License (Ms-PL) which can be found in the file | 
 | // Ms-PL.txt at the root of this distribution. | 
 |  | 
 | #ifndef __ATLDDX_H__ | 
 | #define __ATLDDX_H__ | 
 |  | 
 | #pragma once | 
 |  | 
 | #ifndef __cplusplus | 
 | 	#error ATL requires C++ compilation (use a .cpp suffix) | 
 | #endif | 
 |  | 
 | #ifndef __ATLAPP_H__ | 
 | 	#error atlddx.h requires atlapp.h to be included first | 
 | #endif | 
 |  | 
 | #if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) | 
 | 	#error Cannot use floating point DDX with _ATL_MIN_CRT defined | 
 | #endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) | 
 |  | 
 | #ifdef _ATL_USE_DDX_FLOAT | 
 |   #include <float.h> | 
 | #endif // _ATL_USE_DDX_FLOAT | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // Classes in this file: | 
 | // | 
 | // CWinDataExchange<T> | 
 |  | 
 |  | 
 | namespace WTL | 
 | { | 
 |  | 
 | // Constants | 
 | #define DDX_LOAD	FALSE | 
 | #define DDX_SAVE	TRUE | 
 |  | 
 | // DDX map macros | 
 | #define BEGIN_DDX_MAP(thisClass) \ | 
 | 	BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \ | 
 | 	{ \ | 
 | 		bSaveAndValidate; \ | 
 | 		nCtlID; | 
 |  | 
 | #define DDX_TEXT(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_TEXT_LEN(nID, var, len) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_INT(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_INT_RANGE(nID, var, min, max) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_UINT(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_UINT_RANGE(nID, var, min, max) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #ifdef _ATL_USE_DDX_FLOAT | 
 | #define DDX_FLOAT(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Float(nID, var, bSaveAndValidate)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_FLOAT_RANGE(nID, var, min, max) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 | #define DDX_FLOAT_P(nID, var, precision) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 |  | 
 | #define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 		{ \ | 
 | 			if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \ | 
 | 				return FALSE; \ | 
 | 		} | 
 | #endif // _ATL_USE_DDX_FLOAT | 
 |  | 
 | #define DDX_CONTROL(nID, obj) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 			DDX_Control(nID, obj, bSaveAndValidate); | 
 |  | 
 | #define DDX_CONTROL_HANDLE(nID, obj) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 			DDX_Control_Handle(nID, obj, bSaveAndValidate); | 
 |  | 
 | #define DDX_CHECK(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 			DDX_Check(nID, var, bSaveAndValidate); | 
 |  | 
 | #define DDX_RADIO(nID, var) \ | 
 | 		if(nCtlID == (UINT)-1 || nCtlID == nID) \ | 
 | 			DDX_Radio(nID, var, bSaveAndValidate); | 
 |  | 
 | #define END_DDX_MAP() \ | 
 | 		return TRUE; \ | 
 | 	} | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CWinDataExchange - provides support for DDX | 
 |  | 
 | template <class T> | 
 | class CWinDataExchange | 
 | { | 
 | public: | 
 | // Data exchange method - override in your derived class | 
 | 	BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1) | 
 | 	{ | 
 | 		// this one should never be called, override it in | 
 | 		// your derived class by implementing DDX map | 
 | 		ATLASSERT(FALSE); | 
 | 		return FALSE; | 
 | 	} | 
 |  | 
 | // 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; | 
 | 		}; | 
 | 	}; | 
 |  | 
 | // Text exchange | 
 | 	BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			HWND hWndCtrl = pT->GetDlgItem(nID); | 
 | 			int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR)); | 
 | 			if(nRetLen < ::GetWindowTextLength(hWndCtrl)) | 
 | 				bSuccess = FALSE; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); | 
 | 			bSuccess = pT->SetDlgItemText(nID, lpstrText); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nLength > 0); | 
 | 			if(lstrlen(lpstrText) > nLength) | 
 | 			{ | 
 | 				_XData data = { ddxDataText }; | 
 | 				data.textData.nLength = lstrlen(lpstrText); | 
 | 				data.textData.nMaxLength = nLength; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 |  | 
 | 	BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			bSuccess = pT->GetDlgItemText(nID, bstrText); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			USES_CONVERSION; | 
 | 			LPTSTR lpstrText = OLE2T(bstrText); | 
 | 			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); | 
 | 			bSuccess = pT->SetDlgItemText(nID, lpstrText); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nLength > 0); | 
 | 			if((int)::SysStringLen(bstrText) > nLength) | 
 | 			{ | 
 | 				_XData data = { ddxDataText }; | 
 | 				data.textData.nLength = (int)::SysStringLen(bstrText); | 
 | 				data.textData.nMaxLength = nLength; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 |  | 
 | 	BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			USES_CONVERSION; | 
 | 			LPTSTR lpstrText = OLE2T(bstrText); | 
 | 			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); | 
 | 			bSuccess = pT->SetDlgItemText(nID, lpstrText); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nLength > 0); | 
 | 			if((int)bstrText.Length() > nLength) | 
 | 			{ | 
 | 				_XData data = { ddxDataText }; | 
 | 				data.textData.nLength = (int)bstrText.Length(); | 
 | 				data.textData.nMaxLength = nLength; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 |  | 
 | #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) | 
 | 	BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			HWND hWndCtrl = pT->GetDlgItem(nID); | 
 | 			int nLen = ::GetWindowTextLength(hWndCtrl); | 
 | 			int nRetLen = -1; | 
 | 			LPTSTR lpstr = strText.GetBufferSetLength(nLen); | 
 | 			if(lpstr != NULL) | 
 | 			{ | 
 | 				nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1); | 
 | 				strText.ReleaseBuffer(); | 
 | 			} | 
 | 			if(nRetLen < nLen) | 
 | 				bSuccess = FALSE; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			bSuccess = pT->SetDlgItemText(nID, strText); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nLength > 0); | 
 | 			if(strText.GetLength() > nLength) | 
 | 			{ | 
 | 				_XData data = { ddxDataText }; | 
 | 				data.textData.nLength = strText.GetLength(); | 
 | 				data.textData.nMaxLength = nLength; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 | #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) | 
 |  | 
 | // Numeric exchange | 
 | 	template <class Type> | 
 | 	BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); | 
 | 			bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nMin != nMax); | 
 | 			if(nVal < nMin || nVal > nMax) | 
 | 			{ | 
 | 				_XData data = { ddxDataInt }; | 
 | 				data.intData.nVal = (long)nVal; | 
 | 				data.intData.nMin = (long)nMin; | 
 | 				data.intData.nMax = (long)nMax; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 |  | 
 | // Float exchange | 
 | #ifdef _ATL_USE_DDX_FLOAT | 
 | 	static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d) | 
 | 	{ | 
 | 		ATLASSERT(lpszText != NULL); | 
 | 		while (*lpszText == _T(' ') || *lpszText == _T('\t')) | 
 | 			lpszText++; | 
 |  | 
 | 		TCHAR chFirst = lpszText[0]; | 
 | 		d = _tcstod(lpszText, (LPTSTR*)&lpszText); | 
 | 		if (d == 0.0 && chFirst != _T('0')) | 
 | 			return FALSE;   // could not convert | 
 | 		while (*lpszText == _T(' ') || *lpszText == _T('\t')) | 
 | 			lpszText++; | 
 |  | 
 | 		if (*lpszText != _T('\0')) | 
 | 			return FALSE;   // not terminated properly | 
 |  | 
 | 		return TRUE; | 
 | 	} | 
 |  | 
 | 	BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 | 		const int cchBuff = 32; | 
 | 		TCHAR szBuff[cchBuff] = { 0 }; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			pT->GetDlgItemText(nID, szBuff, cchBuff); | 
 | 			double d = 0; | 
 | 			if(_AtlSimpleFloatParse(szBuff, d)) | 
 | 				nVal = (float)d; | 
 | 			else | 
 | 				bSuccess = FALSE; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); | 
 | 			SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); | 
 | 			bSuccess = pT->SetDlgItemText(nID, szBuff); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nMin != nMax); | 
 | 			if(nVal < nMin || nVal > nMax) | 
 | 			{ | 
 | 				_XData data = { ddxDataFloat }; | 
 | 				data.floatData.nVal = (double)nVal; | 
 | 				data.floatData.nMin = (double)nMin; | 
 | 				data.floatData.nMax = (double)nMax; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 |  | 
 | 	BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		BOOL bSuccess = TRUE; | 
 | 		const int cchBuff = 32; | 
 | 		TCHAR szBuff[cchBuff] = { 0 }; | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			pT->GetDlgItemText(nID, szBuff, cchBuff); | 
 | 			double d = 0; | 
 | 			if(_AtlSimpleFloatParse(szBuff, d)) | 
 | 				nVal = d; | 
 | 			else | 
 | 				bSuccess = FALSE; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); | 
 | 			SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); | 
 | 			bSuccess = pT->SetDlgItemText(nID, szBuff); | 
 | 		} | 
 |  | 
 | 		if(!bSuccess) | 
 | 		{ | 
 | 			pT->OnDataExchangeError(nID, bSave); | 
 | 		} | 
 | 		else if(bSave && bValidate)   // validation | 
 | 		{ | 
 | 			ATLASSERT(nMin != nMax); | 
 | 			if(nVal < nMin || nVal > nMax) | 
 | 			{ | 
 | 				_XData data = { ddxDataFloat }; | 
 | 				data.floatData.nVal = nVal; | 
 | 				data.floatData.nMin = nMin; | 
 | 				data.floatData.nMax = nMax; | 
 | 				pT->OnDataValidateError(nID, bSave, data); | 
 | 				bSuccess = FALSE; | 
 | 			} | 
 | 		} | 
 | 		return bSuccess; | 
 | 	} | 
 | #endif // _ATL_USE_DDX_FLOAT | 
 |  | 
 | // Full control subclassing (for CWindowImpl derived controls) | 
 | 	template <class TControl> | 
 | 	void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave) | 
 | 	{ | 
 | 		if(!bSave && ctrl.m_hWnd == NULL) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			ctrl.SubclassWindow(pT->GetDlgItem(nID)); | 
 | 		} | 
 | 	} | 
 |  | 
 | // Simple control attaching (for HWND wrapper controls) | 
 | 	template <class TControl> | 
 | 	void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave) | 
 | 	{ | 
 | 		if(!bSave && ctrl.m_hWnd == NULL) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			ctrl = pT->GetDlgItem(nID); | 
 | 		} | 
 | 	} | 
 |  | 
 | // Control state | 
 | 	void DDX_Check(UINT nID, int& nValue, BOOL bSave) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		HWND hWndCtrl = pT->GetDlgItem(nID); | 
 | 		if(bSave) | 
 | 		{ | 
 | 			nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); | 
 | 			ATLASSERT(nValue >= 0 && nValue <= 2); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			if(nValue < 0 || nValue > 2) | 
 | 			{ | 
 | 				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue); | 
 | 				nValue = 0;  // default to off | 
 | 			} | 
 | 			::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// variant that supports bool (checked/not-checked, no intermediate state) | 
 | 	void DDX_Check(UINT nID, bool& bCheck, BOOL bSave) | 
 | 	{ | 
 | 		int nValue = bCheck ? 1 : 0; | 
 | 		DDX_Check(nID, nValue, bSave); | 
 |  | 
 | 		if(bSave) | 
 | 		{ | 
 | 			if(nValue == 2) | 
 | 				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue); | 
 | 			bCheck = (nValue == 1); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	void DDX_Radio(UINT nID, int& nValue, BOOL bSave) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		HWND hWndCtrl = pT->GetDlgItem(nID); | 
 | 		ATLASSERT(hWndCtrl != NULL); | 
 |  | 
 | 		// must be first in a group of auto radio buttons | 
 | 		ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP); | 
 | 		ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); | 
 |  | 
 | 		if(bSave) | 
 | 			nValue = -1;     // value if none found | 
 |  | 
 | 		// walk all children in group | 
 | 		int nButton = 0; | 
 | 		do | 
 | 		{ | 
 | 			if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) | 
 | 			{ | 
 | 				// control in group is a radio button | 
 | 				if(bSave) | 
 | 				{ | 
 | 					if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) | 
 | 					{ | 
 | 						ATLASSERT(nValue == -1);    // only set once | 
 | 						nValue = nButton; | 
 | 					} | 
 | 				} | 
 | 				else | 
 | 				{ | 
 | 					// select button | 
 | 					::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L); | 
 | 				} | 
 | 				nButton++; | 
 | 			} | 
 | 			else | 
 | 			{ | 
 | 				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n")); | 
 | 			} | 
 | 			hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); | 
 | 		} | 
 | 		while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)); | 
 | 	} | 
 |  | 
 | // Overrideables | 
 | 	void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) | 
 | 	{ | 
 | 		// Override to display an error message | 
 | 		::MessageBeep((UINT)-1); | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		::SetFocus(pT->GetDlgItem(nCtrlID)); | 
 | 	} | 
 |  | 
 | 	void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) | 
 | 	{ | 
 | 		// Override to display an error message | 
 | 		::MessageBeep((UINT)-1); | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		::SetFocus(pT->GetDlgItem(nCtrlID)); | 
 | 	} | 
 | }; | 
 |  | 
 | }; // namespace WTL | 
 |  | 
 | #endif // __ATLDDX_H__ |