atlddx.h 16 KB

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