INFOCTRL.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:25k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /***************************************************************************
  11.  *                                                                         *
  12.  *  MODULE      : infoctrl.c                                               *
  13.  *                                                                         *
  14.  *  PURPOSE     : Functions for the infoctrl control class                 *
  15.  *                                                                         *
  16.  ***************************************************************************/
  17. /*
  18.  * INFOCTRL.C
  19.  *
  20.  * This module implements a custom information display control which
  21.  * can present up to 7 seperate strings of information at once and is
  22.  * sizeable and moveable with the mouse.
  23.  */
  24. #include <windows.h>
  25. #include <string.h>
  26. #include <tchar.h>
  27. #include <memory.h>
  28. #include "infoctrl.h"
  29. #include "track.h"
  30. TCHAR szClass[] = TEXT("InfoCtrl_class");
  31. DWORD cCreated = 0;
  32. TCHAR szNULL[] = TEXT("");
  33. INT cxMargin = 0;
  34. INT cyMargin = 0;
  35. HBRUSH hFocusBrush;
  36. LONG  APIENTRY InfoCtrlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  37. VOID MyDrawText(HDC hdc, LPRECT lprc, PTSTR psz, DWORD wFormat);
  38. VOID DrawFocus(HDC hdc, HWND hwnd, DWORD style);
  39. INT CountWindows(HWND hwndParent);
  40. VOID GetCascadeWindowPos(HWND hwndParent, INT  iWindow, LPRECT lprc);
  41. /****************************************************************************
  42.  *                                                                          *
  43.  *  FUNCTION   :                                                            *
  44.  *                                                                          *
  45.  *  PURPOSE    :                                                            *
  46.  *                                                                          *
  47.  *  RETURNS    :                                                            *
  48.  *                                                                          *
  49.  ****************************************************************************/
  50. HWND CreateInfoCtrl(
  51. LPTSTR pszCenter,              // NULL is ok.
  52. INT x,
  53. INT y,
  54. INT cx,
  55. INT cy,
  56. HWND hwndParent,
  57. HANDLE hInst,
  58. LPTSTR pszUL,                // NULLs here are fine.
  59. LPTSTR pszUC,
  60. LPTSTR pszUR,
  61. LPTSTR pszLL,
  62. LPTSTR pszLC,
  63. LPTSTR pszLR,
  64. DWORD  style,
  65. HMENU id,
  66. DWORD dwUser)
  67. {
  68.     INFOCTRL_DATA *picd;
  69.     HWND hwnd;
  70.     if (!cCreated) {
  71.         WNDCLASS wc;
  72.         TEXTMETRIC metrics;
  73.         HDC hdc;
  74.         wc.style = CS_VREDRAW | CS_HREDRAW;
  75.         wc.lpfnWndProc = InfoCtrlWndProc;
  76.         wc.cbClsExtra = 0;
  77.         wc.cbWndExtra = ICCBWNDEXTRA;
  78.         wc.hInstance = hInst;
  79.         wc.hIcon = NULL;
  80.         wc.hCursor = NULL;
  81.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  82.         wc.lpszMenuName =  NULL;
  83.         wc.lpszClassName = szClass;
  84.         RegisterClass(&wc);
  85.         hdc = GetDC(hwndParent);
  86.         GetTextMetrics(hdc, &metrics);
  87.         cyMargin = metrics.tmHeight;
  88.         cxMargin = metrics.tmAveCharWidth * 2;
  89.         ReleaseDC(hwndParent, hdc);
  90.         hFocusBrush = CreateSolidBrush(RGB(0, 0, 255));
  91.     }
  92.     if (!(picd = (INFOCTRL_DATA *)LocalAlloc(LPTR, sizeof(INFOCTRL_DATA))))
  93.         return(FALSE);
  94.     if (pszCenter) {
  95.         picd->pszCenter = (PTSTR)(PTSTR)LocalAlloc(LPTR,
  96.                 (_tcslen(pszCenter) + 1) * sizeof(TCHAR));
  97.         _tcscpy(picd->pszCenter, pszCenter);
  98.     } else {
  99.         picd->pszCenter = NULL;
  100.     }
  101.     if (pszUL) {
  102.         picd->pszUL = (PTSTR)(PTSTR)LocalAlloc(LPTR,
  103.             (_tcslen(pszUL) + 1) * sizeof(TCHAR));
  104.         _tcscpy(picd->pszUL, pszUL);
  105.     } else {
  106.         picd->pszUL = NULL;
  107.     }
  108.     if (pszUC) {
  109.         picd->pszUC = (PTSTR)LocalAlloc(LPTR,
  110.             (_tcslen(pszUC) + 1) * sizeof(TCHAR));
  111.         _tcscpy(picd->pszUC, pszUC);
  112.     } else {
  113.         picd->pszUC = NULL;
  114.     }
  115.     if (pszUR) {
  116.         picd->pszUR = (PTSTR)LocalAlloc(LPTR,
  117.             (_tcslen(pszUR) + 1) * sizeof(TCHAR));
  118.         _tcscpy(picd->pszUR, pszUR);
  119.     } else {
  120.         picd->pszUR = NULL;
  121.     }
  122.     if (pszLL) {
  123.         picd->pszLL = (PTSTR)LocalAlloc(LPTR,
  124.             (_tcslen(pszLL) + 1) * sizeof(TCHAR));
  125.         _tcscpy(picd->pszLL, pszLL);
  126.     } else {
  127.         picd->pszLL = NULL;
  128.     }
  129.     if (pszLC) {
  130.         picd->pszLC = (PTSTR)LocalAlloc(LPTR,
  131.             (_tcslen(pszLC) + 1) * sizeof(TCHAR));
  132.         _tcscpy(picd->pszLC, pszLC);
  133.     } else {
  134.         picd->pszLC = NULL;
  135.     }
  136.     if (pszLR) {
  137.         picd->pszLR = (PTSTR)LocalAlloc(LPTR,
  138.             (_tcslen(pszLR) + 1) * sizeof(TCHAR));
  139.         _tcscpy(picd->pszLR, pszLR);
  140.     } else {
  141.         picd->pszLR = NULL;
  142.     }
  143.     picd->style = style;
  144.     picd->hInst = hInst;
  145.     if (hwnd = CreateWindow(szClass, szNULL,
  146.             WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
  147.             x, y, cx, cy, hwndParent, id, hInst, (LPTSTR)picd)) {
  148.         cCreated++;
  149.         SetWindowLong(hwnd, GWL_USER, dwUser);
  150.         BringWindowToTop(hwnd);
  151.         ShowWindow(hwnd, SW_SHOW);
  152.         return(hwnd);
  153.     }
  154.     return(FALSE);
  155. }
  156. /****************************************************************************
  157.  *                                                                          *
  158.  *  FUNCTION   : MyDrawText                                                 *
  159.  *                                                                          *
  160.  *  PURPOSE    : Draws psz within lprc in hdc according to wFormat.         *
  161.  *                                                                          *
  162.  *  RETURNS    : Nothing.                                                   *
  163.  *                                                                          *
  164.  ****************************************************************************/
  165. VOID MyDrawText(
  166. HDC hdc,
  167. LPRECT lprc,
  168. PTSTR psz,
  169. DWORD wFormat)
  170. {
  171.     RECT rc;
  172.     DWORD cx;
  173.     if (psz == NULL || !*psz)
  174.         return; // notin to draw dude.
  175.     SetRect(&rc, 0, 0, 1, 0);
  176.     DrawText(hdc, psz, -1, &rc, DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE);
  177.     cx = min(rc.right - rc.left, lprc->right - lprc->left);
  178.     CopyRect(&rc, lprc);
  179.     switch (wFormat & (DT_LEFT | DT_CENTER | DT_RIGHT)) {
  180.     case DT_LEFT:
  181.         rc.right = rc.left + cx;
  182.         break;
  183.     case DT_CENTER:
  184.         cx = (rc.right - rc.left - cx) / 2;
  185.         rc.right -= cx;
  186.         rc.left += cx;
  187.         break;
  188.     case DT_RIGHT:
  189.         rc.left = rc.right - cx;
  190.         break;
  191.     }
  192.     DrawText(hdc, psz, -1, &rc, wFormat | DT_VCENTER);
  193. }
  194. /****************************************************************************
  195.  *                                                                          *
  196.  *  FUNCTION   : InfoCtrlWndProc                                            *
  197.  *                                                                          *
  198.  *  PURPOSE    : Main window proc for info controls                         *
  199.  *                                                                          *
  200.  *  RETURNS    : case dependent                                             *
  201.  *                                                                          *
  202.  ****************************************************************************/
  203. LONG  APIENTRY InfoCtrlWndProc(
  204. HWND hwnd,
  205. UINT msg,
  206. WPARAM wParam,
  207. LPARAM lParam)
  208. {
  209.     INFOCTRL_DATA *picd;
  210.     INT i;
  211.     RECT rc;
  212.     HDC hdc;
  213.     switch (msg) {
  214.     case WM_CREATE:
  215.         /*
  216.          * Info controls keep their information in the GWL_INFODATA window
  217.          * word.
  218.          */
  219.         SetWindowLong(hwnd, GWL_INFODATA,
  220.                 (DWORD)(DWORD)(((LPCREATESTRUCT)lParam)->lpCreateParams));
  221.         break;
  222.     case WM_SIZE:
  223.         /*
  224.          * size the info control, updating the hittest rectangles.
  225.          * The window is only allowed to get so small.
  226.          */
  227.         if ((short)LOWORD(lParam) < 2 * cxMargin || (short)HIWORD(lParam) < 2 * cyMargin) {
  228.             MoveWindow(hwnd, 0, 0, max((short)LOWORD(lParam), 2 * cxMargin),
  229.                 max((short)HIWORD(lParam), 2 * cyMargin), TRUE);
  230.         } else {
  231.             picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  232.             SetRect(&picd->rcFocusUL, 0, 0, cxMargin, cyMargin);
  233.             SetRect(&picd->rcFocusUR, (short)LOWORD(lParam) - cxMargin, 0,
  234.                     (short)LOWORD(lParam), cyMargin);
  235.             SetRect(&picd->rcFocusLL, 0, (short)HIWORD(lParam) - cyMargin,
  236.                     cxMargin, (INT)HIWORD(lParam));
  237.             SetRect(&picd->rcFocusLR, picd->rcFocusUR.left, picd->rcFocusLL.top,
  238.                     picd->rcFocusUR.right, picd->rcFocusLL.bottom);
  239.         }
  240.         break;
  241.     case WM_DESTROY:
  242.         /*
  243.          * Info control death:
  244.          *
  245.          * Inform out parent - last chance to access GWL_USER.
  246.          * Free our information if it still exists.
  247.          * Free all strings associated with this control.
  248.          */
  249.         {
  250.             PTSTR *ppsz;
  251.             SendMessage(GetParent(hwnd), ICN_BYEBYE, (WPARAM)hwnd,
  252.                     GetWindowLong(hwnd, GWL_USER));
  253.             SetWindowLong(hwnd, GWL_USER, 0);
  254.             picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  255.             if (picd) {
  256.                 ppsz = &picd->pszUL;
  257.                 for (i = 0; i < 5; i++, ppsz++) {
  258.                     if (*ppsz) {
  259.                         LocalUnlock((HANDLE)*ppsz);
  260.                         *ppsz = (PTSTR)LocalFree((HANDLE)*ppsz);
  261.                     }
  262.                 }
  263.                 LocalUnlock((HANDLE)picd);
  264.                 LocalFree((HANDLE)picd);
  265.                 SetWindowLong(hwnd, GWL_INFODATA, 0);
  266.             }
  267.         }
  268.         break;
  269.     case WM_SETFOCUS:
  270.     case WM_KILLFOCUS:
  271.         /*
  272.          * When focus changes:
  273.          *
  274.          * Alter our look apropriately
  275.          * Bring ourselves to the top if necessary.
  276.          * Inform our parent.
  277.          * Repaint the focus portion of ourselves.
  278.          * Call DefWindowProc()
  279.          */
  280.         picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  281.         if (picd != NULL) {
  282.             if (picd->style & ICSTY_SHOWFOCUS) {
  283.                 if (msg == WM_SETFOCUS)
  284.                     picd->style |= ICSTY_HASFOCUS;
  285.                 else
  286.                     picd->style &= ~ICSTY_HASFOCUS;
  287.                 BringWindowToTop(hwnd);
  288.                 // notify parent
  289.                 SendMessage(GetParent(hwnd), ICN_HASFOCUS,
  290.                         msg == WM_SETFOCUS, (LPARAM)hwnd);
  291.             } else {
  292.                 picd->style &= ~ICSTY_HASFOCUS;
  293.             }
  294.             hdc = GetDC(hwnd);
  295.             DrawFocus(hdc, hwnd, picd->style);
  296.             ReleaseDC(hwnd, hdc);
  297.         }
  298.         goto DoDWP;
  299.         break;
  300.     case WM_MOUSEMOVE:
  301.         /*
  302.          * Keep the cursor updated to show sizing or moving state.
  303.          */
  304.         {
  305.             LPTSTR cursor;
  306.             picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  307.             if (picd->style & ICSTY_SHOWFOCUS) {
  308.                 if ((INT)HIWORD(lParam) < cyMargin) {
  309.                     if ((short)LOWORD(lParam) < cxMargin) {
  310.                         cursor = IDC_SIZENWSE;
  311.                     } else if ((short)LOWORD(lParam) > picd->rcFocusUR.left) {
  312.                         cursor = IDC_SIZENESW;
  313.                     } else {
  314.                         cursor = IDC_SIZENS;
  315.                     }
  316.                 } else if ((INT)HIWORD(lParam) > picd->rcFocusLL.top) {
  317.                     if ((short)LOWORD(lParam) < cxMargin) {
  318.                         cursor = IDC_SIZENESW;
  319.                     } else if ((short)LOWORD(lParam) > picd->rcFocusUR.left) {
  320.                         cursor = IDC_SIZENWSE;
  321.                     } else {
  322.                         cursor = IDC_SIZENS;
  323.                     }
  324.                 } else {
  325.                     if ((short)LOWORD(lParam) < cxMargin) {
  326.                         cursor = IDC_SIZEWE;
  327.                     } else if ((short)LOWORD(lParam) > picd->rcFocusUR.left) {
  328.                         cursor = IDC_SIZEWE;
  329.                     } else {
  330.                         cursor = IDC_CROSS;
  331.                     }
  332.                 }
  333.             } else {
  334.                 cursor = IDC_ARROW;
  335.             }
  336.             SetCursor(LoadCursor(NULL, cursor));
  337.         }
  338.         break;
  339.     case WM_LBUTTONDOWN:
  340.         /*
  341.          * Track window according do mouse location.
  342.          */
  343.         picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  344.         if (picd->style & ICSTY_SHOWFOCUS) {
  345.             DWORD fs = 0;
  346.             if (!(picd->style & ICSTY_HASFOCUS)) {
  347.                 SetFocus(hwnd);
  348.             }
  349.             if ((short)HIWORD(lParam) < cyMargin) {
  350.                 fs = TF_TOP;
  351.             } else if ((INT)HIWORD(lParam) > picd->rcFocusLL.top) {
  352.                 fs = TF_BOTTOM;
  353.             }
  354.             if ((short)LOWORD(lParam) < cxMargin) {
  355.                 fs |= TF_LEFT;
  356.             } else if ((short)LOWORD(lParam) > picd->rcFocusUR.left) {
  357.                 fs |= TF_RIGHT;
  358.             } else if (fs == 0) {
  359.                 fs = TF_MOVE;
  360.             }
  361.             GetClientRect(hwnd, &rc);
  362.             ClientToScreen(hwnd, (LPPOINT)&rc.left);
  363.             ClientToScreen(hwnd, (LPPOINT)&rc.right);
  364.             ScreenToClient(GetParent(hwnd), (LPPOINT)&rc.left);
  365.             ScreenToClient(GetParent(hwnd), (LPPOINT)&rc.right);
  366.             if (TrackRect(picd->hInst, GetParent(hwnd),
  367.                     rc.left, rc.top, rc.right, rc.bottom,
  368.                     2 * cxMargin, 2 * cyMargin,
  369.                     fs | TF_ALLINBOUNDARY, &rc)) {
  370.                 MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left,
  371.                         rc.bottom - rc.top, TRUE);
  372.             }
  373.         }
  374.         break;
  375.     case ICM_SETSTRING:
  376.         /*
  377.          * This message is sent when a info control string value is changeing.
  378.          *
  379.          * wParam = ICSID_ constant
  380.          * lParam = new string.
  381.          *
  382.          * If new string is different from old, free old and allocate space
  383.          * for new one and copy in.
  384.          * Redraw invalidated part of info control.
  385.          */
  386.         {
  387.             PTSTR *ppsz;
  388.             picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  389.             ppsz = (PTSTR *)&picd->pszUL + wParam;
  390.             if (lParam == 0)
  391.                 lParam = (DWORD)(LPTSTR)szNULL;
  392.             if (*ppsz) {
  393.                 if (!_tcscmp(*ppsz, (LPTSTR)lParam)) {
  394.                     return 0;
  395.                 }
  396.                 LocalUnlock((HANDLE)*ppsz);
  397.                 *ppsz = (PTSTR)LocalFree((HANDLE)*ppsz);
  398.             }
  399.             if (lParam) {
  400.                 *ppsz = (PTSTR)LocalAlloc(LPTR,
  401.                     (_tcslen((LPTSTR)lParam) + 1) * sizeof(TCHAR));
  402.                 _tcscpy((LPTSTR)*ppsz, (LPTSTR)lParam);
  403.             }
  404.             GetClientRect(hwnd, &rc);
  405.             switch (wParam) {
  406.             case ICSID_UL:
  407.             case ICSID_UC:
  408.             case ICSID_UR:
  409.                 rc.bottom = cyMargin;
  410.                 break;
  411.             case ICSID_LL:
  412.             case ICSID_LC:
  413.             case ICSID_LR:
  414.                 rc.top = rc.bottom - cyMargin;
  415.                 break;
  416.             case ICSID_CENTER:
  417.                 InflateRect(&rc, -cxMargin, -cyMargin);
  418.                 break;
  419.             }
  420.             InvalidateRect(hwnd, &rc, TRUE);
  421.             UpdateWindow(hwnd);
  422.         }
  423.         break;
  424.     case WM_PAINT:
  425.         /*
  426.          * Paint ourselves.
  427.          *
  428.          * Draw frame.
  429.          * Draw info strings.
  430.          * Send ownerdraw message to parent if ICSTY_OWNERDRAW.
  431.          */
  432.         {
  433.             PAINTSTRUCT ps;
  434.             HANDLE brush;
  435.             picd = (INFOCTRL_DATA *)GetWindowLong(hwnd, GWL_INFODATA);
  436.             BeginPaint(hwnd, &ps);
  437.             // erasure should have already been done for us.
  438.             GetClientRect(hwnd, &rc);
  439.             brush = GetStockObject(BLACK_BRUSH);
  440.             InflateRect(&rc, -cxMargin / 2, -cyMargin / 2);
  441.             FrameRect(ps.hdc, &rc, brush);
  442.             InflateRect(&rc, cxMargin / 2, cyMargin / 2);
  443.             SetRect(&rc, picd->rcFocusUL.right, 0, picd->rcFocusUR.left,
  444.                     cyMargin);
  445.             MyDrawText(ps.hdc, &rc, picd->pszUR, DT_RIGHT);
  446.             MyDrawText(ps.hdc, &rc, picd->pszUL, DT_LEFT);
  447.             MyDrawText(ps.hdc, &rc, picd->pszUC, DT_CENTER);
  448.             SetRect(&rc, picd->rcFocusLL.right, picd->rcFocusLL.top,
  449.                     picd->rcFocusLR.left, picd->rcFocusLR.bottom);
  450.             MyDrawText(ps.hdc, &rc, picd->pszLR, DT_RIGHT);
  451.             MyDrawText(ps.hdc, &rc, picd->pszLL, DT_LEFT);
  452.             MyDrawText(ps.hdc, &rc, picd->pszLC, DT_CENTER);
  453.             GetClientRect(hwnd, &rc);
  454.             InflateRect(&rc, -cxMargin, -cyMargin);
  455.             if (picd->style & ICSTY_OWNERDRAW) {
  456.                 OWNERDRAWPS odps;
  457.                 if (IntersectRect(&odps.rcPaint, &rc, &ps.rcPaint)) {
  458.                     if (IntersectClipRect(ps.hdc, rc.left, rc.top, rc.right,
  459.                             rc.bottom) != NULLREGION) {
  460.                         odps.rcBound = rc;
  461.                         odps.hdc = ps.hdc;
  462.                         odps.dwUser = GetWindowLong(hwnd, GWL_USER);
  463.                         SendMessage(GetParent(hwnd), ICN_OWNERDRAW,
  464.                                 GetWindowLong(hwnd, GWL_ID), (DWORD)(LPTSTR)&odps);
  465.                     }
  466.                 }
  467.             } else {
  468.                 MyDrawText(ps.hdc, &rc, picd->pszCenter, DT_LEFT | DT_WORDBREAK | DT_EXPANDTABS);
  469.             }
  470.             DrawFocus(ps.hdc, hwnd, picd->style);
  471.             EndPaint(hwnd, &ps);
  472.         }
  473.         break;
  474. DoDWP:
  475.     default:
  476.         return (DefWindowProc(hwnd, msg, wParam, lParam));
  477.     }
  478.     return (0);
  479. }
  480. /****************************************************************************
  481.  *                                                                          *
  482.  *  FUNCTION   : DrawFocus                                                  *
  483.  *                                                                          *
  484.  *  PURPOSE    : To draw focus part of info control.                        *
  485.  *                                                                          *
  486.  *  RETURNS    : nothing                                                    *
  487.  *                                                                          *
  488.  ****************************************************************************/
  489. VOID DrawFocus(
  490. HDC hdc,
  491. HWND hwnd,
  492. DWORD style)
  493. {
  494.     RECT rc;
  495.     GetClientRect(hwnd, &rc);
  496.     FrameRect(hdc, &rc, style & ICSTY_HASFOCUS ?
  497.             hFocusBrush : GetStockObject(GRAY_BRUSH));
  498. }
  499. /****************************************************************************
  500.  *                                                                          *
  501.  *  FUNCTION   : CountWindows                                               *
  502.  *                                                                          *
  503.  *  PURPOSE    : Counts how many info controls the parent of this window has*
  504.  *                                                                          *
  505.  *  RETURNS    : the count.                                                 *
  506.  *                                                                          *
  507.  ****************************************************************************/
  508. INT CountWindows(
  509. register HWND hwndParent)
  510. {
  511.   INT cWindows = 0;
  512.   register HWND hwnd;
  513.   for (hwnd=GetWindow(hwndParent, GW_CHILD);
  514.         hwnd;
  515.         hwnd= GetWindow(hwnd, GW_HWNDNEXT)) {
  516.       cWindows++;
  517.   }
  518.   return(cWindows);
  519. }
  520. /****************************************************************************
  521.  *                                                                          *
  522.  *  FUNCTION   : GetCascadeWindowPos                                        *
  523.  *                                                                          *
  524.  *  PURPOSE    : Based on a window index and the parent window size,        *
  525.  *               calculates where to place a cascaded window.               *
  526.  *                                                                          *
  527.  *  RETURNS    : rectangle in lprc.                                         *
  528.  *                                                                          *
  529.  ****************************************************************************/
  530. VOID GetCascadeWindowPos(
  531. HWND hwndParent,
  532. INT  iWindow,
  533. LPRECT lprc)
  534. {
  535.   RECT      rc;
  536.   INT       cStack;
  537.   register INT dxClient, dyClient;
  538.   /* Compute the width and breadth of the situation. */
  539.   GetClientRect(hwndParent, (LPRECT)&rc);
  540.   dxClient = rc.right - rc.left;
  541.   dyClient = rc.bottom - rc.top;
  542.   /* How many windows per stack? */
  543.   cStack = dyClient / (3 * cyMargin);
  544.   lprc->right = dxClient - (cStack * cxMargin);
  545.   lprc->bottom = dyClient - (cStack * cyMargin);
  546.   cStack++;             /* HACK!: Mod by cStack+1 */
  547.   lprc->left = (iWindow % cStack) * cxMargin;
  548.   lprc->top = (iWindow % cStack) * cyMargin;
  549. }
  550. /****************************************************************************
  551.  *                                                                          *
  552.  *  FUNCTION   : MyCascadeChildWindows                                      *
  553.  *                                                                          *
  554.  *  PURPOSE    : Cascades all children of a parent window                   *
  555.  *                                                                          *
  556.  *  RETURNS    : nothing                                                    *
  557.  *                                                                          *
  558.  ****************************************************************************/
  559. VOID MyCascadeChildWindows(
  560. register HWND hwndParent)
  561. {
  562.   INT       i;
  563.   INT       cWindows;
  564.   RECT      rc;
  565.   DWORD      wFlags;
  566.   register HWND hwndMove;
  567.   HANDLE    hDefer;
  568.   cWindows = CountWindows(hwndParent);
  569.   if (!cWindows)
  570.       return;
  571.   hwndMove = GetWindow(hwndParent, GW_CHILD);
  572.   hDefer = BeginDeferWindowPos(cWindows);
  573.   for (i=0; i < cWindows; i++) {
  574.       GetCascadeWindowPos(hwndParent, i, (LPRECT)&rc);
  575.       wFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS;
  576.       /* Size the window. */
  577.       hDefer = DeferWindowPos(hDefer,
  578.                  hwndMove, NULL,
  579.                  rc.left, rc.top,
  580.                  rc.right, rc.bottom,
  581.                  wFlags);
  582.       hwndMove = GetWindow(hwndMove, GW_HWNDNEXT);
  583.   }
  584.   EndDeferWindowPos(hDefer);
  585. }
  586. /****************************************************************************
  587.  *                                                                          *
  588.  *  FUNCTION   : TileChildWindows                                           *
  589.  *                                                                          *
  590.  *  PURPOSE    : Tiles all children of a parent window                      *
  591.  *                                                                          *
  592.  *  RETURNS    : nothing.                                                   *
  593.  *                                                                          *
  594.  ****************************************************************************/
  595. VOID TileChildWindows(
  596. register HWND hwndParent)
  597. {
  598.   INT       i;
  599.   INT       dx;
  600.   INT       dy;
  601.   INT       xRes;
  602.   INT       yRes;
  603.   INT       iCol;
  604.   INT       iRow;
  605.   INT       cCols;
  606.   INT       cRows;
  607.   INT       cExtra;
  608.   INT       cWindows;
  609.   register HWND hwndMove;
  610.   RECT      rcClient;
  611.   HANDLE    hDefer;
  612.   DWORD      wFlags;
  613.   cWindows = CountWindows(hwndParent);
  614.   if (!cWindows)
  615.       return;
  616.   /* Compute the smallest nearest square. */
  617.   for (i=2; i * i <= cWindows; i++);
  618.   cRows = i - 1;
  619.   cCols = cWindows / cRows;
  620.   cExtra = cWindows % cRows;
  621.   GetClientRect(hwndParent, (LPRECT)&rcClient);
  622.   xRes = rcClient.right - rcClient.left;
  623.   yRes = rcClient.bottom - rcClient.top;
  624.   if (xRes<=0 || yRes<=0)
  625.       return;
  626.   hwndMove = GetWindow(hwndParent, GW_CHILD);
  627.   hDefer = BeginDeferWindowPos(cWindows);
  628.   for (iCol=0; iCol < cCols; iCol++) {
  629.       if ((cCols-iCol) <= cExtra)
  630.       cRows++;
  631.       for (iRow=0; iRow < cRows; iRow++) {
  632.           dx = xRes / cCols;
  633.           dy = yRes / cRows;
  634.           wFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS;
  635.           /* Position and size the window. */
  636.           hDefer = DeferWindowPos(hDefer, hwndMove, NULL,
  637.                      dx * iCol,
  638.                      dy * iRow,
  639.                      dx,
  640.                      dy,
  641.                      wFlags);
  642.           hwndMove = GetWindow(hwndMove, GW_HWNDNEXT);
  643.       }
  644.       if ((cCols-iCol) <= cExtra) {
  645.           cRows--;
  646.           cExtra--;
  647.       }
  648.   }
  649.   EndDeferWindowPos(hDefer);
  650. }