home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / SAMPLES / DDEML / CLIENT / INFOCTRL.C_ / INFOCTRL.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  23.0 KB  |  687 lines

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