/jEditLauncher/trunk/extern/wtl/atlddx.h

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