home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / NBBASE.ZIP / NBBASE.C < prev    next >
Text File  |  1993-02-23  |  48KB  |  1,143 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  nbbase.c               AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  10-17-92                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  Just enter NBBASE on the command line.                           *
  9.  *                                                                   *
  10.  * MODULE DESCRIPTION:                                               *
  11.  *                                                                   *
  12.  *  Only module for NBBASE.EXE, a program that demonstrates the base *
  13.  *  functionality of a notebook control. This module creates a       *
  14.  *  standard window with a notebook in it. It then inserts pages     *
  15.  *  into the notebook and turns to the first page. A dialog box is   *
  16.  *  associated with each page and the dialog box is loaded and       *
  17.  *  associated only when the page is brought forward for the first   *
  18.  *  time. This decreases percieved program load time.                *
  19.  *                                                                   *
  20.  *  This program uses MAJOR and MINOR pages. The MAJOR pages have    *
  21.  *  their tabs on the right side of the notebook. The MINOR pages    *
  22.  *  have their tabs on the bottom of the notebook.                   *
  23.  *                                                                   *
  24.  * NOTES:                                                            *
  25.  *                                                                   *
  26.  *  This program is strictly a sample and should be treated as such. *
  27.  *  There is nothing real-world about it and the dialogs that it     *
  28.  *  uses do nothing useful. I think it still demonstrates the        *
  29.  *  notebook control as well as can be expected though.              *
  30.  *                                                                   *
  31.  *  I hope this code proves useful for other PM programmers. The     *
  32.  *  more of us the better!                                           *
  33.  *                                                                   *
  34.  * HISTORY:                                                          *
  35.  *                                                                   *
  36.  *  10-17-92 - Program coded                                         *
  37.  *  11-28-92 - Added code to size the window to the display          *
  38.  *  12-04-92 - Used Notebook messages to get rid of global variables.*
  39.  *  02-22-93 - Added code to size the notebook and frame window      *
  40.  *               based on the size of the largest dialog.            *
  41.  *                                                                   *
  42.  *  Rick Fishman                                                     *
  43.  *  Code Blazers, Inc.                                               *
  44.  *  4113 Apricot                                                     *
  45.  *  Irvine, CA. 92720                                                *
  46.  *  CIS ID: 72251,750                                                *
  47.  *                                                                   *
  48.  *********************************************************************/
  49.  
  50. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  51.  
  52. /*********************************************************************/
  53. /*------- Include relevant sections of the OS/2 header files --------*/
  54. /*********************************************************************/
  55.  
  56. #define  INCL_DOSRESOURCES
  57. #define  INCL_GPILCIDS
  58. #define  INCL_GPIPRIMITIVES
  59. #define  INCL_WINDIALOGS
  60. #define  INCL_WINERRORS
  61. #define  INCL_WINFRAMEMGR
  62. #define  INCL_WINMESSAGEMGR
  63. #define  INCL_WINRECTANGLES
  64. #define  INCL_WINSTDBOOK
  65. #define  INCL_WINSYS
  66. #define  INCL_WINWINDOWMGR
  67.  
  68. /**********************************************************************/
  69. /*----------------------------- INCLUDES -----------------------------*/
  70. /**********************************************************************/
  71.  
  72. #include <os2.h>
  73. #include <stdio.h>
  74. #include <stdarg.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include "nbbase.h"
  78.  
  79. /*********************************************************************/
  80. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  81. /*********************************************************************/
  82.  
  83. #define FRAME_FLAGS           (FCF_TASKLIST | FCF_TITLEBAR   | FCF_SYSMENU | \
  84.                                FCF_MINMAX   | FCF_SIZEBORDER | FCF_ICON)
  85.  
  86. #define FRAME_X               10   // In dialog units!
  87. #define FRAME_Y               10   // In dialog units!
  88.  
  89. #define TAB_WIDTH_MARGIN      10   // Padding for the width of a notebook tab
  90. #define TAB_HEIGHT_MARGIN     6    // Padding for the height of a notebook tab
  91. #define DEFAULT_NB_TAB_HEIGHT 16   // Default if Gpi calls fail
  92.  
  93. /**********************************************************************/
  94. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  95. /**********************************************************************/
  96.  
  97.        INT  main               ( VOID );
  98. static BOOL TurnToFirstPage    ( HWND hwndClient );
  99. static BOOL SetFramePos        ( HWND hwndFrame );
  100. static BOOL GetFrameSize       ( HWND hwndNB, PRECTL prclFrame );
  101. static BOOL GetDialogDimensions( ULONG idDlg, PLONG plCx, PLONG plCy,
  102.                                  PULONG pidFocus );
  103. static BOOL CreateNotebook     ( HWND hwndClient );
  104. static BOOL SetUpPage          ( HWND hwndNB, INT iArrayIndex );
  105. static BOOL SetTabDimensions   ( HWND hwndNB );
  106. static INT  GetStringSize      ( HPS hps, HWND hwndNB, PSZ szString);
  107. static BOOL ControlMsg         ( HWND hwndClient, USHORT usCtl, USHORT usEvent,
  108.                                  MPARAM mp2);
  109. static VOID SetNBPage          ( HWND hwndClient, PPAGESELECTNOTIFY ppsn );
  110. static HWND LoadAndAssociate   ( HWND hwndClient, PNBPAGE pnbp,
  111.                                  PPAGESELECTNOTIFY ppsn );
  112. static VOID Msg                ( PSZ szFormat, ... );
  113.  
  114. FNWP wpClient, wpPage1, wpPage2A, wpPage2B, wpPage3;
  115.  
  116. /**********************************************************************/
  117. /*------------------------ GLOBAL VARIABLES --------------------------*/
  118. /**********************************************************************/
  119.  
  120. NBPAGE nbpage[] =    // INFORMATION ABOUT NOTEBOOK PAGES (see NBBASE.H)
  121. {
  122.     { wpPage1,     "Page 1",  "Page ~1",  IDD_PAGE1,  EF_1,  FALSE, BKA_MAJOR },
  123.  
  124.     { (PFNWP) NULL,"Page 2",  "Page ~2",  0,         0,      TRUE,  BKA_MAJOR },
  125.  
  126.     { wpPage2A,    "Page 2A", "Page 2~A", IDD_PAGE2A, EF_2A, FALSE, BKA_MINOR },
  127.  
  128.     { wpPage2B,    "Page 2B", "Page 2~B", IDD_PAGE2B, EF_2B, FALSE, BKA_MINOR },
  129.  
  130.     { wpPage3,     "Page 3",  "Page ~3",  IDD_PAGE3,  EF_3,  FALSE, BKA_MAJOR }
  131. };
  132.  
  133. #define PAGE_COUNT (sizeof( nbpage ) / sizeof( NBPAGE ))
  134.  
  135. /**********************************************************************/
  136. /*------------------------------- main -------------------------------*/
  137. /*                                                                    */
  138. /*  PROGRAM ENTRYPOINT                                                */
  139. /*                                                                    */
  140. /*  PARMS: nothing                                                    */
  141. /*                                                                    */
  142. /*  NOTES:                                                            */
  143. /*                                                                    */
  144. /*  RETURNS: nothing                                                  */
  145. /*                                                                    */
  146. /*--------------------------------------------------------------------*/
  147. /**********************************************************************/
  148. INT main( VOID )
  149. {
  150.     BOOL  fSuccess;
  151.     HAB   hab;
  152.     HMQ   hmq;
  153.     HWND  hwndFrame, hwndClient;
  154.     QMSG  qmsg;
  155.     ULONG flFrame = FRAME_FLAGS;
  156.  
  157.     // This macro is defined for the debug version of the C Set/2 Memory
  158.     // Management routines. Since the debug version writes to stderr, we
  159.     // send all stderr output to a debuginfo file. Look in MAKEFILE to see how
  160.     // to enable the debug version of those routines.
  161.  
  162. #ifdef __DEBUG_ALLOC__
  163.     freopen( DEBUG_FILENAME, "w", stderr );
  164. #endif
  165.  
  166.     hab = WinInitialize( 0 );
  167.  
  168.     if( hab )
  169.         hmq = WinCreateMsgQueue( hab, 0 );
  170.     else
  171.     {
  172.         WinAlarm( HWND_DESKTOP, WA_ERROR );
  173.  
  174.         (void) fprintf( stderr, "WinInitialize failed!" );
  175.     }
  176.  
  177.     if( hmq )
  178.  
  179.         // CS_CLIPCHILDREN so the client doesn't need to paint the area covered
  180.         // by the notebook. CS_SIZEREDRAW so the notebook gets sized correctly
  181.         // the first time the Frame/Client get drawn.
  182.  
  183.         fSuccess = WinRegisterClass( hab, NOTEBOOK_WINCLASS, wpClient,
  184.                                      CS_CLIPCHILDREN | CS_SIZEREDRAW, 0 );
  185.     else
  186.     {
  187.         WinAlarm( HWND_DESKTOP, WA_ERROR );
  188.  
  189.         (void) fprintf( stderr, "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  190.     }
  191.  
  192.     if( fSuccess )
  193.         hwndFrame = WinCreateStdWindow( HWND_DESKTOP, 0, &flFrame,
  194.                                         NOTEBOOK_WINCLASS, NULL, 0, NULLHANDLE,
  195.                                         ID_NBWINFRAME, &hwndClient );
  196.     else
  197.         Msg( "WinRegisterClass RC(%X)", HABERR( hab ) );
  198.  
  199.     if( hwndFrame )
  200.     {
  201.         // If the TURNTOPAGE is sent during WM_CREATE processing, the dialog
  202.         // box for page 1 won't be visible.
  203.  
  204.         fSuccess = TurnToFirstPage( hwndClient );
  205.  
  206.         if( fSuccess )
  207.             fSuccess = SetFramePos( hwndFrame );
  208.  
  209.         if( fSuccess )
  210.             WinSetWindowText( hwndFrame, PROGRAM_TITLE );
  211.     }
  212.  
  213.     if( hwndFrame )
  214.         while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  215.             WinDispatchMsg( hab, &qmsg );
  216.  
  217.     if( hwndFrame )
  218.         WinDestroyWindow( hwndFrame );
  219.  
  220.     if( hmq )
  221.         WinDestroyMsgQueue( hmq );
  222.  
  223.     if( hab )
  224.         WinTerminate( hab );
  225.  
  226. #ifdef __DEBUG_ALLOC__
  227.     _dump_allocated( -1 );
  228. #endif
  229.  
  230.     return 0;
  231. }
  232.  
  233. /**********************************************************************/
  234. /*----------------------------- wpClient -----------------------------*/
  235. /*                                                                    */
  236. /*  CLIENT WINDOW PROCEDURE                                           */
  237. /*                                                                    */
  238. /*  PARMS: window proc params                                         */
  239. /*                                                                    */
  240. /*  NOTES:                                                            */
  241. /*                                                                    */
  242. /*  RETURNS: retcode from processing message                          */
  243. /*                                                                    */
  244. /*--------------------------------------------------------------------*/
  245. /**********************************************************************/
  246. MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  247. {
  248.     switch( msg )
  249.     {
  250.         case WM_CREATE:
  251.  
  252.             // Don't create the window if notebook creation fails
  253.  
  254.             if( !CreateNotebook( hwnd ) )
  255.                 return (MRESULT) TRUE;
  256.  
  257.             break;
  258.  
  259.  
  260.         case WM_SIZE:
  261.  
  262.             // Size the notebook with the client window
  263.  
  264.             WinSetWindowPos( WinWindowFromID( hwnd, ID_NB ), 0, 0, 0,
  265.                              SHORT1FROMMP( mp2 ), SHORT2FROMMP( mp2 ),
  266.                              SWP_SIZE | SWP_SHOW );
  267.  
  268.             break;
  269.  
  270.  
  271.         case WM_ERASEBACKGROUND:
  272.  
  273.             // Paint the client in the default background color
  274.  
  275.             return (MRESULT) TRUE;
  276.  
  277.  
  278.         case WM_CONTROL:
  279.  
  280.             if( ControlMsg( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ),
  281.                             mp2 ) )
  282.                 return 0;
  283.             else
  284.                 break;
  285.     }
  286.  
  287.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  288. }
  289.  
  290. /**********************************************************************/
  291. /*------------------------- TurnToFirstPage --------------------------*/
  292. /*                                                                    */
  293. /*  TURN TO THE FIRST PAGE IN THE NOTEBOOK.                           */
  294. /*                                                                    */
  295. /*  PARMS: client window handle                                       */
  296. /*                                                                    */
  297. /*  NOTES:                                                            */
  298. /*                                                                    */
  299. /*  RETURNS: TRUE or FALSE if successful or not                       */
  300. /*                                                                    */
  301. /*--------------------------------------------------------------------*/
  302. /**********************************************************************/
  303. static BOOL TurnToFirstPage( HWND hwndClient )
  304. {
  305.     HWND  hwndNB = WinWindowFromID( hwndClient, ID_NB );
  306.     ULONG ulFirstPage;
  307.     BOOL  fSuccess = TRUE;
  308.  
  309.     ulFirstPage = (ULONG) WinSendMsg( hwndNB, BKM_QUERYPAGEID, NULL,
  310.                                       MPFROM2SHORT( BKA_FIRST, BKA_MAJOR ) );
  311.  
  312.     if( ulFirstPage == (ULONG) BOOKERR_INVALID_PARAMETERS )
  313.     {
  314.         fSuccess = FALSE;
  315.  
  316.         Msg( "TurnToFirstPage BKM_QUERYPAGEID Invalid page specified" );
  317.     }
  318.     else
  319.     if( ulFirstPage )
  320.     {
  321.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_TURNTOPAGE,
  322.                                        MPFROMLONG( ulFirstPage ), NULL );
  323.  
  324.         if( !fSuccess )
  325.             Msg( "TurnToFirstPage BKM_TURNTOPAGE RC(%X)", HWNDERR( hwndNB ) );
  326.     }
  327.     else
  328.     {
  329.         fSuccess = FALSE;
  330.  
  331.         Msg( "TurnToFirstPage BKM_QUERYPAGEID RC(%X)", HWNDERR( hwndNB ) );
  332.     }
  333.  
  334.     return fSuccess;
  335. }
  336.  
  337. /**********************************************************************/
  338. /*---------------------------- SetFramePos ---------------------------*/
  339. /*                                                                    */
  340. /*  SET THE FRAME ORIGIN AND SIZE.                                    */
  341. /*                                                                    */
  342. /*  PARMS: frame window handle                                        */
  343. /*                                                                    */
  344. /*  NOTES:                                                            */
  345. /*                                                                    */
  346. /*  RETURNS: TRUE or FALSE if successful or not                       */
  347. /*                                                                    */
  348. /*--------------------------------------------------------------------*/
  349. /**********************************************************************/
  350. static BOOL SetFramePos( HWND hwndFrame )
  351. {
  352.     BOOL   fSuccess;
  353.     RECTL  rclFrame;
  354.     HWND   hwndNB;
  355.  
  356.     hwndNB = WinWindowFromID( WinWindowFromID( hwndFrame, FID_CLIENT ), ID_NB );
  357.  
  358.     fSuccess = GetFrameSize( hwndNB, &rclFrame );
  359.  
  360.     if( fSuccess )
  361.     {
  362.         fSuccess = WinSetWindowPos( hwndFrame, NULLHANDLE,
  363.                        rclFrame.xLeft, rclFrame.yBottom,
  364.                        (rclFrame.xRight - rclFrame.xLeft) + 1,
  365.                        (rclFrame.yTop - rclFrame.yBottom) + 1,
  366.                        SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE );
  367.  
  368.         if( !fSuccess )
  369.             Msg( "WinSetWindowPos for frame RC(%X)", HWNDERR( hwndFrame ) );
  370.     }
  371.  
  372.     return fSuccess;
  373. }
  374.  
  375. /**********************************************************************/
  376. /*---------------------------- GetFrameSize --------------------------*/
  377. /*                                                                    */
  378. /*  GET THE FRAME SIZE BASED ON THE LARGEST DIALOG BOX.               */
  379. /*                                                                    */
  380. /*  PARMS: notebook window handle,                                    */
  381. /*         pointer to a RECTL struct that will contain the frame      */
  382. /*           dimensions                                               */
  383. /*                                                                    */
  384. /*  NOTES:                                                            */
  385. /*                                                                    */
  386. /*  RETURNS: TRUE or FALSE if successful or not                       */
  387. /*                                                                    */
  388. /*--------------------------------------------------------------------*/
  389. /**********************************************************************/
  390. static BOOL GetFrameSize( HWND hwndNB, PRECTL prclFrame )
  391. {
  392.     BOOL   fSuccess = TRUE;
  393.     INT    i;
  394.     RECTL  rcl;
  395.     LONG   cx, cy;
  396.  
  397.     (void) memset( &rcl, 0, sizeof( RECTL ) );
  398.  
  399.     // Get the size of a notebook page by finding the dimensions of the largest
  400.     // dialog.
  401.  
  402.     for( i = 0; i < PAGE_COUNT; i++ )
  403.     {
  404.         // Get the height and width of the dialog. Also fill in the id of the
  405.         // item that is to get focus when the dialog is brought up.
  406.  
  407.         if( nbpage[ i ].idDlg )
  408.         {
  409.             fSuccess = GetDialogDimensions( nbpage[ i ].idDlg, &cx, &cy,
  410.                                             &(nbpage[ i ].idFocus) );
  411.  
  412.             if( fSuccess )
  413.             {
  414.                 if( cx > rcl.xRight )
  415.                     rcl.xRight = cx;
  416.  
  417.                 if( cy > rcl.yTop )
  418.                     rcl.yTop = cy;
  419.             }
  420.         }
  421.     }
  422.  
  423.     if( fSuccess )
  424.     {
  425.         // Convert size from dialog units to pixels.
  426.  
  427.         WinMapDlgPoints( HWND_DESKTOP, (PPOINTL) &rcl, 2, TRUE );
  428.  
  429.         // Calculate the size of the notebook from the size of the page. Since
  430.         // the notebook fills the client area, the size of the notebook is also
  431.         // the size of the client.
  432.  
  433.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_CALCPAGERECT,
  434.                                       MPFROMP( &rcl ), MPFROMLONG( FALSE ) );
  435.  
  436.         if( fSuccess )
  437.         {
  438.             // Calculate the size of the frame from the size of the client
  439.  
  440.             fSuccess = (BOOL) WinSendMsg( BOOKFRAME( hwndNB ),
  441.                                          WM_CALCFRAMERECT,
  442.                                          MPFROMP( &rcl ), MPFROMLONG( FALSE ) );
  443.  
  444.             if( fSuccess )
  445.             {
  446.                 // BKM_CALCPAGERECT and WM_CALCFRAMERECT take the x,y into
  447.                 // consideration when they do their work so we need to
  448.                 // calculate the actual cx and cy based upon its results. Keep
  449.                 // in mind we are only working with width and height at this
  450.                 // time.
  451.  
  452.                 rcl.xRight = rcl.xRight - rcl.xLeft;
  453.                 rcl.yTop   = rcl.yTop - rcl.yBottom;
  454.  
  455.                 // Now do the x and y origin
  456.  
  457.                 rcl.xLeft   = FRAME_X;
  458.                 rcl.yBottom = FRAME_Y;
  459.  
  460.                 // Convert origin from dialog units to pixels.
  461.  
  462.                 WinMapDlgPoints( HWND_DESKTOP, (PPOINTL) &rcl, 1, TRUE );
  463.  
  464.                 // Adjust cx,cy for new x,y. Until now it was assumed that the
  465.                 // origin was 0,0.
  466.  
  467.                 rcl.xRight += (rcl.xLeft - 1);
  468.                 rcl.yTop   += (rcl.yBottom - 1);
  469.  
  470.                 // Put the results in the caller's RECTL struct
  471.  
  472.                 fSuccess = WinCopyRect( ANCHOR( hwndNB ), prclFrame, &rcl );
  473.  
  474.                 if( !fSuccess )
  475.                     Msg( "GetFrameSize WinCopyRect RC(%X)", HWNDERR( hwndNB ) );
  476.             }
  477.             else
  478.                 Msg( "GetFrameSize WM_CALCFRAMERECT RC(%X)", HWNDERR( hwndNB ));
  479.         }
  480.         else
  481.             Msg( "GetFrameSize BKM_CALCPAGERECT RC(%X)", HWNDERR( hwndNB ));
  482.     }
  483.  
  484.     return fSuccess;
  485. }
  486.  
  487. /**********************************************************************/
  488. /*------------------------ GetDialogDimensions -----------------------*/
  489. /*                                                                    */
  490. /*  RETURN THE WIDTH AND HEIGHT OF A DIALOG BOX.                      */
  491. /*                                                                    */
  492. /*  PARMS: dialog box id,                                             */
  493. /*         address of the width,                                      */
  494. /*         address of the height,                                     */
  495. /*         address of the id of the control that will get the focus   */
  496. /*           when the dialog box is brought up                        */
  497. /*                                                                    */
  498. /*  NOTES:                                                            */
  499. /*                                                                    */
  500. /*  RETURNS: TRUE or FALSE if successful or not                       */
  501. /*                                                                    */
  502. /*--------------------------------------------------------------------*/
  503. /**********************************************************************/
  504. static BOOL GetDialogDimensions( ULONG idDlg, PLONG plCx, PLONG plCy,
  505.                                  PULONG pidFocus)
  506. {
  507.     BOOL   fSuccess = TRUE;
  508.     APIRET rc;
  509.     PDLGTEMPLATE pDlgTemplate = NULL;
  510.  
  511.     rc = DosGetResource( 0, RT_DIALOG, idDlg, (PPVOID) &pDlgTemplate );
  512.  
  513.     if( !rc )
  514.     {
  515.         PDLGTITEM pDlgItem;
  516.  
  517.         // Get offset to the item table
  518.  
  519.         pDlgItem = (PDLGTITEM) ((PBYTE) pDlgTemplate + pDlgTemplate->offadlgti);
  520.  
  521.         *plCx = (LONG) pDlgItem->cx;
  522.         *plCy = (LONG) pDlgItem->cy;
  523.  
  524.         // Currently the focus item doesn't seem to be set properly so it will
  525.         // be hard-coded in the constant array.
  526.         //*pidFocus = (ULONG) (pDlgItem + pDlgTemplate->iItemFocus)->id;
  527.         *pidFocus = *pidFocus;
  528.     }
  529.     else
  530.     {
  531.         fSuccess = FALSE;
  532.  
  533.         Msg( "GetDialogDimensions DosGetResource RC(%u)", rc );
  534.     }
  535.  
  536.     return fSuccess;
  537. }
  538.  
  539. /**********************************************************************/
  540. /*-------------------------- CreateNotebook --------------------------*/
  541. /*                                                                    */
  542. /*  CREATE THE NOTEBOOK WINDOW                                        */
  543. /*                                                                    */
  544. /*  INPUT: client window handle                                       */
  545. /*                                                                    */
  546. /*  1.                                                                */
  547. /*                                                                    */
  548. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  549. /*                                                                    */
  550. /*--------------------------------------------------------------------*/
  551. /**********************************************************************/
  552. static BOOL CreateNotebook( HWND hwndClient )
  553. {
  554.     BOOL fSuccess = TRUE;
  555.     HWND hwndNB;
  556.     INT  i;
  557.  
  558.     // Create the notebook. Its parent and owner will be the client window.
  559.     // Its pages will show on the bottom right of the notebook. Its major tabs
  560.     // will be on the right and they will be rounded. The status text will be
  561.     // centered. Its binding will be spiraled rather than solid. The tab text
  562.     // will be left-justified.
  563.  
  564.     hwndNB = WinCreateWindow( hwndClient, WC_NOTEBOOK, NULL,
  565.                 BKS_BACKPAGESBR | BKS_MAJORTABRIGHT | BKS_ROUNDEDTABS |
  566.                 BKS_STATUSTEXTCENTER | BKS_SPIRALBIND | BKS_TABTEXTLEFT |
  567.                 WS_GROUP | WS_TABSTOP | WS_VISIBLE,
  568.                 0, 0, 0, 0, hwndClient, HWND_TOP, ID_NB, NULL, NULL );
  569.  
  570.     if( hwndNB )
  571.     {
  572.         // Set the page background color to grey so it is the same as a dlg box.
  573.  
  574.         if( !WinSendMsg( hwndNB, BKM_SETNOTEBOOKCOLORS,
  575.                          MPFROMLONG( SYSCLR_FIELDBACKGROUND ),
  576.                          MPFROMSHORT( BKA_BACKGROUNDPAGECOLORINDEX ) ) )
  577.             Msg( "BKM_SETNOTEBOOKCOLORS failed! RC(%X)", HWNDERR( hwndClient ));
  578.  
  579.         if( !SetTabDimensions( hwndNB ) )
  580.             fSuccess = FALSE;
  581.  
  582.         // Insert all the pages into the notebook and configure them. The dialog
  583.         // boxes are not going to be loaded and associated with those pages yet.
  584.  
  585.         for( i = 0; i < PAGE_COUNT && fSuccess; i++ )
  586.             fSuccess = SetUpPage( hwndNB, i );
  587.     }
  588.     else
  589.     {
  590.         fSuccess = FALSE;
  591.  
  592.         Msg( "Notebook creation failed! RC(%X)", HWNDERR( hwndClient ) );
  593.     }
  594.  
  595.     return fSuccess;
  596. }
  597.  
  598. /**********************************************************************/
  599. /*----------------------------- SetUpPage ----------------------------*/
  600. /*                                                                    */
  601. /*  SET UP A NOTEBOOK PAGE.                                           */
  602. /*                                                                    */
  603. /*  INPUT: window handle of notebook control,                         */
  604. /*         index into nbpage array                                    */
  605. /*                                                                    */
  606. /*  1.                                                                */
  607. /*                                                                    */
  608. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  609. /*                                                                    */
  610. /*--------------------------------------------------------------------*/
  611. /**********************************************************************/
  612. static BOOL SetUpPage( HWND hwndNB, INT iPage )
  613. {
  614.     BOOL  fSuccess = TRUE;
  615.     ULONG ulPageId;
  616.  
  617.     // Insert a page into the notebook. Specify that it is to have status text
  618.     // and the window associated with each page will be automatically sized by
  619.     // the notebook according to the size of the page.
  620.  
  621.     ulPageId = (ULONG) WinSendMsg( hwndNB, BKM_INSERTPAGE, NULL,
  622.                             MPFROM2SHORT( nbpage[ iPage ].usTabType |
  623.                                           BKA_STATUSTEXTON | BKA_AUTOPAGESIZE,
  624.                                           BKA_LAST ) );
  625.  
  626.     if( ulPageId )
  627.     {
  628.         // Insert a pointer to this page's info into the space available
  629.         // in each page (its PAGE DATA that is available to the application).
  630.  
  631.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETPAGEDATA,
  632.                                       MPFROMLONG( ulPageId ),
  633.                                       MPFROMP( &nbpage[ iPage ] ) );
  634.  
  635.         // Set the text into the status line.
  636.  
  637.         if( fSuccess )
  638.         {
  639.             fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETSTATUSLINETEXT,
  640.                                           MPFROMP( ulPageId ),
  641.                         MPFROMP( nbpage[ iPage ].szStatusLineText ) );
  642.  
  643.             if( !fSuccess )
  644.                 Msg( "BKM_SETSTATUSLINETEXT RC(%X)", HWNDERR( hwndNB ) );
  645.         }
  646.         else
  647.             Msg( "BKM_SETPAGEDATA RC(%X)", HWNDERR( hwndNB ) );
  648.  
  649.         // Set the text into the tab for this page.
  650.  
  651.         if( fSuccess )
  652.         {
  653.             fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETTABTEXT,
  654.                                           MPFROMP( ulPageId ),
  655.                                    MPFROMP( nbpage[ iPage ].szTabText ) );
  656.  
  657.             if( !fSuccess )
  658.                 Msg( "BKM_SETTABTEXT RC(%X)", HWNDERR( hwndNB ) );
  659.         }
  660.     }
  661.     else
  662.     {
  663.         fSuccess = FALSE;
  664.  
  665.         Msg( "BKM_INSERTPAGE RC(%X)", HWNDERR( hwndNB ) );
  666.     }
  667.  
  668.     return fSuccess;
  669. }
  670.  
  671. /**********************************************************************/
  672. /*-------------------------- SetTabDimensions ------------------------*/
  673. /*                                                                    */
  674. /*  SET THE DIMENSIONS OF THE NOTEBOOK TABS.                          */
  675. /*                                                                    */
  676. /*  INPUT: window handle of notebook control                          */
  677. /*                                                                    */
  678. /*  1.                                                                */
  679. /*                                                                    */
  680. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  681. /*                                                                    */
  682. /*--------------------------------------------------------------------*/
  683. /**********************************************************************/
  684. static BOOL SetTabDimensions( HWND hwndNB )
  685. {
  686.     BOOL         fSuccess = TRUE;
  687.     HPS          hps = WinGetPS( hwndNB );
  688.     FONTMETRICS  fm;
  689.     INT          i, iSize, iLongestMajText = 0, iLongestMinText = 0;
  690.  
  691.     if( !hps )
  692.     {
  693.         Msg( "SetTabDimensions WinGetPS RC(%X)", HWNDERR( hwndNB ) );
  694.  
  695.         return FALSE;
  696.     }
  697.  
  698.     (void) memset( &fm, 0, sizeof( FONTMETRICS ) );
  699.  
  700.     // Calculate the height of a tab as the height of an average font character
  701.     // plus a margin value.
  702.  
  703.     if( GpiQueryFontMetrics( hps, sizeof( FONTMETRICS ), &fm ) )
  704.         fm.lMaxBaselineExt += (TAB_HEIGHT_MARGIN * 2);
  705.     else
  706.     {
  707.         fm.lMaxBaselineExt = DEFAULT_NB_TAB_HEIGHT + (TAB_HEIGHT_MARGIN * 2);
  708.  
  709.         Msg( "SetTabDimensions GpiQueryFontMetrics RC(%X)", HWNDERR( hwndNB ) );
  710.     }
  711.  
  712.     // Calculate the longest tab text for both the MAJOR and MINOR pages
  713.  
  714.     for( i = 0; i < PAGE_COUNT; i++ )
  715.     {
  716.         iSize = GetStringSize( hps, hwndNB, nbpage[ i ].szTabText );
  717.  
  718.         if( nbpage[ i ].usTabType == BKA_MAJOR )
  719.         {
  720.             if( iSize > iLongestMajText )
  721.                 iLongestMajText = iSize;
  722.         }
  723.         else
  724.         {
  725.             if( iSize > iLongestMinText )
  726.                 iLongestMinText = iSize;
  727.         }
  728.     }
  729.  
  730.     WinReleasePS( hps );
  731.  
  732.     // Add a margin amount to the longest tab text
  733.  
  734.     if( iLongestMajText )
  735.         iLongestMajText += TAB_WIDTH_MARGIN;
  736.  
  737.     if( iLongestMinText )
  738.         iLongestMinText += TAB_WIDTH_MARGIN;
  739.  
  740.     // Set the tab dimensions for the MAJOR and MINOR pages. Note that the
  741.     // docs as of this writing say to use BKA_MAJOR and BKA_MINOR in mp2 but
  742.     // you really need BKA_MAJORTAB and BKA_MINORTAB.
  743.  
  744.     if( iLongestMajText )
  745.     {
  746.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETDIMENSIONS,
  747.                     MPFROM2SHORT( iLongestMajText, (SHORT)fm.lMaxBaselineExt ),
  748.                     MPFROMSHORT( BKA_MAJORTAB ) );
  749.  
  750.         if( !fSuccess )
  751.             Msg( "BKM_SETDIMENSIONS(MAJOR) RC(%X)", HWNDERR( hwndNB ) );
  752.     }
  753.  
  754.     if( fSuccess && iLongestMinText )
  755.     {
  756.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETDIMENSIONS,
  757.                     MPFROM2SHORT( iLongestMinText, (SHORT)fm.lMaxBaselineExt ),
  758.                     MPFROMSHORT( BKA_MINORTAB ) );
  759.  
  760.         if( !fSuccess )
  761.             Msg( "BKM_SETDIMENSIONS(MINOR) RC(%X)", HWNDERR( hwndNB ) );
  762.     }
  763.  
  764.     return fSuccess;
  765. }
  766.  
  767. /**********************************************************************/
  768. /*-------------------------- GetStringSize ---------------------------*/
  769. /*                                                                    */
  770. /*  GET THE SIZE IN PIXELS OF A STRING.                               */
  771. /*                                                                    */
  772. /*  INPUT: presentation space handle,                                 */
  773. /*         notebook window handle,                                    */
  774. /*         pointer to string                                          */
  775. /*                                                                    */
  776. /*  1.                                                                */
  777. /*                                                                    */
  778. /*  OUTPUT: nothing                                                   */
  779. /*                                                                    */
  780. /*--------------------------------------------------------------------*/
  781. /**********************************************************************/
  782. static INT GetStringSize( HPS hps, HWND hwndNB, PSZ szString )
  783. {
  784.     POINTL aptl[ TXTBOX_COUNT ];
  785.  
  786.     // Get the size, in pixels, of the string passed.
  787.  
  788.     if( !GpiQueryTextBox( hps, strlen( szString ), szString, TXTBOX_COUNT,
  789.                           aptl ) )
  790.     {
  791.         Msg( "GetStringSize GpiQueryTextBox RC(%X)", HWNDERR( hwndNB ) );
  792.  
  793.         return 0;
  794.     }
  795.     else
  796.         return aptl[ TXTBOX_CONCAT ].x;
  797. }
  798.  
  799. /**********************************************************************/
  800. /*---------------------------- ControlMsg ----------------------------*/
  801. /*                                                                    */
  802. /*  THE ENTRY DIALOG PROC GOT A WM_CONTROL MESSAGE.                   */
  803. /*                                                                    */
  804. /*  INPUT: client window handle,                                      */
  805. /*         control id,                                                */
  806. /*         control event code,                                        */
  807. /*         2nd message parameter from WM_CONTROL message              */
  808. /*                                                                    */
  809. /*  1.                                                                */
  810. /*                                                                    */
  811. /*  OUTPUT: nothing                                                   */
  812. /*                                                                    */
  813. /*--------------------------------------------------------------------*/
  814. /**********************************************************************/
  815. static BOOL ControlMsg( HWND hwnd, USHORT usControl, USHORT usEvent,
  816.                         MPARAM mp2 )
  817. {
  818.     BOOL fProcessed = FALSE;
  819.  
  820.     switch( usControl )
  821.     {
  822.         case ID_NB:
  823.  
  824.             switch( usEvent )
  825.             {
  826.                 case BKN_PAGESELECTED:
  827.  
  828.                     // A new page has been selected by the user. If the dialog
  829.                     // box needs to be loaded, load it and associate it with
  830.                     // the new page.
  831.  
  832.                     SetNBPage( hwnd, (PPAGESELECTNOTIFY) mp2 );
  833.  
  834.                     fProcessed = TRUE;
  835.  
  836.                     break;
  837.             }
  838.  
  839.             break;
  840.     }
  841.  
  842.     return fProcessed;
  843. }
  844.  
  845. /**********************************************************************/
  846. /*---------------------------- SetNBPage -----------------------------*/
  847. /*                                                                    */
  848. /*  SET THE TOP PAGE IN THE NOTEBOOK CONTROL.                         */
  849. /*                                                                    */
  850. /*  INPUT: client window handle,                                      */
  851. /*         pointer to the PAGESELECTNOTIFY struct                     */
  852. /*                                                                    */
  853. /*  1.                                                                */
  854. /*                                                                    */
  855. /*  OUTPUT: nothing                                                   */
  856. /*                                                                    */
  857. /*--------------------------------------------------------------------*/
  858. /**********************************************************************/
  859. static VOID SetNBPage( HWND hwndClient, PPAGESELECTNOTIFY ppsn )
  860. {
  861.     HWND hwndDlg;
  862.  
  863.     // Get a pointer to the page information that is associated with this page.
  864.     // It was stored in the page's PAGE DATA in the SetUpPage function.
  865.  
  866.     PNBPAGE pnbp = (PNBPAGE) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEDATA,
  867.                                         MPFROMLONG( ppsn->ulPageIdNew ), NULL );
  868.  
  869.     if( !pnbp )
  870.         return;
  871.     else if( pnbp == (PNBPAGE) BOOKERR_INVALID_PARAMETERS )
  872.     {
  873.         Msg( "SetNBPage BKM_QUERYPAGEDATA Invalid page id" );
  874.  
  875.         return;
  876.     }
  877.  
  878.     // If this is a BKA_MAJOR page and it is what this app terms a 'parent'
  879.     // page, that means when the user selects this page we actually want to go
  880.     // to its first MINOR page. So in effect the MAJOR page is just a dummy page
  881.     // that has a tab that acts as a placeholder for its MINOR pages. If the
  882.     // user is using the left arrow to scroll thru the pages and they hit this
  883.     // dummy MAJOR page, that means they have already been to its MINOR pages in
  884.     // reverse order. They would now expect to see the page before the dummy
  885.     // MAJOR page, so we skip the dummy page. Otherwise the user is going the
  886.     // other way and wants to see the first MINOR page associated with this
  887.     // 'parent' page so we skip the dummy page and show its first MINOR page.
  888.  
  889.     if( pnbp->fParent )
  890.     {
  891.         ULONG ulPageFwd, ulPageNew;
  892.  
  893.         ulPageFwd = (ULONG) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEID,
  894.                                         MPFROMLONG( ppsn->ulPageIdNew ),
  895.                                         MPFROM2SHORT( BKA_NEXT, BKA_MINOR ) );
  896.  
  897.         // If this is true, the user is going in reverse order
  898.  
  899.         if( ulPageFwd == ppsn->ulPageIdCur )
  900.             ulPageNew = (ULONG) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEID,
  901.                                             MPFROMLONG( ppsn->ulPageIdNew ),
  902.                                             MPFROM2SHORT(BKA_PREV, BKA_MAJOR) );
  903.         else
  904.             ulPageNew = ulPageFwd;
  905.  
  906.         if( ulPageNew == (ULONG) BOOKERR_INVALID_PARAMETERS )
  907.             Msg( "SetNBPage BKM_QUERYPAGEID Invalid page specified" );
  908.         else if( ulPageNew )
  909.             if( !WinSendMsg( ppsn->hwndBook, BKM_TURNTOPAGE,
  910.                              MPFROMLONG( ulPageNew ), NULL ) )
  911.                 Msg( "BKM_TURNTOPAGE RC(%X)", HWNDERR( ppsn->hwndBook ) );
  912.     }
  913.     else
  914.     {
  915.         hwndDlg = (HWND) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEWINDOWHWND,
  916.                                      MPFROMLONG( ppsn->ulPageIdNew ), NULL );
  917.  
  918.         if( hwndDlg == (HWND) BOOKERR_INVALID_PARAMETERS )
  919.         {
  920.             hwndDlg = NULLHANDLE;
  921.  
  922.             Msg( "SetNBPage BKM_QUERYPAGEWINDOWHWND Invalid page specified" );
  923.         }
  924.         else if( !hwndDlg )
  925.  
  926.             // It is time to load this dialog because the user has flipped pages
  927.             // to a page that hasn't yet had the dialog associated with it.
  928.  
  929.             hwndDlg = LoadAndAssociate( hwndClient, pnbp, ppsn );
  930.     }
  931.  
  932.     // Set focus to the first control in the dialog. This is not automatically
  933.     // done by the notebook.
  934.  
  935.     if( hwndDlg && !pnbp->fParent )
  936.         if( !WinSetFocus( HWND_DESKTOP,
  937.                           WinWindowFromID( hwndDlg, pnbp->idFocus ) ) )
  938.         {
  939.             // Bug in 2.0! Developers left some debug code in there!
  940.  
  941.             USHORT usErr = HWNDERR( ppsn->hwndBook );
  942.  
  943.             if( usErr != PMERR_WIN_DEBUGMSG )
  944.                 Msg( "SetNBPage WinSetFocus RC(%X)", usErr );
  945.         }
  946.  
  947.     return;
  948. }
  949.  
  950. /**********************************************************************/
  951. /*------------------------- LoadAndAssociate -------------------------*/
  952. /*                                                                    */
  953. /*  LOAD A DIALOG BOX AND ASSOCIATE IT WITH A NOTEBOOK PAGE.          */
  954. /*                                                                    */
  955. /*  INPUT: client window handle,                                      */
  956. /*         pointer to the NBPAGE structure for this page,             */
  957. /*         pointer to the PAGESELECTNOTIFY struct                     */
  958. /*                                                                    */
  959. /*  1.                                                                */
  960. /*                                                                    */
  961. /*  OUTPUT: Dialog box window handle                                  */
  962. /*                                                                    */
  963. /*--------------------------------------------------------------------*/
  964. /**********************************************************************/
  965. static HWND LoadAndAssociate( HWND hwndClient, PNBPAGE pnbp,
  966.                               PPAGESELECTNOTIFY ppsn )
  967. {
  968.     // We set the client window as the parent and owner of the dialog. This
  969.     // works fine. From my experience, you can also use HWND_DESKTOP for both.
  970.     // Since I've had luck this way, I'll stay with it.
  971.  
  972.     HWND hwndDlg = WinLoadDlg( hwndClient, hwndClient, pnbp->pfnwpDlg, 0,
  973.                                pnbp->idDlg, NULL );
  974.  
  975.     if( hwndDlg )
  976.     {
  977.         // Associate the dialog with the page.
  978.  
  979.         if( !WinSendMsg( ppsn->hwndBook, BKM_SETPAGEWINDOWHWND,
  980.                          MPFROMP( ppsn->ulPageIdNew ),
  981.                          MPFROMLONG( hwndDlg ) ) )
  982.         {
  983.             WinDestroyWindow( hwndDlg );
  984.  
  985.             hwndDlg = NULLHANDLE;
  986.  
  987.             Msg( "BKM_SETPAGEWINDOWHWND RC(%X)", HWNDERR( ppsn->hwndBook ) );
  988.         }
  989.     }
  990.     else
  991.         Msg( "LoadAndAssociate WinLoadDlg RC(%X)", HWNDERR( ppsn->hwndBook ) );
  992.  
  993.     return hwndDlg;
  994. }
  995.  
  996. /**********************************************************************/
  997. /*----------------------------- wpPage1 ------------------------------*/
  998. /*                                                                    */
  999. /*  WINDOW PROCEDURE FOR PAGE 1 DIALOG                                */
  1000. /*                                                                    */
  1001. /*  INPUT: window handle, message id, message parameter 1 and 2.      */
  1002. /*                                                                    */
  1003. /*  1.                                                                */
  1004. /*                                                                    */
  1005. /*  OUTPUT: return code                                               */
  1006. /*--------------------------------------------------------------------*/
  1007. /**********************************************************************/
  1008. MRESULT EXPENTRY wpPage1( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1009. {
  1010.     switch( msg )
  1011.     {
  1012.         case WM_COMMAND:
  1013.  
  1014.             return 0;
  1015.     }
  1016.  
  1017.     return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1018. }
  1019.  
  1020. /**********************************************************************/
  1021. /*---------------------------- wpPage2A ------------------------------*/
  1022. /*                                                                    */
  1023. /*  WINDOW PROCEDURE FOR PAGE 2A DIALOG                               */
  1024. /*                                                                    */
  1025. /*  INPUT: window handle, message id, message parameter 1 and 2.      */
  1026. /*                                                                    */
  1027. /*  1.                                                                */
  1028. /*                                                                    */
  1029. /*  OUTPUT: return code                                               */
  1030. /*--------------------------------------------------------------------*/
  1031. /**********************************************************************/
  1032. MRESULT EXPENTRY wpPage2A( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1033. {
  1034.     switch( msg )
  1035.     {
  1036.         case WM_COMMAND:
  1037.  
  1038.             return 0;
  1039.     }
  1040.  
  1041.     return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1042. }
  1043.  
  1044. /**********************************************************************/
  1045. /*---------------------------- wpPage2B ------------------------------*/
  1046. /*                                                                    */
  1047. /*  WINDOW PROCEDURE FOR PAGE 2B DIALOG                               */
  1048. /*                                                                    */
  1049. /*  INPUT: window handle, message id, message parameter 1 and 2.      */
  1050. /*                                                                    */
  1051. /*  1.                                                                */
  1052. /*                                                                    */
  1053. /*  OUTPUT: return code                                               */
  1054. /*--------------------------------------------------------------------*/
  1055. /**********************************************************************/
  1056. MRESULT EXPENTRY wpPage2B( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1057. {
  1058.     switch( msg )
  1059.     {
  1060.         case WM_COMMAND:
  1061.  
  1062.             return 0;
  1063.     }
  1064.  
  1065.     return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1066. }
  1067.  
  1068. /**********************************************************************/
  1069. /*----------------------------- wpPage3 ------------------------------*/
  1070. /*                                                                    */
  1071. /*  WINDOW PROCEDURE FOR PAGE 3 DIALOG                                */
  1072. /*                                                                    */
  1073. /*  INPUT: window handle, message id, message parameter 1 and 2.      */
  1074. /*                                                                    */
  1075. /*  1.                                                                */
  1076. /*                                                                    */
  1077. /*  OUTPUT: return code                                               */
  1078. /*--------------------------------------------------------------------*/
  1079. /**********************************************************************/
  1080. MRESULT EXPENTRY wpPage3( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1081. {
  1082.     switch( msg )
  1083.     {
  1084.         case WM_COMMAND:
  1085.  
  1086.             return 0;
  1087.     }
  1088.  
  1089.     return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1090. }
  1091.  
  1092. /**********************************************************************/
  1093. /*------------------------------- Msg --------------------------------*/
  1094. /*                                                                    */
  1095. /*  DISPLAY A MESSAGE TO THE USER.                                    */
  1096. /*                                                                    */
  1097. /*  INPUT: a message in printf format with its parms                  */
  1098. /*                                                                    */
  1099. /*  1. Format the message using vsprintf.                             */
  1100. /*  2. Sound a warning sound.                                         */
  1101. /*  3. Display the message in a message box.                          */
  1102. /*                                                                    */
  1103. /*  OUTPUT: nothing                                                   */
  1104. /*                                                                    */
  1105. /*--------------------------------------------------------------------*/
  1106. /**********************************************************************/
  1107.  
  1108. #define MESSAGE_SIZE 1024
  1109.  
  1110. VOID Msg( PSZ szFormat,... )
  1111. {
  1112.     PSZ     szMsg;
  1113.     va_list argptr;
  1114.  
  1115.     if( (szMsg = (PSZ) malloc( MESSAGE_SIZE )) == NULL )
  1116.     {
  1117.         DosBeep( 1000, 1000 );
  1118.  
  1119.         return;
  1120.     }
  1121.  
  1122.     va_start( argptr, szFormat );
  1123.  
  1124.     vsprintf( szMsg, szFormat, argptr );
  1125.  
  1126.     va_end( argptr );
  1127.  
  1128.     szMsg[ MESSAGE_SIZE - 1 ] = 0;
  1129.  
  1130.     (void) WinAlarm( HWND_DESKTOP, WA_WARNING );
  1131.  
  1132.     (void) WinMessageBox(  HWND_DESKTOP, HWND_DESKTOP, szMsg,
  1133.                            PROGRAM_TITLE, 1, MB_OK | MB_MOVEABLE );
  1134.  
  1135.     free( szMsg );
  1136.  
  1137.     return;
  1138. }
  1139.  
  1140. /************************************************************************
  1141.  *                      E N D   O F   S O U R C E                       *
  1142.  ************************************************************************/
  1143.