Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

779 lines
24 KiB

  1. /***************************************************************************\
  2. *
  3. * DLGMGR2.C
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Dialog Management Routines
  8. *
  9. * ??-???-???? mikeke Ported from Win 3.0 sources
  10. * 12-Feb-1991 mikeke Added Revalidation code
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /***************************************************************************\
  15. * xxxRemoveDefaultButton
  16. *
  17. * Scan through all the controls in the dialog box and remove the default
  18. * button style from any button that has it. This is done since at times we
  19. * do not know who has the default button.
  20. *
  21. * History:
  22. *
  23. * Bug 19449 - joejo
  24. *
  25. * Stop infinite loop when pwnd != pwndStart but pwnd == pwnd after calling
  26. * _NextControl!
  27. \***************************************************************************/
  28. void xxxRemoveDefaultButton(
  29. PWND pwndRoot,
  30. PWND pwndStart)
  31. {
  32. UINT code;
  33. PWND pwnd;
  34. PWND pwndDup;
  35. TL tlpwnd;
  36. CheckLock(pwndRoot);
  37. CheckLock(pwndStart);
  38. if (!pwndStart || TestWF(pwndStart, WEFCONTROLPARENT))
  39. pwndStart = _NextControl(pwndRoot, NULL, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
  40. else
  41. pwndStart = _GetChildControl(pwndRoot, pwndStart);
  42. if (!pwndStart)
  43. return;
  44. pwnd = pwndStart;
  45. do {
  46. pwndDup = pwnd;
  47. ThreadLock(pwnd, &tlpwnd);
  48. code = (UINT)SendMessage(HWq(pwnd), WM_GETDLGCODE, 0, 0L);
  49. if (code & DLGC_DEFPUSHBUTTON) {
  50. SendMessage(HWq(pwnd), BM_SETSTYLE, BS_PUSHBUTTON, (LONG)TRUE);
  51. }
  52. pwnd = _NextControl(pwndRoot, pwnd, 0);
  53. ThreadUnlock(&tlpwnd);
  54. } while (pwnd && (pwnd != pwndStart) && (pwnd != pwndDup));
  55. #if DBG
  56. if (pwnd && (pwnd != pwndStart) && (pwnd != pwndDup)) {
  57. RIPMSG0(RIP_WARNING, "xxxRemoveDefaultButton bailing potential infinite loop!");
  58. }
  59. #endif
  60. }
  61. /***************************************************************************\
  62. * xxxCheckDefPushButton
  63. *
  64. * History:
  65. \***************************************************************************/
  66. void xxxCheckDefPushButton(
  67. PWND pwndDlg,
  68. HWND hwndOldFocus,
  69. HWND hwndNewFocus)
  70. {
  71. PWND pwndNewFocus;
  72. PWND pwndOldFocus;
  73. TL tlpwndT;
  74. PWND pwndT;
  75. UINT codeNewFocus = 0;
  76. UINT styleT;
  77. LONG lT;
  78. int id;
  79. if (hwndNewFocus)
  80. pwndNewFocus = ValidateHwnd(hwndNewFocus);
  81. else
  82. pwndNewFocus = NULL;
  83. if (hwndOldFocus)
  84. pwndOldFocus = ValidateHwnd(hwndOldFocus);
  85. else
  86. pwndOldFocus = NULL;
  87. CheckLock(pwndDlg);
  88. CheckLock(pwndNewFocus);
  89. CheckLock(pwndOldFocus);
  90. if (pwndNewFocus)
  91. {
  92. // Do nothing if clicking on dialog background or recursive dialog
  93. // background.
  94. if (TestWF(pwndNewFocus, WEFCONTROLPARENT))
  95. return;
  96. codeNewFocus = (UINT)SendMessage(hwndNewFocus, WM_GETDLGCODE, 0, 0L);
  97. }
  98. if (SAMEWOWHANDLE(hwndOldFocus, hwndNewFocus)) {
  99. //
  100. // NEW FOR 4.0:
  101. //
  102. // There is a very common frustrating scenario for ISVs who try to
  103. // set the default ID. Our dialog manager assumes that if a push
  104. // button has the focus, it is the default button also. As such
  105. // it passes in the focus window to this routine. If someone tries
  106. // to change the focus or set the def ID such that they reside with
  107. // two different push buttons, the double-default-push button case
  108. // will result shortly.
  109. //
  110. // As such, for 4.0 dialogs, we will go check the def ID and see if
  111. // is the same as hwndOldFocus' ID. If not, then we will find IT
  112. // and use that dude as hwndOldFocus
  113. //
  114. if (codeNewFocus & DLGC_UNDEFPUSHBUTTON)
  115. {
  116. if (TestWF(pwndDlg, WFWIN40COMPAT) && hwndOldFocus)
  117. {
  118. lT = (LONG)SendMessage(HWq(pwndDlg), DM_GETDEFID, 0, 0L);
  119. id = (HIWORD(lT) == DC_HASDEFID ? LOWORD(lT) : IDOK);
  120. lT = MAKELONG(id, 0);
  121. if (lT != PtrToLong(pwndNewFocus->spmenu))
  122. {
  123. if (pwndOldFocus = _FindDlgItem(pwndDlg, lT))
  124. {
  125. hwndOldFocus = HW(pwndOldFocus);
  126. if (SendMessage(hwndOldFocus, WM_GETDLGCODE, 0, 0L) & DLGC_DEFPUSHBUTTON)
  127. {
  128. xxxRemoveDefaultButton(pwndDlg, pwndOldFocus);
  129. goto SetNewDefault;
  130. }
  131. }
  132. }
  133. }
  134. SendMessage(hwndNewFocus, BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
  135. }
  136. return;
  137. }
  138. /*
  139. * If the focus is changing to or from a pushbutton, then remove the
  140. * default style from the current default button
  141. */
  142. if ((hwndOldFocus != NULL && (SendMessage(hwndOldFocus, WM_GETDLGCODE,
  143. 0, 0) & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))) ||
  144. (hwndNewFocus != NULL &&
  145. (codeNewFocus & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)))) {
  146. xxxRemoveDefaultButton(pwndDlg, pwndNewFocus);
  147. }
  148. SetNewDefault:
  149. /*
  150. * If moving to a button, make that button the default.
  151. */
  152. if (codeNewFocus & DLGC_UNDEFPUSHBUTTON) {
  153. SendMessage(hwndNewFocus, BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
  154. } else {
  155. /*
  156. * Otherwise, make sure the original default button is default
  157. * and no others.
  158. */
  159. /*
  160. * Get the original default button handle
  161. */
  162. lT = (LONG)SendMessage(HWq(pwndDlg), DM_GETDEFID, 0, 0L);
  163. id = (HIWORD(lT) == DC_HASDEFID ? LOWORD(lT) : IDOK);
  164. pwndT = _FindDlgItem(pwndDlg, id);
  165. if (pwndT == NULL)
  166. return;
  167. ThreadLockAlways(pwndT, &tlpwndT);
  168. /*
  169. * If it already has the default button style, do nothing.
  170. */
  171. if ((styleT = (UINT)SendMessage(HWq(pwndT), WM_GETDLGCODE, 0, 0L)) & DLGC_DEFPUSHBUTTON) {
  172. ThreadUnlock(&tlpwndT);
  173. return;
  174. }
  175. /*
  176. * Also check to make sure it is really a button.
  177. */
  178. if (!(styleT & DLGC_UNDEFPUSHBUTTON)) {
  179. ThreadUnlock(&tlpwndT);
  180. return;
  181. }
  182. if (!TestWF(pwndT, WFDISABLED)) {
  183. SendMessage(HWq(pwndT), BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
  184. }
  185. ThreadUnlock(&tlpwndT);
  186. }
  187. }
  188. /***************************************************************************\
  189. * IsDialogMessage (API)
  190. *
  191. * History:
  192. \***************************************************************************/
  193. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsDialogMessageA, HWND, hwndDlg, LPMSG, lpmsg)
  194. BOOL IsDialogMessageA(
  195. HWND hwndDlg,
  196. LPMSG lpmsg)
  197. {
  198. WPARAM wParamSaved = lpmsg->wParam;
  199. BOOL bRet;
  200. switch (lpmsg->message) {
  201. #ifdef FE_SB // IsDialogMessageA()
  202. case WM_CHAR:
  203. case EM_SETPASSWORDCHAR:
  204. /*
  205. * BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA() macro will return TRUE
  206. * for DBCS leadbyte message everytime, then we check there is some
  207. * possibility the return value become FALSE, here.
  208. *
  209. * These code originally come from IsDialogMessageW().
  210. */
  211. if (IS_DBCS_ENABLED()) {
  212. PWND pwndDlg, pwnd;
  213. TL tlpwndDlg;
  214. BOOL fLockDlg = FALSE;
  215. if ((pwndDlg = ValidateHwndNoRip(hwndDlg)) == NULL) {
  216. return FALSE;
  217. }
  218. if (lpmsg->hwnd == NULL) {
  219. return FALSE;
  220. }
  221. pwnd = ValidateHwnd(lpmsg->hwnd);
  222. //
  223. // THIS IS FOR MFC.
  224. //
  225. // This solves many problems with apps that use MFC but want to take
  226. // advantage of DS_CONTROL. MFC blindly passes in child dialogs sometimes
  227. // to IsDialogMessage, which can mess up tabbing etc.
  228. //
  229. if (TestWF(pwndDlg, WEFCONTROLPARENT) && TestWF(pwndDlg, WFCHILD)) {
  230. pwndDlg = GetParentDialog(pwndDlg);
  231. ThreadLock(pwndDlg, &tlpwndDlg);
  232. fLockDlg = TRUE;
  233. hwndDlg = HWq(pwndDlg);
  234. }
  235. if (pwnd != pwndDlg && !_IsChild(pwndDlg, pwnd)) {
  236. if (fLockDlg)
  237. ThreadUnlock(&tlpwndDlg);
  238. return FALSE;
  239. }
  240. /*
  241. * Build DBCS-aware message.
  242. */
  243. BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA(lpmsg->message,lpmsg->wParam,TRUE);
  244. /*
  245. * Fall through.....
  246. */
  247. }
  248. #else
  249. case WM_CHAR:
  250. case EM_SETPASSWORDCHAR:
  251. #endif // FE_SB
  252. case WM_CHARTOITEM:
  253. case WM_DEADCHAR:
  254. case WM_SYSCHAR:
  255. case WM_SYSDEADCHAR:
  256. case WM_MENUCHAR:
  257. #ifdef FE_IME // IsDialogMessageA()
  258. case WM_IME_CHAR:
  259. case WM_IME_COMPOSITION:
  260. #endif // FE_IME
  261. RtlMBMessageWParamCharToWCS(lpmsg->message, &lpmsg->wParam);
  262. }
  263. bRet = IsDialogMessageW(hwndDlg, lpmsg);
  264. /*
  265. * Restore the original ANSI char.
  266. */
  267. lpmsg->wParam = wParamSaved;
  268. return bRet;
  269. }
  270. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsDialogMessageW, HWND, hwndDlg, LPMSG, lpMsg)
  271. BOOL IsDialogMessageW(
  272. HWND hwndDlg,
  273. LPMSG lpMsg)
  274. {
  275. PWND pwndDlg;
  276. PWND pwnd;
  277. PWND pwnd2;
  278. HWND hwnd2;
  279. HWND hwndFocus;
  280. int iOK;
  281. BOOL fBack;
  282. UINT code;
  283. LONG lT;
  284. TL tlpwnd;
  285. TL tlpwndDlg;
  286. BOOL fLockDlg = FALSE;
  287. TL tlpwnd2;
  288. WORD langID;
  289. langID = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID()));
  290. if ((pwndDlg = ValidateHwndNoRip(hwndDlg)) == NULL) {
  291. return FALSE;
  292. }
  293. CheckLock(pwndDlg);
  294. /*
  295. * If this is a synchronous-only message (takes a pointer in wParam or
  296. * lParam), then don't allow this message to go through since those
  297. * parameters have not been thunked, and are pointing into outer-space
  298. * (which would case exceptions to occur).
  299. *
  300. * (This api is only called in the context of a message loop, and you
  301. * don't get synchronous-only messages in a message loop).
  302. */
  303. if (TESTSYNCONLYMESSAGE(lpMsg->message, lpMsg->wParam)) {
  304. /*
  305. * Fail if 32 bit app is calling.
  306. */
  307. if (!(GetClientInfo()->dwTIFlags & TIF_16BIT)) {
  308. RIPERR0(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, "IsDialogMessage: must be sync only");
  309. return FALSE;
  310. }
  311. /*
  312. * For wow apps, allow it to go through (for compatibility). Change
  313. * the message id so our code doesn't understand the message - wow
  314. * will get the message and strip out this bit before dispatching
  315. * the message to the application.
  316. */
  317. lpMsg->message |= MSGFLAG_WOW_RESERVED;
  318. }
  319. if (CallMsgFilter(lpMsg, MSGF_DIALOGBOX))
  320. return TRUE;
  321. if (lpMsg->hwnd == NULL) {
  322. return FALSE;
  323. }
  324. pwnd = ValidateHwnd(lpMsg->hwnd);
  325. //
  326. // THIS IS FOR MFC.
  327. //
  328. // This solves many problems with apps that use MFC but want to take
  329. // advantage of DS_CONTROL. MFC blindly passes in child dialogs sometimes
  330. // to IsDialogMessage, which can mess up tabbing etc.
  331. //
  332. if (TestWF(pwndDlg, WEFCONTROLPARENT) && TestWF(pwndDlg, WFCHILD)) {
  333. pwndDlg = GetParentDialog(pwndDlg);
  334. ThreadLock(pwndDlg, &tlpwndDlg);
  335. fLockDlg = TRUE;
  336. hwndDlg = HWq(pwndDlg);
  337. }
  338. if (pwnd != pwndDlg && !_IsChild(pwndDlg, pwnd)) {
  339. if (fLockDlg)
  340. ThreadUnlock(&tlpwndDlg);
  341. return FALSE;
  342. }
  343. ThreadLock(pwnd, &tlpwnd);
  344. fBack = FALSE;
  345. iOK = IDCANCEL;
  346. switch (lpMsg->message) {
  347. case WM_LBUTTONDOWN:
  348. /*
  349. * Move the default button styles around on button clicks in the
  350. * same way as TABs.
  351. */
  352. if ((pwnd != pwndDlg) && ((hwndFocus = GetFocus()) != NULL)) {
  353. xxxCheckDefPushButton(pwndDlg, hwndFocus, lpMsg->hwnd);
  354. }
  355. break;
  356. case WM_SYSCHAR:
  357. /*
  358. * If no control has focus, and Alt not down, then ignore.
  359. */
  360. if ((GetFocus() == NULL) && (GetKeyState(VK_MENU) >= 0)) {
  361. if (lpMsg->wParam == VK_RETURN && TestWF(pwnd, WFMINIMIZED)) {
  362. /*
  363. * If this is an iconic dialog box window and the user hits
  364. * return, send the message off to DefWindowProc so that it
  365. * can be restored. Especially useful for apps whose top
  366. * level window is a dialog box.
  367. */
  368. goto CallDefWindowProcAndReturnTrue;
  369. } else {
  370. NtUserMessageBeep(0);
  371. }
  372. ThreadUnlock(&tlpwnd);
  373. if (fLockDlg)
  374. ThreadUnlock(&tlpwndDlg);
  375. return TRUE;
  376. }
  377. /*
  378. * If alt+menuchar, process as menu.
  379. */
  380. if (lpMsg->wParam == MENUSYSMENU) {
  381. DefWindowProcWorker(pwndDlg, lpMsg->message, lpMsg->wParam,
  382. lpMsg->lParam, FALSE);
  383. ThreadUnlock(&tlpwnd);
  384. if (fLockDlg)
  385. ThreadUnlock(&tlpwndDlg);
  386. return TRUE;
  387. }
  388. /*
  389. *** FALL THRU **
  390. */
  391. case WM_CHAR:
  392. /*
  393. * Ignore chars sent to the dialog box (rather than the control).
  394. */
  395. if (pwnd == pwndDlg) {
  396. ThreadUnlock(&tlpwnd);
  397. if (fLockDlg)
  398. ThreadUnlock(&tlpwndDlg);
  399. return TRUE;
  400. }
  401. code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
  402. (LPARAM)lpMsg);
  403. /*
  404. * If the control wants to process the message, then don't check for
  405. * possible mnemonic key.
  406. */
  407. if ((lpMsg->message == WM_CHAR) && (code & (DLGC_WANTCHARS | DLGC_WANTMESSAGE)))
  408. break;
  409. /* If the control wants tabs, then don't let tab fall thru here
  410. */
  411. if ((lpMsg->wParam == VK_TAB) && (code & DLGC_WANTTAB))
  412. break;
  413. /*
  414. * HACK ALERT
  415. *
  416. * If ALT is held down (i.e., SYSCHARs), then ALWAYS do mnemonic
  417. * processing. If we do away with SYSCHARS, then we should
  418. * check key state of ALT instead.
  419. */
  420. /*
  421. * Space is not a valid mnemonic, but it IS the char that toggles
  422. * button states. Don't look for it as a mnemonic or we will
  423. * beep when it is typed....
  424. */
  425. if (lpMsg->wParam == VK_SPACE) {
  426. ThreadUnlock(&tlpwnd);
  427. if (fLockDlg)
  428. ThreadUnlock(&tlpwndDlg);
  429. return TRUE;
  430. }
  431. if (!(pwnd2 = xxxGotoNextMnem(pwndDlg, pwnd, (WCHAR)lpMsg->wParam))) {
  432. if (code & DLGC_WANTMESSAGE)
  433. break;
  434. /*
  435. * No mnemonic could be found so we will send the sys char over
  436. * to xxxDefWindowProc so that any menu bar on the dialog box is
  437. * handled properly.
  438. */
  439. if (lpMsg->message == WM_SYSCHAR) {
  440. CallDefWindowProcAndReturnTrue:
  441. DefWindowProcWorker(pwndDlg, lpMsg->message, lpMsg->wParam,
  442. lpMsg->lParam, FALSE);
  443. ThreadUnlock(&tlpwnd);
  444. if (fLockDlg)
  445. ThreadUnlock(&tlpwndDlg);
  446. return TRUE;
  447. }
  448. NtUserMessageBeep(0);
  449. } else {
  450. /*
  451. * pwnd2 is 1 if the mnemonic took us to a pushbutton. We
  452. * don't change the default button status here since doing this
  453. * doesn't change the focus.
  454. */
  455. if (pwnd2 != (PWND)1) {
  456. ThreadLockAlways(pwnd2, &tlpwnd2);
  457. xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, HWq(pwnd2));
  458. ThreadUnlock(&tlpwnd2);
  459. }
  460. }
  461. ThreadUnlock(&tlpwnd);
  462. if (fLockDlg)
  463. ThreadUnlock(&tlpwndDlg);
  464. return TRUE;
  465. case WM_SYSKEYDOWN:
  466. /*
  467. * If Alt is down, deal with keyboard cues
  468. */
  469. if ((HIWORD(lpMsg->lParam) & SYS_ALTERNATE) && TEST_KbdCuesPUSIF) {
  470. if (TestWF(pwnd, WEFPUIFOCUSHIDDEN) || (TestWF(pwnd, WEFPUIACCELHIDDEN))) {
  471. SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
  472. MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0, FALSE);
  473. }
  474. }
  475. break;
  476. case WM_KEYDOWN:
  477. code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
  478. (LPARAM)lpMsg);
  479. if (code & (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE))
  480. break;
  481. switch (lpMsg->wParam) {
  482. case VK_TAB:
  483. if (code & DLGC_WANTTAB)
  484. break;
  485. pwnd2 = _GetNextDlgTabItem(pwndDlg, pwnd,
  486. (GetKeyState(VK_SHIFT) & 0x8000));
  487. if (TEST_KbdCuesPUSIF) {
  488. if (TestWF(pwnd, WEFPUIFOCUSHIDDEN)) {
  489. SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
  490. MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0, FALSE);
  491. }
  492. }
  493. if (pwnd2 != NULL) {
  494. hwnd2 = HWq(pwnd2);
  495. ThreadLockAlways(pwnd2, &tlpwnd2);
  496. DlgSetFocus(hwnd2);
  497. xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
  498. ThreadUnlock(&tlpwnd2);
  499. }
  500. ThreadUnlock(&tlpwnd);
  501. if (fLockDlg)
  502. ThreadUnlock(&tlpwndDlg);
  503. return TRUE;
  504. /*
  505. * For Arabic and Hebrew locales the arrow keys are reversed. Also reverse them if
  506. * the dialog is RTL mirrored.
  507. */
  508. case VK_LEFT:
  509. if ((((langID == LANG_ARABIC) || (langID == LANG_HEBREW)) && TestWF(pwndDlg,WEFRTLREADING))
  510. ^ (!!TestWF(pwndDlg, WEFLAYOUTRTL))) {
  511. goto DoKeyStuff;
  512. }
  513. case VK_UP:
  514. fBack = TRUE;
  515. goto DoKeyStuff;
  516. /*
  517. *** FALL THRU **
  518. */
  519. case VK_RIGHT:
  520. if ((((langID == LANG_ARABIC) || (langID == LANG_HEBREW)) && TestWF(pwndDlg,WEFRTLREADING))
  521. ^ (!!TestWF(pwndDlg, WEFLAYOUTRTL))) {
  522. fBack = TRUE;
  523. }
  524. case VK_DOWN:
  525. DoKeyStuff:
  526. if (code & DLGC_WANTARROWS)
  527. break;
  528. if (TEST_KbdCuesPUSIF) {
  529. if (TestWF(pwnd, WEFPUIFOCUSHIDDEN)) {
  530. SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
  531. MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0, FALSE);
  532. }
  533. }
  534. pwnd2 = _GetNextDlgGroupItem(pwndDlg, pwnd, fBack);
  535. if (pwnd2 == NULL) {
  536. ThreadUnlock(&tlpwnd);
  537. if (fLockDlg)
  538. ThreadUnlock(&tlpwndDlg);
  539. return TRUE;
  540. }
  541. hwnd2 = HWq(pwnd2);
  542. ThreadLockAlways(pwnd2, &tlpwnd2);
  543. code = (UINT)SendMessage(hwnd2, WM_GETDLGCODE, lpMsg->wParam,
  544. (LPARAM)lpMsg);
  545. /*
  546. * We are just moving the focus rect around! So, do not send
  547. * BN_CLICK messages, when WM_SETFOCUSing. Fix for Bug
  548. * #4358.
  549. */
  550. if (code & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)) {
  551. PBUTN pbutn;
  552. BOOL fIsNTButton = IS_BUTTON(pwnd2);
  553. if (fIsNTButton) {
  554. pbutn = ((PBUTNWND)pwnd2)->pbutn;
  555. BUTTONSTATE(pbutn) |= BST_DONTCLICK;
  556. }
  557. DlgSetFocus(hwnd2);
  558. if (fIsNTButton) {
  559. BUTTONSTATE(pbutn) &= ~BST_DONTCLICK;
  560. }
  561. xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
  562. } else if (code & DLGC_RADIOBUTTON) {
  563. DlgSetFocus(hwnd2);
  564. xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
  565. if (TestWF(pwnd2, BFTYPEMASK) == LOBYTE(BS_AUTORADIOBUTTON)) {
  566. /*
  567. * So that auto radio buttons get clicked on
  568. */
  569. if (!SendMessage(hwnd2, BM_GETCHECK, 0, 0L)) {
  570. SendMessage(hwnd2, BM_CLICK, TRUE, 0L);
  571. }
  572. }
  573. } else if (!(code & DLGC_STATIC)) {
  574. DlgSetFocus(hwnd2);
  575. xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
  576. }
  577. ThreadUnlock(&tlpwnd2);
  578. ThreadUnlock(&tlpwnd);
  579. if (fLockDlg)
  580. ThreadUnlock(&tlpwndDlg);
  581. return TRUE;
  582. case VK_EXECUTE:
  583. case VK_RETURN:
  584. /*
  585. * Guy pressed return - if button with focus is
  586. * defpushbutton, return its ID. Otherwise, return id
  587. * of original defpushbutton.
  588. */
  589. if (!(hwndFocus = GetFocus()))
  590. code = 0;
  591. else
  592. {
  593. code = (WORD)(DWORD)SendMessage(hwndFocus, WM_GETDLGCODE,
  594. 0, 0L);
  595. }
  596. if (code & DLGC_DEFPUSHBUTTON)
  597. {
  598. iOK = GetDlgCtrlID(hwndFocus);
  599. pwnd2 = ValidateHwnd(hwndFocus);
  600. goto HaveWindow;
  601. }
  602. else
  603. {
  604. lT = (LONG)SendMessage(hwndDlg, DM_GETDEFID, 0, 0L);
  605. iOK = MAKELONG(
  606. (HIWORD(lT)==DC_HASDEFID ? LOWORD(lT) : IDOK),
  607. 0);
  608. }
  609. // FALL THRU
  610. case VK_ESCAPE:
  611. case VK_CANCEL:
  612. /*
  613. * Make sure button is not disabled.
  614. */
  615. pwnd2 = _FindDlgItem(pwndDlg, iOK);
  616. HaveWindow:
  617. if (pwnd2 != NULL && TestWF(pwnd2, WFDISABLED)) {
  618. NtUserMessageBeep(0);
  619. } else {
  620. SendMessage(hwndDlg, WM_COMMAND,
  621. MAKELONG(iOK, BN_CLICKED), (LPARAM)HW(pwnd2));
  622. }
  623. ThreadUnlock(&tlpwnd);
  624. if (fLockDlg)
  625. ThreadUnlock(&tlpwndDlg);
  626. return TRUE;
  627. }
  628. break;
  629. }
  630. ThreadUnlock(&tlpwnd);
  631. if (fLockDlg)
  632. ThreadUnlock(&tlpwndDlg);
  633. TranslateMessage(lpMsg);
  634. DispatchMessage(lpMsg);
  635. return TRUE;
  636. }
  637. /***************************************************************************\
  638. *
  639. * FindDlgItem32()
  640. *
  641. * Given a dialog, finds the window with the given ID anywhere w/in the
  642. * descendant chain.
  643. *
  644. \***************************************************************************/
  645. PWND _FindDlgItem(PWND pwndParent, DWORD id)
  646. {
  647. PWND pwndChild;
  648. PWND pwndOrig;
  649. // QUICK TRY:
  650. pwndChild = _GetDlgItem(pwndParent, id);
  651. if (pwndChild || !TestWF(pwndParent, WFWIN40COMPAT))
  652. return(pwndChild);
  653. pwndOrig = _NextControl(pwndParent, NULL, CWP_SKIPINVISIBLE);
  654. if (pwndOrig == pwndParent)
  655. return(NULL);
  656. pwndChild = pwndOrig;
  657. // VerifyWindow(pwndChild);
  658. do
  659. {
  660. if (PtrToUlong(pwndChild->spmenu) == id)
  661. return(pwndChild);
  662. pwndChild = _NextControl(pwndParent, pwndChild, CWP_SKIPINVISIBLE);
  663. }
  664. while (pwndChild && (pwndChild != pwndOrig));
  665. return(NULL);
  666. }