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.

1814 lines
46 KiB

  1. /* Copyright (c) 1995, Microsoft Corporation, all rights reserved
  2. **
  3. ** ui.c
  4. ** UI helper routines
  5. ** Listed alphabetically
  6. **
  7. ** 08/25/95 Steve Cobb
  8. */
  9. #include <windows.h> // Win32 root
  10. #include <windowsx.h> // Win32 macro extensions
  11. #include <commctrl.h> // Win32 common controls
  12. #include <debug.h> // Trace and assert
  13. #include <uiutil.h> // Our public header
  14. /*----------------------------------------------------------------------------
  15. ** Globals
  16. **----------------------------------------------------------------------------
  17. */
  18. /* See SetOffDesktop.
  19. */
  20. static LPCWSTR g_SodContextId = NULL;
  21. /* Set when running in a mode where WinHelp does not work. This is a
  22. ** workaround to the problem where WinHelp does not work correctly before a
  23. ** user is logged on. See AddContextHelpButton.
  24. */
  25. BOOL g_fNoWinHelp = FALSE;
  26. /*----------------------------------------------------------------------------
  27. ** Local datatypes
  28. **----------------------------------------------------------------------------
  29. */
  30. /* SetOffDesktop context.
  31. */
  32. #define SODINFO struct tagSODINFO
  33. SODINFO
  34. {
  35. RECT rectOrg;
  36. BOOL fWeMadeInvisible;
  37. };
  38. /*----------------------------------------------------------------------------
  39. ** Local prototypes
  40. **----------------------------------------------------------------------------
  41. */
  42. BOOL CALLBACK
  43. CancelOwnedWindowsEnumProc(
  44. IN HWND hwnd,
  45. IN LPARAM lparam );
  46. BOOL CALLBACK
  47. CloseOwnedWindowsEnumProc(
  48. IN HWND hwnd,
  49. IN LPARAM lparam );
  50. /*----------------------------------------------------------------------------
  51. ** Utility routines
  52. **----------------------------------------------------------------------------
  53. */
  54. VOID
  55. AddContextHelpButton(
  56. IN HWND hwnd )
  57. /* Turns on title bar context help button in 'hwnd'.
  58. **
  59. ** Dlgedit.exe doesn't currently support adding this style at dialog
  60. ** resource edit time. When that's fixed set DS_CONTEXTHELP in the dialog
  61. ** definition and remove this routine.
  62. */
  63. {
  64. LONG lStyle;
  65. if (g_fNoWinHelp)
  66. return;
  67. lStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
  68. if (lStyle)
  69. SetWindowLong( hwnd, GWL_EXSTYLE, lStyle | WS_EX_CONTEXTHELP );
  70. }
  71. VOID
  72. Button_MakeDefault(
  73. IN HWND hwndDlg,
  74. IN HWND hwndPb )
  75. /* Make 'hwndPb' the default button on dialog 'hwndDlg'.
  76. */
  77. {
  78. DWORD dwResult;
  79. HWND hwndPbOldDefault;
  80. dwResult = (DWORD) SendMessage( hwndDlg, DM_GETDEFID, 0, 0 );
  81. if (HIWORD( dwResult ) == DC_HASDEFID)
  82. {
  83. /* Un-default the current default button.
  84. */
  85. hwndPbOldDefault = GetDlgItem( hwndDlg, LOWORD( dwResult ) );
  86. Button_SetStyle( hwndPbOldDefault, BS_PUSHBUTTON, TRUE );
  87. }
  88. /* Set caller's button to the default.
  89. */
  90. SendMessage( hwndDlg, DM_SETDEFID, GetDlgCtrlID( hwndPb ), 0 );
  91. Button_SetStyle( hwndPb, BS_DEFPUSHBUTTON, TRUE );
  92. }
  93. HBITMAP
  94. Button_CreateBitmap(
  95. IN HWND hwndPb,
  96. IN BITMAPSTYLE bitmapstyle )
  97. /* Creates a bitmap of 'bitmapstyle' suitable for display on 'hwndPb. The
  98. ** 'hwndPb' must have been created with BS_BITMAP style.
  99. **
  100. ** 'HwndPb' may be a checkbox with BS_PUSHLIKE style, in which case the
  101. ** button locks down when pressed like a toolbar button. This case
  102. ** requires that a color bitmap be created resulting in two extra
  103. ** restrictions. First, caller must handle WM_SYSCOLORCHANGE and rebuild
  104. ** the bitmaps with the new colors and second, the button cannot be
  105. ** disabled.
  106. **
  107. ** Returns the handle to the bitmap. Caller can display it on the button
  108. ** as follows:
  109. **
  110. ** SendMessage( hwndPb, BM_SETIMAGE, 0, (LPARAM )hbitmap );
  111. **
  112. ** Caller is responsible for calling DeleteObject(hbitmap) when done using
  113. ** the bitmap, typically when the dialog is destroyed.
  114. **
  115. ** (Adapted from a routine by Tony Romano)
  116. */
  117. {
  118. RECT rect;
  119. HDC hdc;
  120. HDC hdcMem;
  121. HBITMAP hbitmap;
  122. HFONT hfont;
  123. HPEN hpen;
  124. SIZE sizeText;
  125. SIZE sizeBitmap;
  126. INT x;
  127. INT y;
  128. TCHAR* psz;
  129. TCHAR* pszText;
  130. TCHAR* pszText2;
  131. DWORD dxBitmap;
  132. DWORD dxBetween;
  133. BOOL fOnRight;
  134. BOOL fPushLike;
  135. hdc = NULL;
  136. hdcMem = NULL;
  137. hbitmap = NULL;
  138. hpen = NULL;
  139. pszText = NULL;
  140. pszText2 = NULL;
  141. switch (bitmapstyle)
  142. {
  143. case BMS_UpArrowOnLeft:
  144. case BMS_DownArrowOnLeft:
  145. case BMS_UpArrowOnRight:
  146. case BMS_DownArrowOnRight:
  147. dxBitmap = 5;
  148. dxBetween = 4;
  149. break;
  150. case BMS_UpTriangleOnLeft:
  151. case BMS_DownTriangleOnLeft:
  152. case BMS_UpTriangleOnRight:
  153. case BMS_DownTriangleOnRight:
  154. dxBitmap = 7;
  155. dxBetween = 6;
  156. break;
  157. default:
  158. return NULL;
  159. }
  160. fOnRight = (bitmapstyle & BMS_OnRight);
  161. fPushLike = (GetWindowLong( hwndPb, GWL_STYLE ) & BS_PUSHLIKE);
  162. /* Get a memory DC compatible with the button window.
  163. */
  164. hdc = GetDC( hwndPb );
  165. if (!hdc)
  166. return NULL;
  167. hdcMem = CreateCompatibleDC( hdc );
  168. if (!hdcMem)
  169. goto BCB_Error;
  170. /* Create a compatible bitmap covering the entire button in the memory DC.
  171. **
  172. ** For a push button, the bitmap is created compatible with the memory DC,
  173. ** NOT the display DC. This causes the bitmap to be monochrome, the
  174. ** default for memory DCs. When GDI maps monochrome bitmaps into color,
  175. ** white is replaced with the background color and black is replaced with
  176. ** the text color, which is exactly what we want. With this technique, we
  177. ** are relieved from explicit handling of changes in system colors.
  178. **
  179. ** For a push-like checkbox the bitmap is created compatible with the
  180. ** button itself, so the bitmap is typically color.
  181. */
  182. GetClientRect( hwndPb, &rect );
  183. hbitmap = CreateCompatibleBitmap(
  184. (fPushLike) ? hdc : hdcMem, rect.right, rect.bottom );
  185. if (!hbitmap)
  186. goto BCB_Error;
  187. ReleaseDC( hwndPb, hdc );
  188. hdc = NULL;
  189. SelectObject( hdcMem, hbitmap );
  190. /* Select the font the button says it's using.
  191. */
  192. hfont = (HFONT )SendMessage( hwndPb, WM_GETFONT, 0, 0 );
  193. if (hfont)
  194. SelectObject( hdcMem, hfont );
  195. /* Set appropriate colors for regular and stuck-down states. Don't need
  196. ** to do anything for the monochrome case as the default black pen and
  197. ** white background are what we want.
  198. */
  199. if (fPushLike)
  200. {
  201. INT nColor;
  202. if (bitmapstyle == BMS_UpArrowOnLeft
  203. || bitmapstyle == BMS_UpArrowOnRight
  204. || bitmapstyle == BMS_UpTriangleOnLeft
  205. || bitmapstyle == BMS_UpTriangleOnRight)
  206. {
  207. nColor = COLOR_BTNHILIGHT;
  208. }
  209. else
  210. {
  211. nColor = COLOR_BTNFACE;
  212. }
  213. SetBkColor( hdcMem, GetSysColor( nColor ) );
  214. hpen = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNTEXT ) );
  215. if (hpen)
  216. SelectObject( hdcMem, hpen );
  217. }
  218. /* The created bitmap is random, so we erase it to the background color.
  219. ** No text is written here.
  220. */
  221. ExtTextOut( hdcMem, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
  222. /* Get the button label and make a copy with the '&' accelerator-escape
  223. ** removed, which would otherwise mess up our width calculations.
  224. */
  225. pszText = GetText( hwndPb );
  226. pszText2 = StrDup( pszText );
  227. if (!pszText || !pszText2)
  228. goto BCB_Error;
  229. for (psz = pszText2; *psz; psz = CharNext( psz ) )
  230. {
  231. if (*psz == TEXT('&'))
  232. {
  233. lstrcpy( psz, psz + 1 );
  234. break;
  235. }
  236. }
  237. /* Calculate the width of the button label text.
  238. */
  239. sizeText.cx = 0;
  240. sizeText.cy = 0;
  241. GetTextExtentPoint32( hdcMem, pszText2, lstrlen( pszText2 ), &sizeText );
  242. /* Draw the text off-center horizontally enough so it is centered with the
  243. ** bitmap symbol added.
  244. */
  245. --rect.bottom;
  246. sizeBitmap.cx = dxBitmap;
  247. sizeBitmap.cy = 0;
  248. rect.left +=
  249. ((rect.right - (sizeText.cx + sizeBitmap.cx) - dxBetween) / 2);
  250. if (fOnRight)
  251. {
  252. DrawText( hdcMem, pszText, -1, &rect,
  253. DT_VCENTER + DT_SINGLELINE + DT_EXTERNALLEADING );
  254. rect.left += sizeText.cx + dxBetween;
  255. }
  256. else
  257. {
  258. rect.left += dxBitmap + dxBetween;
  259. DrawText( hdcMem, pszText, -1, &rect,
  260. DT_VCENTER + DT_SINGLELINE + DT_EXTERNALLEADING );
  261. rect.left -= dxBitmap + dxBetween;
  262. }
  263. /* Eliminate the top and bottom 3 pixels of button from consideration for
  264. ** the bitmap symbol. This leaves the button control room to do the
  265. ** border and 3D edges.
  266. */
  267. InflateRect( &rect, 0, -3 );
  268. /* Draw the bitmap symbol. The rectangle is now 'dxBitmap' wide and
  269. ** centered vertically with variable height depending on the button size.
  270. */
  271. switch (bitmapstyle)
  272. {
  273. case BMS_UpArrowOnLeft:
  274. case BMS_UpArrowOnRight:
  275. {
  276. /* v-left
  277. ** ..... <-top
  278. ** .....
  279. ** .....
  280. ** ..*.. \
  281. ** .***. |
  282. ** ***** |
  283. ** ..*.. |
  284. ** ..*.. |
  285. ** ..*.. > varies depending on font height
  286. ** ..*.. |
  287. ** ..*.. |
  288. ** ..*.. |
  289. ** ..*.. |
  290. ** ..*.. /
  291. ** .....
  292. ** .....
  293. ** .....
  294. ** ..... <-bottom
  295. */
  296. /* Draw the vertical line.
  297. */
  298. x = rect.left + 2;
  299. y = rect.top + 3;
  300. MoveToEx( hdcMem, x, y, NULL );
  301. LineTo( hdcMem, x, rect.bottom - 3 );
  302. /* Draw the 2 crossbars.
  303. */
  304. MoveToEx( hdcMem, x - 1, ++y, NULL );
  305. LineTo( hdcMem, x + 2, y );
  306. MoveToEx( hdcMem, x - 2, ++y, NULL );
  307. LineTo( hdcMem, x + 3, y );
  308. break;
  309. }
  310. case BMS_DownArrowOnLeft:
  311. case BMS_DownArrowOnRight:
  312. {
  313. /* v-left
  314. ** ..... <-top
  315. ** .....
  316. ** .....
  317. ** ..*.. \
  318. ** ..*.. |
  319. ** ..*.. |
  320. ** ..*.. |
  321. ** ..*.. |
  322. ** ..*.. > varies depending on font height
  323. ** ..*.. |
  324. ** ..*.. |
  325. ** ***** |
  326. ** .***. |
  327. ** ..*.. /
  328. ** .....
  329. ** .....
  330. ** .....
  331. ** ..... <-bottom
  332. */
  333. /* Draw the vertical line.
  334. */
  335. x = rect.left + 2;
  336. y = rect.top + 3;
  337. MoveToEx( hdcMem, x, y, NULL );
  338. LineTo( hdcMem, x, rect.bottom - 3 );
  339. /* Draw the 2 crossbars.
  340. */
  341. y = rect.bottom - 6;
  342. MoveToEx( hdcMem, x - 2, y, NULL );
  343. LineTo( hdcMem, x + 3, y );
  344. MoveToEx( hdcMem, x - 1, ++y, NULL );
  345. LineTo( hdcMem, x + 2, y );
  346. break;
  347. }
  348. case BMS_UpTriangleOnLeft:
  349. case BMS_UpTriangleOnRight:
  350. {
  351. /* v-left
  352. ** ....... <-top
  353. ** .......
  354. ** .......
  355. ** .......
  356. ** .......
  357. ** .......
  358. ** .......
  359. ** ...o... <- o indicates x,y origin
  360. ** ..***..
  361. ** .*****.
  362. ** *******
  363. ** .......
  364. ** .......
  365. ** .......
  366. ** .......
  367. ** .......
  368. ** .......
  369. ** ....... <-bottom
  370. */
  371. x = rect.left + 3;
  372. y = ((rect.bottom - rect.top) / 2) + 2;
  373. MoveToEx( hdcMem, x, y, NULL );
  374. LineTo( hdcMem, x + 1, y );
  375. ++y;
  376. MoveToEx( hdcMem, x - 1, y, NULL );
  377. LineTo( hdcMem, x + 2, y );
  378. ++y;
  379. MoveToEx( hdcMem, x - 2, y, NULL );
  380. LineTo( hdcMem, x + 3, y );
  381. ++y;
  382. MoveToEx( hdcMem, x - 3, y, NULL );
  383. LineTo( hdcMem, x + 4, y );
  384. break;
  385. }
  386. case BMS_DownTriangleOnLeft:
  387. case BMS_DownTriangleOnRight:
  388. {
  389. /* v-left
  390. ** ....... <-top
  391. ** .......
  392. ** .......
  393. ** .......
  394. ** .......
  395. ** .......
  396. ** .......
  397. ** ***o*** <- o indicates x,y origin
  398. ** .*****.
  399. ** ..***..
  400. ** ...*...
  401. ** .......
  402. ** .......
  403. ** .......
  404. ** .......
  405. ** .......
  406. ** .......
  407. ** ....... <-bottom
  408. */
  409. x = rect.left + 3;
  410. y = ((rect.bottom - rect.top) / 2) + 2;
  411. MoveToEx( hdcMem, x - 3, y, NULL );
  412. LineTo( hdcMem, x + 4, y );
  413. ++y;
  414. MoveToEx( hdcMem, x - 2, y, NULL );
  415. LineTo( hdcMem, x + 3, y );
  416. ++y;
  417. MoveToEx( hdcMem, x - 1, y, NULL );
  418. LineTo( hdcMem, x + 2, y );
  419. ++y;
  420. MoveToEx( hdcMem, x, y, NULL );
  421. LineTo( hdcMem, x + 1, y );
  422. break;
  423. }
  424. }
  425. BCB_Error:
  426. Free0( pszText );
  427. Free0( pszText2 );
  428. if (hdc)
  429. ReleaseDC( hwndPb, hdc );
  430. if (hdcMem)
  431. DeleteDC( hdcMem );
  432. if (hpen)
  433. DeleteObject( hpen );
  434. return hbitmap;
  435. }
  436. VOID
  437. CenterWindow(
  438. IN HWND hwnd,
  439. IN HWND hwndRef )
  440. /* Center window 'hwnd' on window 'hwndRef' or if 'hwndRef' is NULL on
  441. ** screen. The window position is adjusted so that no parts are clipped
  442. ** by the edge of the screen, if necessary. If 'hwndRef' has been moved
  443. ** off-screen with SetOffDesktop, the original position is used.
  444. */
  445. {
  446. RECT rectCur;
  447. LONG dxCur;
  448. LONG dyCur;
  449. RECT rectRef;
  450. LONG dxRef;
  451. LONG dyRef;
  452. GetWindowRect( hwnd, &rectCur );
  453. dxCur = rectCur.right - rectCur.left;
  454. dyCur = rectCur.bottom - rectCur.top;
  455. if (hwndRef)
  456. {
  457. if (!SetOffDesktop( hwndRef, SOD_GetOrgRect, &rectRef ))
  458. GetWindowRect( hwndRef, &rectRef );
  459. }
  460. else
  461. {
  462. rectRef.top = rectRef.left = 0;
  463. rectRef.right = GetSystemMetrics( SM_CXSCREEN );
  464. rectRef.bottom = GetSystemMetrics( SM_CYSCREEN );
  465. }
  466. dxRef = rectRef.right - rectRef.left;
  467. dyRef = rectRef.bottom - rectRef.top;
  468. rectCur.left = rectRef.left + ((dxRef - dxCur) / 2);
  469. rectCur.top = rectRef.top + ((dyRef - dyCur) / 2);
  470. SetWindowPos(
  471. hwnd, NULL,
  472. rectCur.left, rectCur.top, 0, 0,
  473. SWP_NOZORDER + SWP_NOSIZE );
  474. UnclipWindow( hwnd );
  475. }
  476. //Add this function for whislter bug 320863 gangz
  477. //
  478. //Center expand the window horizontally in its parent window
  479. // this expansion will remain the left margin between the child window
  480. // and the parent window
  481. // hwnd: Child Window
  482. // hwndRef: Reference window
  483. // bHoriz: TRUE, means expand horizontally, let the right margin equal the left margin
  484. // bVert: TRUE, elongate the height proportial to the width;
  485. // hwndVertBound: the window that our vertical expandasion cannot overlap with
  486. //
  487. VOID
  488. CenterExpandWindowRemainLeftMargin(
  489. IN HWND hwnd,
  490. IN HWND hwndRef,
  491. BOOL bHoriz,
  492. BOOL bVert,
  493. IN HWND hwndVertBottomBound)
  494. {
  495. RECT rectCur, rectRef, rectVbBound;
  496. LONG dxCur, dyCur, dxRef;
  497. POINT ptTemp;
  498. double ratio;
  499. BOOL bvbBound = FALSE;
  500. if (hwnd)
  501. {
  502. GetWindowRect( hwnd, &rectCur );
  503. if (hwndRef)
  504. {
  505. GetWindowRect( hwndRef, &rectRef );
  506. if(hwndVertBottomBound)
  507. {
  508. GetWindowRect( hwndVertBottomBound, &rectVbBound );
  509. //We only consider normal cases, if hwnd and hwndVertBound are already
  510. //overlapped, that is the problem beyond this function.
  511. //
  512. if ( rectCur.top < rectVbBound.top )
  513. {
  514. bvbBound = TRUE;
  515. }
  516. }
  517. dxRef = rectRef.right - rectRef.left +1;
  518. dxCur = rectCur.right - rectCur.left +1;
  519. dyCur = rectCur.bottom - rectCur.top +1;
  520. ratio = dyCur*1.0/dxCur;
  521. if(bHoriz)
  522. {
  523. rectCur.right = rectRef.right - (rectCur.left - rectRef.left);
  524. }
  525. if(bVert)
  526. {
  527. rectCur.bottom = rectCur.top +
  528. (LONG)( (rectCur.right - rectCur.left+1) * ratio );
  529. }
  530. if(bvbBound)
  531. {
  532. //if overlapping occurs w/o expansion, we need to fix it
  533. //then we do the vertical centering,
  534. // this bounding is basically for JPN bugs 329700 329715 which
  535. // wont happen on English build
  536. //
  537. if(rectCur.bottom > rectVbBound.top )
  538. {
  539. LONG dxResult, dyResult, dyVRef;
  540. dyResult = rectVbBound.top - rectCur.top;
  541. dxResult = (LONG)(dyResult/ratio);
  542. ptTemp.x = rectVbBound.left;
  543. ptTemp.y = rectVbBound.top-1;
  544. //For whistler bug 371914 gangz
  545. //Cannot use ScreenToClient() here
  546. //On RTL build, we must use MapWindowPoint() instead
  547. //
  548. MapWindowPoints(HWND_DESKTOP,
  549. hwndRef,
  550. &ptTemp,
  551. 1);
  552. dyVRef = ptTemp.y + 1;
  553. rectCur.left = rectRef.left + (dxRef - dxResult)/2;
  554. rectCur.right = rectRef.right - (dxRef-dxResult)/2;
  555. rectCur.bottom = rectVbBound.top - (dyVRef-dyResult)/2;
  556. rectCur.top = rectCur.bottom - dyResult;
  557. }
  558. }
  559. ptTemp.x = rectCur.left;
  560. ptTemp.y = rectCur.top;
  561. MapWindowPoints(HWND_DESKTOP,
  562. hwndRef,
  563. &ptTemp,
  564. 1);
  565. rectCur.left = ptTemp.x;
  566. rectCur.top = ptTemp.y;
  567. ptTemp.x = rectCur.right;
  568. ptTemp.y = rectCur.bottom;
  569. MapWindowPoints(HWND_DESKTOP,
  570. hwndRef,
  571. &ptTemp,
  572. 1);
  573. rectCur.right = ptTemp.x;
  574. rectCur.bottom = ptTemp.y;
  575. //For mirrored build
  576. //
  577. if ( rectCur.right < rectCur.left )
  578. {
  579. int tmp;
  580. tmp = rectCur.right;
  581. rectCur.right = rectCur.left;
  582. rectCur.left = tmp;
  583. }
  584. SetWindowPos(
  585. hwnd,
  586. NULL,
  587. rectCur.left,
  588. rectCur.top,
  589. rectCur.right - rectCur.left + 1,
  590. rectCur.bottom - rectCur.top +1,
  591. SWP_NOZORDER);
  592. }
  593. }
  594. }
  595. VOID
  596. CancelOwnedWindows(
  597. IN HWND hwnd )
  598. /* Sends WM_COMMAND(IDCANCEL) to all windows that are owned by 'hwnd' in
  599. ** the current thread.
  600. */
  601. {
  602. EnumThreadWindows( GetCurrentThreadId(),
  603. CloseOwnedWindowsEnumProc, (LPARAM )hwnd );
  604. }
  605. BOOL CALLBACK
  606. CancelOwnedWindowsEnumProc(
  607. IN HWND hwnd,
  608. IN LPARAM lparam )
  609. /* Standard Win32 EnumThreadWindowsWndProc used by CancelOwnedWindows.
  610. */
  611. {
  612. HWND hwndThis;
  613. for (hwndThis = GetParent( hwnd );
  614. hwndThis;
  615. hwndThis = GetParent( hwndThis ))
  616. {
  617. if (hwndThis == (HWND )lparam)
  618. {
  619. FORWARD_WM_COMMAND(
  620. hwnd, IDCANCEL, NULL, 0, SendMessage );
  621. break;
  622. }
  623. }
  624. return TRUE;
  625. }
  626. VOID
  627. CloseOwnedWindows(
  628. IN HWND hwnd )
  629. /* Sends WM_CLOSE to all windows that are owned by 'hwnd' in the current
  630. ** thread.
  631. */
  632. {
  633. EnumThreadWindows( GetCurrentThreadId(),
  634. CloseOwnedWindowsEnumProc, (LPARAM )hwnd );
  635. }
  636. BOOL CALLBACK
  637. CloseOwnedWindowsEnumProc(
  638. IN HWND hwnd,
  639. IN LPARAM lparam )
  640. /* Standard Win32 EnumThreadWindowsWndProc used by CloseOwnedWindows.
  641. */
  642. {
  643. HWND hwndThis;
  644. for (hwndThis = GetParent( hwnd );
  645. hwndThis;
  646. hwndThis = GetParent( hwndThis ))
  647. {
  648. if (hwndThis == (HWND )lparam)
  649. {
  650. SendMessage( hwnd, WM_CLOSE, 0, 0 );
  651. break;
  652. }
  653. }
  654. return TRUE;
  655. }
  656. INT
  657. ComboBox_AddItem(
  658. IN HWND hwndLb,
  659. IN LPCTSTR pszText,
  660. IN VOID* pItem )
  661. /* Adds data item 'pItem' with displayed text 'pszText' to listbox
  662. ** 'hwndLb'. The item is added sorted if the listbox has LBS_SORT style,
  663. ** or to the end of the list otherwise. If the listbox has LB_HASSTRINGS
  664. ** style, 'pItem' is a null terminated string, otherwise it is any user
  665. ** defined data.
  666. **
  667. ** Returns the index of the item in the list or negative if error.
  668. */
  669. {
  670. INT nIndex;
  671. nIndex = ComboBox_AddString( hwndLb, pszText );
  672. if (nIndex >= 0)
  673. ComboBox_SetItemData( hwndLb, nIndex, pItem );
  674. return nIndex;
  675. }
  676. INT
  677. ComboBox_AddItemFromId(
  678. IN HINSTANCE hinstance,
  679. IN HWND hwndLb,
  680. IN DWORD dwStringId,
  681. IN VOID* pItem )
  682. /* Adds data item 'pItem' to listbox 'hwndLb'. 'dwStringId' is the string
  683. ** ID of the item's displayed text. 'Hinstance' is the app or module
  684. ** instance handle.
  685. **
  686. ** Returns the index of the item in the list or negative if error.
  687. */
  688. {
  689. INT i;
  690. LPCTSTR psz;
  691. psz = PszLoadString( hinstance, dwStringId );
  692. if (psz)
  693. {
  694. i = ComboBox_AddItem( hwndLb, psz, pItem );
  695. }
  696. else
  697. {
  698. i = LB_ERRSPACE;
  699. }
  700. return i;
  701. }
  702. INT
  703. ComboBox_AddItemSorted(
  704. IN HWND hwndLb,
  705. IN LPCTSTR pszText,
  706. IN VOID* pItem )
  707. /* Adds data item 'pItem' with displayed text 'pszText' to listbox
  708. ** 'hwndLb' in order sorted by 'pszText'. It is assumed all items added
  709. ** to the list to this point are sorted. If the listbox has LB_HASSTRINGS
  710. ** style, 'pItem' is a null terminated string, otherwise it is any user
  711. ** defined data.
  712. **
  713. ** Returns the index of the item in the list or negative if error.
  714. */
  715. {
  716. INT nIndex;
  717. INT i;
  718. INT c;
  719. c = ComboBox_GetCount( hwndLb );
  720. for (i = 0; i < c; ++i)
  721. {
  722. TCHAR* psz;
  723. psz = ComboBox_GetPsz( hwndLb, i );
  724. if (psz)
  725. {
  726. if (lstrcmp( pszText, psz ) < 0)
  727. break;
  728. Free( psz );
  729. }
  730. }
  731. if (i >= c)
  732. i = -1;
  733. nIndex = ComboBox_InsertString( hwndLb, i, pszText );
  734. if (nIndex >= 0)
  735. ComboBox_SetItemData( hwndLb, nIndex, pItem );
  736. return nIndex;
  737. }
  738. VOID
  739. ComboBox_AutoSizeDroppedWidth(
  740. IN HWND hwndLb )
  741. /* Set the width of the drop-down list 'hwndLb' to the width of the
  742. ** longest item (or the width of the list box if that's wider).
  743. */
  744. {
  745. HDC hdc;
  746. HFONT hfont;
  747. TCHAR* psz;
  748. SIZE size;
  749. DWORD cch;
  750. DWORD dxNew;
  751. DWORD i;
  752. hfont = (HFONT )SendMessage( hwndLb, WM_GETFONT, 0, 0 );
  753. if (!hfont)
  754. return;
  755. hdc = GetDC( hwndLb );
  756. if (!hdc)
  757. return;
  758. SelectObject( hdc, hfont );
  759. dxNew = 0;
  760. for (i = 0; psz = ComboBox_GetPsz( hwndLb, i ); ++i)
  761. {
  762. cch = lstrlen( psz );
  763. if (GetTextExtentPoint32( hdc, psz, cch, &size ))
  764. {
  765. if (dxNew < (DWORD )size.cx)
  766. dxNew = (DWORD )size.cx;
  767. }
  768. Free( psz );
  769. }
  770. ReleaseDC( hwndLb, hdc );
  771. /* Allow for the spacing on left and right added by the control.
  772. */
  773. dxNew += 6;
  774. /* Figure out if the vertical scrollbar will be displayed and, if so,
  775. ** allow for it's width.
  776. */
  777. {
  778. RECT rectD;
  779. RECT rectU;
  780. DWORD dyItem;
  781. DWORD cItemsInDrop;
  782. DWORD cItemsInList;
  783. GetWindowRect( hwndLb, &rectU );
  784. SendMessage( hwndLb, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM )&rectD );
  785. dyItem = (DWORD)SendMessage( hwndLb, CB_GETITEMHEIGHT, 0, 0 );
  786. cItemsInDrop = (rectD.bottom - rectU.bottom) / dyItem;
  787. cItemsInList = ComboBox_GetCount( hwndLb );
  788. if (cItemsInDrop < cItemsInList)
  789. dxNew += GetSystemMetrics( SM_CXVSCROLL );
  790. }
  791. SendMessage( hwndLb, CB_SETDROPPEDWIDTH, dxNew, 0 );
  792. }
  793. #if 0
  794. VOID
  795. ComboBox_FillFromPszList(
  796. IN HWND hwndLb,
  797. IN DTLLIST* pdtllistPsz )
  798. /* Loads 'hwndLb' with an item form each node in the list strings,
  799. ** 'pdtllistPsz'.
  800. */
  801. {
  802. DTLNODE* pNode;
  803. if (!pdtllistPsz)
  804. return;
  805. for (pNode = DtlGetFirstNode( pdtllistPsz );
  806. pNode;
  807. pNode = DtlGetNextNode( pNode ))
  808. {
  809. TCHAR* psz;
  810. psz = (TCHAR* )DtlGetData( pNode );
  811. ASSERT(psz);
  812. ComboBox_AddString( hwndLb, psz );
  813. }
  814. }
  815. #endif
  816. VOID*
  817. ComboBox_GetItemDataPtr(
  818. IN HWND hwndLb,
  819. IN INT nIndex )
  820. /* Returns the address of the 'nIndex'th item context in 'hwndLb' or NULL
  821. ** if none.
  822. */
  823. {
  824. LRESULT lResult;
  825. if (nIndex < 0)
  826. return NULL;
  827. lResult = ComboBox_GetItemData( hwndLb, nIndex );
  828. if (lResult < 0)
  829. return NULL;
  830. return (VOID* )lResult;
  831. }
  832. TCHAR*
  833. ComboBox_GetPsz(
  834. IN HWND hwnd,
  835. IN INT nIndex )
  836. /* Returns heap block containing the text contents of the 'nIndex'th item
  837. ** of combo box 'hwnd' or NULL. It is caller's responsibility to Free the
  838. ** returned string.
  839. */
  840. {
  841. INT cch;
  842. TCHAR* psz;
  843. cch = ComboBox_GetLBTextLen( hwnd, nIndex );
  844. if (cch < 0)
  845. return NULL;
  846. psz = Malloc( (cch + 1) * sizeof(TCHAR) );
  847. if (psz)
  848. {
  849. *psz = TEXT('\0');
  850. ComboBox_GetLBText( hwnd, nIndex, psz );
  851. }
  852. return psz;
  853. }
  854. VOID
  855. ComboBox_SetCurSelNotify(
  856. IN HWND hwndLb,
  857. IN INT nIndex )
  858. /* Set selection in listbox 'hwndLb' to 'nIndex' and notify parent as if
  859. ** user had clicked the item which Windows doesn't do for some reason.
  860. */
  861. {
  862. ComboBox_SetCurSel( hwndLb, nIndex );
  863. SendMessage(
  864. GetParent( hwndLb ),
  865. WM_COMMAND,
  866. (WPARAM )MAKELONG(
  867. (WORD )GetDlgCtrlID( hwndLb ), (WORD )CBN_SELCHANGE ),
  868. (LPARAM )hwndLb );
  869. }
  870. TCHAR*
  871. Ellipsisize(
  872. IN HDC hdc,
  873. IN TCHAR* psz,
  874. IN INT dxColumn,
  875. IN INT dxColText OPTIONAL )
  876. /* Returns a heap string containing the 'psz' shortened to fit in the
  877. ** given width, if necessary, by truncating and adding "...". 'Hdc' is the
  878. ** device context with the appropiate font selected. 'DxColumn' is the
  879. ** width of the column. It is caller's responsibility to Free the
  880. ** returned string.
  881. */
  882. {
  883. const TCHAR szDots[] = TEXT("...");
  884. SIZE size;
  885. TCHAR* pszResult;
  886. TCHAR* pszResultLast;
  887. TCHAR* pszResult2nd;
  888. DWORD cch;
  889. cch = lstrlen( psz );
  890. pszResult = Malloc( (cch * sizeof(TCHAR)) + sizeof(szDots) );
  891. if (!pszResult)
  892. return NULL;
  893. lstrcpy( pszResult, psz );
  894. dxColumn -= dxColText;
  895. if (dxColumn <= 0)
  896. {
  897. /* None of the column text will be visible so bag the calculations and
  898. ** just return the original string.
  899. */
  900. return pszResult;
  901. }
  902. if (!GetTextExtentPoint32( hdc, pszResult, cch, &size ))
  903. {
  904. Free( pszResult );
  905. return NULL;
  906. }
  907. pszResult2nd = CharNext( pszResult );
  908. pszResultLast = pszResult + cch;
  909. while (size.cx > dxColumn && pszResultLast > pszResult2nd)
  910. {
  911. /* Doesn't fit. Lop off a character, add the ellipsis, and try again.
  912. ** The minimum result is "..." for empty original or "x..." for
  913. ** non-empty original.
  914. */
  915. pszResultLast = CharPrev( pszResult2nd, pszResultLast );
  916. lstrcpy( pszResultLast, szDots );
  917. if (!GetTextExtentPoint( hdc, pszResult, lstrlen( pszResult ), &size ))
  918. {
  919. Free( pszResult );
  920. return NULL;
  921. }
  922. }
  923. return pszResult;
  924. }
  925. VOID
  926. ExpandWindow(
  927. IN HWND hwnd,
  928. IN LONG dx,
  929. IN LONG dy )
  930. /* Expands window 'hwnd' 'dx' pels to the right and 'dy' pels down from
  931. ** it's current size.
  932. */
  933. {
  934. RECT rect;
  935. GetWindowRect( hwnd, &rect );
  936. SetWindowPos( hwnd, NULL,
  937. 0, 0, rect.right - rect.left + dx, rect.bottom - rect.top + dy,
  938. SWP_NOMOVE + SWP_NOZORDER );
  939. }
  940. TCHAR*
  941. GetText(
  942. IN HWND hwnd )
  943. /* Returns heap block containing the text contents of the window 'hwnd' or
  944. ** NULL. It is caller's responsibility to Free the returned string.
  945. */
  946. {
  947. INT cch;
  948. TCHAR* psz;
  949. cch = GetWindowTextLength( hwnd );
  950. psz = Malloc( (cch + 1) * sizeof(TCHAR) );
  951. if (psz)
  952. {
  953. *psz = TEXT('\0');
  954. GetWindowText( hwnd, psz, cch + 1 );
  955. }
  956. return psz;
  957. }
  958. HWND
  959. HwndFromCursorPos(
  960. IN HINSTANCE hinstance,
  961. IN POINT* ppt OPTIONAL )
  962. /* Returns a "Static" control window created at the specified position
  963. ** (or at the cursor position if NULL is passed in).
  964. ** The window is moved off the desktop using SetOffDesktop()
  965. ** so that it can be specified as the owner window
  966. ** for a popup dialog shown using MsgDlgUtil.
  967. ** The window returned should be destroyed using DestroyWindow().
  968. */
  969. {
  970. HWND hwnd;
  971. POINT pt;
  972. if (ppt) { pt = *ppt; }
  973. else { GetCursorPos(&pt); }
  974. //
  975. // create the window
  976. //
  977. hwnd = CreateWindowEx(
  978. WS_EX_TOOLWINDOW, TEXT("Static"), NULL, WS_POPUP, pt.x, pt.y,
  979. 1, 1, NULL, NULL, hinstance, NULL
  980. );
  981. if (!hwnd) { return NULL; }
  982. //
  983. // move it off the desktop
  984. //
  985. SetOffDesktop(hwnd, SOD_MoveOff, NULL);
  986. ShowWindow(hwnd, SW_SHOW);
  987. return hwnd;
  988. }
  989. LPTSTR
  990. IpGetAddressAsText(
  991. HWND hwndIp )
  992. {
  993. if (SendMessage( hwndIp, IPM_ISBLANK, 0, 0 ))
  994. {
  995. return NULL;
  996. }
  997. else
  998. {
  999. DWORD dwIpAddrHost;
  1000. TCHAR szIpAddr [32];
  1001. SendMessage( hwndIp, IPM_GETADDRESS, 0, (LPARAM)&dwIpAddrHost );
  1002. IpHostAddrToPsz( dwIpAddrHost, szIpAddr );
  1003. return StrDup( szIpAddr );
  1004. }
  1005. }
  1006. void
  1007. IpSetAddressText(
  1008. HWND hwndIp,
  1009. LPCTSTR pszIpAddress )
  1010. {
  1011. if (pszIpAddress)
  1012. {
  1013. DWORD dwIpAddrHost = IpPszToHostAddr( pszIpAddress );
  1014. SendMessage( hwndIp, IPM_SETADDRESS, 0, dwIpAddrHost );
  1015. }
  1016. else
  1017. {
  1018. SendMessage( hwndIp, IPM_CLEARADDRESS, 0, 0 );
  1019. }
  1020. }
  1021. INT
  1022. ListBox_AddItem(
  1023. IN HWND hwndLb,
  1024. IN TCHAR* pszText,
  1025. IN VOID* pItem )
  1026. /* Adds data item 'pItem' with displayed text 'pszText' to listbox
  1027. ** 'hwndLb'. The item is added sorted if the listbox has LBS_SORT style,
  1028. ** or to the end of the list otherwise. If the listbox has LB_HASSTRINGS
  1029. ** style, 'pItem' is a null terminated string, otherwise it is any user
  1030. ** defined data.
  1031. **
  1032. ** Returns the index of the item in the list or negative if error.
  1033. */
  1034. {
  1035. INT nIndex;
  1036. nIndex = ListBox_AddString( hwndLb, pszText );
  1037. if (nIndex >= 0)
  1038. ListBox_SetItemData( hwndLb, nIndex, pItem );
  1039. return nIndex;
  1040. }
  1041. TCHAR*
  1042. ListBox_GetPsz(
  1043. IN HWND hwnd,
  1044. IN INT nIndex )
  1045. /* Returns heap block containing the text contents of the 'nIndex'th item
  1046. ** of list box 'hwnd' or NULL. It is caller's responsibility to Free the
  1047. ** returned string.
  1048. */
  1049. {
  1050. INT cch;
  1051. TCHAR* psz;
  1052. cch = ListBox_GetTextLen( hwnd, nIndex );
  1053. psz = Malloc( (cch + 1) * sizeof(TCHAR) );
  1054. if (psz)
  1055. {
  1056. *psz = TEXT('\0');
  1057. ListBox_GetText( hwnd, nIndex, psz );
  1058. }
  1059. return psz;
  1060. }
  1061. INT
  1062. ListBox_IndexFromString(
  1063. IN HWND hwnd,
  1064. IN TCHAR* psz )
  1065. /* Returns the index of the item in string list 'hwnd' that matches 'psz'
  1066. ** or -1 if not found. Unlike, ListBox_FindStringExact, this compare in
  1067. ** case sensitive.
  1068. */
  1069. {
  1070. INT i;
  1071. INT c;
  1072. c = ListBox_GetCount( hwnd );
  1073. for (i = 0; i < c; ++i)
  1074. {
  1075. TCHAR* pszThis;
  1076. pszThis = ListBox_GetPsz( hwnd, i );
  1077. if (pszThis)
  1078. {
  1079. BOOL f;
  1080. f = (lstrcmp( psz, pszThis ) == 0);
  1081. Free( pszThis );
  1082. if (f)
  1083. return i;
  1084. }
  1085. }
  1086. return -1;
  1087. }
  1088. VOID
  1089. ListBox_SetCurSelNotify(
  1090. IN HWND hwndLb,
  1091. IN INT nIndex )
  1092. /* Set selection in listbox 'hwndLb' to 'nIndex' and notify parent as if
  1093. ** user had clicked the item which Windows doesn't do for some reason.
  1094. */
  1095. {
  1096. ListBox_SetCurSel( hwndLb, nIndex );
  1097. SendMessage(
  1098. GetParent( hwndLb ),
  1099. WM_COMMAND,
  1100. (WPARAM )MAKELONG(
  1101. (WORD )GetDlgCtrlID( hwndLb ), (WORD )LBN_SELCHANGE ),
  1102. (LPARAM )hwndLb );
  1103. }
  1104. VOID*
  1105. ListView_GetParamPtr(
  1106. IN HWND hwndLv,
  1107. IN INT iItem )
  1108. /* Returns the lParam address of the 'iItem' item in 'hwndLv' or NULL if
  1109. ** none or error.
  1110. */
  1111. {
  1112. LV_ITEM item;
  1113. ZeroMemory( &item, sizeof(item) );
  1114. item.mask = LVIF_PARAM;
  1115. item.iItem = iItem;
  1116. if (!ListView_GetItem( hwndLv, &item ))
  1117. return NULL;
  1118. return (VOID* )item.lParam;
  1119. }
  1120. VOID*
  1121. ListView_GetSelectedParamPtr(
  1122. IN HWND hwndLv )
  1123. /* Returns the lParam address of the first selected item in 'hwndLv' or
  1124. ** NULL if none or error.
  1125. */
  1126. {
  1127. INT iSel;
  1128. LV_ITEM item;
  1129. iSel = ListView_GetNextItem( hwndLv, -1, LVNI_SELECTED );
  1130. if (iSel < 0)
  1131. return NULL;
  1132. return ListView_GetParamPtr( hwndLv, iSel );
  1133. }
  1134. VOID
  1135. ListView_InsertSingleAutoWidthColumn(
  1136. HWND hwndLv )
  1137. // Insert a single auto-sized column into listview 'hwndLv', e.g. for a
  1138. // list of checkboxes with no visible column header.
  1139. //
  1140. {
  1141. LV_COLUMN col;
  1142. ZeroMemory( &col, sizeof(col) );
  1143. col.mask = LVCF_FMT;
  1144. col.fmt = LVCFMT_LEFT;
  1145. ListView_InsertColumn( hwndLv, 0, &col );
  1146. ListView_SetColumnWidth( hwndLv, 0, LVSCW_AUTOSIZE );
  1147. }
  1148. BOOL
  1149. ListView_SetParamPtr(
  1150. IN HWND hwndLv,
  1151. IN INT iItem,
  1152. IN VOID* pParam )
  1153. /* Set the lParam address of the 'iItem' item in 'hwndLv' to 'pParam'.
  1154. ** Return true if successful, false otherwise.
  1155. */
  1156. {
  1157. LV_ITEM item;
  1158. ZeroMemory( &item, sizeof(item) );
  1159. item.mask = LVIF_PARAM;
  1160. item.iItem = iItem;
  1161. item.lParam = (LPARAM )pParam;
  1162. return ListView_SetItem( hwndLv, &item );
  1163. }
  1164. VOID
  1165. Menu_CreateAccelProxies(
  1166. IN HINSTANCE hinst,
  1167. IN HWND hwndParent,
  1168. IN DWORD dwMid )
  1169. /* Causes accelerators on a popup menu to choose menu commands when the
  1170. ** popup menu is not dropped down. 'Hinst' is the app/dll instance.
  1171. ** 'HwndParent' is the window that receives the popup menu command
  1172. ** messages. 'DwMid' is the menu ID of the menu bar containing the popup
  1173. ** menu.
  1174. */
  1175. {
  1176. #define MCF_cbBuf 512
  1177. HMENU hmenuBar;
  1178. HMENU hmenuPopup;
  1179. TCHAR szBuf[ MCF_cbBuf ];
  1180. MENUITEMINFO item;
  1181. INT i;
  1182. hmenuBar = LoadMenu( hinst, MAKEINTRESOURCE( dwMid ) );
  1183. ASSERT(hmenuBar);
  1184. hmenuPopup = GetSubMenu( hmenuBar, 0 );
  1185. ASSERT(hmenuPopup);
  1186. /* Loop thru menu items on the popup menu.
  1187. */
  1188. for (i = 0; TRUE; ++i)
  1189. {
  1190. ZeroMemory( &item, sizeof(item) );
  1191. item.cbSize = sizeof(item);
  1192. item.fMask = MIIM_TYPE + MIIM_ID;
  1193. item.dwTypeData = szBuf;
  1194. item.cch = MCF_cbBuf;
  1195. if (!GetMenuItemInfo( hmenuPopup, i, TRUE, &item ))
  1196. break;
  1197. if (item.fType != MFT_STRING)
  1198. continue;
  1199. /* Create an off-screen button on the parent with the same ID and
  1200. ** text as the menu item.
  1201. */
  1202. CreateWindow( TEXT("button"), szBuf, WS_CHILD,
  1203. 30000, 30000, 0, 0, hwndParent, (HMENU )UlongToPtr(item.wID), hinst, NULL );
  1204. }
  1205. DestroyMenu( hmenuBar );
  1206. }
  1207. VOID
  1208. ScreenToClientRect(
  1209. IN HWND hwnd,
  1210. IN OUT RECT* pRect )
  1211. /* Converts '*pRect' from screen to client coordinates of 'hwnd'.
  1212. */
  1213. {
  1214. POINT xyUL;
  1215. POINT xyBR;
  1216. xyUL.x = pRect->left;
  1217. xyUL.y = pRect->top;
  1218. xyBR.x = pRect->right;
  1219. xyBR.y = pRect->bottom;
  1220. ScreenToClient( hwnd, &xyUL );
  1221. ScreenToClient( hwnd, &xyBR );
  1222. pRect->left = xyUL.x;
  1223. pRect->top = xyUL.y;
  1224. pRect->right = xyBR.x;
  1225. pRect->bottom = xyBR.y;
  1226. }
  1227. BOOL
  1228. SetOffDesktop(
  1229. IN HWND hwnd,
  1230. IN DWORD dwAction,
  1231. OUT RECT* prectOrg )
  1232. /* Move 'hwnd' back and forth from the visible desktop to the area
  1233. ** off-screen. Use this when you want to "hide" your owner window without
  1234. ** hiding yourself which Windows automatically does.
  1235. **
  1236. ** 'dwAction' describes the action to take:
  1237. ** SOD_Moveoff: Move 'hwnd' off the desktop.
  1238. ** SOD_MoveBackFree: Undo SOD_MoveOff.
  1239. ** SOD_GetOrgRect: Retrieves original 'hwnd' position.
  1240. ** SOD_Free: Free SOD_MoveOff context without restoring.
  1241. ** SOD_MoveBackHidden: Move window back, but hidden so you can call
  1242. ** routines that internally query the position
  1243. ** of the window. Undo with SOD_Moveoff.
  1244. **
  1245. ** '*prectOrg' is set to the original window position when 'dwAction' is
  1246. ** SOD_GetOrgRect. Otherwise, it is ignored, and may be NULL.
  1247. **
  1248. ** Returns true if the window has a SODINFO context, false otherwise.
  1249. */
  1250. {
  1251. SODINFO* pInfo;
  1252. TRACE2("SetOffDesktop(h=$%08x,a=%d)",hwnd,dwAction);
  1253. if (!g_SodContextId)
  1254. {
  1255. g_SodContextId = (LPCTSTR )GlobalAddAtom( TEXT("RASSETOFFDESKTOP") );
  1256. if (!g_SodContextId)
  1257. return FALSE;
  1258. }
  1259. pInfo = (SODINFO* )GetProp( hwnd, g_SodContextId );
  1260. if (dwAction == SOD_MoveOff)
  1261. {
  1262. if (pInfo)
  1263. {
  1264. /* Caller is undoing a SOD_MoveBackHidden.
  1265. */
  1266. SetWindowPos( hwnd, NULL,
  1267. pInfo->rectOrg.left, GetSystemMetrics( SM_CYSCREEN ),
  1268. 0, 0, SWP_NOSIZE + SWP_NOZORDER );
  1269. if (pInfo->fWeMadeInvisible)
  1270. {
  1271. ShowWindow( hwnd, SW_SHOW );
  1272. pInfo->fWeMadeInvisible = FALSE;
  1273. }
  1274. }
  1275. else
  1276. {
  1277. BOOL f;
  1278. pInfo = (SODINFO* )Malloc( sizeof(SODINFO) );
  1279. if (!pInfo)
  1280. return FALSE;
  1281. f = IsWindowVisible( hwnd );
  1282. if (!f)
  1283. ShowWindow( hwnd, SW_HIDE );
  1284. GetWindowRect( hwnd, &pInfo->rectOrg );
  1285. SetWindowPos( hwnd, NULL, pInfo->rectOrg.left,
  1286. GetSystemMetrics( SM_CYSCREEN ),
  1287. 0, 0, SWP_NOSIZE + SWP_NOZORDER );
  1288. if (!f)
  1289. ShowWindow( hwnd, SW_SHOW );
  1290. pInfo->fWeMadeInvisible = FALSE;
  1291. SetProp( hwnd, g_SodContextId, pInfo );
  1292. }
  1293. }
  1294. else if (dwAction == SOD_MoveBackFree || dwAction == SOD_Free)
  1295. {
  1296. if (pInfo)
  1297. {
  1298. if (dwAction == SOD_MoveBackFree)
  1299. {
  1300. SetWindowPos( hwnd, NULL,
  1301. pInfo->rectOrg.left, pInfo->rectOrg.top, 0, 0,
  1302. SWP_NOSIZE + SWP_NOZORDER );
  1303. }
  1304. Free( pInfo );
  1305. RemoveProp( hwnd, g_SodContextId );
  1306. }
  1307. return FALSE;
  1308. }
  1309. else if (dwAction == SOD_GetOrgRect)
  1310. {
  1311. if (!pInfo)
  1312. return FALSE;
  1313. *prectOrg = pInfo->rectOrg;
  1314. }
  1315. else
  1316. {
  1317. ASSERT(dwAction==SOD_MoveBackHidden);
  1318. if (!pInfo)
  1319. return FALSE;
  1320. if (IsWindowVisible( hwnd ))
  1321. {
  1322. ShowWindow( hwnd, SW_HIDE );
  1323. pInfo->fWeMadeInvisible = TRUE;
  1324. }
  1325. SetWindowPos( hwnd, NULL,
  1326. pInfo->rectOrg.left, pInfo->rectOrg.top, 0, 0,
  1327. SWP_NOSIZE + SWP_NOZORDER );
  1328. }
  1329. return TRUE;
  1330. }
  1331. BOOL
  1332. SetDlgItemNum(
  1333. IN HWND hwndDlg,
  1334. IN INT iDlgItem,
  1335. IN UINT uValue )
  1336. /* Similar to SetDlgItemInt, but this function uses commas (or the
  1337. ** locale-specific separator) to delimit thousands
  1338. */
  1339. {
  1340. DWORD dwSize;
  1341. TCHAR szNumber[32];
  1342. dwSize = 30;
  1343. GetNumberString(uValue, szNumber, &dwSize);
  1344. return SetDlgItemText(hwndDlg, iDlgItem, szNumber);
  1345. }
  1346. BOOL
  1347. SetEvenTabWidths(
  1348. IN HWND hwndDlg,
  1349. IN DWORD cPages )
  1350. /* Set the tabs on property sheet 'hwndDlg' to have even fixed width.
  1351. ** 'cPages' is the number of pages on the property sheet.
  1352. **
  1353. ** Returns true if successful, false if any of the tabs requires more than
  1354. ** the fixed width in which case the call has no effect.
  1355. */
  1356. {
  1357. HWND hwndTab;
  1358. LONG lStyle;
  1359. RECT rect;
  1360. INT dxFixed;
  1361. /* The tab control uses hard-coded 1-inch tabs when you set FIXEDWIDTH
  1362. ** style while we want the tabs to fill the page, so we figure out the
  1363. ** correct width ourselves. For some reason, without a fudge-factor (the
  1364. ** -10) the expansion does not fit on a single line. The factor
  1365. ** absolutely required varies between large and small fonts and the number
  1366. ** of tabs does not seem to be a factor.
  1367. */
  1368. hwndTab = PropSheet_GetTabControl( hwndDlg );
  1369. GetWindowRect( hwndTab, &rect );
  1370. dxFixed = (rect.right - rect.left - 10 ) / cPages;
  1371. while (cPages > 0)
  1372. {
  1373. RECT rectTab;
  1374. --cPages;
  1375. if (!TabCtrl_GetItemRect( hwndTab, cPages, &rectTab )
  1376. || dxFixed < rectTab.right - rectTab.left)
  1377. {
  1378. /* This tab requires more than the fixed width. Since the fixed
  1379. ** width is unworkable do nothing.
  1380. */
  1381. return FALSE;
  1382. }
  1383. }
  1384. TabCtrl_SetItemSize( hwndTab, dxFixed, 0 );
  1385. lStyle = GetWindowLong( hwndTab, GWL_STYLE );
  1386. SetWindowLong( hwndTab, GWL_STYLE, lStyle | TCS_FIXEDWIDTH );
  1387. return TRUE;
  1388. }
  1389. HFONT
  1390. SetFont(
  1391. HWND hwndCtrl,
  1392. TCHAR* pszFaceName,
  1393. BYTE bfPitchAndFamily,
  1394. INT nPointSize,
  1395. BOOL fUnderline,
  1396. BOOL fStrikeout,
  1397. BOOL fItalic,
  1398. BOOL fBold )
  1399. /* Sets font of control 'hwndCtrl' to a font matching the specified
  1400. ** attributes. See LOGFONT documentation.
  1401. **
  1402. ** Returns the HFONT of the created font if successful or NULL. Caller
  1403. ** should DeleteObject the returned HFONT when the control is destroyed.
  1404. */
  1405. {
  1406. LOGFONT logfont;
  1407. INT nPelsPerInch;
  1408. HFONT hfont;
  1409. {
  1410. HDC hdc = GetDC( NULL );
  1411. if (hdc == NULL)
  1412. {
  1413. return NULL;
  1414. }
  1415. nPelsPerInch = GetDeviceCaps( hdc, LOGPIXELSY );
  1416. ReleaseDC( NULL, hdc );
  1417. }
  1418. ZeroMemory( &logfont, sizeof(logfont) );
  1419. logfont.lfHeight = -MulDiv( nPointSize, nPelsPerInch, 72 );
  1420. {
  1421. DWORD cp;
  1422. CHARSETINFO csi;
  1423. cp = GetACP();
  1424. if (TranslateCharsetInfo( &cp, &csi, TCI_SRCCODEPAGE ))
  1425. logfont.lfCharSet = (UCHAR)csi.ciCharset;
  1426. else
  1427. logfont.lfCharSet = ANSI_CHARSET;
  1428. }
  1429. logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  1430. logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  1431. logfont.lfQuality = DEFAULT_QUALITY;
  1432. logfont.lfPitchAndFamily = bfPitchAndFamily;
  1433. lstrcpy( logfont.lfFaceName, pszFaceName );
  1434. logfont.lfUnderline = (BYTE)fUnderline;
  1435. logfont.lfStrikeOut = (BYTE)fStrikeout;
  1436. logfont.lfItalic = (BYTE)fItalic;
  1437. logfont.lfWeight = (fBold) ? FW_BOLD : FW_NORMAL;
  1438. hfont = CreateFontIndirect( &logfont );
  1439. if (hfont)
  1440. {
  1441. SendMessage( hwndCtrl,
  1442. WM_SETFONT, (WPARAM )hfont, MAKELPARAM( TRUE, 0 ) );
  1443. }
  1444. return hfont;
  1445. }
  1446. VOID
  1447. SlideWindow(
  1448. IN HWND hwnd,
  1449. IN HWND hwndParent,
  1450. IN LONG dx,
  1451. IN LONG dy )
  1452. /* Moves window 'hwnd' 'dx' pels right and 'dy' pels down from it's
  1453. ** current position. 'HwndParent' is the handle of 'hwnd's parent or NULL
  1454. ** if 'hwnd' is not a child window.
  1455. */
  1456. {
  1457. RECT rect;
  1458. POINT xy;
  1459. GetWindowRect( hwnd, &rect );
  1460. xy.x = rect.left;
  1461. xy.y = rect.top;
  1462. if (GetParent( hwnd ))
  1463. {
  1464. /*
  1465. * For mirrored parents we us the right point not the left.
  1466. */
  1467. if (GetWindowLongPtr(GetParent( hwnd ), GWL_EXSTYLE) & WS_EX_LAYOUTRTL) {
  1468. xy.x = rect.right;
  1469. }
  1470. ScreenToClient( hwndParent, &xy );
  1471. }
  1472. SetWindowPos( hwnd, NULL,
  1473. xy.x + dx, xy.y + dy, 0, 0,
  1474. SWP_NOSIZE + SWP_NOZORDER );
  1475. }
  1476. VOID
  1477. UnclipWindow(
  1478. IN HWND hwnd )
  1479. /* Moves window 'hwnd' so any clipped parts are again visible on the
  1480. ** screen. The window is moved only as far as necessary to achieve this.
  1481. */
  1482. {
  1483. RECT rect;
  1484. INT dxScreen = GetSystemMetrics( SM_CXSCREEN );
  1485. INT dyScreen = GetSystemMetrics( SM_CYSCREEN );
  1486. GetWindowRect( hwnd, &rect );
  1487. if (rect.right > dxScreen)
  1488. rect.left = dxScreen - (rect.right - rect.left);
  1489. if (rect.left < 0)
  1490. rect.left = 0;
  1491. if (rect.bottom > dyScreen)
  1492. rect.top = dyScreen - (rect.bottom - rect.top);
  1493. if (rect.top < 0)
  1494. rect.top = 0;
  1495. SetWindowPos(
  1496. hwnd, NULL,
  1497. rect.left, rect.top, 0, 0,
  1498. SWP_NOZORDER + SWP_NOSIZE );
  1499. }