home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / frmsub.zip / toolbar.c < prev    next >
C/C++ Source or Header  |  1994-06-03  |  28KB  |  604 lines

  1. /* ********************************************************************** */
  2. /*                                                                        */
  3. /*   ToolBar  Main Module                                                 */
  4. /*                                                                        */
  5. /*   This sample program implements two menu bars: a standard action bar  */
  6. /*   and a "toolbar". The toolbar consists of "buttons" that can be       */
  7. /*   pressed. The toolbar is actually a regular class menu whose items    */
  8. /*   have the style MIS_BITMAP. The toolbar is positioned in between      */
  9. /*   the standard titlebar and the standard action or menu bar.           */
  10. /*                                                                        */
  11. /*   The purpose of this sample is to demonstrate subclassing the frame   */
  12. /*   window to add frame controls.                                        */
  13. /*                                                                        */
  14. /*   This code was written quickly for demonstration of a technique, not  */
  15. /*   as an example of production level coding. Error checking was left    */
  16. /*   out in many areas to make the code less "cluttered". The code was    */
  17. /*   also written for readability, not for optimal use of resources.      */
  18. /*   In other words, please don't judge it too harshly :-)                */
  19. /*                                                                        */
  20. /*   This is a revision of a sample that was originally distributed       */
  21. /*   under the same name. This is a minor revision to add some simple     */
  22. /*   functionality, fix some bugs, and tight up the code a bit. The       */
  23. /*   changes include:                                                     */
  24. /*     *  Added identification of SWP structs during WM_FORMATFRAME       */
  25. /*        processing, rathering than using fixed position indexing.       */
  26. /*     *  Added check and adjustment for vertical scroll bar              */
  27. /*     *  Added WM_CALCFRAMERECT message processing                       */
  28. /*     *  Fixed bug so that WM_FORMATFRAME assigns client rect            */
  29. /*        parameter in mp2                                                */
  30. /*     *  Added responses (tones for buttons, message boxed for           */
  31. /*        menus) to menu/toolbar selections                               */
  32. /*                                                                        */
  33. /*   DISCLAIMER OF WARRANTIES.  The following [enclosed] code is          */
  34. /*   sample code created by IBM Corporation. This sample code is not      */
  35. /*   part of any standard or IBM product and is provided to you solely    */
  36. /*   for  the purpose of assisting you in the development of your         */
  37. /*   applications.  The code is provided "AS IS", without                 */
  38. /*   warranty of any kind.  IBM shall not be liable for any damages       */
  39. /*   arising out of your use of the sample code, even if they have been   */
  40. /*   advised of the possibility of   such damages.                        */
  41. /*                                                                        */
  42. /*   Copyright 1994, IBM Corp                                             */
  43. /*                                                                        */
  44. /* ********************************************************************** */
  45.  
  46.  
  47. #define INCL_WIN
  48. #define INCL_GPI
  49. #define INCL_DOS
  50. #define INCL_DOSMISC
  51. #define INCL_DOSERRORS
  52. #include <os2.h>
  53.  
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include "toolbar.h"
  57.  
  58. HAB     hab;
  59. HMQ     hmq;
  60. HWND    hwndClient;
  61. HWND    hwndFrame;
  62. HWND    hwndToolBar ;
  63. HWND    hwndMenuBar ;
  64. QMSG    qmsg;
  65.  
  66. PSZ    pszClassName  = "ToolBarClass" ;
  67. PSZ    pszMainTitle  = "ToolBar" ;
  68. PSZ    pszErrorTitle = "ToolBar Error" ;
  69.  
  70.         /* ----------------  Prototypes  ------------------------ */
  71. MRESULT EXPENTRY MainWindowProc( HWND, USHORT, MPARAM, MPARAM );
  72. MRESULT EXPENTRY NewFrameProc( HWND, USHORT, MPARAM, MPARAM );
  73. VOID             ShowErrorWindow( PSZ, BOOL );
  74.  
  75.  
  76.  
  77. /* ********************************************************************** */
  78. /*                                                                        */
  79. /*   Main                                                                 */
  80. /*                                                                        */
  81. /* ********************************************************************** */
  82.  
  83. VOID main()
  84. {
  85.  
  86.   if ( (hab = WinInitialize( 0L )) == (HAB) NULL ){
  87.      DosBeep( 60, 250 );
  88.      DosBeep( 120, 250 );
  89.   }
  90.   else {
  91.      if ( (hmq = WinCreateMsgQueue( hab, 0 )) == (HMQ) NULL ){
  92.         DosBeep( 60, 250 );
  93.         DosBeep( 120, 250 );
  94.         DosBeep( 60, 250 );
  95.      }
  96.      else {
  97.  
  98.        ULONG fulCreate= FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  99.                         FCF_MINMAX | FCF_SHELLPOSITION | FCF_ICON  ;
  100.                /*
  101.                 *  Note: no menu was specificed in create flags
  102.                 */
  103.  
  104.         WinSetPointer( HWND_DESKTOP,
  105.                        WinQuerySysPointer(HWND_DESKTOP,SPTR_WAIT,TRUE));
  106.  
  107.         WinRegisterClass(hab, pszClassName, (PFNWP)MainWindowProc, CS_SIZEREDRAW, 0);
  108.  
  109.         hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  110.                                        0L,
  111.                                        (PULONG)&fulCreate,
  112.                                        pszClassName ,
  113.                                        pszMainTitle,
  114.                                        0L,
  115.                                        (HMODULE)NULL,
  116.                                        ID_MAIN_WIN,
  117.                                        &hwndClient);
  118.         if ( hwndFrame == NULLHANDLE ) {
  119.            ShowErrorWindow( "Error creating Main window !", TRUE );
  120.         }
  121.         else {
  122.            PFNWP     pfnwpOldFrameProc ;
  123.  
  124.              /* ---------  subclass frame proc  ------------------ */
  125.            pfnwpOldFrameProc = WinSubclassWindow( hwndFrame,
  126.                                                   (PFNWP) NewFrameProc );
  127.            if ( pfnwpOldFrameProc == (PFNWP)0L ){
  128.                ShowErrorWindow( "Error subclassing frame window !", TRUE );
  129.            }
  130.            else {
  131.               PID       pid ;
  132.               SWCNTRL   swCntrl;
  133.               HSWITCH   hSwitch ;
  134.  
  135.  
  136.                 /* -------  store old frame proc with handle  ------- */
  137.               WinSetWindowULong( hwndFrame,
  138.                                  QWL_USER,
  139.                                  (ULONG) pfnwpOldFrameProc );
  140.  
  141.                 /* ------------------ load menus  ------------------- */
  142.               hwndMenuBar = WinLoadMenu( hwndFrame,
  143.                                          (HMODULE)NULL,
  144.                                          MID_MENUBAR );
  145.  
  146.               hwndToolBar = WinLoadMenu( hwndFrame,
  147.                                          (HMODULE)NULL,
  148.                                          MID_TOOLBAR );
  149.                 /*
  150.                  *  Note that the last menu loaded, the toolbar, is the
  151.                  *  one that is associated with the frame as "the" menu
  152.                  *  (i.e. FID_MENU). This means that hwndMenuBar is the
  153.                  *  only link to the regular action bar, so hang onto
  154.                  *  it tightly.
  155.                  */
  156.  
  157.                 /* ---------  set window size and pos  -------------- */
  158.               WinSetWindowPos( hwndFrame,
  159.                                HWND_TOP,
  160.                                0, 0, 370, 300,
  161.                                SWP_SIZE | SWP_SHOW | SWP_ACTIVATE );
  162.  
  163.                /* ----------- add program to tasklist  --------------- */
  164.               WinQueryWindowProcess( hwndFrame, &pid, NULL );
  165.               swCntrl.hwnd = hwndFrame ;
  166.               swCntrl.hwndIcon = (HWND) NULL ;
  167.               swCntrl.hprog = (HPROGRAM) NULL ;
  168.               swCntrl.idProcess = pid ;
  169.               swCntrl.idSession = (LONG) NULL ;
  170.               swCntrl.uchVisibility = SWL_VISIBLE ;
  171.               swCntrl.fbJump = SWL_JUMPABLE ;
  172.               strcpy( swCntrl.szSwtitle, pszMainTitle );
  173.               hSwitch = WinAddSwitchEntry((PSWCNTRL)&swCntrl);
  174.  
  175.  
  176.               WinSetPointer(HWND_DESKTOP,
  177.                             WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  178.  
  179.                  /* ---------- start the main processing loop ----------- */
  180.               while (WinGetMsg(hab, &qmsg,NULLHANDLE,0,0)){
  181.                   WinDispatchMsg(hab, &qmsg);
  182.               }
  183.  
  184.               WinRemoveSwitchEntry( hSwitch );
  185.            } // end of else ( pfnwpOldFrameProc ) 
  186.  
  187.            WinSetPointer(HWND_DESKTOP,
  188.                          WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  189.            WinDestroyWindow(hwndFrame);
  190.         }  // end of else (hwndFrame == NULLHANDLE) 
  191.  
  192.         WinSetPointer(HWND_DESKTOP,
  193.                       WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  194.         WinDestroyMsgQueue(hmq);
  195.      }  // end of else ( ...WinCreateMsgQueue() 
  196.  
  197.    WinTerminate(hab);
  198.    }  // end of else (...WinInitialize(NULL) 
  199. }  //  end of main() 
  200.  
  201. /* ********************************************************************** */
  202. /*                                                                        */
  203. /*   MainWindowProc                                                       */
  204. /*                                                                        */
  205. /* ********************************************************************** */
  206.  
  207. MRESULT EXPENTRY
  208. MainWindowProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  209. {
  210.  
  211.   switch (msg) {
  212.  
  213.        /* --------  Have PM paint the client window area  ------ */
  214.     case WM_ERASEBACKGROUND :
  215.        return( (MRESULT)TRUE );
  216.  
  217.        /* --------  Handle commands from *both* menus ---------- */
  218.     case WM_COMMAND :
  219.         {
  220.         switch ( SHORT1FROMMP( mp1 )){
  221.              /* ----- Toolbar items -------- */
  222.           case  MID_TB_1 :
  223.                DosBeep( 440,250 ) ;
  224.                break;
  225.           case  MID_TB_2 :
  226.                DosBeep( 466,250 ) ;
  227.                break;
  228.           case  MID_TB_3 :
  229.                DosBeep( 494,250 ) ;
  230.                break;
  231.           case  MID_TB_4 :
  232.                DosBeep( 524,250 ) ;
  233.                break;
  234.           case  MID_TB_5 :
  235.                DosBeep( 550,250 ) ;
  236.                break;
  237.           case  MID_TB_6 :
  238.                DosBeep( 588,250 ) ;
  239.                break;
  240.           case  MID_TB_7 :
  241.                DosBeep( 624,250 ) ;
  242.                break;
  243.           case  MID_TB_8 :
  244.                DosBeep( 662,250 ) ;
  245.                break;
  246.           case  MID_TB_9 :
  247.                DosBeep( 701,250 ) ;
  248.                break;
  249.           case  MID_TB_10:
  250.                DosBeep( 743,250 ) ;
  251.                break;
  252.               /* -------- Menu Bar items ----------- */
  253.           case  MID_SUB11 :
  254.                 WinMessageBox( HWND_DESKTOP,
  255.                                hwnd,
  256.                                "Menu 1, Item 1 Selected",
  257.                                pszMainTitle ,
  258.                                0,
  259.                                MB_ICONASTERISK | MB_OK );
  260.                break;
  261.           case  MID_SUB21 :
  262.                 WinMessageBox( HWND_DESKTOP,
  263.                                hwnd,
  264.                                "Menu 2, Item 1 Selected",
  265.                                pszMainTitle ,
  266.                                0,
  267.                                MB_ICONASTERISK | MB_OK );
  268.                break;
  269.           case  MID_SUB22 :
  270.                 WinMessageBox( HWND_DESKTOP,
  271.                                hwnd,
  272.                                "Menu 2, Item 2 Selected",
  273.                                pszMainTitle ,
  274.                                0,
  275.                                MB_ICONASTERISK | MB_OK );
  276.                break;
  277.           case  MID_SUB31 :
  278.                 WinMessageBox( HWND_DESKTOP,
  279.                                hwnd,
  280.                                "Menu 3, Item 1 Selected",
  281.                                pszMainTitle ,
  282.                                0,
  283.                                MB_ICONASTERISK | MB_OK );
  284.                break;
  285.           case  MID_SUB32 :
  286.                 WinMessageBox( HWND_DESKTOP,
  287.                                hwnd,
  288.                                "Menu 3, Item 2 Selected",
  289.                                pszMainTitle ,
  290.                                0,
  291.                                MB_ICONASTERISK | MB_OK );
  292.                break;
  293.           case  MID_SUB33 :
  294.                 WinMessageBox( HWND_DESKTOP,
  295.                                hwnd,
  296.                                "Menu 3, Item 3 Selected",
  297.                                pszMainTitle ,
  298.                                0,
  299.                                MB_ICONASTERISK | MB_OK );
  300.                break;
  301.  
  302.           default:
  303.                break;
  304.           } // end of switch() 
  305.         }
  306.         break;
  307.  
  308.     default:
  309.       return( WinDefWindowProc(hwnd,msg,mp1,mp2) );
  310.  
  311.   } //  end of switch () 
  312.   return( FALSE );
  313.  
  314. } //  end of MainWindowProc()
  315. /* ********************************************************************** */
  316. /*                                                                        */
  317. /*   NewFrameProc                                                         */
  318. /*                                                                        */
  319. /*       This frame proc subclasses the original frame proc. By           */
  320. /*   handling just a few key messages, we can seamlessly add a new        */
  321. /*   control to the standard set of Frame window controls. The messages   */
  322. /*   of interest are :  WM_QUERYFRAMECTLCOUNT, WM_FORMATFRAME, and        */
  323. /*   WM_CALCFRAMERECT.                                                    */
  324. /*                                                                        */
  325. /*                      WM_QUERYFRAMECTLCOUNT                             */
  326. /*      By catching WM_QUERYFRAMECTLCOUNT, we can return the count of the */
  327. /*   total number of frame controls, both original and new.  This count   */
  328. /*   is used to allocate SWP structures for the array during frame        */
  329. /*   formating.  To add a new control, we will take the default           */
  330. /*   number returned by the original message processing and then          */
  331. /*   simply add one.                                                      */
  332. /*                                                                        */
  333. /*                         WM_FORMATFRAME                                 */
  334. /*      This is the message where most of the interesting work            */
  335. /*   involve with added a new control happens. When we process            */
  336. /*   WM_FORMATFRAME, we first call the original frame proc to setup       */
  337. /*   the SWP array for all the original frame controls (i.e. system menu, */
  338. /*   titlebar, min/max buttons, etc).  Note that among these "original"   */
  339. /*   frame controls is the toolbar, since it was set to the frame when    */
  340. /*   it was loaded (i.e. it is the FID_MENU menu).  We will add the       */
  341. /*   regular action bar as a second menu below the toolbar.  The original */
  342. /*   processing of WM_FORMATFRAME will return the count of original frame */
  343. /*   controls (note that because we modified WM_QUERYFRAMECTLCOUNT the    */
  344. /*   SWP array will actually contain an extra allocated SWP for our       */
  345. /*   second menu).  We will setup the SWP for our second menu based upon  */
  346. /*   setting for the first menu. We will also have to adjust the client   */
  347. /*   window size to make room for the additional menu.  Likewise, we will */
  348. /*   need to check if there is a vertical scroll bar and adjust it. We    */
  349. /*   will us a simple technique of comparing the hwnd field from the SWP  */
  350. /*   array with our global variable hwnds to determine which SWP          */
  351. /*   structures in the array we are interested in.                        */
  352. /*                                                                        */
  353. /*                            WM_CALCFRAMERECT                            */
  354. /*        This message is generated by the API call WinCalcFrameRect().   */
  355. /*   When the Frame procedure receives this messages, it takes the        */
  356. /*   passed in rectangle, and calculates a target rectangle. If the       */
  357. /*   passed in rectangle is the Frame window rectangle, it calculates the */
  358. /*   Client window rectangle that fits this frame size; if the passed in  */
  359. /*   rectangle is the Client window rectangle, it calculates the Frame    */
  360. /*   window rectangle that fits this client size. We must catch this      */
  361. /*   message to adjust the Client window portion of the calculation to    */
  362. /*   compensate for the second menu. This means that when we are          */
  363. /*   calculating a Frame rectangle, we will add to the resulting          */
  364. /*   rectangle, and when we are calculating a Client rectangle, we will   */
  365. /*   subtract from the resulting rectangle.                               */
  366. /*                                                                        */
  367. /*      It is important to note that we are making the assumption that    */
  368. /*   the Frame window controls will be positioned in their normal         */
  369. /*   orientation. For example, we are assuming that the FID_MENU menu     */
  370. /*   (the toolbar in our case), will be positioned by default at the top  */
  371. /*   of the client window, under the titlebar window. Since we control    */
  372. /*   the client window processing in this sample this is an easy          */
  373. /*   assumption to make. However, if the Client window proc were to       */
  374. /*   reposition the Frame controls by processing the WM_FORMATFRAME       */
  375. /*   message, the sample code, as is, could run into some problems. If    */
  376. /*   there is a possibility that the Client window proc may manipulate    */
  377. /*   the Frame controls by processing WM_FORMATFRAME, extra code to       */
  378. /*   handle this situations may be called for in this proc.               */
  379. /*                                                                        */
  380. /* ********************************************************************** */
  381.  
  382. MRESULT EXPENTRY
  383. NewFrameProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  384. {
  385.   PFNWP   pfnwpOldFrameProc ;
  386.  
  387.      /* ------- get original frame procedure  --------- */
  388.   pfnwpOldFrameProc = (PFNWP) WinQueryWindowULong( hwnd, QWL_USER );
  389.  
  390.   switch (msg) {
  391.     case WM_QUERYFRAMECTLCOUNT :
  392.          {
  393.           USHORT   usItemCount ;
  394.  
  395.                 /* ---- get count of original frame controls --- */
  396.           usItemCount = SHORT1FROMMR( pfnwpOldFrameProc( hwnd,
  397.                                                          msg,
  398.                                                          mp1, mp2 ));
  399.                 /* ------- add 1 for new toolbar control  ------ */
  400.           return ( (MRESULT) ++usItemCount );
  401.          }
  402.  
  403.     case WM_FORMATFRAME :
  404.        {
  405.          PSWP     pSWP ;               // pointer to array of frame ctl SWPs
  406.          USHORT   usItemCount ;        // count of original frame controls
  407.          USHORT   usNewMenuIndex ;     // index of new menu SWP
  408.          USHORT   usToolBarIndex ;     // index of Tool Bar menu SWP
  409.          USHORT   usClientIndex ;      // index of client window SWP
  410.          USHORT   usVertScrollIndex ;  // index of vertical scrollbar SWP
  411.          HWND     hwndVertScroll ;     // hwnd of vertical scrollbar
  412.          PRECTL   prectlClient ;       // pointer to Client rect (in mp2)
  413.  
  414.             /* ------- get a pointer to the SWP array ---------- */
  415.          pSWP = PVOIDFROMMP( mp1 );
  416.  
  417.            /* ---- run regular processing for original controls --- */
  418.            /*
  419.             *  Note that the original frame proc will setup all
  420.             *  the SWP sturctures for the standard frame window
  421.             *  controls starting at the beginning of the array.
  422.             *  A count of how many SWP structures were initialized
  423.             *  is returned.
  424.             *  All SWP structures for new controls that are to be
  425.             *  added ( in our case, 1 ) will be uninitialized and
  426.             *  at the end of the array. The start of the uninitialied
  427.             *  SWP structure start at an index equal to the returned
  428.             *  count.
  429.             */
  430.          usItemCount = SHORT1FROMMR( pfnwpOldFrameProc( hwnd,
  431.                                                         msg,
  432.                                                         mp1, mp2 ));
  433.  
  434.             /* ------------- locate SWP for 1st menu  ---------- */
  435.             /*
  436.              *  We will use the settings of the 1st menu to help initialize
  437.              *  the SWP for the second menu. We look for the proper SWP
  438.              *  by scanning the array for the matching hwnd.
  439.              */
  440.          for ( usToolBarIndex = 0; 
  441.                usToolBarIndex < usItemCount; 
  442.                usToolBarIndex++) {
  443.             if (pSWP[usToolBarIndex].hwnd == hwndToolBar){
  444.                break;
  445.             }
  446.          } // end of for( usToolBarIndex...
  447.  
  448.             /* ------------- locate SWP for client window  ---------- */
  449.             /*
  450.              *  We will need to adjust the vertical height of the client
  451.              *  window to make room for the second menu. We look for the
  452.              *  proper SWP by scanning the array for a matching hwnd.
  453.              */
  454.          for ( usClientIndex = 0;
  455.                usClientIndex < usItemCount;
  456.                usClientIndex++){
  457.             if (pSWP[usClientIndex].hwnd == hwndClient ){
  458.                break;
  459.             }
  460.          } // end of for ( usClientIndex...
  461.  
  462.             /* --- locate SWP for vert scroll (if exists) --- */
  463.             /*
  464.              *  First we will check if this window has a vert. scroll bar.
  465.              *  We will need to adjust the vertical height of the scroll
  466.              *  bar to make room for the second menu. We look for the
  467.              *  proper SWP by scanning the array for a matching hwnd.
  468.              */
  469.  
  470.          if ( ( hwndVertScroll =
  471.                     WinWindowFromID( hwnd, FID_VERTSCROLL)) != NULLHANDLE ){
  472.             for ( usVertScrollIndex = 0;
  473.                   usVertScrollIndex < usItemCount;
  474.                   usVertScrollIndex++){
  475.                if (pSWP[usVertScrollIndex].hwnd == hwndVertScroll ){
  476.                   break;
  477.                }
  478.             } // end of for ( usClientIndex...
  479.          } // end of if (( hwndVertScroll...
  480.  
  481.  
  482.           /* ------ the new SWP starts after standard control SWPs ----- */
  483.          usNewMenuIndex = usItemCount ;
  484.  
  485.           /* ---- get size values for 2nd menu bar  -------- */
  486.          pSWP[ usNewMenuIndex ].fl = SWP_SIZE;
  487.          pSWP[ usNewMenuIndex ].cx =  pSWP[usToolBarIndex].cx ;  // set some
  488.          pSWP[ usNewMenuIndex ].cy =  pSWP[usToolBarIndex].cy ;  // defaults
  489.          pSWP[ usNewMenuIndex ].hwndInsertBehind = HWND_TOP ;
  490.          pSWP[ usNewMenuIndex ].hwnd = hwndMenuBar ;
  491.  
  492.            /* -- get the menu code to make the actual size adjustments -- */
  493.          WinSendMsg( hwndMenuBar,
  494.                      WM_ADJUSTWINDOWPOS,
  495.                      MPFROMP( pSWP+usNewMenuIndex ),
  496.                      (MPARAM) 0L );
  497.  
  498.          /* ------ position menu directly below other menu  ------- */
  499.          pSWP[usNewMenuIndex].x = pSWP[usToolBarIndex].x ;
  500.          pSWP[usNewMenuIndex].y = pSWP[usToolBarIndex].y -
  501.                                                pSWP[usNewMenuIndex].cy ;
  502.          pSWP[usNewMenuIndex].fl = pSWP[usToolBarIndex].fl ;
  503.  
  504.          /* --------  adjust client window size for 2nd menu ------- */
  505.          pSWP[usClientIndex].cy -= pSWP[usNewMenuIndex].cy ;
  506.  
  507.          /* --------  set new client size in rectl param  ---------- */
  508.          /*
  509.           * Note that the rectangle was set to default by old frame proc
  510.           */
  511.          prectlClient = (PRECTL) PVOIDFROMMP( mp2 );
  512.          if ( prectlClient ){
  513.             prectlClient->yTop -=
  514.                             (prectlClient->yTop - prectlClient->yBottom) -
  515.                             pSWP[usClientIndex].cy;
  516.          }
  517.  
  518.          /* -------- adjust vertical scroll size for 2nd menu  ----- */
  519.          if ( hwndVertScroll != NULLHANDLE ){
  520.              pSWP[usVertScrollIndex].cy -= pSWP[usNewMenuIndex].cy ;
  521.          }
  522.  
  523.          /* ---  return total count of controls ( +1 for 2nd menu ) --- */
  524.          return( MRFROMSHORT( ++usItemCount )  );
  525.        }
  526.        break;
  527.  
  528.     case WM_CALCFRAMERECT :
  529.        {
  530.         PRECTL   prectl;              // in/out rect parameter (mp1)
  531.         BOOL     fCalcClientRect ;    // flag defining calc type (mp2)
  532.         SWP      swp ;                // position struct for 2nd menu
  533.  
  534.            /* ----- first call old proc for defaults  ------- */
  535.         if ( pfnwpOldFrameProc( hwnd, msg, mp1, mp2 ) ){
  536.  
  537.               /* ----- get the passed parameters  -------- */
  538.            prectl = (PRECTL) PVOIDFROMMP( mp1 );
  539.            fCalcClientRect = (BOOL) SHORT1FROMMP( mp2 );
  540.  
  541.               /* ---- determine height of second menu ---- */
  542.            swp.cy = 0 ;  // just in case call fails
  543.            WinQueryWindowPos( hwndMenuBar, &swp );
  544.            if ( fCalcClientRect ){
  545.               /*
  546.                *  we are calculating the client rect so we must SUBTRACT
  547.                *  the height of the 2nd menu from the default client size
  548.                */
  549.                prectl->yTop -= swp.cy ;
  550.            }
  551.            else{
  552.               /*
  553.                *  we are calculating the frame rect so we must ADD
  554.                *  the height of the 2nd menu to the default frame size
  555.                */
  556.                prectl->yTop += swp.cy ;
  557.            }
  558.         } // end of if ( pfnwpOldFrameProc(...
  559.         else {
  560.           return( FALSE );  // error occurred
  561.         }
  562.        }
  563.        return( (MRESULT)TRUE );
  564.  
  565.     default:
  566.       return( pfnwpOldFrameProc(hwnd,msg,mp1,mp2) );
  567.  
  568.   } // end of switch () 
  569.  
  570.   return( FALSE );
  571.  
  572. } // end of NewFrameProc() 
  573. /* ********************************************************************** */
  574. /*                                                                        */
  575. /*   ShowErrorWindow                                                      */
  576. /*                                                                        */
  577. /* ********************************************************************** */
  578. VOID
  579. ShowErrorWindow( PSZ  pszErrorMsg, BOOL bUseLastError )
  580. {
  581.   CHAR      acErrorBuffer[256] ;
  582.  
  583.   if ( bUseLastError ) {
  584.       ERRORID   errorID = WinGetLastError( hab );
  585.  
  586.       sprintf( acErrorBuffer,
  587.                "%s \n(code = 0x%lX)",
  588.                pszErrorMsg,
  589.                (ULONG) errorID );
  590.       pszErrorMsg = (PSZ) acErrorBuffer ;
  591.   }  // end of if ( bUseLastError ) 
  592.  
  593.   WinMessageBox( HWND_DESKTOP,
  594.                  HWND_DESKTOP,
  595.                  pszErrorMsg ,
  596.                  pszErrorTitle ,
  597.                  0,
  598.                  MB_CUACRITICAL | MB_OK );
  599.  
  600. } // end of ShowErrorWindow()
  601.  
  602. /* ********************************************************************** */
  603. /* ********************************************************************** */
  604.