PageRenderTime 53ms CodeModel.GetById 13ms app.highlight 34ms RepoModel.GetById 2ms app.codeStats 0ms

/thirdparty/wtl/atlddx.h

http://crashrpt.googlecode.com/
C++ Header | 685 lines | 564 code | 81 blank | 40 comment | 178 complexity | 1dd8d8141663f3ab7b52ea55f652561c MD5 | raw file
  1// Windows Template Library - WTL version 8.1
  2// Copyright (C) Microsoft Corporation. All rights reserved.
  3//
  4// This file is a part of the Windows Template Library.
  5// The use and distribution terms for this software are covered by the
  6// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
  7// which can be found in the file CPL.TXT at the root of this distribution.
  8// By using this software in any fashion, you are agreeing to be bound by
  9// the terms of this license. You must not remove this notice, or
 10// any other, from this software.
 11
 12#ifndef __ATLDDX_H__
 13#define __ATLDDX_H__
 14
 15#pragma once
 16
 17#ifndef __ATLAPP_H__
 18	#error atlddx.h requires atlapp.h to be included first
 19#endif
 20
 21#if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
 22	#error Cannot use floating point DDX with _ATL_MIN_CRT defined
 23#endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)
 24
 25#ifdef _ATL_USE_DDX_FLOAT
 26  #include <float.h>
 27#endif // _ATL_USE_DDX_FLOAT
 28
 29
 30///////////////////////////////////////////////////////////////////////////////
 31// Classes in this file:
 32//
 33// CWinDataExchange<T>
 34
 35
 36namespace WTL
 37{
 38
 39// Constants
 40#define DDX_LOAD	FALSE
 41#define DDX_SAVE	TRUE
 42
 43// DDX map macros
 44#define BEGIN_DDX_MAP(thisClass) \
 45	BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \
 46	{ \
 47		bSaveAndValidate; \
 48		nCtlID;
 49
 50#define DDX_TEXT(nID, var) \
 51		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 52		{ \
 53			if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
 54				return FALSE; \
 55		}
 56
 57#define DDX_TEXT_LEN(nID, var, len) \
 58		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 59		{ \
 60			if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
 61				return FALSE; \
 62		}
 63
 64#define DDX_INT(nID, var) \
 65		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 66		{ \
 67			if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \
 68				return FALSE; \
 69		}
 70
 71#define DDX_INT_RANGE(nID, var, min, max) \
 72		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 73		{ \
 74			if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \
 75				return FALSE; \
 76		}
 77
 78#define DDX_UINT(nID, var) \
 79		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 80		{ \
 81			if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \
 82				return FALSE; \
 83		}
 84
 85#define DDX_UINT_RANGE(nID, var, min, max) \
 86		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 87		{ \
 88			if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \
 89				return FALSE; \
 90		}
 91
 92#ifdef _ATL_USE_DDX_FLOAT
 93#define DDX_FLOAT(nID, var) \
 94		if(nCtlID == (UINT)-1 || nCtlID == nID) \
 95		{ \
 96			if(!DDX_Float(nID, var, bSaveAndValidate)) \
 97				return FALSE; \
 98		}
 99
100#define DDX_FLOAT_RANGE(nID, var, min, max) \
101		if(nCtlID == (UINT)-1 || nCtlID == nID) \
102		{ \
103			if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \
104				return FALSE; \
105		}
106#define DDX_FLOAT_P(nID, var, precision) \
107		if(nCtlID == (UINT)-1 || nCtlID == nID) \
108		{ \
109			if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \
110				return FALSE; \
111		}
112
113#define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \
114		if(nCtlID == (UINT)-1 || nCtlID == nID) \
115		{ \
116			if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \
117				return FALSE; \
118		}
119#endif // _ATL_USE_DDX_FLOAT
120
121#define DDX_CONTROL(nID, obj) \
122		if(nCtlID == (UINT)-1 || nCtlID == nID) \
123			DDX_Control(nID, obj, bSaveAndValidate);
124
125#define DDX_CONTROL_HANDLE(nID, obj) \
126		if(nCtlID == (UINT)-1 || nCtlID == nID) \
127			DDX_Control_Handle(nID, obj, bSaveAndValidate);
128
129#define DDX_CHECK(nID, var) \
130		if(nCtlID == (UINT)-1 || nCtlID == nID) \
131			DDX_Check(nID, var, bSaveAndValidate);
132
133#define DDX_RADIO(nID, var) \
134		if(nCtlID == (UINT)-1 || nCtlID == nID) \
135			DDX_Radio(nID, var, bSaveAndValidate);
136
137#define END_DDX_MAP() \
138		return TRUE; \
139	}
140
141// DDX support for Tab, Combo, ListBox and ListView selection index
142// Note: Specialized versions require atlctrls.h to be included first
143#if (_MSC_VER >= 1300)
144
145#define DDX_INDEX(CtrlClass, nID, var) \
146	if(nCtlID == (UINT)-1 || nCtlID == nID) \
147		DDX_Index<CtrlClass>(nID, var, bSaveAndValidate);
148
149#ifdef __ATLCTRLS_H__
150  #define DDX_TAB_INDEX(nID, var)      DDX_INDEX(WTL::CTabCtrl, nID, var)
151  #define DDX_COMBO_INDEX(nID, var)    DDX_INDEX(WTL::CComboBox, nID, var)
152  #define DDX_LISTBOX_INDEX(nID, var)  DDX_INDEX(WTL::CListBox, nID, var)
153  #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var)
154#endif // __ATLCTRLS_H__
155
156#endif // (_MSC_VER >= 1300)
157
158
159///////////////////////////////////////////////////////////////////////////////
160// CWinDataExchange - provides support for DDX
161
162template <class T>
163class CWinDataExchange
164{
165public:
166// Data exchange method - override in your derived class
167	BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
168	{
169		// this one should never be called, override it in
170		// your derived class by implementing DDX map
171		ATLASSERT(FALSE);
172		return FALSE;
173	}
174
175// Helpers for validation error reporting
176	enum _XDataType
177	{
178		ddxDataNull = 0,
179		ddxDataText = 1,
180		ddxDataInt = 2,
181		ddxDataFloat = 3,
182		ddxDataDouble = 4
183	};
184
185	struct _XTextData
186	{
187		int nLength;
188		int nMaxLength;
189	};
190
191	struct _XIntData
192	{
193		long nVal;
194		long nMin;
195		long nMax;
196	};
197
198	struct _XFloatData
199	{
200		double nVal;
201		double nMin;
202		double nMax;
203	};
204
205	struct _XData
206	{
207		_XDataType nDataType;
208		union
209		{
210			_XTextData textData;
211			_XIntData intData;
212			_XFloatData floatData;
213		};
214	};
215
216// Text exchange
217	BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
218	{
219		T* pT = static_cast<T*>(this);
220		BOOL bSuccess = TRUE;
221
222		if(bSave)
223		{
224			HWND hWndCtrl = pT->GetDlgItem(nID);
225			int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR));
226			if(nRetLen < ::GetWindowTextLength(hWndCtrl))
227				bSuccess = FALSE;
228		}
229		else
230		{
231			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
232			bSuccess = pT->SetDlgItemText(nID, lpstrText);
233		}
234
235		if(!bSuccess)
236		{
237			pT->OnDataExchangeError(nID, bSave);
238		}
239		else if(bSave && bValidate)   // validation
240		{
241			ATLASSERT(nLength > 0);
242			if(lstrlen(lpstrText) > nLength)
243			{
244				_XData data = { ddxDataText };
245				data.textData.nLength = lstrlen(lpstrText);
246				data.textData.nMaxLength = nLength;
247				pT->OnDataValidateError(nID, bSave, data);
248				bSuccess = FALSE;
249			}
250		}
251		return bSuccess;
252	}
253
254	BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
255	{
256		T* pT = static_cast<T*>(this);
257		BOOL bSuccess = TRUE;
258
259		if(bSave)
260		{
261			bSuccess = pT->GetDlgItemText(nID, bstrText);
262		}
263		else
264		{
265			USES_CONVERSION;
266			LPTSTR lpstrText = OLE2T(bstrText);
267			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
268			bSuccess = pT->SetDlgItemText(nID, lpstrText);
269		}
270
271		if(!bSuccess)
272		{
273			pT->OnDataExchangeError(nID, bSave);
274		}
275		else if(bSave && bValidate)   // validation
276		{
277			ATLASSERT(nLength > 0);
278			if((int)::SysStringLen(bstrText) > nLength)
279			{
280				_XData data = { ddxDataText };
281				data.textData.nLength = (int)::SysStringLen(bstrText);
282				data.textData.nMaxLength = nLength;
283				pT->OnDataValidateError(nID, bSave, data);
284				bSuccess = FALSE;
285			}
286		}
287		return bSuccess;
288	}
289
290	BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
291	{
292		T* pT = static_cast<T*>(this);
293		BOOL bSuccess = TRUE;
294
295		if(bSave)
296		{
297			bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);
298		}
299		else
300		{
301			USES_CONVERSION;
302			LPTSTR lpstrText = OLE2T(bstrText);
303			ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength);
304			bSuccess = pT->SetDlgItemText(nID, lpstrText);
305		}
306
307		if(!bSuccess)
308		{
309			pT->OnDataExchangeError(nID, bSave);
310		}
311		else if(bSave && bValidate)   // validation
312		{
313			ATLASSERT(nLength > 0);
314			if((int)bstrText.Length() > nLength)
315			{
316				_XData data = { ddxDataText };
317				data.textData.nLength = (int)bstrText.Length();
318				data.textData.nMaxLength = nLength;
319				pT->OnDataValidateError(nID, bSave, data);
320				bSuccess = FALSE;
321			}
322		}
323		return bSuccess;
324	}
325
326#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
327	BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
328	{
329		T* pT = static_cast<T*>(this);
330		BOOL bSuccess = TRUE;
331
332		if(bSave)
333		{
334			HWND hWndCtrl = pT->GetDlgItem(nID);
335			int nLen = ::GetWindowTextLength(hWndCtrl);
336			int nRetLen = -1;
337			LPTSTR lpstr = strText.GetBufferSetLength(nLen);
338			if(lpstr != NULL)
339			{
340				nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1);
341				strText.ReleaseBuffer();
342			}
343			if(nRetLen < nLen)
344				bSuccess = FALSE;
345		}
346		else
347		{
348			bSuccess = pT->SetDlgItemText(nID, strText);
349		}
350
351		if(!bSuccess)
352		{
353			pT->OnDataExchangeError(nID, bSave);
354		}
355		else if(bSave && bValidate)   // validation
356		{
357			ATLASSERT(nLength > 0);
358			if(strText.GetLength() > nLength)
359			{
360				_XData data = { ddxDataText };
361				data.textData.nLength = strText.GetLength();
362				data.textData.nMaxLength = nLength;
363				pT->OnDataValidateError(nID, bSave, data);
364				bSuccess = FALSE;
365			}
366		}
367		return bSuccess;
368	}
369#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
370
371// Numeric exchange
372	template <class Type>
373	BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)
374	{
375		T* pT = static_cast<T*>(this);
376		BOOL bSuccess = TRUE;
377
378		if(bSave)
379		{
380			nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);
381		}
382		else
383		{
384			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
385			bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);
386		}
387
388		if(!bSuccess)
389		{
390			pT->OnDataExchangeError(nID, bSave);
391		}
392		else if(bSave && bValidate)   // validation
393		{
394			ATLASSERT(nMin != nMax);
395			if(nVal < nMin || nVal > nMax)
396			{
397				_XData data = { ddxDataInt };
398				data.intData.nVal = (long)nVal;
399				data.intData.nMin = (long)nMin;
400				data.intData.nMax = (long)nMax;
401				pT->OnDataValidateError(nID, bSave, data);
402				bSuccess = FALSE;
403			}
404		}
405		return bSuccess;
406	}
407
408// Float exchange
409#ifdef _ATL_USE_DDX_FLOAT
410	static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)
411	{
412		ATLASSERT(lpszText != NULL);
413		while (*lpszText == _T(' ') || *lpszText == _T('\t'))
414			lpszText++;
415
416		TCHAR chFirst = lpszText[0];
417		d = _tcstod(lpszText, (LPTSTR*)&lpszText);
418		if (d == 0.0 && chFirst != _T('0'))
419			return FALSE;   // could not convert
420		while (*lpszText == _T(' ') || *lpszText == _T('\t'))
421			lpszText++;
422
423		if (*lpszText != _T('\0'))
424			return FALSE;   // not terminated properly
425
426		return TRUE;
427	}
428
429	BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG)
430	{
431		T* pT = static_cast<T*>(this);
432		BOOL bSuccess = TRUE;
433		const int cchBuff = 32;
434		TCHAR szBuff[cchBuff] = { 0 };
435
436		if(bSave)
437		{
438			pT->GetDlgItemText(nID, szBuff, cchBuff);
439			double d = 0;
440			if(_AtlSimpleFloatParse(szBuff, d))
441				nVal = (float)d;
442			else
443				bSuccess = FALSE;
444		}
445		else
446		{
447			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
448			SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
449			bSuccess = pT->SetDlgItemText(nID, szBuff);
450		}
451
452		if(!bSuccess)
453		{
454			pT->OnDataExchangeError(nID, bSave);
455		}
456		else if(bSave && bValidate)   // validation
457		{
458			ATLASSERT(nMin != nMax);
459			if(nVal < nMin || nVal > nMax)
460			{
461				_XData data = { ddxDataFloat };
462				data.floatData.nVal = (double)nVal;
463				data.floatData.nMin = (double)nMin;
464				data.floatData.nMax = (double)nMax;
465				pT->OnDataValidateError(nID, bSave, data);
466				bSuccess = FALSE;
467			}
468		}
469		return bSuccess;
470	}
471
472	BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG)
473	{
474		T* pT = static_cast<T*>(this);
475		BOOL bSuccess = TRUE;
476		const int cchBuff = 32;
477		TCHAR szBuff[cchBuff] = { 0 };
478
479		if(bSave)
480		{
481			pT->GetDlgItemText(nID, szBuff, cchBuff);
482			double d = 0;
483			if(_AtlSimpleFloatParse(szBuff, d))
484				nVal = d;
485			else
486				bSuccess = FALSE;
487		}
488		else
489		{
490			ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax);
491			SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
492			bSuccess = pT->SetDlgItemText(nID, szBuff);
493		}
494
495		if(!bSuccess)
496		{
497			pT->OnDataExchangeError(nID, bSave);
498		}
499		else if(bSave && bValidate)   // validation
500		{
501			ATLASSERT(nMin != nMax);
502			if(nVal < nMin || nVal > nMax)
503			{
504				_XData data = { ddxDataFloat };
505				data.floatData.nVal = nVal;
506				data.floatData.nMin = nMin;
507				data.floatData.nMax = nMax;
508				pT->OnDataValidateError(nID, bSave, data);
509				bSuccess = FALSE;
510			}
511		}
512		return bSuccess;
513	}
514#endif // _ATL_USE_DDX_FLOAT
515
516// Full control subclassing (for CWindowImpl derived controls)
517	template <class TControl>
518	void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
519	{
520		if(!bSave && ctrl.m_hWnd == NULL)
521		{
522			T* pT = static_cast<T*>(this);
523			ctrl.SubclassWindow(pT->GetDlgItem(nID));
524		}
525	}
526
527// Simple control attaching (for HWND wrapper controls)
528	template <class TControl>
529	void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)
530	{
531		if(!bSave && ctrl.m_hWnd == NULL)
532		{
533			T* pT = static_cast<T*>(this);
534			ctrl = pT->GetDlgItem(nID);
535		}
536	}
537
538// Control state
539	void DDX_Check(UINT nID, int& nValue, BOOL bSave)
540	{
541		T* pT = static_cast<T*>(this);
542		HWND hWndCtrl = pT->GetDlgItem(nID);
543		if(bSave)
544		{
545			nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
546			ATLASSERT(nValue >= 0 && nValue <= 2);
547		}
548		else
549		{
550			if(nValue < 0 || nValue > 2)
551			{
552				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue);
553				nValue = 0;  // default to off
554			}
555			::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);
556		}
557	}
558
559	// variant that supports bool (checked/not-checked, no intermediate state)
560	void DDX_Check(UINT nID, bool& bCheck, BOOL bSave)
561	{
562		int nValue = bCheck ? 1 : 0;
563		DDX_Check(nID, nValue, bSave);
564
565		if(bSave)
566		{
567			if(nValue == 2)
568				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue);
569			bCheck = (nValue == 1);
570		}
571	}
572
573	void DDX_Radio(UINT nID, int& nValue, BOOL bSave)
574	{
575		T* pT = static_cast<T*>(this);
576		HWND hWndCtrl = pT->GetDlgItem(nID);
577		ATLASSERT(hWndCtrl != NULL);
578
579		// must be first in a group of auto radio buttons
580		ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
581		ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
582
583		if(bSave)
584			nValue = -1;     // value if none found
585
586		// walk all children in group
587		int nButton = 0;
588		do
589		{
590			if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
591			{
592				// control in group is a radio button
593				if(bSave)
594				{
595					if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
596					{
597						ATLASSERT(nValue == -1);    // only set once
598						nValue = nButton;
599					}
600				}
601				else
602				{
603					// select button
604					::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);
605				}
606				nButton++;
607			}
608			else
609			{
610				ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n"));
611			}
612			hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
613		}
614		while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
615	}
616
617// DDX support for Tab, Combo, ListBox and ListView selection index
618#if (_MSC_VER >= 1300)
619	template <class TCtrl>
620	INT _getSel(TCtrl& tCtrl)
621	{
622		return tCtrl.GetCurSel();
623	}
624
625	template <class TCtrl>
626	void _setSel(TCtrl& tCtrl, INT iSel)
627	{
628		if(iSel < 0)
629			tCtrl.SetCurSel(-1);
630		else
631			tCtrl.SetCurSel(iSel);
632	}
633
634#ifdef __ATLCTRLS_H__
635	// ListViewCtrl specialization
636	template <>
637	INT _getSel(WTL::CListViewCtrl& tCtrl)
638	{
639		return tCtrl.GetSelectedIndex();
640	}
641
642	template <>
643	void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel)
644	{
645		if(iSel < 0)
646			tCtrl.SelectItem(-1);
647		else
648			tCtrl.SelectItem(iSel);
649	}
650#endif // __ATLCTRLS_H__
651
652	template <class TCtrl>
653	void DDX_Index(UINT nID, INT& nVal, BOOL bSave)
654	{
655		T* pT = static_cast<T*>(this);
656		TCtrl ctrl(pT->GetDlgItem(nID));
657
658		if(bSave)
659			nVal = _getSel(ctrl);
660		else
661			_setSel(ctrl, nVal);
662	}
663#endif // (_MSC_VER >= 1300)
664
665// Overrideables
666	void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)
667	{
668		// Override to display an error message
669		::MessageBeep((UINT)-1);
670		T* pT = static_cast<T*>(this);
671		::SetFocus(pT->GetDlgItem(nCtrlID));
672	}
673
674	void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)
675	{
676		// Override to display an error message
677		::MessageBeep((UINT)-1);
678		T* pT = static_cast<T*>(this);
679		::SetFocus(pT->GetDlgItem(nCtrlID));
680	}
681};
682
683}; // namespace WTL
684
685#endif // __ATLDDX_H__