home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / framctl3.zip / FRAMECTL.C < prev    next >
C/C++ Source or Header  |  1996-10-07  |  53KB  |  1,059 lines

  1. /************************************************************************/
  2. /*                                                                      */
  3. /* Program name:   FrameCtl.C                                           */
  4. /* Title:          A Picture Perfect Control                            */
  5. /*                 OS/2 Magazine - GUI Corner                           */
  6. /*                 December 1996 issue                                  */
  7. /*                                                                      */
  8. /* Author:         Mark Benge   IBM Corp.                               */
  9. /*                 Matt Smith   Prominare Inc.                          */
  10. /*                                                                      */
  11. /* Description:    Illustrates how to add frame control extensions.     */
  12. /*                                                                      */
  13. /* DISCLAIMER OF WARRANTIES:                                            */
  14. /* -------------------------                                            */
  15. /* The following [enclosed] code is sample code created by IBM          */
  16. /* Corporation and Prominare Inc.  This sample code is not part of any  */
  17. /* standard IBM product and is provided to you solely for the purpose   */
  18. /* of assisting you in the development of your applications.  The code  */
  19. /* is provided "AS IS", without warranty of any kind.  Neither IBM nor  */
  20. /* Prominare shall be liable for any damages arising out of your        */
  21. /* use of the sample code, even if they have been advised of the        */
  22. /* possibility of such damages.                                         */
  23. /************************************************************************/
  24.  
  25. #define INCL_DOS                   /* Include OS/2 DOS Kernal           */
  26. #define INCL_GPI                   /* Include OS/2 PM GPI Interface     */
  27. #define INCL_WIN                   /* Include OS/2 PM Windows Interface */
  28.  
  29. #include <os2.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <malloc.h>
  33.  
  34. #include "framectl.h"
  35.  
  36. /************************************************************************/
  37. /* This module contains example installable control that can be used    */
  38. /* by any OS/2 2.x and Warp Presentation Manager application.  The      */
  39. /* sample demonstrates the principles of adding frame control           */
  40. /* extensions such that other extensions can be added using this as     */
  41. /* a model.                                                             */
  42. /*                                                                      */
  43. /* Filename : FrameCtl.C                                                */
  44. /* Version  : 1.00                                                      */
  45. /* Created  : 1996-06-07                                                */
  46. /* Revised  : 1996-09-18                                                */
  47. /* Released :                                                           */
  48. /*                                                                      */
  49. /* Routines:  MRESULT EXPENTRY FrameWndProc( HWND hWnd, ULONG msg,      */
  50. /*                                           MPARAM mp1, MPARAM mp2 )   */
  51. /*            MRESULT EXPENTRY AnimateWndProc( HWND hWnd, ULONG msg,    */
  52. /*                                             MPARAM mp1, MPARAM mp2 ) */
  53. /*            LONG CalcMenuBarMinWidth( HWND hWnd )                     */
  54. /*            LONG CalcSeparatorWidth( HWND hWnd )                      */
  55. /*            int main(int argc, char* argv[] )                         */
  56. /*                                                                      */
  57. /* Copyright ╕ International Business Machines Corp., 1991,1996.        */
  58. /* Copyright ╕ 1989-1996  Prominare Inc.  All Rights Reserved.          */
  59. /*                                                                      */
  60. /************************************************************************/
  61.  
  62. HAB  hAB;                          /* Anchor Block Handle               */
  63. HWND hwndHelpBtn;                  /* Help Button Handle                */
  64. HWND hwndComboBox;                 /* Combo Box Handle                  */
  65. HWND hwndStaticText;               /* Static Text Handle                */
  66. HWND hwndAnimate;                  /* Animated Window Handle            */
  67. PFNWP DefFrameWndProc;             /* Frame Control Subclass Procedure  */
  68.  
  69. LONG lMinTitleHeight = 0;          /* Height of the title bar           */
  70. LONG lMinMenuHeight = 0;           /* Height of the menu bar            */
  71. POINTL staticTextPos;              /* Static Text position              */
  72. POINTL animatedCatBmpPos;          /* Animated Cat Bitmap position      */
  73.  
  74. LONG colorArray[] = { CLR_DARKBLUE, CLR_WHITE, CLR_RED,
  75.                       CLR_GREEN, CLR_BLACK };
  76.  
  77. /************************************************************************/
  78. /* Prototypes                                                           */
  79. /************************************************************************/
  80. int main( int, char* [] );
  81. MRESULT EXPENTRY FrameWndProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2 );
  82. MRESULT EXPENTRY AnimateWndProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2 );
  83. LONG CalcMenuBarMinWidth( HWND hWnd );
  84. LONG CalcSeparatorWidth( HWND hWnd );
  85.  
  86. /* --- FrameWndProc ----------------------------------- [ Private ] --- */
  87. /*                                                                      */
  88. /*     This function is used to process the messages for the frame      */
  89. /*     control window.                                                  */
  90. /*                                                                      */
  91. /*     Upon Entry:                                                      */
  92. /*                                                                      */
  93. /*     HWND   hWnd; = Window Handle                                     */
  94. /*     ULONG  msg;  = PM Message                                        */
  95. /*     MPARAM mp1;  = Message Parameter 1                               */
  96. /*     MPARAM mp2;  = Message Parameter 2                               */
  97. /*                                                                      */
  98. /*     Upon Exit:                                                       */
  99. /*                                                                      */
  100. /* -------------------------------------------------------------------- */
  101. MRESULT EXPENTRY FrameWndProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  102. {
  103.   switch ( msg )
  104.   {
  105.     case WM_FORMATFRAME :
  106.     {
  107.       /******************************************************************/
  108.       /* Query the number of standard frame controls                    */
  109.       /******************************************************************/
  110.       ULONG ulStdCtlCount = (ULONG)DefFrameWndProc( hWnd, msg, mp1, mp2 );
  111.       ULONG ulIdx = ulStdCtlCount;
  112.  
  113.       /******************************************************************/
  114.       /* Access the SWP array that is passed to us                      */
  115.       /******************************************************************/
  116.       ULONG i;
  117.       PSWP swpArr = (PSWP)mp1;
  118.  
  119.       for (i=0; i < ulStdCtlCount; i++)
  120.       {
  121.         if ( WinQueryWindowUShort( swpArr[i].hwnd, QWS_ID ) == FID_TITLEBAR )
  122.         {
  123.           /**************************************************************/
  124.           /* Initialize the SWPs for our graphic button control.        */
  125.           /* Since the SWP array for the std frame controls is 0-based  */
  126.           /* and occupy indexes 0 thru n-1 (where n is the total        */
  127.           /* count), we use index n for our graphic button control.     */
  128.           /* Please note that the width and height of our button is the */
  129.           /* same as the height of the title bar.                       */
  130.           /**************************************************************/
  131.           swpArr[ulIdx].fl = SWP_MOVE | SWP_SIZE | SWP_NOADJUST;
  132.           swpArr[ulIdx].cy = swpArr[i].cy;
  133.           swpArr[ulIdx].cx = swpArr[i].cy;
  134.           swpArr[ulIdx].y  = swpArr[i].y;
  135.           swpArr[ulIdx].hwndInsertBehind = HWND_TOP;
  136.  
  137.           /**************************************************************/
  138.           /* Calculate the x-position for the help graphic button, and  */
  139.           /* set its window handle.                                     */
  140.           /**************************************************************/
  141.           swpArr[ulIdx].x = swpArr[i].x + swpArr[i].cx - swpArr[ulIdx].cx;
  142.           swpArr[ulIdx].hwnd = hwndHelpBtn;
  143.  
  144.           /**************************************************************/
  145.           /* Adjust width of the title bar to accomodate the help       */
  146.           /* graphic button.                                            */
  147.           /**************************************************************/
  148.           swpArr[i].cx -= swpArr[ulIdx].cx ;
  149.  
  150.           /**************************************************************/
  151.           /* Save the minimum title bar height that we'll use in        */
  152.           /* WM_QUERYTRACKINFO processing to calculate the minimum      */
  153.           /* tracking height.                                           */
  154.           /**************************************************************/
  155.           lMinTitleHeight = (swpArr[i].cy > lMinTitleHeight) ? swpArr[i].cy
  156.                                                              : lMinTitleHeight;
  157.         }
  158.  
  159.         if ( WinQueryWindowUShort( swpArr[i].hwnd, QWS_ID ) == FID_MENU )
  160.         {
  161.           /**************************************************************/
  162.           /* Initialize the SWP for our drop down combo box.  Since     */
  163.           /* the SWP array for the std frame controls is 0-based and    */
  164.           /* occupy indexes 0 thru n-1 (where n is the total count),    */
  165.           /* and the graphic button occupies n, we use index n+1 for    */
  166.           /* our drop down combo box.                                   */
  167.           /**************************************************************/
  168.           swpArr[ulIdx+1].fl = SWP_MOVE | SWP_SIZE | SWP_NOADJUST;
  169.           swpArr[ulIdx+1].cy = COMBOBOX_HEIGHT;
  170.           swpArr[ulIdx+1].cx = COMBOBOX_WIDTH;
  171.           swpArr[ulIdx+1].y  = swpArr[i].y -
  172.                                (COMBOBOX_HEIGHT - swpArr[i].cy - 1);
  173.           swpArr[ulIdx+1].hwndInsertBehind = HWND_TOP;
  174.  
  175.           /**************************************************************/
  176.           /* Calculate the x-position for the drop down combo box, and  */
  177.           /* set its window handle.                                     */
  178.           /**************************************************************/
  179.           swpArr[ulIdx+1].x = swpArr[i].x + swpArr[i].cx - swpArr[ulIdx+1].cx;
  180.           swpArr[ulIdx+1].hwnd = hwndComboBox;
  181.  
  182.           /**************************************************************/
  183.           /* Adjust the width of the menu bar to accomodate our drop    */
  184.           /* down combo box.                                            */
  185.           /**************************************************************/
  186.           swpArr[i].cx -= swpArr[ulIdx+1].cx;
  187.  
  188.           /**************************************************************/
  189.           /* Save the minimum menu bar height that we'll use in         */
  190.           /* WM_QUERYTRACKINFO processing to calculate the minimum      */
  191.           /* tracking height.                                           */
  192.           /**************************************************************/
  193.           lMinMenuHeight = (swpArr[i].cy > lMinMenuHeight) ? swpArr[i].cy
  194.                                                            : lMinMenuHeight;
  195.         }
  196.  
  197.         if ( WinQueryWindowUShort( swpArr[i].hwnd, QWS_ID ) == FID_CLIENT )
  198.         {
  199.           /**************************************************************/
  200.           /* Initialize the SWP for our static text control.  Since     */
  201.           /* the SWP array for the std frame controls is 0-based and    */
  202.           /* occupy indexes 0 thru n-1 (where n is the total count),    */
  203.           /* and the graphic button and combo box occupy n and n+1, we  */
  204.           /* use index n+2 for our static text control.                 */
  205.           /**************************************************************/
  206.           swpArr[ulIdx+2].fl = SWP_MOVE | SWP_SIZE | SWP_NOADJUST;
  207.           swpArr[ulIdx+2].cy = STATICTEXT_HEIGHT;
  208.           swpArr[ulIdx+2].cx = swpArr[i].cx - CAT_BMP_WIDTH - SEPARATOR_WIDTH;
  209.           staticTextPos.y = swpArr[ulIdx+2].y  = swpArr[i].y;
  210.           staticTextPos.x = swpArr[ulIdx+2].x = swpArr[i].x;
  211.           swpArr[ulIdx+2].hwndInsertBehind = HWND_TOP;
  212.           swpArr[ulIdx+2].hwnd = hwndStaticText;
  213.  
  214.           /**************************************************************/
  215.           /* Initialize the SWP for our animated window control.  We    */
  216.           /* use index n+3 for our animate window control.              */
  217.           /**************************************************************/
  218.           swpArr[ulIdx+3].fl = SWP_MOVE | SWP_SIZE | SWP_NOADJUST;
  219.           swpArr[ulIdx+3].cy = CAT_BMP_HEIGHT;
  220.           swpArr[ulIdx+3].cx = CAT_BMP_WIDTH;
  221.           animatedCatBmpPos.y = swpArr[ulIdx+3].y  = swpArr[i].y;
  222.           animatedCatBmpPos.x = swpArr[ulIdx+3].x = staticTextPos.x +
  223.                                 swpArr[ulIdx+2].cx + SEPARATOR_WIDTH;
  224.           swpArr[ulIdx+3].hwndInsertBehind = HWND_TOP;
  225.           swpArr[ulIdx+3].hwnd = hwndAnimate;
  226.  
  227.           /**************************************************************/
  228.           /* Adjust the origin and height of the client to accomodate   */
  229.           /* our static text control.  Remember to leave enough space   */
  230.           /* for the separator bar.                                     */
  231.           /**************************************************************/
  232.           swpArr[i].y += swpArr[ulIdx+2].cy + SEPARATOR_WIDTH;
  233.           swpArr[i].cy -= (swpArr[ulIdx+2].cy + SEPARATOR_WIDTH);
  234.         }
  235.       }
  236.  
  237.       /******************************************************************/
  238.       /* Increment the number of frame controls to include our graphic  */
  239.       /* button control, drop down combo box, static text, and animated */
  240.       /* window control.                                                */
  241.       /******************************************************************/
  242.       return( (MRESULT)(ulIdx + 4) );
  243.     }
  244.  
  245.     case WM_QUERYFRAMECTLCOUNT :
  246.       /******************************************************************/
  247.       /* Query the standard frame controls count and increment to       */
  248.       /* include our graphic button control, drop down combo box,       */
  249.       /* static text, and animated window control.                      */
  250.       /******************************************************************/
  251.       return( (MRESULT)((ULONG)DefFrameWndProc( hWnd, msg, mp1, mp2 ) + 4) );
  252.  
  253.     case WM_QUERYTRACKINFO :
  254.     {
  255.       /******************************************************************/
  256.       /* Query the default tracking information for the standard frame  */
  257.       /* control.                                                       */
  258.       /******************************************************************/
  259.       BOOL rc = (BOOL)DefFrameWndProc( hWnd, msg, mp1, mp2 );
  260.       PTRACKINFO pTrackInfo = (PTRACKINFO)mp2;
  261.  
  262.       /******************************************************************/
  263.       /* Calculate the minimum width that we require for the menu bar.  */
  264.       /******************************************************************/
  265.       LONG lMinMenuBarWidth = CalcMenuBarMinWidth( hWnd );
  266.  
  267.       if ( lMinMenuBarWidth == MIT_ERROR )
  268.         return( (MRESULT)FALSE );
  269.  
  270.       /******************************************************************/
  271.       /* Calculate and set the minimum tracking width and height.  Note */
  272.       /* that we only use the menu bar to calculate the minmum width.   */
  273.       /* You may want to expand this calculation to include the title   */
  274.       /* bar or other factors.                                          */
  275.       /******************************************************************/
  276.       pTrackInfo->ptlMinTrackSize.x = COMBOBOX_WIDTH +
  277.                                       lMinMenuBarWidth +
  278.                                       (WinQuerySysValue( HWND_DESKTOP,
  279.                                                          SV_CXSIZEBORDER ) * 2);
  280.       pTrackInfo->ptlMinTrackSize.y = STATICTEXT_HEIGHT + SEPARATOR_WIDTH +
  281.                                       lMinTitleHeight + lMinMenuHeight +
  282.                                       WinQuerySysValue( HWND_DESKTOP,
  283.                                                         SV_CYHSCROLL ) - 1 +
  284.                                       (WinQuerySysValue( HWND_DESKTOP,
  285.                                                          SV_CYSIZEBORDER ) * 2);
  286.       return( (MRESULT)TRUE );
  287.     }
  288.  
  289.     case WM_CALCFRAMERECT:
  290.       {
  291.         /******************************************************************/
  292.         /* Calculate the rectl of the client                              */
  293.         /* control.                                                       */
  294.         /******************************************************************/
  295.         BOOL rc = TRUE;
  296.         PRECTL pRectl = (PRECTL)mp1;
  297.         LONG lExtensionHeight = STATICTEXT_HEIGHT + SEPARATOR_WIDTH;
  298.  
  299.         if ( SHORT1FROMMP(mp2) )
  300.         {
  301.           /****************************************************************/
  302.           /* Calculate the rectl of the client                            */
  303.           /*--------------------------------------------------------------*/
  304.           /* Call default window procedure to subtract child frame        */
  305.           /* controls from the rectangle's height.                        */
  306.           /****************************************************************/
  307.           LONG lClientHeight;
  308.           rc = (BOOL)DefFrameWndProc( hWnd, msg, mp1, mp2 );
  309.  
  310.           /****************************************************************/
  311.           /* Position the static text frame extension below the client.   */
  312.           /****************************************************************/
  313.           lClientHeight = pRectl->yTop - pRectl->yBottom;
  314.           if ( lExtensionHeight  > lClientHeight  )
  315.           {
  316.             /**************************************************************/
  317.             /* Extension is taller than client, so set client height to 0.*/
  318.             /**************************************************************/
  319.             pRectl->yTop = pRectl->yBottom;
  320.           }
  321.           else
  322.           {
  323.             /**************************************************************/
  324.             /* Set the origin of the client and shrink it based upon the  */
  325.             /* static text control's height.                              */
  326.             /**************************************************************/
  327.             pRectl->yBottom += lExtensionHeight;
  328.             pRectl->yTop -= lExtensionHeight;
  329.           }
  330.         }
  331.         else
  332.         {
  333.           /****************************************************************/
  334.           /* Calculate the rectl of the frame                             */
  335.           /*--------------------------------------------------------------*/
  336.           /* Call default window procedure to subtract child frame        */
  337.           /* controls from the rectangle's height.                        */
  338.           /* Set the origin of the frame and increase it based upon the   */
  339.           /* static text control's height.                                */
  340.           /****************************************************************/
  341.           pRectl->yBottom -= lExtensionHeight;
  342.           pRectl->yTop += lExtensionHeight;
  343.         }
  344.         return( (MRESULT)rc );
  345.       }
  346.  
  347.     case WM_PAINT:
  348.       {
  349.         /******************************************************************/
  350.         /* Process WM_PAINT to draw the separator bar.                    */
  351.         /******************************************************************/
  352.         USHORT i;
  353.         POINTL start[5],
  354.                end[5];
  355.  
  356.         LONG color[5] = { SYSCLR_BUTTONDARK, SYSCLR_BUTTONMIDDLE,
  357.                           SYSCLR_BUTTONMIDDLE, SYSCLR_BUTTONMIDDLE,
  358.                           SYSCLR_BUTTONLIGHT };
  359.  
  360.         /******************************************************************/
  361.         /* Allow default proc to draw all of the frame.                   */
  362.         /******************************************************************/
  363.         BOOL rc = (BOOL)DefFrameWndProc( hWnd, msg, mp1, mp2 );
  364.  
  365.         /******************************************************************/
  366.         /* Get presentation space handle for drawing.                     */
  367.         /******************************************************************/
  368.         HPS hps = WinGetPS( hWnd );
  369.  
  370.         /******************************************************************/
  371.         /* Init the POINTL arrays for drawing the horizontal separator    */
  372.         /******************************************************************/
  373.         LONG lSeparatorWidth = CalcSeparatorWidth( hWnd );
  374.  
  375.         start[0].x = start[1].x = start[2].x = start[3].x =
  376.             start[4].x = staticTextPos.x;
  377.         start[0].y = start[1].y = start[2].y = start[3].y =
  378.             start[4].y = staticTextPos.y + STATICTEXT_HEIGHT;
  379.         start[1].y += 1;
  380.         start[2].y += 2;
  381.         start[3].y += 3;
  382.         start[4].y += 4;
  383.         end[0] = start[0];
  384.         end[0].x += lSeparatorWidth;
  385.         end[1] = start[1];
  386.         end[1].x += lSeparatorWidth;
  387.         end[2] = start[2];
  388.         end[2].x += lSeparatorWidth;
  389.         end[3] = start[3];
  390.         end[3].x += lSeparatorWidth;
  391.         end[4] = start[4];
  392.         end[4].x += lSeparatorWidth;
  393.  
  394.         /******************************************************************/
  395.         /* Draw the horizontal separator bar.                             */
  396.         /******************************************************************/
  397.         for (i=0; i< SEPARATOR_WIDTH; i++)
  398.         {
  399.           LONG lSysColor = WinQuerySysColor( HWND_DESKTOP, color[i], 0L );
  400.           GpiSetColor( hps, GpiQueryColorIndex( hps, 0, lSysColor ) );
  401.           GpiMove( hps, &start[i] );
  402.           GpiLine( hps, &end[i] );
  403.         }
  404.  
  405.         /******************************************************************/
  406.         /* Init the POINTL arrays for drawing the vertical separator      */
  407.         /******************************************************************/
  408.         start[0].x = start[1].x = start[2].x = start[3].x =
  409.             start[4].x = animatedCatBmpPos.x;
  410.         start[0].y = start[1].y = start[2].y = start[3].y =
  411.             start[4].y = staticTextPos.y;
  412.         start[0].x -= 5;
  413.         start[1].x -= 4;
  414.         start[2].x -= 3;
  415.         start[3].x -= 2;
  416.         start[4].x -= 1;
  417.         end[0] = start[0];
  418.         end[0].y += STATICTEXT_HEIGHT;
  419.         end[1] = start[1];
  420.         end[1].y += STATICTEXT_HEIGHT;
  421.         end[2] = start[2];
  422.         end[2].y += STATICTEXT_HEIGHT;
  423.         end[3] = start[3];
  424.         end[3].y += STATICTEXT_HEIGHT;
  425.         end[4] = start[4];
  426.         end[4].y += STATICTEXT_HEIGHT;
  427.  
  428.  
  429.         /******************************************************************/
  430.         /* Draw the vertical separator bar.                               */
  431.         /******************************************************************/
  432.         for (i=0; i< SEPARATOR_WIDTH; i++)
  433.         {
  434.           LONG lSysColor = WinQuerySysColor( HWND_DESKTOP, color[i], 0L );
  435.           GpiSetColor( hps, GpiQueryColorIndex( hps, 0, lSysColor ) );
  436.           GpiMove( hps, &start[i] );
  437.           GpiLine( hps, &end[i] );
  438.         }
  439.  
  440.         /******************************************************************/
  441.         /* Release presentation space handle.                             */
  442.         /******************************************************************/
  443.         WinReleasePS( hps );
  444.  
  445.         return( (MRESULT)TRUE );
  446.       }
  447.  
  448.     case WM_COMMAND :
  449.       if ( SHORT1FROMMP(mp2) == CMDSRC_MENU )
  450.       {
  451.         switch ( SHORT1FROMMP(mp1) )
  452.         {
  453.           /****************************************************************/
  454.           /* Process the Exit request.                                    */
  455.           /****************************************************************/
  456.           case MI_FILE_EXIT:
  457.           {
  458.             /**************************************************************/
  459.             /* Close the frame extensions sample application.             */
  460.             /**************************************************************/
  461.             WinPostMsg( hWnd, WM_CLOSE, 0, 0 );
  462.             return( (MRESULT)FALSE );
  463.           }
  464.  
  465.           /****************************************************************/
  466.           /* Start the animated cat bitmap                                */
  467.           /****************************************************************/
  468.           case MI_CAT_START:
  469.           {
  470.             /**************************************************************/
  471.             /* Start the animation timer so it shows 5 frames a second    */
  472.             /**************************************************************/
  473.             WinStartTimer( hAB, hwndAnimate, TIMER_ANIMATE, 200UL );
  474.             return( (MRESULT)FALSE );
  475.           }
  476.  
  477.           /****************************************************************/
  478.           /* Stop the animated cat bitmap                                 */
  479.           /****************************************************************/
  480.           case MI_CAT_STOP:
  481.           {
  482.             /**************************************************************/
  483.             /* Stop the animation timer                                   */
  484.             /**************************************************************/
  485.             WinStopTimer( hAB, hwndAnimate, TIMER_ANIMATE );
  486.             return( (MRESULT)FALSE );
  487.           }
  488.  
  489.           default:
  490.             break;
  491.         } /* end switch */
  492.       }
  493.       return( DefFrameWndProc( hWnd, msg, mp1, mp2 ) );
  494.  
  495.     case WM_CONTROL :
  496.       if ( (SHORT1FROMMP(mp1) == COMBOBOX_ID)  &&
  497.            (SHORT2FROMMP(mp1) == CBN_LBSELECT) )
  498.       {
  499.         /****************************************************************/
  500.         /* Process the list box selection notification.                 */
  501.         /****************************************************************/
  502.         LONG lFgnColor;
  503.         LONG lSelIndex = (LONG)WinSendMsg( (HWND)mp2,
  504.                                            LM_QUERYSELECTION,
  505.                                            MPFROMLONG(LIT_FIRST),
  506.                                            0 );
  507.         if ( lSelIndex == LIT_NONE )
  508.           return( FALSE );
  509.  
  510.         lFgnColor = colorArray[lSelIndex];
  511.         WinSetPresParam( WinWindowFromID( hWnd, FID_CLIENT ),
  512.                          PP_FOREGROUNDCOLORINDEX,
  513.                          4UL,
  514.                          &lFgnColor );
  515.  
  516.       }
  517.       return( DefFrameWndProc( hWnd, msg, mp1, mp2 ) );
  518.  
  519.     case WM_HELP :
  520.       /******************************************************************/
  521.       /* Process a click on the help graphic button.                    */
  522.       /******************************************************************/
  523.       if ( (USHORT)mp1 == HELP_BUTTON_ID )
  524.       {
  525.         /****************************************************************/
  526.         /* Display the help panel for this sample.                      */
  527.         /****************************************************************/
  528.         return( WinSendMsg( WinQueryHelpInstance( hWnd ),
  529.                             HM_DISPLAY_HELP,
  530.                             mp1,
  531.                             HM_RESOURCEID ) );
  532.       }
  533.  
  534.     case WM_MENUSELECT :
  535.       {
  536.         char buffer[20];
  537.         if ( SHORT1FROMMP(mp1) != 0xFFFF )
  538.         {
  539.           /* Menu item is being selected */
  540.           if ( WinLoadString( WinQueryAnchorBlock( hWnd ),
  541.                               NULLHANDLE,
  542.                               SHORT1FROMMP(mp1),
  543.                               20,
  544.                               buffer ) )
  545.           {
  546.             WinSetWindowText( hwndStaticText, buffer );
  547.           }
  548.           else
  549.             WinSetWindowText( hwndStaticText, NULL );
  550.         }
  551.         else
  552.         {
  553.           /* Menu item is being deselected */
  554.           /* Get owner window.  If the owner is another menu, then reset the
  555.              info area text to the menu text, otherwise set inactive text */
  556.           HWND hwndOwner = WinQueryWindow( (HWND)mp2, QW_OWNER );
  557.           if (hwndOwner)
  558.           {
  559.             WinQueryClassName( hwndOwner, 20, buffer );
  560.             if ( !memcmp( buffer, "#4", 3 ) )
  561.             {
  562.               SHORT sItem = (SHORT)WinSendMsg( hwndOwner, MM_QUERYSELITEMID,
  563.                                                0, 0 );
  564.               if (( sItem == MIT_ERROR) || ( sItem == MIT_NONE ))
  565.                 WinSetWindowText( hwndStaticText, NULL );
  566.               else
  567.               {
  568.                 WinSendMsg( hWnd, WM_MENUSELECT,
  569.                             MPFROMSHORT(sItem), MPFROMHWND(hwndOwner) );
  570.               }
  571.             }
  572.             else
  573.               WinSetWindowText( hwndStaticText, NULL );
  574.           }
  575.           else
  576.             WinSetWindowText( hwndStaticText, NULL );
  577.         }
  578.  
  579.         return( (MRESULT)TRUE );
  580.       }
  581.  
  582.     case WM_MENUEND :
  583.       WinSetWindowText( hwndStaticText, NULL );
  584.       return( (MRESULT)FALSE );
  585.  
  586.     default:
  587.       return( DefFrameWndProc( hWnd, msg, mp1, mp2 ) );
  588.   }
  589.  
  590.   return( (MRESULT)FALSE );
  591. }
  592.  
  593.  
  594. /* --- CalcMenuBarMinWidth ---------------------------- [ Private ] --- */
  595. /*                                                                      */
  596. /*     This function is used to dynamically calculate the minimum menu  */
  597. /*     bar width required to display the entire menu bar.               */
  598. /*                                                                      */
  599. /*     Upon Entry:                                                      */
  600. /*                                                                      */
  601. /*     HWND   hWnd; = Frame Window Handle                               */
  602. /*                                                                      */
  603. /*     Upon Exit:                                                       */
  604. /*                                                                      */
  605. /* -------------------------------------------------------------------- */
  606. LONG CalcMenuBarMinWidth( HWND hWnd )
  607. {
  608.   RECTL rect;
  609.   LONG i;
  610.   LONG lMinWidth = 0;
  611.   HWND hwndMenuBar = WinWindowFromID( hWnd, FID_MENU );
  612.  
  613.   /**********************************************************************/
  614.   /* Get the count of the menu items on the menu bar.                   */
  615.   /**********************************************************************/
  616.   LONG lMenuItemsCount = (LONG)WinSendMsg( hwndMenuBar,
  617.                                            MM_QUERYITEMCOUNT,
  618.                                            0,
  619.                                            0 );
  620.  
  621.   for ( i=0; i < lMenuItemsCount; i++ )
  622.   {
  623.     /********************************************************************/
  624.     /* Get the id of the menu item.                                     */
  625.     /********************************************************************/
  626.     LONG itemID = (LONG)WinSendMsg( hwndMenuBar,
  627.                                      MM_ITEMIDFROMPOSITION,
  628.                                      MPFROMLONG( i ),
  629.                                      0 );
  630.     if ( itemID == MIT_ERROR )
  631.       return( MIT_ERROR );
  632.  
  633.     /********************************************************************/
  634.     /* Get the rectangle for the menu item.                             */
  635.     /********************************************************************/
  636.     if ( WinSendMsg( hwndMenuBar,
  637.                      MM_QUERYITEMRECT,
  638.                      MPFROM2SHORT((USHORT)itemID, FALSE),
  639.                      MPFROMP(&rect) ) )
  640.     {
  641.       /******************************************************************/
  642.       /* Calculate the item's width and add it to the width of the      */
  643.       /* other items.                                                   */
  644.       /******************************************************************/
  645.       lMinWidth += (rect.xRight - rect.xLeft);
  646.     }
  647.     else
  648.       return( MIT_ERROR );
  649.   }
  650.  
  651.   return( lMinWidth );
  652. }
  653.  
  654. /* --- CalcSeparatorWidth ----------------------------- [ Private ] --- */
  655. /*                                                                      */
  656. /*     This function is used to calculate the width of the separator    */
  657. /*     bar that we draw to visually separate the static text control    */
  658. /*     and animated cat bitmap from the client.  It is the same width   */
  659. /*     as the client, so we return the client's width minus 1.          */
  660. /*                                                                      */
  661. /*     Upon Entry:                                                      */
  662. /*                                                                      */
  663. /*     Upon Exit:                                                       */
  664. /*                                                                      */
  665. /* -------------------------------------------------------------------- */
  666. LONG CalcSeparatorWidth( HWND hWnd )
  667. {
  668.   RECTL rectl;
  669.   LONG lWidth = 0;
  670.  
  671.   if ( WinQueryWindowRect( WinWindowFromID( hWnd, FID_CLIENT ), &rectl ) )
  672.     lWidth = rectl.xRight - rectl.xLeft - 1;
  673.  
  674.   lWidth = (lWidth < 0) ? 0 : lWidth;
  675.   return( lWidth );
  676. }
  677.  
  678. /* --- AnimateWndProc --------------------------------- [ Private ] --- */
  679. /*                                                                      */
  680. /*     This function is used to process the messages for the animated   */
  681. /*     control window.                                                  */
  682. /*                                                                      */
  683. /*     Upon Entry:                                                      */
  684. /*                                                                      */
  685. /*     HWND   hWnd; = Window Handle                                     */
  686. /*     ULONG  msg;  = PM Message                                        */
  687. /*     MPARAM mp1;  = Message Parameter 1                               */
  688. /*     MPARAM mp2;  = Message Parameter 2                               */
  689. /*                                                                      */
  690. /*     Upon Exit:                                                       */
  691. /*                                                                      */
  692. /* -------------------------------------------------------------------- */
  693. MRESULT EXPENTRY AnimateWndProc( HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  694. {
  695.   PANIMATE pAnimate;       /* Animation Data              */
  696.   HPS  hPS;                /* Presentation Space Handle   */
  697.  
  698.   switch ( msg )
  699.   {
  700.     case WM_CREATE :
  701.       /******************************************************************/
  702.       /* Allocate memory for the animation data and save the address    */
  703.       /* in the window's reserved memory.                               */
  704.       /******************************************************************/
  705.       pAnimate = (PANIMATE)malloc( sizeof(ANIMATE) );
  706.       WinSetWindowULong( hWnd, QWL_USER, (ULONG)pAnimate );
  707.  
  708.       /******************************************************************/
  709.       /* Load the animation bitmap.  The bitmap image is 280 x 28 which */
  710.       /* yields 10-28 x 28 frames.                                      */
  711.       /******************************************************************/
  712.       pAnimate->hbm = GpiLoadBitmap( hPS = WinGetPS(hWnd),
  713.                                      (HMODULE)NULL,
  714.                                      CATS_BMP_ID, 0L, 0L );
  715.  
  716.       /******************************************************************/
  717.       /* Set the starting image index to start at the first frame       */
  718.       /******************************************************************/
  719.       pAnimate->iImage = 0UL;
  720.  
  721.       /******************************************************************/
  722.       /* Initialize the source and target bitmap points.  The target    */
  723.       /* points will always be the same whereas the source points will  */
  724.       /* slide across the bitmap image for each frame shown.            */
  725.       /******************************************************************/
  726.       pAnimate->aptl[0].x = 0L;
  727.       pAnimate->aptl[0].y = 0L;
  728.       pAnimate->aptl[1].x = 28L;
  729.       pAnimate->aptl[1].y = 28L;
  730.       pAnimate->aptl[2].x = 0L;
  731.       pAnimate->aptl[2].y = 0L;
  732.       pAnimate->aptl[3].x = 28L;
  733.       pAnimate->aptl[3].y = 28L;
  734.       WinReleasePS( hPS );
  735.       break;
  736.  
  737.     case WM_TIMER :
  738.       switch ( SHORT1FROMMP(mp1) )
  739.       {
  740.         /****************************************************************/
  741.         /* 1/5 second has elapsed, show a new image                     */
  742.         /****************************************************************/
  743.         case TIMER_ANIMATE :
  744.           {
  745.             /************************************************************/
  746.             /* Get the animation data from the window's reserved memory */
  747.             /************************************************************/
  748.             pAnimate = (PANIMATE)WinQueryWindowULong( hWnd, QWL_USER );
  749.  
  750.             /************************************************************/
  751.             /* Check to see if the image has wrapped around to the      */
  752.             /* beginning again and if so, set the the source points     */
  753.             /* back to the start of the bitmap image otherwise slide    */
  754.             /* the source points across by 28 bits.                     */
  755.             /************************************************************/
  756.             if ( (pAnimate->iImage++ % 10UL) == 0 )
  757.             {
  758.               pAnimate->aptl[2].x = 0L;
  759.               pAnimate->aptl[3].x = 28L;
  760.             }
  761.             else
  762.             {
  763.               pAnimate->aptl[2].x += 28L;
  764.               pAnimate->aptl[3].x += 28L;
  765.             }
  766.  
  767.             /************************************************************/
  768.             /* Display the new bitmap image                             */
  769.             /************************************************************/
  770.             GpiWCBitBlt( hPS = WinGetPS(hWnd),
  771.                          pAnimate->hbm, 4L,
  772.                          pAnimate->aptl, ROP_SRCCOPY, BBO_IGNORE );
  773.             WinReleasePS( hPS );
  774.           }
  775.           break;
  776.  
  777.         default :
  778.           return( WinDefWindowProc( hWnd, msg, mp1, mp2 ) );
  779.       } /* end switch */
  780.       break;
  781.  
  782.     case WM_PAINT :
  783.       {
  784.         /****************************************************************/
  785.         /* Get the animation data from the window's reserved memory     */
  786.         /****************************************************************/
  787.         pAnimate = (PANIMATE)WinQueryWindowULong( hWnd, QWL_USER );
  788.  
  789.         /****************************************************************/
  790.         /* Display the current bitmap image                             */
  791.         /****************************************************************/
  792.         GpiWCBitBlt( hPS = WinBeginPaint( hWnd, (HWND)NULL, NULL ),
  793.                      pAnimate->hbm, 4L,
  794.                      pAnimate->aptl, ROP_SRCCOPY, BBO_IGNORE );
  795.         WinEndPaint( hPS );
  796.         break;
  797.       }
  798.  
  799.     case WM_DESTROY :
  800.       /******************************************************************/
  801.       /* Get the animation data from the window's reserved memory       */
  802.       /******************************************************************/
  803.       pAnimate = (PANIMATE)WinQueryWindowULong( hWnd, QWL_USER );
  804.  
  805.       /******************************************************************/
  806.       /* Delete the bitmap                                              */
  807.       /******************************************************************/
  808.       GpiDeleteBitmap( pAnimate->hbm );
  809.  
  810.       /******************************************************************/
  811.       /* Release the memory used for the animation data                 */
  812.       /******************************************************************/
  813.       free( pAnimate );
  814.       break;
  815.  
  816.     default :
  817.       return( WinDefWindowProc( hWnd, msg, mp1, mp2 ) );
  818.   } /* end switch */
  819.  
  820.   return( (MRESULT)FALSE );
  821. }
  822.  
  823.  
  824. /* --- main ----------------------------------------------------------- */
  825. /*     Main function.                                                   */
  826. /* -------------------------------------------------------------------- */
  827. int main( int argc, char* argv[] )
  828. {
  829.   HMQ      hMQ;                    /* Message Queue Handle              */
  830.   HWND     hwndClient;             /* Client Handle                     */
  831.   HWND     hwndFrame;              /* Frame Handle                      */
  832.   QMSG     qmsg;                   /* PM Message Queue Holder           */
  833.   ULONG    flCreateFlags;          /* Window Creation Flags             */
  834.   LONG     lFgnColor;              /* Foreground Color Holder           */
  835.   LONG     lBgnColor;              /* Background Color Holder           */
  836.   HWND     hwndHelp;               /* Help Instance Handle              */
  837.   HELPINIT helpInit;               /* Help Instance Structure           */
  838.   LBOXINFO lboxinfo;               /* List Box Info Structure           */
  839.   BOOL     bWarpV4 = FALSE;        /* OS/2 Warp V4.0 indicator          */
  840.   ULONG    ulVersion;              /* Version Return Variable           */
  841.   LONG     lCount,
  842.            lWidth,
  843.            lHeight;
  844.   ULONG    i;
  845.   PSZ      itemsArray[] = { "Blue Text",  "White Text", "Red Text",
  846.                             "Green Text", "Black Text" };
  847.  
  848.   /**********************************************************************/
  849.   /* Initialize the program for PM, create the message queue, and set   */
  850.   /* the codepage.                                                      */
  851.   /**********************************************************************/
  852.   hAB = WinInitialize( 0 );
  853.   hMQ = WinCreateMsgQueue( hAB, 0 );
  854.   WinSetCp( hMQ, 850 );
  855.  
  856.   /**********************************************************************/
  857.   /* Create a standard frame window, specifying a static text control   */
  858.   /* for the client area.                                               */
  859.   /**********************************************************************/
  860.   flCreateFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MENU | FCF_SIZEBORDER |
  861.                   FCF_MINMAX | FCF_VERTSCROLL | FCF_HORZSCROLL | FCF_TASKLIST;
  862.  
  863.   hwndFrame = WinCreateStdWindow( HWND_DESKTOP,
  864.                                   0,
  865.                                   &flCreateFlags,
  866.                                   WC_STATIC,
  867.                                   "Frame Extensions",
  868.                                   (WS_VISIBLE | SS_TEXT | DT_CENTER |
  869.                                    DT_VCENTER),
  870.                                   (HMODULE)0L,
  871.                                   FRAME_WND_ID,
  872.                                   &hwndClient );
  873.   if ( !hwndFrame )
  874.     return( TRUE );
  875.  
  876.   /**********************************************************************/
  877.   /* Set the text for the static text control as well as the            */
  878.   /* foreground and background color of the control.                    */
  879.   /**********************************************************************/
  880.   lFgnColor = colorArray[0];
  881.   WinSetPresParam( hwndClient, PP_FOREGROUNDCOLORINDEX, 4UL, &lFgnColor );
  882.   lBgnColor = SYSCLR_DIALOGBACKGROUND;
  883.   WinSetPresParam( hwndClient, PP_BACKGROUNDCOLORINDEX, 4UL, &lBgnColor );
  884.  
  885.   WinSetWindowText( hwndClient, "Frame Extensions Test" );
  886.  
  887.   /**********************************************************************/
  888.   /* Create and associate the help instance.                            */
  889.   /**********************************************************************/
  890.   helpInit.cb                       = sizeof(HELPINIT);
  891.   helpInit.ulReturnCode             = 0;
  892.   helpInit.pszTutorialName          = 0;
  893.   helpInit.phtHelpTable             = (PHELPTABLE)MAKELONG(0, 0xffff);
  894.   helpInit.hmodHelpTableModule      = 0;
  895.   helpInit.hmodAccelActionBarModule = 0;
  896.   helpInit.idAccelTable             = 0;
  897.   helpInit.idActionBar              = 0;
  898.   helpInit.pszHelpWindowTitle       = "Frame Extensions Sample";
  899.   helpInit.fShowPanelId             = CMIC_HIDE_PANEL_ID;
  900.   helpInit.pszHelpLibraryName       = "framectl.hlp";
  901.  
  902.   hwndHelp = WinCreateHelpInstance( hAB, &helpInit );
  903.   if ( !hwndHelp )
  904.     return( TRUE );
  905.  
  906.   if ( !WinAssociateHelpInstance( hwndHelp, hwndFrame ) )
  907.     return( TRUE );
  908.  
  909.   /**********************************************************************/
  910.   /* Use the "new look" help bitmap for OS/2 Warp V4 (aka Merlin) if    */
  911.   /* V4 is detected.                                                    */
  912.   /**********************************************************************/
  913.   ulVersion = WinQueryVersion( hAB );
  914.   if ( ((ulVersion & 0xFF) == 20) &&
  915.        (((ulVersion >> 8) & 0xFF) == 40) )
  916.   {
  917.     bWarpV4 = TRUE;
  918.   }
  919.  
  920.   /**********************************************************************/
  921.   /* Create the help graphic button which we will use as a frame        */
  922.   /* extension on the title bar.                                        */
  923.   /**********************************************************************/
  924.   hwndHelpBtn = WinCreateWindow( hwndFrame,
  925.                                  WC_BUTTON,
  926.                                  ( (bWarpV4) ? "#400" : "#300" ),
  927.                                  (BS_BITMAP | BS_PUSHBUTTON | BS_NOBORDER |
  928.                                   BS_NOPOINTERFOCUS | BS_AUTOSIZE |
  929.                                   BS_HELP | WS_VISIBLE),
  930.                                  0L, 0L, -1L, -1L,
  931.                                  hwndFrame,
  932.                                  HWND_TOP,
  933.                                  HELP_BUTTON_ID,
  934.                                  (PVOID)NULL,
  935.                                  (PVOID)NULL );
  936.   if ( !hwndHelpBtn )
  937.     return( TRUE );
  938.  
  939.   /**********************************************************************/
  940.   /* Create the drop down combo box which we will use as a frame        */
  941.   /* extension on the menu bar.                                         */
  942.   /**********************************************************************/
  943.   hwndComboBox = WinCreateWindow( hwndFrame,
  944.                                  WC_COMBOBOX,
  945.                                  (PSZ)NULL,
  946.                                  (CBS_DROPDOWNLIST |  WS_VISIBLE),
  947.                                  0L, 0L, -1L, -1L,
  948.                                  hwndFrame,
  949.                                  HWND_TOP,
  950.                                  COMBOBOX_ID,
  951.                                  (PVOID)NULL,
  952.                                  (PVOID)NULL );
  953.   if ( !hwndComboBox )
  954.     return( TRUE );
  955.  
  956. #if 0
  957.   lboxinfo.lItemIndex = LIT_END;
  958.   lboxinfo.ulItemCount = 5;
  959.  
  960.   lCount = (LONG)WinSendMsg( hwndComboBox, LM_INSERTMULTITEMS,
  961.                              &lboxinfo, itemsArray[0] );
  962. #endif
  963.  
  964.   /**********************************************************************/
  965.   /* Populate the drop down combo box.                                  */
  966.   /**********************************************************************/
  967.   for (i = 0; i < 5; i++)
  968.   {
  969.     WinSendMsg( hwndComboBox, LM_INSERTITEM, (MPARAM)LIT_END, itemsArray[i] );
  970.   }
  971.  
  972.   WinSendMsg( hwndComboBox, LM_SELECTITEM, 0L, (MPARAM)TRUE );
  973.  
  974.   /**********************************************************************/
  975.   /* Create the static text control which we will set as a frame        */
  976.   /* extension below the client.                                        */
  977.   /**********************************************************************/
  978.   hwndStaticText = WinCreateWindow( hwndFrame,
  979.                                     WC_STATIC,
  980.                                     (PSZ)NULL,
  981.                                     (SS_TEXT | DT_LEFT | DT_VCENTER |
  982.                                      DT_ERASERECT | WS_VISIBLE ),
  983.                                     0L, 0L, -1L, -1L,
  984.                                     hwndFrame,
  985.                                     HWND_TOP,
  986.                                     STATICTEXT_ID,
  987.                                     (PVOID)NULL,
  988.                                     (PVOID)NULL );
  989.   if ( !hwndStaticText )
  990.     return( TRUE );
  991.  
  992.   WinSetPresParam( hwndStaticText, PP_BACKGROUNDCOLORINDEX, 4UL, &lBgnColor );
  993.  
  994.   /**********************************************************************/
  995.   /* Register the animated control window's class.                      */
  996.   /**********************************************************************/
  997.   if ( !WinRegisterClass(hAB, "Animate.Window", (PFNWP)AnimateWndProc,
  998.              CS_SYNCPAINT | CS_MOVENOTIFY | CS_SIZEREDRAW, 4UL) )
  999.      return(0);
  1000.  
  1001.   /**********************************************************************/
  1002.   /* Create the animated window control which we will set as a frame    */
  1003.   /* extension below the client.                                        */
  1004.   /**********************************************************************/
  1005.   hwndAnimate = WinCreateWindow( hwndFrame,
  1006.                                  "Animate.Window",
  1007.                                  (PSZ)NULL,
  1008.                                  WS_VISIBLE,
  1009.                                  0L, 0L, -1L, -1L,
  1010.                                  hwndFrame,
  1011.                                  HWND_TOP,
  1012.                                  ANIMATED_ID,
  1013.                                  (PVOID)NULL,
  1014.                                  (PVOID)NULL );
  1015.  
  1016.   /**********************************************************************/
  1017.   /* Subclass the frame control.  The subclass procedure is where we    */
  1018.   /* will add the frame extensions during processing of WM_FORMATFRAME. */
  1019.   /**********************************************************************/
  1020.   DefFrameWndProc = WinSubclassWindow( hwndFrame, (PFNWP)FrameWndProc );
  1021.  
  1022.   if ( !DefFrameWndProc )
  1023.     return( TRUE );
  1024.  
  1025.   /**********************************************************************/
  1026.   /* Indicate to PM that the frame needs updating.                      */
  1027.   /**********************************************************************/
  1028.   WinSendMsg( hwndFrame, WM_UPDATEFRAME, (MPARAM)~0, NULL );
  1029.  
  1030.   /**********************************************************************/
  1031.   /* Position (center on the desktop), size, and show the frame window. */
  1032.   /**********************************************************************/
  1033.   lWidth = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  1034.   lHeight = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  1035.   WinSetWindowPos( hwndFrame,
  1036.                    HWND_TOP,
  1037.                    (lWidth - FRAME_WIDTH)/ 2,
  1038.                    (lHeight - FRAME_HEIGHT)/ 2,
  1039.                    FRAME_WIDTH,
  1040.                    FRAME_HEIGHT,
  1041.                    SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ACTIVATE );
  1042.  
  1043.   /**********************************************************************/
  1044.   /* Message dispatch loop.                                             */
  1045.   /**********************************************************************/
  1046.   while ( WinGetMsg( hAB, &qmsg, (HWND)NULL, 0, 0 ) )
  1047.     WinDispatchMsg( hAB, &qmsg );
  1048.  
  1049.   /**********************************************************************/
  1050.   /* Termination processing                                             */
  1051.   /**********************************************************************/
  1052.   WinDestroyHelpInstance( hwndHelp );
  1053.   WinDestroyWindow( hwndFrame );
  1054.   WinDestroyMsgQueue( hMQ );
  1055.   WinTerminate( hAB );
  1056.   return( FALSE );
  1057. }
  1058.  
  1059.