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.

1450 lines
43 KiB

  1. /***************************************************************************\
  2. *
  3. * DLGMGR.C -
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Dialog Box Manager Routines
  8. *
  9. * ??-???-???? mikeke Ported from Win 3.0 sources
  10. * 12-Feb-1991 mikeke Added Revalidation code
  11. * 19-Feb-1991 JimA Added access checks
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define UNICODE_MINUS_SIGN 0x2212
  16. LOOKASIDE DialogLookaside;
  17. BOOL ValidateCallback(HANDLE h);
  18. #define IsInForegroundQueue(hwnd) \
  19. (NtUserQueryWindow(hwnd, WindowIsForegroundThread) != NULL)
  20. #define IsCurrentThreadForeground() \
  21. ((BOOL)NtUserGetThreadState(UserThreadStateIsForeground))
  22. /***************************************************************************\
  23. *
  24. * GetParentDialog()
  25. *
  26. * Gets top level window, not a control parent. If not a dialog, then use
  27. * "highest" control parent guy.
  28. *
  29. * BOGUS
  30. * Need a way to mark a window as a dialog. If it ever comes into
  31. * DefDlgProc(), set an internal flag. Will be used by thunking and
  32. * CallDlgProc() optimizations also!
  33. *
  34. \***************************************************************************/
  35. PWND GetParentDialog(PWND pwndDialog)
  36. {
  37. PWND pwndParent;
  38. pwndParent = pwndDialog;
  39. //
  40. // Walk up the parent chain. We're looking for the top-most dialog
  41. // window. Most cases, the window is a top level one. But in case of
  42. // backup app, the window will be a child of some other window.
  43. //
  44. for (; pwndDialog; pwndDialog = REBASEPWND(pwndDialog, spwndParent))
  45. {
  46. if (TestWF(pwndDialog, WFDIALOGWINDOW))
  47. {
  48. //
  49. // For old guys: If not DS_RECURSE, then stop here.
  50. // that way old apps which try to do the nested dialog
  51. // stuff in their old limited way don't die.
  52. //
  53. if (TestWF(pwndDialog, WEFCONTROLPARENT))
  54. pwndParent = pwndDialog;
  55. else if (!TestWF(pwndDialog, DFCONTROL))
  56. break;
  57. }
  58. if (!TestWF(pwndDialog, WFCHILD))
  59. break;
  60. }
  61. return(pwndParent);
  62. }
  63. /***************************************************************************\
  64. * xxxSaveDlgFocus
  65. *
  66. * History:
  67. * 02-18-92 JimA Ported from Win31 sources
  68. \***************************************************************************/
  69. BOOL xxxSaveDlgFocus(
  70. PWND pwnd)
  71. {
  72. HWND hwndFocus = GetFocus();
  73. CheckLock(pwnd);
  74. if (hwndFocus != NULL && IsChild(HWq(pwnd), hwndFocus) &&
  75. PDLG(pwnd)->hwndFocusSave == NULL) {
  76. PDLG(pwnd)->hwndFocusSave = hwndFocus;
  77. xxxRemoveDefaultButton(pwnd, ValidateHwnd(hwndFocus));
  78. return TRUE;
  79. }
  80. return FALSE;
  81. }
  82. /***************************************************************************\
  83. * xxxRestoreDlgFocus
  84. *
  85. * History:
  86. * 02-18-92 JimA Ported from Win31 sources
  87. * 01-01-2001 Mohamed Need to re-validate the window before cleanup.
  88. \***************************************************************************/
  89. // LATER
  90. // 21-Mar-1992 mikeke
  91. // does pwndFocusSave need to be unlocked when the dialog is destroyed?
  92. BOOL xxxRestoreDlgFocus(
  93. PWND pwnd)
  94. {
  95. HWND hwndFocus;
  96. HWND hwndFocusSave;
  97. BOOL fRestored = FALSE;
  98. CheckLock(pwnd);
  99. if (PDLG(pwnd)->hwndFocusSave && !TestWF(pwnd, WFMINIMIZED)) {
  100. hwndFocus = GetFocus();
  101. hwndFocusSave = KHWND_TO_HWND(PDLG(pwnd)->hwndFocusSave);
  102. if (IsWindow(hwndFocusSave)) {
  103. xxxCheckDefPushButton(pwnd, hwndFocus, hwndFocusSave);
  104. fRestored = (NtUserSetFocus(hwndFocusSave) != NULL);
  105. }
  106. //
  107. // After calling SetFocus(), we need to re-validate
  108. // the window. PDLG(pwnd) might be NULL.
  109. //
  110. if (ValidateDialogPwnd(pwnd)) {
  111. PDLG(pwnd)->hwndFocusSave = NULL;
  112. }
  113. }
  114. return fRestored;
  115. }
  116. /***************************************************************************\
  117. * DlgSetFocus
  118. *
  119. * History:
  120. \***************************************************************************/
  121. void DlgSetFocus(
  122. HWND hwnd)
  123. {
  124. if (((UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0)) & DLGC_HASSETSEL) {
  125. SendMessage(hwnd, EM_SETSEL, 0, MAXLONG);
  126. }
  127. NtUserSetFocus(hwnd);
  128. }
  129. FUNCLOG1(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetDlgCtrlID, HWND, hwnd)
  130. int GetDlgCtrlID(
  131. HWND hwnd)
  132. {
  133. PWND pwnd;
  134. pwnd = ValidateHwnd(hwnd);
  135. if (pwnd == NULL)
  136. return 0;
  137. return PtrToLong(pwnd->spmenu);
  138. }
  139. /***************************************************************************\
  140. * ValidateDialogPwnd
  141. *
  142. * Under Win3, DLGWINDOWEXTRA is 30 bytes. We cannot change that for 16 bit
  143. * compatibility reasons. Problem is there is no way to tell if a given
  144. * 16 bit window depends on byte count. If there was, this would be easy.
  145. * The only way to tell is when a window is about to be used as a dialog
  146. * window. This window may be of the class DIALOGCLASS, but again it may
  147. * not!! So we keep dialog window words at 30 bytes, and allocate another
  148. * structure for the real dialog structure fields. Problem is that this
  149. * structure has to be created lazily! And that's what we're doing here.
  150. *
  151. * 05-21-91 ScottLu Created.
  152. \***************************************************************************/
  153. BOOL ValidateDialogPwnd(
  154. PWND pwnd)
  155. {
  156. static BOOL sfInit = TRUE;
  157. PDLG pdlg;
  158. /*
  159. * This bit is set if we've already run through this initialization and
  160. * have identified this window as a dialog window (able to withstand
  161. * peeks into window words at random moments in time).
  162. */
  163. if (TestWF(pwnd, WFDIALOGWINDOW))
  164. return TRUE;
  165. if (pwnd->cbwndExtra < DLGWINDOWEXTRA) {
  166. RIPERR0(ERROR_WINDOW_NOT_DIALOG, RIP_VERBOSE, "");
  167. return FALSE;
  168. }
  169. /*
  170. * See if the pdlg was destroyed and this is a rogue message to be ignored
  171. */
  172. if (pwnd->fnid & FNID_STATUS_BITS) {
  173. return FALSE;
  174. }
  175. /*
  176. * If the lookaside buffer has not been initialized, do it now.
  177. */
  178. if (sfInit) {
  179. if (!NT_SUCCESS(InitLookaside(&DialogLookaside, sizeof(DLG), 2))) {
  180. return FALSE;
  181. }
  182. sfInit = FALSE;
  183. }
  184. if ((pdlg = (PDLG)AllocLookasideEntry(&DialogLookaside)) == NULL) {
  185. return FALSE;
  186. }
  187. NtUserCallHwndParam(HWq(pwnd), (ULONG_PTR)pdlg, SFI_SETDIALOGPOINTER);
  188. return TRUE;
  189. }
  190. /***************************************************************************\
  191. * CvtDec
  192. *
  193. * LATER!!! convert to itoa?
  194. *
  195. * History:
  196. \***************************************************************************/
  197. void CvtDec(
  198. int u,
  199. LPWSTR *lplpch)
  200. {
  201. if (u >= 10) {
  202. CvtDec(u / 10, lplpch);
  203. u %= 10;
  204. }
  205. *(*lplpch)++ = (WCHAR)(u + '0');
  206. }
  207. /***************************************************************************\
  208. * SetDlgItemInt
  209. *
  210. * History:
  211. \***************************************************************************/
  212. FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetDlgItemInt, HWND, hwnd, int, item, UINT, u, BOOL, fSigned)
  213. BOOL SetDlgItemInt(
  214. HWND hwnd,
  215. int item,
  216. UINT u,
  217. BOOL fSigned)
  218. {
  219. LPWSTR lpch;
  220. WCHAR rgch[16];
  221. lpch = rgch;
  222. if (fSigned) {
  223. if ((int)u < 0) {
  224. *lpch++ = TEXT('-');
  225. u = (UINT)(-(int)u);
  226. }
  227. } else {
  228. if (u & 0x80000000) {
  229. CvtDec(u / 10, (LPWSTR FAR *)&lpch);
  230. u = u % 10;
  231. }
  232. }
  233. CvtDec(u, (LPWSTR FAR *)&lpch);
  234. *lpch = 0;
  235. return SetDlgItemTextW(hwnd, item, rgch);
  236. }
  237. /***************************************************************************\
  238. * CheckDlgButton
  239. *
  240. * History:
  241. \***************************************************************************/
  242. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CheckDlgButton, HWND, hwnd, int, id, UINT, cmdCheck)
  243. BOOL CheckDlgButton(
  244. HWND hwnd,
  245. int id,
  246. UINT cmdCheck)
  247. {
  248. if ((hwnd = GetDlgItem(hwnd, id)) == NULL) {
  249. return FALSE;
  250. }
  251. SendMessage(hwnd, BM_SETCHECK, cmdCheck, 0);
  252. return TRUE;
  253. }
  254. /***************************************************************************\
  255. * GetDlgItemInt
  256. *
  257. * History:
  258. \***************************************************************************/
  259. UINT GetDlgItemInt(
  260. HWND hwnd,
  261. int item,
  262. BOOL FAR *lpfValOK,
  263. BOOL fSigned)
  264. {
  265. int i, digit, ch;
  266. int maxTens, maxUnits;
  267. BOOL fOk, fNeg;
  268. LPWSTR lpch;
  269. WCHAR rgch[48];
  270. WCHAR rgchDigits[48];
  271. fOk = FALSE;
  272. if (lpfValOK != NULL)
  273. *lpfValOK = FALSE;
  274. if (!GetDlgItemTextW(hwnd, item, rgch, sizeof(rgch)/sizeof(WCHAR) - 1))
  275. return 0;
  276. lpch = rgch;
  277. /*
  278. * Skip leading white space.
  279. */
  280. while (*lpch == TEXT(' '))
  281. lpch++;
  282. fNeg = FALSE;
  283. while (fSigned && ((*lpch == L'-') || (*lpch == UNICODE_MINUS_SIGN))) {
  284. lpch++;
  285. fNeg ^= TRUE;
  286. }
  287. if (fSigned) {
  288. maxTens = INT_MAX/10;
  289. maxUnits = INT_MAX%10;
  290. } else {
  291. maxTens = UINT_MAX/10;
  292. maxUnits = UINT_MAX%10;
  293. }
  294. /*
  295. * Convert all decimal digits to ASCII Unicode digits 0x0030 - 0x0039
  296. */
  297. FoldStringW(MAP_FOLDDIGITS, lpch, -1, rgchDigits,
  298. sizeof(rgchDigits)/sizeof(rgchDigits[0]));
  299. lpch = rgchDigits;
  300. i = 0;
  301. while (ch = *lpch++) {
  302. digit = ch - TEXT('0');
  303. if (digit < 0 || digit > 9) {
  304. break;
  305. }
  306. if ((UINT)i >= (UINT)maxTens) {
  307. /*
  308. * We need to special case INT_MIN as the i = -i
  309. * would damage it
  310. */
  311. if (i == maxTens) {
  312. if (digit == maxUnits+1 && fNeg && (*lpch) == 0) {
  313. i = INT_MIN;
  314. goto HaveResult;
  315. } else if (digit > maxUnits) {
  316. return 0;
  317. }
  318. } else {
  319. return 0;
  320. }
  321. }
  322. fOk = TRUE;
  323. i = ((UINT)i * 10) + digit;
  324. }
  325. if (fNeg)
  326. i = -i;
  327. HaveResult:
  328. if (lpfValOK != NULL)
  329. *lpfValOK = ((ch == 0) && fOk);
  330. return (UINT)i;
  331. }
  332. /***************************************************************************\
  333. * CheckRadioButton
  334. *
  335. * History:
  336. \***************************************************************************/
  337. FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CheckRadioButton, HWND, hwnd, int, idFirst, int, idLast, int, id)
  338. BOOL CheckRadioButton(
  339. HWND hwnd,
  340. int idFirst,
  341. int idLast,
  342. int id)
  343. {
  344. PWND pwnd, pwndDialog;
  345. BOOL fCheckOn;
  346. pwndDialog = ValidateHwnd(hwnd);
  347. if (pwndDialog == NULL)
  348. return 0;
  349. for (pwnd = REBASE(pwndDialog, spwndChild); pwnd; pwnd = REBASE(pwnd, spwndNext)) {
  350. if ((PtrToLong(pwnd->spmenu) >= idFirst) &&
  351. (PtrToLong(pwnd->spmenu) <= idLast)) {
  352. fCheckOn = (PtrToLong(pwnd->spmenu) == id);
  353. SendMessage(PtoHq(pwnd), BM_SETCHECK, fCheckOn, 0L);
  354. }
  355. }
  356. return TRUE;
  357. }
  358. /***************************************************************************\
  359. * IsDlgButtonChecked
  360. *
  361. * History:
  362. \***************************************************************************/
  363. FUNCLOG2(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, IsDlgButtonChecked, HWND, hwnd, int, id)
  364. UINT IsDlgButtonChecked(
  365. HWND hwnd,
  366. int id)
  367. {
  368. if ((hwnd = GetDlgItem(hwnd, id)) != NULL) {
  369. return (UINT)SendMessage(hwnd, BM_GETCHECK, 0, 0);
  370. }
  371. return FALSE;
  372. }
  373. /***************************************************************************\
  374. * DefDlgProc
  375. *
  376. * History:
  377. \***************************************************************************/
  378. LRESULT DefDlgProcWorker(
  379. PWND pwnd,
  380. UINT message,
  381. WPARAM wParam,
  382. LPARAM lParam,
  383. DWORD fAnsi)
  384. {
  385. HWND hwnd = HWq(pwnd);
  386. TL tlpwndT1, tlpwndT2, tlpwndT3, tlpwndTop;
  387. PWND pwndT;
  388. PWND pwndT1, pwndT2, pwndT3, pwndTop;
  389. HWND hwndT1;
  390. LRESULT result;
  391. BOOL fSetBit;
  392. DLGPROC pfn;
  393. CheckLock(pwnd);
  394. /*
  395. * use the Win 3.1 documented size
  396. */
  397. VALIDATECLASSANDSIZE(pwnd, FNID_DIALOG);
  398. /*
  399. * Must do special validation here to make sure pwnd is a dialog window.
  400. */
  401. if (!ValidateDialogPwnd(pwnd))
  402. return 0;
  403. if (((PDIALOG)pwnd)->resultWP != 0)
  404. NtUserSetWindowLongPtr(hwnd, DWLP_MSGRESULT, 0, FALSE);
  405. result = 0; // no dialog proc
  406. if (message == WM_FINALDESTROY) {
  407. goto DoCleanup;
  408. }
  409. if ((pfn = PDLG(pwnd)->lpfnDlg) != NULL) {
  410. /* Bug 234292 - joejo
  411. * Since the called window/dialog proc may have a different calling
  412. * convention, we must wrap the call and, check esp and replace with
  413. * a good esp when the call returns. This is what UserCallWinProc* does.
  414. */
  415. if (UserCallDlgProcCheckWow(pwnd->pActCtx, pfn, hwnd, message, wParam, lParam, &(pwnd->state), &result)) {
  416. return result;
  417. }
  418. /*
  419. * Get out if the window was destroyed in the dialog proc.
  420. */
  421. if ((RevalidateHwnd(hwnd)==NULL) || (pwnd->fnid & FNID_STATUS_BITS))
  422. return result;
  423. }
  424. /*
  425. * SPECIAL CASED ... and DOCUMENTED that way !!!
  426. * These 6, and ONLY these 6, should be hacked in this fashion.
  427. * Anybody who needs the REAL return value to a message should
  428. * use SetDlgMsgResult in WINDOWSX.H
  429. */
  430. switch (message)
  431. {
  432. case WM_COMPAREITEM:
  433. case WM_VKEYTOITEM:
  434. case WM_CHARTOITEM:
  435. case WM_INITDIALOG:
  436. case WM_QUERYDRAGICON:
  437. return ((LRESULT)(DWORD)result);
  438. case WM_CTLCOLOR:
  439. case WM_CTLCOLORMSGBOX:
  440. case WM_CTLCOLOREDIT:
  441. case WM_CTLCOLORLISTBOX:
  442. case WM_CTLCOLORBTN:
  443. case WM_CTLCOLORDLG:
  444. case WM_CTLCOLORSCROLLBAR:
  445. case WM_CTLCOLORSTATIC:
  446. // QuarkXPress doesn't like finding the WM_CTLCOLOR result in
  447. // resultWP -- we should never be setting resultWP -- that's meant
  448. // as a pass-thru return value -- so let's go back to doing it the
  449. // old way -- Win95B B#21269 -- 03/13/95 -- tracysh (cr: jeffbog)
  450. if (result)
  451. return result;
  452. break;
  453. }
  454. if (!result) {
  455. /*
  456. * Save the result value in case our private memory is freed
  457. * before we return
  458. */
  459. // result = PDLG(pwnd)->resultWP;
  460. switch (message) {
  461. case WM_CTLCOLOR:
  462. case WM_CTLCOLORMSGBOX:
  463. case WM_CTLCOLOREDIT:
  464. case WM_CTLCOLORLISTBOX:
  465. case WM_CTLCOLORBTN:
  466. case WM_CTLCOLORDLG:
  467. case WM_CTLCOLORSCROLLBAR:
  468. case WM_CTLCOLORSTATIC:
  469. {
  470. //
  471. // HACK OF DEATH:
  472. // To get 3D colors for non 4.0 apps who use 3DLOOK,
  473. // we temporarily add on the 4.0 compat bit, pass this
  474. // down to DWP, and clear it.
  475. //
  476. // Use "result" var for bool saying we have to add/clear 4.0
  477. // compat bit.
  478. fSetBit = (TestWF(pwnd, DF3DLOOK)!= 0) &&
  479. (TestWF(pwnd, WFWIN40COMPAT) == 0);
  480. if (fSetBit)
  481. SetWindowState(pwnd, WFWIN40COMPAT);
  482. result = DefWindowProcWorker(pwnd, message,
  483. wParam, lParam, fAnsi);
  484. if (fSetBit)
  485. ClearWindowState(pwnd, WFWIN40COMPAT);
  486. return result;
  487. }
  488. case WM_ERASEBKGND:
  489. FillWindow(hwnd, hwnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG);
  490. return TRUE;
  491. case WM_SHOWWINDOW:
  492. /*
  493. * If hiding the window, save the focus. If showing the window
  494. * by means of a SW_* command and the fEnd bit is set, do not
  495. * pass to DWP so it won't get shown.
  496. */
  497. if (GetParentDialog(pwnd) == pwnd) {
  498. if (!wParam) {
  499. xxxSaveDlgFocus(pwnd);
  500. } else {
  501. if (LOWORD(lParam) != 0 && PDLG(pwnd)->fEnd)
  502. break;
  503. /*
  504. * Snap the cursor to the center of the default button.
  505. * Only do this if the current thread is in the foreground.
  506. * The _ShowCursor() code is added to work around a
  507. * problem with hardware cursors. If change is done
  508. * in the same refresh cycle, the display of the cursor
  509. * would not reflect the new position.
  510. */
  511. if (TEST_PUSIF(PUSIF_SNAPTO) &&
  512. IsInForegroundQueue(hwnd)) {
  513. hwndT1 = GetDlgItem(hwnd, (int)PDLG(pwnd)->result);
  514. if (hwndT1) {
  515. RECT rc;
  516. NtUserShowCursor(FALSE);
  517. GetWindowRect(hwndT1, &rc);
  518. NtUserSetCursorPos(rc.left + ((rc.right - rc.left)/2),
  519. rc.top + ((rc.bottom - rc.top)/2));
  520. NtUserShowCursor(TRUE);
  521. }
  522. }
  523. }
  524. }
  525. goto CallDWP;
  526. case WM_SYSCOMMAND:
  527. if (GetParentDialog(pwnd) == pwnd) {
  528. /*
  529. * If hiding the window, save the focus. If showing the window
  530. * by means of a SW_* command and the fEnd bit is set, do not
  531. * pass to DWP so it won't get shown.
  532. */
  533. if ((int)wParam == SC_MINIMIZE)
  534. xxxSaveDlgFocus(pwnd);
  535. }
  536. goto CallDWP;
  537. case WM_ACTIVATE:
  538. pwndT1 = GetParentDialog(pwnd);
  539. if ( pwndT1 != pwnd) {
  540. /*
  541. * This random bit is used during key processing - bit
  542. * 08000000 of WM_CHAR messages is set if a dialog is currently
  543. * active.
  544. */
  545. NtUserSetThreadState(wParam ? QF_DIALOGACTIVE : 0, QF_DIALOGACTIVE);
  546. }
  547. ThreadLock(pwndT1, &tlpwndT1);
  548. if (wParam != 0)
  549. xxxRestoreDlgFocus(pwndT1);
  550. else
  551. xxxSaveDlgFocus(pwndT1);
  552. ThreadUnlock(&tlpwndT1);
  553. break;
  554. case WM_SETFOCUS:
  555. pwndT1 = GetParentDialog(pwnd);
  556. if (!PDLG(pwndT1)->fEnd && !xxxRestoreDlgFocus(pwndT1)) {
  557. pwndT = _GetNextDlgTabItem(pwndT1, NULL, FALSE);
  558. DlgSetFocus(HW(pwndT));
  559. }
  560. break;
  561. case WM_CLOSE:
  562. /*
  563. * Make sure cancel button is not disabled before sending the
  564. * IDCANCEL. Note that we need to do this as a message instead
  565. * of directly calling the dlg proc so that any dialog box
  566. * filters get this.
  567. */
  568. pwndT1 = _GetDlgItem(pwnd, IDCANCEL);
  569. if (pwndT1 && TestWF(pwndT1, WFDISABLED))
  570. NtUserMessageBeep(0);
  571. else
  572. PostMessage(hwnd, WM_COMMAND, MAKELONG(IDCANCEL, BN_CLICKED),
  573. (LPARAM)HW(pwndT1));
  574. break;
  575. case WM_NCDESTROY:
  576. case WM_FINALDESTROY:
  577. DoCleanup:
  578. NtUserSetThreadState(0, QF_DIALOGACTIVE);
  579. if (!(pwnd->style & DS_LOCALEDIT)) {
  580. if (PDLG(pwnd)->hData) {
  581. ReleaseEditDS(KHANDLE_TO_HANDLE(PDLG(pwnd)->hData));
  582. PDLG(pwnd)->hData = NULL;
  583. }
  584. }
  585. /*
  586. * Delete the user defined font if any
  587. */
  588. if (PDLG(pwnd)->hUserFont) {
  589. DeleteObject(KHFONT_TO_HFONT(PDLG(pwnd)->hUserFont));
  590. PDLG(pwnd)->hUserFont = NULL;
  591. }
  592. /*
  593. * Free the dialog memory and mark this as a non-dialog window
  594. */
  595. FreeLookasideEntry(&DialogLookaside, KPVOID_TO_PVOID(PDLG(pwnd)));
  596. NtUserCallHwndParam(hwnd, 0, SFI_SETDIALOGPOINTER);
  597. break;
  598. case DM_REPOSITION:
  599. {
  600. RECT rc;
  601. PMONITOR pMonitor;
  602. // DAT recorder APP sends it's own private message 0x402
  603. // through and we mistake it to be DM_REPOSITION. To avoid
  604. // this confusion, we do the following check.
  605. // Fix for Bug#25747 -- 9/29/94 --
  606. if (!TestWF(pwnd, WEFCONTROLPARENT) ||
  607. (GETFNID(pwnd) != FNID_DESKTOP &&
  608. GETFNID(REBASEPWND(pwnd, spwndParent)) != FNID_DESKTOP)) {
  609. goto CallDWP;
  610. }
  611. CopyRect(&rc, KPRECT_TO_PRECT(&pwnd->rcWindow));
  612. pMonitor = _MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY);
  613. RepositionRect(pMonitor, &rc, pwnd->style, pwnd->ExStyle);
  614. NtUserSetWindowPos(hwnd, HWND_TOP, rc.left, rc.top,
  615. rc.right-rc.left, rc.bottom-rc.top,
  616. SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  617. }
  618. break;
  619. case DM_SETDEFID:
  620. pwndT1 = GetParentDialog(pwnd);
  621. ThreadLock(pwndT1, &tlpwndT1);
  622. if (!(PDLG(pwndT1)->fEnd)) {
  623. pwndT2 = NULL;
  624. if (PDLG(pwndT1)->result != 0)
  625. pwndT2 = _FindDlgItem(pwndT1, (int)PDLG(pwndT1)->result);
  626. pwndT3 = NULL;
  627. if (wParam != 0) {
  628. pwndT3 = _GetDlgItem(pwnd, (UINT)wParam);
  629. }
  630. ThreadLock(pwndT2, &tlpwndT2);
  631. ThreadLock(pwndT3, &tlpwndT3);
  632. xxxCheckDefPushButton(pwndT1, HW(pwndT2), HW(pwndT3));
  633. ThreadUnlock(&tlpwndT3);
  634. ThreadUnlock(&tlpwndT2);
  635. PDLG(pwndT1)->result = (UINT)wParam;
  636. // if (PDLG(pwnd)->spwndFocusSave) {
  637. // Lock(&(PDLG(pwnd)->spwndFocusSave), pwndT2);
  638. // }
  639. NotifyWinEvent(EVENT_OBJECT_DEFACTIONCHANGE, HW(pwndT1), OBJID_CLIENT, INDEXID_CONTAINER);
  640. }
  641. ThreadUnlock(&tlpwndT1);
  642. return TRUE;
  643. case DM_GETDEFID:
  644. pwndT1 = GetParentDialog(pwnd);
  645. if (!PDLG(pwndT1)->fEnd && PDLG(pwndT1)->result)
  646. return(MAKELONG(PDLG(pwndT1)->result, DC_HASDEFID));
  647. else
  648. return 0;
  649. break;
  650. /*
  651. * This message was added so that user defined controls that want
  652. * tab keys can pass the tab off to the next/previous control in the
  653. * dialog box. Without this, all they could do was set the focus
  654. * which didn't do the default button stuff.
  655. */
  656. case WM_NEXTDLGCTL:
  657. pwndTop = GetParentDialog(pwnd);
  658. ThreadLock(pwndTop, &tlpwndTop);
  659. hwndT1 = GetFocus();
  660. pwndT2 = ValidateHwndNoRip(hwndT1);
  661. if (LOWORD(lParam)) {
  662. if (pwndT2 == NULL)
  663. pwndT2 = pwndTop;
  664. /*
  665. * wParam contains the pwnd of the ctl to set focus to.
  666. */
  667. if ((pwndT1 = ValidateHwnd((HWND)wParam)) == NULL) {
  668. ThreadUnlock(&tlpwndTop);
  669. return TRUE;
  670. }
  671. } else {
  672. if (pwndT2 == NULL) {
  673. /*
  674. * Set focus to the first tab item.
  675. */
  676. pwndT1 = _GetNextDlgTabItem(pwndTop, NULL, FALSE);
  677. pwndT2 = pwndTop;
  678. } else {
  679. /*
  680. * If window with focus not a dlg ctl, ignore message.
  681. */
  682. if (!_IsChild(pwndTop, pwndT2)) {
  683. ThreadUnlock(&tlpwndTop);
  684. return TRUE;
  685. }
  686. /*
  687. * wParam = TRUE for previous, FALSE for next
  688. */
  689. pwndT1 = _GetNextDlgTabItem(pwndTop, pwndT2, (wParam != 0));
  690. /*
  691. * If there is no next item, ignore the message.
  692. */
  693. if (pwndT1 == NULL) {
  694. ThreadUnlock(&tlpwndTop);
  695. return TRUE;
  696. }
  697. }
  698. }
  699. ThreadLock(pwndT1, &tlpwndT1);
  700. ThreadLock(pwndT2, &tlpwndT2);
  701. DlgSetFocus(HW(pwndT1));
  702. xxxCheckDefPushButton(pwndTop, HW(pwndT2), HW(pwndT1));
  703. ThreadUnlock(&tlpwndT2);
  704. ThreadUnlock(&tlpwndT1);
  705. ThreadUnlock(&tlpwndTop);
  706. return TRUE;
  707. case WM_ENTERMENULOOP:
  708. /*
  709. * We need to pop up the combo box window if the user brings
  710. * down a menu.
  711. *
  712. * ... FALL THROUGH...
  713. */
  714. case WM_LBUTTONDOWN:
  715. case WM_NCLBUTTONDOWN:
  716. hwndT1 = GetFocus();
  717. if (hwndT1 != NULL) {
  718. pwndT1 = ValidateHwndNoRip(hwndT1);
  719. if (GETFNID(pwndT1) == FNID_COMBOBOX) {
  720. /*
  721. * If user clicks anywhere in dialog box and a combo box (or
  722. * the editcontrol of a combo box) has the focus, then hide
  723. * it's listbox.
  724. */
  725. ThreadLockAlways(pwndT1, &tlpwndT1);
  726. SendMessage(HWq(pwndT1), CB_SHOWDROPDOWN, FALSE, 0);
  727. ThreadUnlock(&tlpwndT1);
  728. } else {
  729. PWND pwndParent;
  730. /*
  731. * It's a subclassed combo box. See if the listbox and edit
  732. * boxes exist (this is a very cheezy evaluation - what if
  733. * these controls are subclassed too? NOTE: Not checking
  734. * for EditWndProc: it's a client proc address.
  735. */
  736. pwndParent = REBASEPWND(pwndT1, spwndParent);
  737. if (GETFNID(pwndParent) == FNID_COMBOBOX) {
  738. pwndT1 = pwndParent;
  739. ThreadLock(pwndT1, &tlpwndT1);
  740. SendMessage(HWq(pwndT1), CB_SHOWDROPDOWN, FALSE, 0);
  741. ThreadUnlock(&tlpwndT1);
  742. }
  743. }
  744. }
  745. /*
  746. * Always send the message off to DefWndProc
  747. */
  748. goto CallDWP;
  749. case WM_GETFONT:
  750. return (LRESULT)PDLG(pwnd)->hUserFont;
  751. case WM_VKEYTOITEM:
  752. case WM_COMPAREITEM:
  753. case WM_CHARTOITEM:
  754. case WM_INITDIALOG:
  755. /*
  756. * We need to return the 0 the app may have returned for these
  757. * items instead of calling defwindow proc.
  758. */
  759. return result;
  760. case WM_NOTIFYFORMAT:
  761. if (lParam == NF_QUERY)
  762. return((PDLG(pwnd)->flags & DLGF_ANSI ) ? NFR_ANSI : NFR_UNICODE);
  763. return result;
  764. case WM_INPUTLANGCHANGEREQUEST:
  765. if (IS_IME_ENABLED()) {
  766. /*
  767. * #115190
  768. * For dialogbox itself, buttons/static controls on top of
  769. * dialogbox, we'll simply discard this message. B#3843-win95c
  770. */
  771. break;
  772. }
  773. if (PDLG(pwnd)->lpfnDlg == MB_DlgProc) {
  774. break;
  775. }
  776. goto CallDWP;
  777. default:
  778. CallDWP:
  779. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  780. }
  781. } else if ((message == WM_SHOWWINDOW) && result) {
  782. /*
  783. * For a visible-case we want to snap the cursor regardless of
  784. * what was returned from the dialog-handler on the client. If
  785. * we're going visible, snap the cursor to the dialog-button.
  786. */
  787. if (GetParentDialog(pwnd) == pwnd) {
  788. if (wParam && ((LOWORD(lParam) == 0) || !PDLG(pwnd)->fEnd)) {
  789. /*
  790. * Snap the cursor to the center of the default button.
  791. * Only do this if the current thread is in the foreground.
  792. * The _ShowCursor() code is added to work around a
  793. * problem with hardware cursors. If change is done
  794. * in the same refresh cycle, the display of the cursor
  795. * would not reflect the new position.
  796. */
  797. if (TEST_PUSIF(PUSIF_SNAPTO) &&
  798. IsInForegroundQueue(hwnd)) {
  799. hwndT1 = GetDlgItem(hwnd, (int)PDLG(pwnd)->result);
  800. if (hwndT1) {
  801. RECT rc;
  802. NtUserShowCursor(FALSE);
  803. GetWindowRect(hwndT1, &rc);
  804. NtUserSetCursorPos(rc.left + ((rc.right - rc.left)/2),
  805. rc.top + ((rc.bottom - rc.top)/2));
  806. NtUserShowCursor(TRUE);
  807. }
  808. }
  809. }
  810. }
  811. }
  812. /*
  813. * If this is still marked as a dialog window then return the real
  814. * result. Otherwise, we've already processed the WM_NCDESTROY message
  815. * and freed our private memory so return the stored value.
  816. */
  817. if (TestWF(pwnd, WFDIALOGWINDOW))
  818. return KERNEL_LRESULT_TO_LRESULT(((PDIALOG)pwnd)->resultWP);
  819. else
  820. return result;
  821. }
  822. /***************************************************************************\
  823. * DefDlgProc
  824. *
  825. * Translates the message, calls DefDlgProc on server side. DefDlgProc
  826. * is the default WindowProc for dialogs (NOT the dialog's dialog proc)
  827. *
  828. * 04-11-91 ScottLu Created.
  829. \***************************************************************************/
  830. FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefDlgProcW, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
  831. LRESULT WINAPI DefDlgProcW(
  832. HWND hwnd,
  833. UINT message,
  834. WPARAM wParam,
  835. LPARAM lParam)
  836. {
  837. PWND pwnd;
  838. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  839. return (0L);
  840. }
  841. return DefDlgProcWorker(pwnd, message, wParam, lParam, FALSE);
  842. }
  843. FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefDlgProcA, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
  844. LRESULT WINAPI DefDlgProcA(
  845. HWND hwnd,
  846. UINT message,
  847. WPARAM wParam,
  848. LPARAM lParam)
  849. {
  850. PWND pwnd;
  851. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  852. return (0L);
  853. }
  854. return DefDlgProcWorker(pwnd, message, wParam, lParam, TRUE);
  855. }
  856. /***************************************************************************\
  857. * DialogBox2
  858. *
  859. * History:
  860. \***************************************************************************/
  861. INT_PTR DialogBox2(
  862. HWND hwnd,
  863. HWND hwndOwner,
  864. BOOL fDisabled,
  865. BOOL fOwnerIsActiveWindow)
  866. {
  867. MSG msg;
  868. INT_PTR result;
  869. BOOL fShown;
  870. BOOL fWantIdleMsgs;
  871. BOOL fSentIdleMessage = FALSE;
  872. HWND hwndCapture;
  873. PWND pwnd;
  874. if (hwnd) {
  875. pwnd = ValidateHwnd(hwnd);
  876. } else {
  877. pwnd = NULL;
  878. }
  879. CheckLock(pwnd);
  880. if (pwnd == NULL) {
  881. if ((hwndOwner != NULL) && !fDisabled && IsWindow(hwndOwner)) {
  882. NtUserEnableWindow(hwndOwner, TRUE);
  883. if (fOwnerIsActiveWindow) {
  884. /*
  885. * The dialog box failed but we disabled the owner in
  886. * xxxDialogBoxIndirectParam and if it had the focus, the
  887. * focus was set to NULL. Now, when we enable the window, it
  888. * doesn't get the focus back if it had it previously so we
  889. * need to correct this.
  890. */
  891. NtUserSetFocus(hwndOwner);
  892. }
  893. }
  894. return -1;
  895. }
  896. hwndCapture = GetCapture();
  897. if (hwndCapture != NULL) {
  898. SendMessage(hwndCapture, WM_CANCELMODE, 0, 0);
  899. }
  900. /*
  901. * Set the 'parent disabled' flag for EndDialog().
  902. * convert BOOL to definite bit 0 or 1
  903. */
  904. PDLG(pwnd)->fDisabled = !!fDisabled;
  905. fShown = TestWF(pwnd, WFVISIBLE);
  906. /*
  907. * Should the WM_ENTERIDLE messages be sent?
  908. */
  909. fWantIdleMsgs = !(pwnd->style & DS_NOIDLEMSG);
  910. if ((SYSMET(SLOWMACHINE) & 1) && !fShown && !PDLG(pwnd)->fEnd)
  911. goto ShowIt;
  912. while (PDLG(pwnd) && (!PDLG(pwnd)->fEnd)) {
  913. if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  914. ShowIt:
  915. if (!fShown) {
  916. fShown = TRUE;
  917. #ifdef SYSMODALWINDOWS
  918. if (pwnd == gspwndSysModal) {
  919. /*
  920. * Make this a topmost window
  921. */
  922. NtUserSetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  923. SWP_NOSIZE | SWP_NOMOVE |
  924. SWP_NOREDRAW | SWP_NOACTIVATE);
  925. }
  926. #endif
  927. NtUserShowWindow(hwnd, SHOW_OPENWINDOW);
  928. UpdateWindow(hwnd);
  929. NotifyWinEvent(EVENT_SYSTEM_DIALOGSTART, hwnd, OBJID_WINDOW, INDEXID_CONTAINER);
  930. } else {
  931. /*
  932. * Make sure window still exists
  933. */
  934. if (hwndOwner && !IsWindow(hwndOwner))
  935. hwndOwner = NULL;
  936. if (hwndOwner && fWantIdleMsgs && !fSentIdleMessage) {
  937. fSentIdleMessage = TRUE;
  938. SendMessage(hwndOwner, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd);
  939. } else {
  940. if ((RevalidateHwnd(hwnd)==NULL) || (pwnd->fnid & FNID_STATUS_BITS))
  941. break;
  942. NtUserWaitMessage();
  943. }
  944. }
  945. } else {
  946. /*
  947. * We got a real message. Reset fSentIdleMessage so that we send
  948. * one next time things are calm.
  949. */
  950. fSentIdleMessage = FALSE;
  951. if (msg.message == WM_QUIT) {
  952. PostQuitMessage((int)msg.wParam);
  953. break;
  954. }
  955. /*
  956. * If pwnd is a message box, allow Ctrl-C and Ctrl-Ins
  957. * to copy its content to the clipboard.
  958. * Fall through in case hooking apps look for these keys.
  959. */
  960. if (TestWF(pwnd, WFMSGBOX)) {
  961. if ( (msg.message == WM_CHAR && LOBYTE(msg.wParam) == 3) ||
  962. (msg.message == WM_KEYDOWN && LOBYTE(msg.wParam) == VK_INSERT && GetKeyState(VK_CONTROL) < 0)) {
  963. /*
  964. * Send the WM_COPY message and let the original message fall through
  965. * as some apps might want it
  966. */
  967. SendMessage(hwnd, WM_COPY, 0, 0);
  968. }
  969. }
  970. /*
  971. * Moved the msg filter hook call to IsDialogMessage to allow
  972. * messages to be hooked for both modal and modeless dialog
  973. * boxes.
  974. */
  975. if (!IsDialogMessage(hwnd, &msg)) {
  976. TranslateMessage(&msg);
  977. DispatchMessage(&msg);
  978. }
  979. /*
  980. * If we get a timer message, go ahead and show the window.
  981. * We may continuously get timer msgs if there are zillions of
  982. * apps running.
  983. *
  984. * If we get a syskeydown message, show the dialog box because
  985. * the user may be bringing down a menu and we want the dialog
  986. * box to become visible.
  987. */
  988. if (!fShown && (msg.message == WM_TIMER ||
  989. msg.message == WM_SYSTIMER || msg.message == WM_SYSKEYDOWN))
  990. goto ShowIt;
  991. }
  992. if (!RevalidateHwnd(hwnd)) {
  993. /*
  994. * Bogus case - we've already been destroyed somehow (by app,
  995. * GP, etc.)
  996. */
  997. RIPMSG0(RIP_WARNING,
  998. "Dialog should be dismissed with EndDialog, not DestroyWindow");
  999. break;
  1000. }
  1001. }
  1002. NotifyWinEvent(EVENT_SYSTEM_DIALOGEND, hwnd, OBJID_WINDOW, INDEXID_CONTAINER);
  1003. /*
  1004. * Make sure the window still exists
  1005. */
  1006. if (!RevalidateHwnd(hwnd)) {
  1007. return 0;
  1008. }
  1009. if (PDLG(pwnd))
  1010. result = KERNEL_INT_PTR_TO_INT_PTR(PDLG(pwnd)->result);
  1011. else
  1012. result = 0;
  1013. NtUserDestroyWindow(hwnd);
  1014. /*
  1015. * If the owner window belongs to another thread, the reactivation
  1016. * of the owner may have failed within DestroyWindow(). Therefore,
  1017. * if the current thread is in the foreground and the owner is not
  1018. * in the foreground we can safely set the foreground back
  1019. * to the owner.
  1020. */
  1021. if (hwndOwner != NULL) {
  1022. if (IsCurrentThreadForeground() &&
  1023. !IsInForegroundQueue(hwndOwner)) {
  1024. NtUserSetForegroundWindow(hwndOwner);
  1025. }
  1026. }
  1027. return result;
  1028. }
  1029. /***************************************************************************\
  1030. * InternalDialogBox
  1031. *
  1032. * Server portion of DialogBoxIndirectParam.
  1033. *
  1034. * 04-05-91 ScottLu Created.
  1035. \***************************************************************************/
  1036. INT_PTR InternalDialogBox(
  1037. HANDLE hModule,
  1038. LPDLGTEMPLATE lpdt,
  1039. HWND hwndOwner,
  1040. DLGPROC pfnDialog,
  1041. LPARAM lParam,
  1042. UINT fSCDLGFlags)
  1043. {
  1044. INT_PTR i;
  1045. BOOL fDisabled = FALSE;
  1046. HWND hwnd;
  1047. PWND pwndOwner;
  1048. BOOL fOwnerIsActiveWindow = FALSE;
  1049. TL tlpwndOwner;
  1050. BOOL fUnlockOwner;
  1051. UserAssert(!(fSCDLGFlags & ~(SCDLG_CLIENT|SCDLG_ANSI|SCDLG_16BIT))); // These are the only valid flags
  1052. /*
  1053. * If hwndOwner == HWNDESKTOP, change it to NULL. This way the desktop
  1054. * (and all its children) won't be disabled if the dialog is modal.
  1055. */
  1056. if (hwndOwner && SAMEWOWHANDLE(hwndOwner, GetDesktopWindow()))
  1057. hwndOwner = NULL;
  1058. /*
  1059. * We return 0 if the ValidateHwnd fails in order to match Win 3.1
  1060. * validation layer which always returns 0 for invalid hwnds even
  1061. * if the function is spec'ed to return -1. Autocad setup bug #3615
  1062. */
  1063. if (hwndOwner) {
  1064. if ((pwndOwner = ValidateHwnd(hwndOwner)) == NULL) {
  1065. return (0L);
  1066. }
  1067. } else {
  1068. pwndOwner = NULL;
  1069. }
  1070. CheckLock(pwndOwner);
  1071. fUnlockOwner = FALSE;
  1072. if (pwndOwner != NULL) {
  1073. /* The following fixes an AV in Corel Photo-Paint 6.0. It passes a
  1074. * 16-bit HWND in, and croaks at some point when it gets 16-bit hwnds
  1075. * back in send messages. FritzS -- fixing bug 12531
  1076. */
  1077. hwndOwner = PtoHq(pwndOwner);
  1078. /*
  1079. * Make sure the owner is a top level window.
  1080. */
  1081. if (TestwndChild(pwndOwner)) {
  1082. pwndOwner = GetTopLevelWindow(pwndOwner);
  1083. hwndOwner = HWq(pwndOwner);
  1084. ThreadLock(pwndOwner, &tlpwndOwner);
  1085. fUnlockOwner = TRUE;
  1086. }
  1087. /*
  1088. * Remember if window was originally disabled (so we can set
  1089. * the correct state when the dialog goes away.
  1090. */
  1091. fDisabled = TestWF(pwndOwner, WFDISABLED);
  1092. fOwnerIsActiveWindow = (SAMEWOWHANDLE(hwndOwner, GetActiveWindow()));
  1093. /*
  1094. * Disable the window.
  1095. */
  1096. NtUserEnableWindow(hwndOwner, FALSE);
  1097. }
  1098. /*
  1099. * Don't show cursors on a mouseless system. Put up an hour glass while
  1100. * the dialog comes up.
  1101. */
  1102. if (SYSMET(MOUSEPRESENT)) {
  1103. NtUserSetCursor(LoadCursor(NULL, IDC_WAIT));
  1104. }
  1105. /*
  1106. * Creates the dialog. Frees the menu if this routine fails.
  1107. */
  1108. hwnd = InternalCreateDialog(hModule, lpdt, 0, hwndOwner,
  1109. pfnDialog, lParam, fSCDLGFlags);
  1110. if (hwnd == NULL) {
  1111. /*
  1112. * The dialog creation failed. Re-enable the window, destroy the
  1113. * menu, ie., fail gracefully.
  1114. */
  1115. if (!fDisabled && hwndOwner != NULL)
  1116. NtUserEnableWindow(hwndOwner, TRUE);
  1117. if (fUnlockOwner)
  1118. ThreadUnlock(&tlpwndOwner);
  1119. return -1;
  1120. }
  1121. i = DialogBox2(hwnd, hwndOwner, fDisabled, fOwnerIsActiveWindow);
  1122. if (fUnlockOwner)
  1123. ThreadUnlock(&tlpwndOwner);
  1124. return i;
  1125. }
  1126. /***************************************************************************\
  1127. **
  1128. ** RepositionRect()
  1129. **
  1130. ** Used to ensure that toplevel dialogs are still visible within the
  1131. ** desktop area after they've resized.
  1132. **
  1133. \***************************************************************************/
  1134. void
  1135. RepositionRect(
  1136. PMONITOR pMonitor,
  1137. LPRECT lprc,
  1138. DWORD dwStyle,
  1139. DWORD dwExStyle)
  1140. {
  1141. LPRECT lprcClip;
  1142. int y;
  1143. UserAssert(lprc);
  1144. UserAssert(pMonitor);
  1145. if (dwStyle & WS_CHILD) {
  1146. if (dwExStyle & WS_EX_CONTROLPARENT)
  1147. return;
  1148. /*
  1149. * Old style 3.1 child dialogs--do this nonsense anyway. Keeps
  1150. * FedEx happy.
  1151. */
  1152. pMonitor = GetPrimaryMonitor();
  1153. lprcClip = KPRECT_TO_PRECT(&pMonitor->rcMonitor);
  1154. } else if (dwExStyle & WS_EX_TOOLWINDOW) {
  1155. lprcClip = KPRECT_TO_PRECT(&pMonitor->rcMonitor);
  1156. } else {
  1157. lprcClip = KPRECT_TO_PRECT(&pMonitor->rcWork);
  1158. }
  1159. UserAssert(lprc);
  1160. y = lprcClip->bottom - (SYSMET(CYEDGE) * 2 + SYSMET(CYKANJIWINDOW));
  1161. if (lprc->bottom > y) {
  1162. OffsetRect(lprc, 0, y - lprc->bottom);
  1163. }
  1164. if (lprc->top < lprcClip->top) {
  1165. OffsetRect(lprc, 0, lprcClip->top - lprc->top);
  1166. }
  1167. if (lprc->right > lprcClip->right) {
  1168. OffsetRect(lprc, lprcClip->right - lprc->right, 0);
  1169. }
  1170. if (lprc->left < lprcClip->left) {
  1171. OffsetRect(lprc, lprcClip->left - lprc->left, 0);
  1172. }
  1173. }
  1174. /***************************************************************************\
  1175. * MapDialogRect
  1176. *
  1177. * History:
  1178. \***************************************************************************/
  1179. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, MapDialogRect, HWND, hwnd, LPRECT, lprc)
  1180. BOOL MapDialogRect(
  1181. HWND hwnd,
  1182. LPRECT lprc)
  1183. {
  1184. PWND pwnd;
  1185. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  1186. return FALSE;
  1187. }
  1188. /*
  1189. * Must do special validation here to make sure pwnd is a dialog window.
  1190. */
  1191. if (!ValidateDialogPwnd(pwnd))
  1192. return FALSE;
  1193. lprc->left = XPixFromXDU(lprc->left, PDLG(pwnd)->cxChar);
  1194. lprc->right = XPixFromXDU(lprc->right, PDLG(pwnd)->cxChar);
  1195. lprc->top = YPixFromYDU(lprc->top, PDLG(pwnd)->cyChar);
  1196. lprc->bottom = YPixFromYDU(lprc->bottom, PDLG(pwnd)->cyChar);
  1197. return TRUE;
  1198. }