home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / CNRMNU.ZIP / CNRMENU.C next >
C/C++ Source or Header  |  1993-03-27  |  29KB  |  677 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  cnrmenu.c              AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  10-24-92                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  By just entering CNRMENU on the command line, a container will   *
  9.  *  be created that will contain the files in the current directory. *
  10.  *  Any subdirectories will be included and expandable in Tree view. *
  11.  *  The container starts in Tree view. You can switch to the other   *
  12.  *  supported views.                                                 *
  13.  *                                                                   *
  14.  *  Optionally enter 'CNRMENU directory' and that directory will be  *
  15.  *  displayed.                                                       *
  16.  *                                                                   *
  17.  * MODULE DESCRIPTION:                                               *
  18.  *                                                                   *
  19.  *  Root module for CNRMENU.EXE, a program that demonstrates the     *
  20.  *  base functionality of a container control. This module contains  *
  21.  *  the client window procedure and some supporting functions for    *
  22.  *  the container messages. It builds on the CNRBASE.EXE sample      *
  23.  *  program by adding a context menu, container record sharing,      *
  24.  *  direct editing, source emphasis, and container sorting. It lets  *
  25.  *  you create additional directory windows by double-clicking on    *
  26.  *  a subdirectory in the current window.                            *
  27.  *                                                                   *
  28.  *  The container is populated with records from a secondary thread. *
  29.  *  This is done not to complicate things but to let the user        *
  30.  *  interact with the container before it is completely filled if we *
  31.  *  are traversing a directory with many subdirectories.             *
  32.  *                                                                   *
  33.  *  Drag/Drop, Deltas, Ownerdraw, MiniIcons are not demonstrated     *
  34.  *  in this sample program.                                          *
  35.  *                                                                   *
  36.  * OTHER MODULES:                                                    *
  37.  *                                                                   *
  38.  *  create.c -   contains the code used to create and tailor a       *
  39.  *               container. These functions are called for each      *
  40.  *               container that is created.                          *
  41.  *                                                                   *
  42.  *  populate.c - contains the code for the thread used to fill the   *
  43.  *               container with records.                             *
  44.  *                                                                   *
  45.  *  common.c -   contains common support routines for CNRMENU.EXE.   *
  46.  *                                                                   *
  47.  *  ctxtmenu.c - contains context menu routines.                     *
  48.  *                                                                   *
  49.  *  edit.c -     contains direct editing routines.                   *
  50.  *                                                                   *
  51.  *  sort.c -     contains container sorting routines.                *
  52.  *                                                                   *
  53.  * NOTES:                                                            *
  54.  *                                                                   *
  55.  *  This program has gotten pretty complex as new aspects of the     *
  56.  *  container were added. This makes it a pretty difficult program   *
  57.  *  to follow. I believe it is most useful for exploring the         *
  58.  *  different areas from a working program perspective. I don't      *
  59.  *  think it would be a good idea to try and follow this program     *
  60.  *  through its whole operation as you will quickly get lost in the  *
  61.  *  details.                                                         *
  62.  *                                                                   *
  63.  *  I hope this code proves useful for other PM programmers. The     *
  64.  *  more of us the better!                                           *
  65.  *                                                                   *
  66.  * HISTORY:                                                          *
  67.  *                                                                   *
  68.  *  10-24-92 - Source copied from CNRBASE.EXE sample.                *
  69.  *             Moved SetContainerView to ctxtmenu.c (CtxtmenuSetView)*
  70.  *             Moved WM_COMMAND code to ctxtmenu.c (CtxtmenuCommand) *
  71.  *             Moved WM_CONTROL msg processing to wmControl function *
  72.  *             Added RecordSelected function on CN_ENTER msg.        *
  73.  *             Added directory name to the titlebar text.            *
  74.  *             Added new parameters on CreateDirectoryWin call.      *
  75.  *             Added new parameters on CreateContainer call.         *
  76.  *             Get WINCREATE struct from mp1 on WM_CREATE instead of *
  77.  *               just the directory name.                            *
  78.  *             Moved the CnrBeginEdit and CnrEndEdit functions to    *
  79.  *               edit.c as EditBegin and EditEnd.                    *
  80.  *             Added call to CtxtmenuEnd on a WM_MENUEND msg.        *
  81.  *  12-26-92   Added a WinDestroyWindow of hwndMenu in WM_MENUEND.   *
  82.  *  01-01-93   Initialize fTrue for all while( fTrue ) loops.        *
  83.  *  03-27-93   Changed PSZ szArg to char *szArg  - compiler bug.     *
  84.  *                                                                   *
  85.  *  Rick Fishman                                                     *
  86.  *  Code Blazers, Inc.                                               *
  87.  *  4113 Apricot                                                     *
  88.  *  Irvine, CA. 92720                                                *
  89.  *  CIS ID: 72251,750                                                *
  90.  *                                                                   *
  91.  *********************************************************************/
  92.  
  93. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  94.  
  95. /*********************************************************************/
  96. /*------- Include relevant sections of the OS/2 header files --------*/
  97. /*********************************************************************/
  98.  
  99. #define INCL_DOSERRORS
  100. #define INCL_WINDIALOGS
  101. #define INCL_WINERRORS
  102. #define INCL_WINFRAMEMGR
  103. #define INCL_WINSTDCNR
  104. #define INCL_WINSTDDLGS
  105. #define INCL_WINWINDOWMGR
  106.  
  107. #define GLOBALS_DEFINED        // This module defines the globals in cnrmenu.h
  108.  
  109. /**********************************************************************/
  110. /*----------------------------- INCLUDES -----------------------------*/
  111. /**********************************************************************/
  112.  
  113. #include <os2.h>
  114. #include <stdarg.h>
  115. #include <stdio.h>
  116. #include <stdlib.h>
  117. #include <string.h>
  118. #include "cnrmenu.h"
  119.  
  120. /*********************************************************************/
  121. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  122. /*********************************************************************/
  123.  
  124. /**********************************************************************/
  125. /*---------------------------- STRUCTURES ----------------------------*/
  126. /**********************************************************************/
  127.  
  128. /**********************************************************************/
  129. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  130. /**********************************************************************/
  131.  
  132.        INT   main               ( INT iArgc, char *szArg[] );
  133. static BOOL  InitClient         ( HWND hwndClient, PWINCREATE pwc );
  134. static BOOL  wmControl          ( HWND hwndClient, USHORT idCtrl, MPARAM mp2 );
  135. static VOID  RecordSelected     ( HWND hwndClient, PNOTIFYRECORDENTER pnre );
  136. static VOID  ContainerFilled    ( HWND hwndClient );
  137. static VOID  UserWantsToClose   ( HWND hwndClient );
  138. static VOID  FreeResources      ( HWND hwndClient );
  139.  
  140. FNWP wpClient;
  141.  
  142. /**********************************************************************/
  143. /*------------------------ GLOBAL VARIABLES --------------------------*/
  144. /**********************************************************************/
  145.  
  146. /**********************************************************************/
  147. /*------------------------------ MAIN --------------------------------*/
  148. /*                                                                    */
  149. /*  PROGRAM ENTRYPOINT                                                */
  150. /*                                                                    */
  151. /*  INPUT: command line                                               */
  152. /*                                                                    */
  153. /*  1.                                                                */
  154. /*                                                                    */
  155. /*  OUTPUT: return code                                               */
  156. /*                                                                    */
  157. /*--------------------------------------------------------------------*/
  158. /**********************************************************************/
  159. INT main( INT iArgc, char *szArg[] )
  160. {
  161.     BOOL  fSuccess = FALSE;
  162.     HAB   hab;
  163.     HMQ   hmq = NULLHANDLE;
  164.     QMSG  qmsg;
  165.     PSZ   szStartingDir = NULL;
  166.     HWND  hwndFrame = NULLHANDLE;
  167.  
  168.     // This macro is defined for the debug version of the C Set/2 Memory
  169.     // Management routines. Since the debug version writes to stderr, we
  170.     // send all stderr output to a debuginfo file. Look in MAKEFILE to see how
  171.     // to enable the debug version of those routines.
  172.  
  173. #ifdef __DEBUG_ALLOC__
  174.     freopen( DEBUG_FILENAME, "w", stderr );
  175. #endif
  176.  
  177.     // fTrue will be used for all while( fTrue ) loops. The C Set/2++ compiler
  178.     // took away the ability to use while( TRUE ) and for( ; ; ) constructs.
  179.  
  180.     fTrue = TRUE;
  181.  
  182.     // Get the directory to display from the command line if specified.
  183.  
  184.     if( iArgc > 1 )
  185.         szStartingDir = szArg[ 1 ];
  186.  
  187.     hab = WinInitialize( 0 );
  188.  
  189.     if( hab )
  190.         hmq = WinCreateMsgQueue( hab, 0 );
  191.     else
  192.     {
  193.         DosBeep( 1000, 100 );
  194.  
  195.         (void) fprintf( stderr, "WinInitialize failed!" );
  196.     }
  197.  
  198.     if( hmq )
  199.  
  200.         // CS_SIZEREDRAW needed for initial display of the container in the
  201.         // client window. Allocate enough extra bytes for 1 window word.
  202.  
  203.         fSuccess = WinRegisterClass( hab, DIRECTORY_WINCLASS, wpClient,
  204.                                      CS_SIZEREDRAW, sizeof( PVOID ) );
  205.     else
  206.     {
  207.         DosBeep( 1000, 100 );
  208.  
  209.         (void) fprintf( stderr, "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  210.     }
  211.  
  212.     if( fSuccess )
  213.  
  214.         // CreateDirectoryWin is in CREATE.C
  215.  
  216.         hwndFrame = CreateDirectoryWin( szStartingDir, NULLHANDLE, NULL );
  217.     else
  218.         Msg( "WinRegisterClass RC(%X)", HABERR( hab ) );
  219.  
  220.     if( hwndFrame )
  221.         while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  222.             (void) WinDispatchMsg( hab, &qmsg );
  223.  
  224.     if( hmq )
  225.         (void) WinDestroyMsgQueue( hmq );
  226.  
  227.     if( hab )
  228.         (void) WinTerminate( hab );
  229.  
  230. #ifdef __DEBUG_ALLOC__
  231.     _dump_allocated( -1 );
  232. #endif
  233.  
  234.     return 0;
  235. }
  236.  
  237. /**********************************************************************/
  238. /*---------------------------- wpClient ------------------------------*/
  239. /*                                                                    */
  240. /*  CLIENT WINDOW PROCEDURE FOR THE DIRECTORY WINDOW.                 */
  241. /*                                                                    */
  242. /*  NOTE: This window is created by CreateDirectoryWin in CREATE.C    */
  243. /*                                                                    */
  244. /*  INPUT: standard window procedure parameters                       */
  245. /*                                                                    */
  246. /*  1.                                                                */
  247. /*                                                                    */
  248. /*  OUTPUT: result of message processing                              */
  249. /*                                                                    */
  250. /*--------------------------------------------------------------------*/
  251. /**********************************************************************/
  252. MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  253. {
  254.     switch( msg )
  255.     {
  256.         case WM_CREATE:
  257.  
  258.             // If window initialization fails, don't create window
  259.  
  260.             if( InitClient( hwnd, (PWINCREATE) mp1 ) )
  261.             {
  262.                 iWinCount++;
  263.  
  264.                 break;
  265.             }
  266.             else
  267.                 return (MRESULT) TRUE;
  268.  
  269.  
  270.         case UM_CONTAINER_FILLED:
  271.  
  272.             // This message is posted to us by the thread that fills the
  273.             // container with records. This indicates that the container is
  274.             // now filled.
  275.  
  276.             ContainerFilled( hwnd );
  277.  
  278.             return 0;
  279.  
  280.  
  281.         case WM_ERASEBACKGROUND:
  282.  
  283.             // Paint the client window in the default color
  284.  
  285.             return (MRESULT) TRUE;
  286.  
  287.  
  288.         case WM_SIZE:
  289.  
  290.             // Size the container with the client window
  291.  
  292.             if( !WinSetWindowPos( WinWindowFromID( hwnd, CNR_DIRECTORY ),
  293.                                   NULLHANDLE, 0, 0, SHORT1FROMMP( mp2 ),
  294.                                   SHORT2FROMMP( mp2 ), SWP_MOVE | SWP_SIZE ) )
  295.                 Msg( "WM_SIZE WinSetWindowPos RC(%X)", HWNDERR( hwnd ) );
  296.  
  297.             return 0;
  298.  
  299.  
  300.         case WM_COMMAND:    // Context Menu messages (in ctxtmenu.c)
  301.  
  302.             CtxtmenuCommand( hwnd, SHORT1FROMMP( mp1 ), SHORT1FROMMP( mp2 ) );
  303.  
  304.             return 0;
  305.  
  306.  
  307.         case WM_CONTROL:
  308.  
  309.             // This function returns TRUE if the message was processed
  310.  
  311.             if( wmControl( hwnd, SHORT2FROMMP( mp1 ), mp2 ) )
  312.                 return 0;
  313.             else
  314.                 break;
  315.  
  316.  
  317.         case WM_MENUEND:
  318.  
  319.             // This function in ctxtmenu.c. Interestingly enough, even though
  320.             // we give the menu the id of ID_CONTEXT_MENU, the ID that is
  321.             // actually assigned to the popup menu as a whole is FID_MENU.
  322.             // Since we get WM_MENUEND messages for the submenus of the popup
  323.             // also and we only care when the whole popup is gone, just call
  324.             // this function if it is the popup menu.
  325.  
  326.             if( SHORT1FROMMP( mp1 ) == FID_MENU )
  327.             {
  328.                 CtxtmenuEnd( hwnd );
  329.  
  330.                 // Destroy the window so its resources are freed up for the next
  331.                 // time we do a WinLoadMenu in ctxtmenu.c
  332.  
  333.                 if( !WinDestroyWindow( (HWND) mp2 ) )
  334.                     Msg( "WM_MENUEND WinDestroyWindow RC(%X)", HWNDERR( hwnd ));
  335.             }
  336.  
  337.             break;
  338.  
  339.  
  340.         case WM_CLOSE:
  341.  
  342.             // Don't let the WM_QUIT message get posted. *We* will decide
  343.             // when to shut down the message queue.
  344.  
  345.             UserWantsToClose( hwnd );
  346.  
  347.             return 0;
  348.  
  349.  
  350.         case WM_DESTROY:
  351.  
  352.             FreeResources( hwnd );
  353.  
  354.             // If this is the last window open, shut down the message queue
  355.             // which will kill the process.
  356.  
  357.             if( --iWinCount == 0 )
  358.                 (void) WinPostMsg( NULLHANDLE, WM_QUIT, NULL, NULL );
  359.  
  360.             break;
  361.     }
  362.  
  363.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  364. }
  365.  
  366. /**********************************************************************/
  367. /*--------------------------- InitClient -----------------------------*/
  368. /*                                                                    */
  369. /*  PROCESS WM_CREATE FOR THE CLIENT WINDOW.                          */
  370. /*                                                                    */
  371. /*  INPUT: client window handle,                                      */
  372. /*         pointer to window creation parameters                      */
  373. /*                                                                    */
  374. /*  1.                                                                */
  375. /*                                                                    */
  376. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  377. /*                                                                    */
  378. /*--------------------------------------------------------------------*/
  379. /**********************************************************************/
  380. static BOOL InitClient( HWND hwndClient, PWINCREATE pwc )
  381. {
  382.     BOOL      fSuccess = TRUE;
  383.     PINSTANCE pi = (PINSTANCE) malloc( sizeof( INSTANCE ) );
  384.  
  385.     if( pi )
  386.     {
  387.         (void) memset( pi, 0, sizeof( INSTANCE ) );
  388.  
  389.         if( WinSetWindowPtr( hwndClient, 0, pi ) )
  390.         {
  391.             // CreateContainer is located in CREATE.C
  392.  
  393.             HWND hwndCnr = CreateContainer( hwndClient, pwc->szDirectory,
  394.                                             pwc->hwndCnrShare, pwc->pciParent );
  395.  
  396.             if( hwndCnr )
  397.  
  398.                 // Set the initial container view to Tree/Icon view. This
  399.                 // function is in CTXTMENU.C
  400.  
  401.                 CtxtmenuSetView( hwndClient, CV_TREE | CV_ICON );
  402.             else
  403.                 fSuccess = FALSE;
  404.  
  405.             // This was allocated in create.c in the CreateDirectoryWin function
  406.  
  407.             free( pwc );
  408.         }
  409.         else
  410.         {
  411.             fSuccess = FALSE;
  412.  
  413.             Msg( "InitClient WinSetWindowPtr RC(%X)", HWNDERR( hwndClient ) );
  414.         }
  415.     }
  416.     else
  417.     {
  418.         fSuccess = FALSE;
  419.  
  420.         Msg( "InitClient out of memory!" );
  421.     }
  422.  
  423.     return fSuccess;
  424. }
  425.  
  426. /**********************************************************************/
  427. /*---------------------------- wmControl -----------------------------*/
  428. /*                                                                    */
  429. /*  PROCESS WM_CONTROL MESSAGES FOR THE CLIENT WINDOW.                */
  430. /*                                                                    */
  431. /*  INPUT: client window handle,                                      */
  432. /*         notify code,                                               */
  433. /*         2nd WM_CONTROL message parameter                           */
  434. /*                                                                    */
  435. /*  1.                                                                */
  436. /*                                                                    */
  437. /*  OUTPUT: TRUE or FALSE if message processed                        */
  438. /*                                                                    */
  439. /*--------------------------------------------------------------------*/
  440. /**********************************************************************/
  441. static BOOL wmControl( HWND hwndClient, USHORT usNotifyCode, MPARAM mp2 )
  442. {
  443.     BOOL fProcessed = TRUE;
  444.  
  445.     switch( usNotifyCode )
  446.     {
  447.         case CN_ENTER:
  448.  
  449.             RecordSelected( hwndClient, (PNOTIFYRECORDENTER) mp2 );
  450.  
  451.             break;
  452.  
  453.  
  454.         case CN_CONTEXTMENU:
  455.  
  456.             // In ctxtmenu.c
  457.  
  458.             CtxtmenuCreate( hwndClient, (PCNRITEM) mp2 );
  459.  
  460.             break;
  461.  
  462.  
  463.         case CN_BEGINEDIT:
  464.  
  465.             // In edit.c
  466.  
  467.             EditBegin( hwndClient, (PCNREDITDATA) mp2 );
  468.  
  469.             break;
  470.  
  471.  
  472.         case CN_ENDEDIT:
  473.  
  474.             // In edit.c
  475.  
  476.             EditEnd( hwndClient, (PCNREDITDATA) mp2 );
  477.  
  478.             break;
  479.  
  480.  
  481.         default:
  482.  
  483.             fProcessed = FALSE;
  484.  
  485.             break;
  486.     }
  487.  
  488.     return fProcessed;
  489. }
  490.  
  491. /**********************************************************************/
  492. /*-------------------------- RecordSelected --------------------------*/
  493. /*                                                                    */
  494. /*  PROCESS CN_ENTER NOTIFY MESSAGE.                                  */
  495. /*                                                                    */
  496. /*  INPUT: client window handle,                                      */
  497. /*         pointer to the NOTIFYRECORDENTER structure                 */
  498. /*                                                                    */
  499. /*  1.                                                                */
  500. /*                                                                    */
  501. /*  OUTPUT: nothing                                                   */
  502. /*                                                                    */
  503. /*--------------------------------------------------------------------*/
  504. /**********************************************************************/
  505. static VOID RecordSelected( HWND hwndClient, PNOTIFYRECORDENTER pnre )
  506. {
  507.     PCNRITEM  pci = (PCNRITEM) pnre->pRecord;
  508.     PINSTANCE pi = INSTDATA( hwndClient );
  509.  
  510.     if( !pi )
  511.     {
  512.         Msg( "RecordSelected cant get Inst data. RC(%X)", HWNDERR(hwndClient) );
  513.  
  514.         return;
  515.     }
  516.  
  517.     // If the user selected a directory, create another directory window for it.
  518.     // Don't do anything if the directory is '..' (parent directory) or '.'
  519.     // (current directory) as this program is not equipped to handle them.
  520.  
  521.     if( pci && (pci->attrFile & FILE_DIRECTORY) && pci->szFileName[0] != '.' )
  522.     {
  523.         // Set the selected CNRITEM container record so other functions can get
  524.         // at it.
  525.  
  526.         pi->pciSelected = pci;
  527.  
  528.         // Simulate a IDM_CREATE_NEWWIN menuitem being selected. This allows
  529.         // us to reuse the code that is processed when that menu item is pressed
  530.         // Specify CMDSRC_OTHER so the code that processes the IDM_CREATE_NEWWIN
  531.         // message can differentiate this message from one legitimately sent
  532.         // from the context menu.
  533.  
  534.         WinSendMsg( hwndClient, WM_COMMAND,
  535.                     MPFROM2SHORT( IDM_CREATE_NEWWIN, 0 ),
  536.                     MPFROM2SHORT( CMDSRC_OTHER, 0 ) );
  537.     }
  538.  
  539.     return;
  540. }
  541.  
  542. /**********************************************************************/
  543. /*------------------------- ContainerFilled --------------------------*/
  544. /*                                                                    */
  545. /*  THE FILL THREAD HAS COMPLETED.                                    */
  546. /*                                                                    */
  547. /*  INPUT: client window handle                                       */
  548. /*                                                                    */
  549. /*  1.                                                                */
  550. /*                                                                    */
  551. /*  OUTPUT: nothing                                                   */
  552. /*                                                                    */
  553. /*--------------------------------------------------------------------*/
  554. /**********************************************************************/
  555. static VOID ContainerFilled( HWND hwndClient )
  556. {
  557.     PINSTANCE pi = INSTDATA( hwndClient );
  558.  
  559.     if( !pi )
  560.     {
  561.         Msg( "ContainerFilled cant get Inst data. RC(%X)", HWNDERR(hwndClient));
  562.  
  563.         return;
  564.     }
  565.  
  566.     // If the user closed the window while the Fill thread was executing, we
  567.     // want to shut down this window now.
  568.  
  569.     if( pi->fShutdown )
  570.         WinDestroyWindow( PARENT( hwndClient ) );
  571.     else
  572.     {
  573.         // Set a flag so the window will know the Fill thread has finished
  574.  
  575.         pi->fContainerFilled = TRUE;
  576.  
  577.         // Set the titlebar to the program title. We do this because while
  578.         // the container was being filled, the titlebar text was changed
  579.         // to indicate progress.
  580.  
  581.         SetWindowTitle( hwndClient, "%s [%s]", PROGRAM_TITLE, pi->szDirectory );
  582.     }
  583.  
  584.     return;
  585. }
  586.  
  587. /**********************************************************************/
  588. /*------------------------- UserWantsToClose -------------------------*/
  589. /*                                                                    */
  590. /*  PROCESS THE WM_CLOSE MESSAGE.                                     */
  591. /*                                                                    */
  592. /*  INPUT: client window handle                                       */
  593. /*                                                                    */
  594. /*  1.                                                                */
  595. /*                                                                    */
  596. /*  OUTPUT: nothing                                                   */
  597. /*                                                                    */
  598. /*--------------------------------------------------------------------*/
  599. /**********************************************************************/
  600. static VOID UserWantsToClose( HWND hwndClient )
  601. {
  602.     PINSTANCE pi = INSTDATA( hwndClient );
  603.  
  604.     if( !pi )
  605.     {
  606.         Msg( "UserWantsToClose cant get Inst data. RC(%X)",HWNDERR(hwndClient));
  607.  
  608.         return;
  609.     }
  610.  
  611.     // If the Fill thread has completed, destroy the frame window.
  612.     // If the Fill thread has not completed, set a flag that will cause it to
  613.     // terminate, then the destroy will occur under the UM_CONTAINER_FILLED
  614.     // message.
  615.  
  616.     if( pi->fContainerFilled )
  617.         WinDestroyWindow( PARENT( hwndClient ) );
  618.     else
  619.     {
  620.         // Indicate in the titlebar that the window is in the process of
  621.         // closing.
  622.  
  623.         SetWindowTitle( hwndClient, "%s: CLOSING...", PROGRAM_TITLE );
  624.  
  625.         // Set a flag that will tell the Fill thread to shut down
  626.  
  627.         pi->fShutdown = TRUE;
  628.     }
  629.  
  630.     return;
  631. }
  632.  
  633. /**********************************************************************/
  634. /*-------------------------- FreeResources ---------------------------*/
  635. /*                                                                    */
  636. /*  FREE PROGRAM RESOURCES.                                           */
  637. /*                                                                    */
  638. /*  INPUT: client window handle                                       */
  639. /*                                                                    */
  640. /*  1.                                                                */
  641. /*                                                                    */
  642. /*  OUTPUT: nothing                                                   */
  643. /*                                                                    */
  644. /*--------------------------------------------------------------------*/
  645. /**********************************************************************/
  646. static VOID FreeResources( HWND hwndClient )
  647. {
  648.     PINSTANCE pi = INSTDATA( hwndClient );
  649.  
  650.     if( pi )
  651.         free( pi );
  652.     else
  653.         Msg( "FreeResources cant get Inst data. RC(%X)", HWNDERR( hwndClient ));
  654.  
  655.     // Free the memory that was allocated with CM_ALLOCDETAILFIELDINFO. The
  656.     // zero in the first SHORT of mp2 says to free memory for all columns
  657.  
  658.     if( -1 == (INT) WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY,
  659.                                        CM_REMOVEDETAILFIELDINFO, NULL,
  660.                                        MPFROM2SHORT( 0, CMA_FREE ) ) )
  661.         Msg( "CM_REMOVEDETAILFIELDINFO failed! RC(%X)", HWNDERR( hwndClient ) );
  662.  
  663.     // Free the memory allocated by the CM_INSERTRECORD messages. The zero
  664.     // in the first SHORT of mp2 says to free memory for all records
  665.  
  666.     if( -1 == (INT) WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY,
  667.                                        CM_REMOVERECORD, NULL,
  668.                                        MPFROM2SHORT( 0, CMA_FREE ) ) )
  669.         Msg( "CM_REMOVERECORD failed! RC(%X)", HWNDERR( hwndClient ) );
  670.  
  671.     return;
  672. }
  673.  
  674. /*************************************************************************
  675.  *                     E N D     O F     S O U R C E                     *
  676.  ************************************************* ************************/
  677.