home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / c / cnrbas.zip / CNRBASE.C next >
Text File  |  1992-10-13  |  35KB  |  844 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  cnrbase.c              AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  10-09-92                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  By just entering CNRBASE 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 and a menu lets you switch     *
  12.  *  between the other supported views.                               *
  13.  *                                                                   *
  14.  *  Optionally enter 'CNRBASE directory' and that directory will be  *
  15.  *  displayed.                                                       *
  16.  *                                                                   *
  17.  * MODULE DESCRIPTION:                                               *
  18.  *                                                                   *
  19.  *  Root module for CNRBASE.EXE, a program that demonstrates the     *
  20.  *  base functionality of a container control. This module contains  *
  21.  *  the client window procedure and all the supporting functions for *
  22.  *  the container messages.                                          *
  23.  *                                                                   *
  24.  *  This sample creates a simple Directory folder that displays      *
  25.  *  icons for each file in a directory. It shows the Details, Name,  *
  26.  *  Icon, and Tree views and lets the user switch between them. It   *
  27.  *  shows simple direct-editing. The main purpose for this sample is *
  28.  *  to demonstrate the process of creating a functional container,   *
  29.  *  not to show its use once created.                                *
  30.  *                                                                   *
  31.  *  The container is populated with records from a secondary thread. *
  32.  *  This is done not to complicate things but to let the user        *
  33.  *  interact with the container before it is completely filled if we *
  34.  *  are traversing a directory with many subdirectories.             *
  35.  *                                                                   *
  36.  *  Drag/Drop, Deltas, Context Menus, Ownerdraw, MiniIcons,          *
  37.  *  record-sharing, sorting are not demonstrated in this sample      *
  38.  *  program.                                                         *
  39.  *                                                                   *
  40.  * OTHER MODULES:                                                    *
  41.  *                                                                   *
  42.  *  create.c -   contains the code used to create and tailor the     *
  43.  *               container. Once the container is created there are  *
  44.  *               no functions called in this module.                 *
  45.  *                                                                   *
  46.  *  populate.c - contains the code for the thread used to fill the   *
  47.  *               container with records.                             *
  48.  *                                                                   *
  49.  *  common.c -   contains common support routines for CNRBASE.EXE.   *
  50.  *                                                                   *
  51.  * NOTES:                                                            *
  52.  *                                                                   *
  53.  *  This program loses some simplicity by using PM programming       *
  54.  *  techniques that most non-beginner programmers use such as the    *
  55.  *  use of multiple threads, Window Words and error checking. These  *
  56.  *  techniques are not necessary for this sample and this sample     *
  57.  *  would be easier to understand if they were not used. I believe   *
  58.  *  the benefits outweigh the drawbacks because this program will    *
  59.  *  now serve as a more useful template. It will also more easily    *
  60.  *  allow for the creation of multiple instances of the sample       *
  61.  *  Directory window, which will become important in any program     *
  62.  *  that builds on this one.                                         *
  63.  *                                                                   *
  64.  *  I hope this code proves useful for other PM programmers. The     *
  65.  *  more of us the better!                                           *
  66.  *                                                                   *
  67.  * HISTORY:                                                          *
  68.  *                                                                   *
  69.  *  10-09-92 - Program coded                                         *
  70.  *                                                                   *
  71.  *  Rick Fishman                                                     *
  72.  *  Code Blazers, Inc.                                               *
  73.  *  4113 Apricot                                                     *
  74.  *  Irvine, CA. 92720                                                *
  75.  *  CIS ID: 72251,750                                                *
  76.  *                                                                   *
  77.  *********************************************************************/
  78.  
  79. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  80.  
  81. /*********************************************************************/
  82. /*------- Include relevant sections of the OS/2 header files --------*/
  83. /*********************************************************************/
  84.  
  85. #define INCL_DOSERRORS
  86. #define INCL_WINDIALOGS
  87. #define INCL_WINERRORS
  88. #define INCL_WINFRAMEMGR
  89. #define INCL_WINMLE
  90. #define INCL_WINSTDCNR
  91. #define INCL_WINSTDDLGS
  92. #define INCL_WINWINDOWMGR
  93.  
  94. #define GLOBALS_DEFINED        // This module defines the globals in cnrbase.h
  95.  
  96. /**********************************************************************/
  97. /*----------------------------- INCLUDES -----------------------------*/
  98. /**********************************************************************/
  99.  
  100. #include <os2.h>
  101. #include <stdarg.h>
  102. #include <stdio.h>
  103. #include <stdlib.h>
  104. #include <string.h>
  105. #include "cnrbase.h"
  106.  
  107. /*********************************************************************/
  108. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  109. /*********************************************************************/
  110.  
  111. /**********************************************************************/
  112. /*---------------------------- STRUCTURES ----------------------------*/
  113. /**********************************************************************/
  114.  
  115. /**********************************************************************/
  116. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  117. /**********************************************************************/
  118.  
  119.        INT   main               ( INT iArgc, PSZ szArg[] );
  120. static BOOL  InitClient         ( HWND hwndClient, PSZ szDirectory );
  121. static VOID  SetContainerView   ( HWND hwndClient, ULONG ulViewType );
  122. static VOID  KeepCnrAspectRatio ( HWND hwndClient, ULONG cxNew, ULONG cyNew );
  123. static VOID  CnrBeginEdit       ( HWND hwndClient, PCNREDITDATA pced );
  124. static VOID  CnrEndEdit         ( HWND hwndClient, PCNREDITDATA pced );
  125. static ULONG GetMaxNameSize     ( CHAR chDrive );
  126. static VOID  ContainerFilled    ( HWND hwndClient );
  127. static VOID  UserWantsToClose   ( HWND hwndClient );
  128. static VOID  FreeResources      ( HWND hwndClient );
  129.  
  130. FNWP wpClient;
  131.  
  132. /**********************************************************************/
  133. /*------------------------ GLOBAL VARIABLES --------------------------*/
  134. /**********************************************************************/
  135.  
  136. /**********************************************************************/
  137. /*------------------------------ MAIN --------------------------------*/
  138. /*                                                                    */
  139. /*  PROGRAM ENTRYPOINT                                                */
  140. /*                                                                    */
  141. /*  INPUT: command line                                               */
  142. /*                                                                    */
  143. /*  1.                                                                */
  144. /*                                                                    */
  145. /*  OUTPUT: return code                                               */
  146. /*                                                                    */
  147. /*--------------------------------------------------------------------*/
  148. /**********************************************************************/
  149. INT main( INT iArgc, PSZ szArg[] )
  150. {
  151.     BOOL  fSuccess = FALSE;
  152.     HAB   hab;
  153.     HMQ   hmq = NULLHANDLE;
  154.     QMSG  qmsg;
  155.     PSZ   szStartingDir = NULL;
  156.     HWND  hwndFrame = NULLHANDLE;
  157.  
  158.     // This macro is defined for the debug version of the C Set/2 Memory
  159.     // Management routines. Since the debug version writes to stderr, we
  160.     // send all stderr output to a debuginfo file. Look in MAKEFILE to see how
  161.     // to enable the debug version of those routines.
  162.  
  163. #ifdef __DEBUG_ALLOC__
  164.     freopen( DEBUG_FILENAME, "w", stderr );
  165. #endif
  166.  
  167.     // Get the directory to display from the command line if specified.
  168.  
  169.     if( iArgc > 1 )
  170.         szStartingDir = szArg[ 1 ];
  171.  
  172.     hab = WinInitialize( 0 );
  173.  
  174.     if( hab )
  175.         hmq = WinCreateMsgQueue( hab, 0 );
  176.     else
  177.     {
  178.         DosBeep( 1000, 100 );
  179.  
  180.         (void) fprintf( stderr, "WinInitialize failed!" );
  181.     }
  182.  
  183.     if( hmq )
  184.  
  185.         // CS_SIZEREDRAW needed for initial display of the container in the
  186.         // client window. Allocate enough extra bytes for 1 window word.
  187.  
  188.         fSuccess = WinRegisterClass( hab, DIRECTORY_WINCLASS, wpClient,
  189.                                      CS_SIZEREDRAW, sizeof( PVOID ) );
  190.     else
  191.     {
  192.         DosBeep( 1000, 100 );
  193.  
  194.         (void) fprintf( stderr, "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  195.     }
  196.  
  197.     if( fSuccess )
  198.  
  199.         // CreateDirectoryWin is in CREATE.C
  200.  
  201.         hwndFrame = CreateDirectoryWin( szStartingDir );
  202.     else
  203.         Msg( "WinRegisterClass RC(%X)", HABERR( hab ) );
  204.  
  205.     if( hwndFrame )
  206.         while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  207.             (void) WinDispatchMsg( hab, &qmsg );
  208.  
  209.     if( hmq )
  210.         (void) WinDestroyMsgQueue( hmq );
  211.  
  212.     if( hab )
  213.         (void) WinTerminate( hab );
  214.  
  215. #ifdef __DEBUG_ALLOC__
  216.     _dump_allocated( -1 );
  217. #endif
  218.  
  219.     return 0;
  220. }
  221.  
  222. /**********************************************************************/
  223. /*---------------------------- wpClient ------------------------------*/
  224. /*                                                                    */
  225. /*  CLIENT WINDOW PROCEDURE FOR THE DIRECTORY WINDOW.                 */
  226. /*                                                                    */
  227. /*  NOTE: This window is created by CreateDirectoryWin in CREATE.C    */
  228. /*                                                                    */
  229. /*  INPUT: standard window procedure parameters                       */
  230. /*                                                                    */
  231. /*  1.                                                                */
  232. /*                                                                    */
  233. /*  OUTPUT: result of message processing                              */
  234. /*                                                                    */
  235. /*--------------------------------------------------------------------*/
  236. /**********************************************************************/
  237. MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  238. {
  239.     switch( msg )
  240.     {
  241.         case WM_CREATE:
  242.  
  243.             // If window initialization fails, don't create window
  244.  
  245.             if( InitClient( hwnd, (PSZ) mp1 ) )
  246.             {
  247.                 iWinCount++;
  248.  
  249.                 break;
  250.             }
  251.             else
  252.                 return (MRESULT) TRUE;
  253.  
  254.  
  255.         case UM_CONTAINER_FILLED:
  256.  
  257.             // This message is posted to us by the thread that fills the
  258.             // container with records. This indicates that the container is
  259.             // now filled.
  260.  
  261.             ContainerFilled( hwnd );
  262.  
  263.             return 0;
  264.  
  265.  
  266.         case WM_ERASEBACKGROUND:
  267.  
  268.             // Paint the client window in the default color
  269.  
  270.             return (MRESULT) TRUE;
  271.  
  272.  
  273.         case WM_SIZE:
  274.  
  275.             // Size the container with the client window
  276.  
  277.             if( !WinSetWindowPos( WinWindowFromID( hwnd, CNR_DIRECTORY ),
  278.                                   NULLHANDLE, 0, 0, SHORT1FROMMP( mp2 ),
  279.                                   SHORT2FROMMP( mp2 ), SWP_MOVE | SWP_SIZE ) )
  280.                 Msg( "WM_SIZE WinSetWindowPos RC(%X)", HWNDERR( hwnd ) );
  281.  
  282.             return 0;
  283.  
  284.  
  285.         case WM_COMMAND:    // Menu messages
  286.  
  287.             switch( SHORT1FROMMP( mp1 ) )
  288.             {
  289.                 case IDM_TREE:
  290.  
  291.                     SetContainerView( hwnd, CV_TREE | CV_ICON );
  292.  
  293.                     return 0;
  294.  
  295.                 case IDM_NAME:
  296.  
  297.                     SetContainerView( hwnd, CV_NAME | CV_FLOW );
  298.  
  299.                     return 0;
  300.  
  301.                 case IDM_TEXT:
  302.  
  303.                     SetContainerView( hwnd, CV_TEXT | CV_FLOW );
  304.  
  305.                     return 0;
  306.  
  307.                 case IDM_ICON:
  308.  
  309.                     SetContainerView( hwnd, CV_ICON );
  310.  
  311.                     return 0;
  312.  
  313.                 case IDM_DETAILS:
  314.  
  315.                     SetContainerView( hwnd, CV_DETAIL );
  316.  
  317.                     return 0;
  318.             }
  319.  
  320.             break;
  321.  
  322.  
  323.         case WM_CONTROL:        // These control messages sent by the container
  324.  
  325.             if( SHORT1FROMMP( mp1 ) == CNR_DIRECTORY )
  326.                 switch( SHORT2FROMMP( mp1 ) )
  327.                 {
  328.                     case CN_BEGINEDIT:
  329.  
  330.                         CnrBeginEdit( hwnd, (PCNREDITDATA) mp2 );
  331.  
  332.                         break;
  333.  
  334.  
  335.                     case CN_ENDEDIT:
  336.  
  337.                         CnrEndEdit( hwnd, (PCNREDITDATA) mp2 );
  338.  
  339.                         break;
  340.                 }
  341.  
  342.             break;
  343.  
  344.  
  345.         case WM_CLOSE:
  346.  
  347.             // Don't let the WM_QUIT message get posted. *We* will decide
  348.             // when to shut down the message queue.
  349.  
  350.             UserWantsToClose( hwnd );
  351.  
  352.             return 0;
  353.  
  354.  
  355.         case WM_DESTROY:
  356.  
  357.             FreeResources( hwnd );
  358.  
  359.             // If this is the last window open, shut down the message queue
  360.             // which will kill the .EXE. In this program there is only one
  361.             // window so the first WM_DESTROY will always do this.
  362.  
  363.             if( --iWinCount == 0 )
  364.                 (void) WinPostMsg( NULLHANDLE, WM_QUIT, NULL, NULL );
  365.  
  366.             break;
  367.     }
  368.  
  369.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  370. }
  371.  
  372. /**********************************************************************/
  373. /*--------------------------- InitClient -----------------------------*/
  374. /*                                                                    */
  375. /*  PROCESS WM_CREATE FOR THE CLIENT WINDOW.                          */
  376. /*                                                                    */
  377. /*  INPUT: client window handle,                                      */
  378. /*         pointer to directory to display in container               */
  379. /*                                                                    */
  380. /*  1.                                                                */
  381. /*                                                                    */
  382. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  383. /*                                                                    */
  384. /*--------------------------------------------------------------------*/
  385. /**********************************************************************/
  386. static BOOL InitClient( HWND hwndClient, PSZ szDirectory )
  387. {
  388.     BOOL      fSuccess = TRUE;
  389.     PINSTANCE pi = (PINSTANCE) malloc( sizeof( INSTANCE ) );
  390.  
  391.     if( pi )
  392.     {
  393.         (void) memset( pi, 0, sizeof( INSTANCE ) );
  394.  
  395.         if( WinSetWindowPtr( hwndClient, 0, pi ) )
  396.         {
  397.             // CreateContainer is located in CREATE.C
  398.  
  399.             HWND hwndCnr = CreateContainer( hwndClient, szDirectory );
  400.  
  401.             if( hwndCnr )
  402.  
  403.                 // Set the initial container view to Tree/Icon view
  404.  
  405.                 SetContainerView( hwndClient, CV_TREE | CV_ICON );
  406.             else
  407.                 fSuccess = FALSE;
  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. /*------------------------- SetContainerView -------------------------*/
  428. /*                                                                    */
  429. /*  SET THE TYPE OF VIEW FOR THE CONTAINER                            */
  430. /*                                                                    */
  431. /*  INPUT: client window handle,                                      */
  432. /*         view type to set to                                        */
  433. /*                                                                    */
  434. /*  1.                                                                */
  435. /*                                                                    */
  436. /*  OUTPUT: nothing                                                   */
  437. /*                                                                    */
  438. /*--------------------------------------------------------------------*/
  439. /**********************************************************************/
  440. static VOID SetContainerView( HWND hwndClient, ULONG ulViewType )
  441. {
  442.     PINSTANCE pi = INSTDATA( hwndClient );
  443.     CNRINFO   cnri;
  444.  
  445.     if( !pi )
  446.     {
  447.         Msg( "Set..View cant get Inst data. RC(%X)", HWNDERR( hwndClient ) );
  448.  
  449.         return;
  450.     }
  451.  
  452.     cnri.cb = sizeof( CNRINFO );
  453.  
  454.     // Set the container window attributes: Set the container view mode. Use a
  455.     // container title. Put a separator between the title and the records
  456.     // beneath it. Make the container title read-only.
  457.  
  458.     cnri.flWindowAttr = ulViewType | CA_CONTAINERTITLE | CA_TITLESEPARATOR |
  459.                         CA_TITLEREADONLY;
  460.  
  461.     switch( ulViewType )
  462.     {
  463.         case CV_TREE:
  464.         case (CV_TREE | CV_ICON):
  465.  
  466.             (void) strcpy( pi->szCnrTitle, "Tree/icon view - " );
  467.  
  468.             // Use default spacing between levels in the tree view. Also use
  469.             // the default width of a line that shows record relationships.
  470.  
  471.             cnri.cxTreeIndent = -1;
  472.             cnri.cxTreeLine   = -1;
  473.  
  474.             cnri.flWindowAttr |=  CA_TREELINE;
  475.  
  476.             break;
  477.  
  478.         case CV_ICON:
  479.  
  480.             (void) strcpy( pi->szCnrTitle, "Icon view - " );
  481.  
  482.             break;
  483.  
  484.         case CV_NAME:
  485.         case (CV_NAME | CV_FLOW):
  486.  
  487.             (void) strcpy( pi->szCnrTitle, "Name/flowed view - " );
  488.  
  489.             break;
  490.  
  491.         case CV_DETAIL:
  492.  
  493.             (void) strcpy( pi->szCnrTitle, "Detail view - " );
  494.  
  495.             // If we are in DETAIL view, tell the container that we will be
  496.             // using column headings.
  497.  
  498.             cnri.flWindowAttr |= CA_DETAILSVIEWTITLES;
  499.  
  500.             break;
  501.  
  502.         case CV_TEXT:
  503.         case (CV_TEXT | CV_FLOW):
  504.  
  505.             (void) strcpy( pi->szCnrTitle, "Text/flowed view - " );
  506.  
  507.             break;
  508.     }
  509.  
  510.     (void) strcat( pi->szCnrTitle, pi->szDirectory );
  511.  
  512.     cnri.pszCnrTitle = pi->szCnrTitle;
  513.  
  514.     // Set the line spacing between rows to be the minimal value so we conserve
  515.     // on container whitespace.
  516.  
  517.     cnri.cyLineSpacing = 0;
  518.  
  519.     // Set the container parameters. Note that mp2 specifies which fields of
  520.     // of the CNRINFO structure to use. The CMA_FLWINDOWATTR says to use
  521.     // flWindowAttr to specify which 'Window Attribute' fields to use.
  522.  
  523.     if( !WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY, CM_SETCNRINFO,
  524.                             MPFROMP( &cnri ),
  525.                             MPFROMLONG( CMA_FLWINDOWATTR | CMA_CNRTITLE |
  526.                                         CMA_LINESPACING ) ) )
  527.         Msg( "SetContainerView CM_SETCNRINFO RC(%X)", HWNDERR( hwndClient ) );
  528.  
  529.     // The CM_ARRANGE message is applicable only in ICON view. It will arrange
  530.     // the icons according to CUA. Note that this message is unnecessary if
  531.     // the CCS_AUTOPOSITION style is used on the WinCreateWindow call for the
  532.     // container. The problem with using that style is that you have no control
  533.     // over *when* the arranging is done.
  534.  
  535.     if( ulViewType == CV_ICON )
  536.         if( !WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY, CM_ARRANGE, NULL,
  537.                                 NULL ) )
  538.             Msg( "SetContainerView CM_ARRANGE RC(%X)", HWNDERR( hwndClient ) );
  539. }
  540.  
  541. /**********************************************************************/
  542. /*----------------------- KeepCnrAspectRatio -------------------------*/
  543. /*                                                                    */
  544. /*  KEEP THE CONTAINER FILLING THE CLIENT AREA ON A WM_SIZE MESSAGE.  */
  545. /*                                                                    */
  546. /*  INPUT: client window handle,                                      */
  547. /*         new client window width,                                   */
  548. /*         new client window height                                   */
  549. /*                                                                    */
  550. /*  1.                                                                */
  551. /*                                                                    */
  552. /*  OUTPUT: nothing                                                   */
  553. /*                                                                    */
  554. /*--------------------------------------------------------------------*/
  555. /**********************************************************************/
  556. static VOID KeepCnrAspectRatio( HWND hwndClient, ULONG cxNew, ULONG cyNew )
  557. {
  558.     if( !WinSetWindowPos( WinWindowFromID( hwndClient, CNR_DIRECTORY ),
  559.                           NULLHANDLE, 0, 0, cxNew, cyNew,
  560.                           SWP_MOVE | SWP_SIZE ) )
  561.         Msg( "Keep..Ratio WinSetWindowPos RC(%X)", HWNDERR( hwndClient ) );
  562. }
  563.  
  564. /**********************************************************************/
  565. /*--------------------------- CnrBeginEdit ---------------------------*/
  566. /*                                                                    */
  567. /*  PROCESS CN_BEGINEDIT NOTIFY MESSAGE.                              */
  568. /*                                                                    */
  569. /*  INPUT: client window handle,                                      */
  570. /*         pointer to the CNREDITDATA structure                       */
  571. /*                                                                    */
  572. /*  1.                                                                */
  573. /*                                                                    */
  574. /*  OUTPUT: nothing                                                   */
  575. /*                                                                    */
  576. /*--------------------------------------------------------------------*/
  577. /**********************************************************************/
  578. static VOID CnrBeginEdit( HWND hwndClient, PCNREDITDATA pced )
  579. {
  580.     PFIELDINFO  pfi = pced->pFieldInfo;
  581.     PINSTANCE   pi = INSTDATA( hwndClient );
  582.  
  583.     if( !pi )
  584.     {
  585.         Msg( "CnrBeginEdit cant get Inst data. RC(%X)", HWNDERR( hwndClient ) );
  586.  
  587.         return;
  588.     }
  589.  
  590.     // pfi only available if details view. If we are in details view and
  591.     // the column the user is direct-editing is the file name field, set the
  592.     // text limit of the MLE to the Maximum that the filename can be.
  593.     // If MLM_SETTEXTLIMIT returns a non-zero value, it means that the text
  594.     // length in the MLE is greater than what we are trying to set it to.
  595.  
  596.     if( !pfi || pfi->offStruct == FIELDOFFSET( CNRITEM, pszFileName ) )
  597.         if( WinSendDlgItemMsg( WinWindowFromID( hwndClient, CNR_DIRECTORY ),
  598.                         CID_MLE, MLM_SETTEXTLIMIT,
  599.                         MPFROMLONG( GetMaxNameSize( pi->szDirectory[ 0 ] ) ),
  600.                         NULL) )
  601.             Msg( "MLM_SETTEXTLIMIT failed. RC(%X)", HWNDERR( hwndClient ) );
  602. }
  603.  
  604. /**********************************************************************/
  605. /*-------------------------- GetMaxNameSize --------------------------*/
  606. /*                                                                    */
  607. /*  GET THE MAXIMUM SIZE OF A FILE NAME FOR A DRIVE.                  */
  608. /*                                                                    */
  609. /*  INPUT: drive letter                                               */
  610. /*                                                                    */
  611. /*  1.                                                                */
  612. /*                                                                    */
  613. /*  OUTPUT: max filename size                                         */
  614. /*                                                                    */
  615. /*--------------------------------------------------------------------*/
  616. /**********************************************************************/
  617.  
  618. #define QFSBUFFSIZE 100
  619.  
  620. static ULONG GetMaxNameSize( CHAR chDrive )
  621. {
  622.     APIRET      rc;
  623.     CHAR        szDrive[ 3 ], achBuf[ QFSBUFFSIZE ];
  624.     PFSQBUFFER2 pfsqb = (PFSQBUFFER2) achBuf;
  625.     ULONG       cbFileName = 0, cbBuf = sizeof( achBuf );
  626.     PSZ         szFSDName;
  627.  
  628.     szDrive[ 0 ] = chDrive;
  629.     szDrive[ 1 ] = ':';
  630.     szDrive[ 2 ] = 0;
  631.  
  632.     // Get the file system type for this drive (i.e. HPFS, FAT, etc.)
  633.  
  634.     rc = DosQueryFSAttach( szDrive, 0, FSAIL_QUERYNAME, (PFSQBUFFER2) achBuf,
  635.                            &cbBuf );
  636.  
  637.     // Should probably handle ERROR_BUFFER_OVERFLOW more gracefully, but not
  638.     // in this sample program <g>
  639.  
  640.     if( rc )
  641.         cbFileName = 12;                     // If any errors, assume FAT
  642.     else
  643.     {
  644.         szFSDName = pfsqb->szName + pfsqb->cbName + 1;
  645.  
  646.         if( !stricmp( "FAT", szFSDName ) )
  647.             cbFileName = 12;
  648.         else
  649.             cbFileName = CCHMAXPATH;         // If not FAT, assume maximum path
  650.     }
  651.  
  652.     return cbFileName;
  653. }
  654.  
  655. /**********************************************************************/
  656. /*---------------------------- CnrEndEdit ----------------------------*/
  657. /*                                                                    */
  658. /*  PROCESS CN_ENDEDIT NOTIFY MESSAGE.                                */
  659. /*                                                                    */
  660. /*  INPUT: client window handle,                                      */
  661. /*         pointer to the CNREDITDATA structure                       */
  662. /*                                                                    */
  663. /*  1.                                                                */
  664. /*                                                                    */
  665. /*  OUTPUT: nothing                                                   */
  666. /*                                                                    */
  667. /*--------------------------------------------------------------------*/
  668. /**********************************************************************/
  669. static VOID CnrEndEdit( HWND hwndClient, PCNREDITDATA pced )
  670. {
  671.     PINSTANCE   pi = INSTDATA( hwndClient );
  672.     PCNRITEM    pci = (PCNRITEM) pced->pRecord;
  673.     PFIELDINFO  pfi = pced->pFieldInfo;
  674.     HWND        hwndCnr, hwndMLE;
  675.     CHAR        szData[ CCHMAXPATH + 1 ];
  676.  
  677.     if( !pi )
  678.     {
  679.         Msg( "CnrEndEdit cant get Inst data. RC(%X)", HWNDERR( hwndClient ) );
  680.  
  681.         return;
  682.     }
  683.  
  684.     hwndCnr = WinWindowFromID( hwndClient, CNR_DIRECTORY );
  685.  
  686.     // Get the handle to the MLE that the container uses for direct editing
  687.  
  688.     hwndMLE = WinWindowFromID( hwndCnr, CID_MLE );
  689.  
  690.     // pfi only available if details view
  691.  
  692.     if( !pfi || pfi->offStruct == FIELDOFFSET( CNRITEM, pszFileName ) )
  693.     {
  694.         WinQueryWindowText( hwndMLE, sizeof( szData ), szData );
  695.  
  696.         // Just a cute little test to make sure this is all working...
  697.  
  698.         if( !stricmp( szData, "BADREC" ) )
  699.             (void) WinAlarm( HWND_DESKTOP, WA_WARNING );
  700.     }
  701.  
  702.     // Invalidate the container record that was being direct-edited because
  703.     // the text has probably changed. Note that this should only be done if the
  704.     // text changed. Since this is just a sample program we do it regardless...
  705.  
  706.     if( !WinSendMsg( hwndCnr, CM_INVALIDATERECORD, MPFROMP( &pci ),
  707.                      MPFROM2SHORT( 1, CMA_TEXTCHANGED ) ) )
  708.         Msg( "CnrEndEdit CM_INVALIDATERECORD RC(%X)", HWNDERR( hwndCnr ) );
  709. }
  710.  
  711. /**********************************************************************/
  712. /*------------------------- ContainerFilled --------------------------*/
  713. /*                                                                    */
  714. /*  THE FILL THREAD HAS COMPLETED.                                    */
  715. /*                                                                    */
  716. /*  INPUT: client window handle                                       */
  717. /*                                                                    */
  718. /*  1.                                                                */
  719. /*                                                                    */
  720. /*  OUTPUT: nothing                                                   */
  721. /*                                                                    */
  722. /*--------------------------------------------------------------------*/
  723. /**********************************************************************/
  724. static VOID ContainerFilled( HWND hwndClient )
  725. {
  726.     PINSTANCE pi = INSTDATA( hwndClient );
  727.  
  728.     if( !pi )
  729.     {
  730.         Msg( "ContainerFilled cant get Inst data. RC(%X)", HWNDERR(hwndClient));
  731.  
  732.         return;
  733.     }
  734.  
  735.     // If the user closed the window while the Fill thread was executing, we
  736.     // want to shut down this window now.
  737.  
  738.     if( pi->fShutdown )
  739.         WinDestroyWindow( PARENT( hwndClient ) );
  740.     else
  741.     {
  742.         // Set a flag so the window will know the Fill thread has finished
  743.  
  744.         pi->fContainerFilled = TRUE;
  745.  
  746.         // Set the titlebar to the program title. We do this because while
  747.         // the container was being filled, the titlebar text was changed
  748.         // to indicate progress.
  749.  
  750.         SetWindowTitle( hwndClient, PROGRAM_TITLE );
  751.     }
  752. }
  753.  
  754. /**********************************************************************/
  755. /*------------------------- UserWantsToClose -------------------------*/
  756. /*                                                                    */
  757. /*  PROCESS THE WM_CLOSE MESSAGE.                                     */
  758. /*                                                                    */
  759. /*  INPUT: client window handle                                       */
  760. /*                                                                    */
  761. /*  1.                                                                */
  762. /*                                                                    */
  763. /*  OUTPUT: nothing                                                   */
  764. /*                                                                    */
  765. /*--------------------------------------------------------------------*/
  766. /**********************************************************************/
  767. static VOID UserWantsToClose( HWND hwndClient )
  768. {
  769.     PINSTANCE pi = INSTDATA( hwndClient );
  770.  
  771.     if( !pi )
  772.     {
  773.         Msg( "UserWantsToClose cant get Inst data. RC(%X)",HWNDERR(hwndClient));
  774.  
  775.         return;
  776.     }
  777.  
  778.     // If the Fill thread has completed, destroy the frame window.
  779.     // If the Fill thread has not completed, set a flag that will cause it to
  780.     // terminate, then the destroy will occur under the UM_CONTAINER_FILLED
  781.     // message.
  782.  
  783.     if( pi->fContainerFilled )
  784.         WinDestroyWindow( PARENT( hwndClient ) );
  785.     else
  786.     {
  787.         // Indicate in the titlebar that the window is in the process of
  788.         // closing.
  789.  
  790.         SetWindowTitle( hwndClient, "%s: CLOSING...", PROGRAM_TITLE );
  791.  
  792.         // Set a flag that will tell the Fill thread to shut down
  793.  
  794.         pi->fShutdown = TRUE;
  795.     }
  796. }
  797.  
  798. /**********************************************************************/
  799. /*-------------------------- FreeResources ---------------------------*/
  800. /*                                                                    */
  801. /*  FREE PROGRAM RESOURCES.                                           */
  802. /*                                                                    */
  803. /*  INPUT: client window handle                                       */
  804. /*                                                                    */
  805. /*  1.                                                                */
  806. /*                                                                    */
  807. /*  OUTPUT: nothing                                                   */
  808. /*                                                                    */
  809. /*--------------------------------------------------------------------*/
  810. /**********************************************************************/
  811. static VOID FreeResources( HWND hwndClient )
  812. {
  813.     PINSTANCE pi = INSTDATA( hwndClient );
  814.  
  815.     if( !pi )
  816.     {
  817.         Msg( "FreeResources cant get Inst data. RC(%X)", HWNDERR( hwndClient ));
  818.  
  819.         return;
  820.     }
  821.  
  822.     // Free the memory that was allocated with CM_ALLOCDETAILFIELDINFO. The
  823.     // zero in the first SHORT of mp2 says to free memory for all columns
  824.  
  825.     if( -1 == (INT) WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY,
  826.                                        CM_REMOVEDETAILFIELDINFO, NULL,
  827.                                        MPFROM2SHORT( 0, CMA_FREE ) ) )
  828.         Msg( "CM_REMOVEDETAILFIELDINFO failed! RC(%X)", HWNDERR( hwndClient ) );
  829.  
  830.     // Free the memory allocated by the CM_INSERTRECORD messages. The zero
  831.     // in the first SHORT of mp2 says to free memory for all records
  832.  
  833.     if( -1 == (INT) WinSendDlgItemMsg( hwndClient, CNR_DIRECTORY,
  834.                                        CM_REMOVERECORD, NULL,
  835.                                        MPFROM2SHORT( 0, CMA_FREE ) ) )
  836.         Msg( "CM_REMOVERECORD failed! RC(%X)", HWNDERR( hwndClient ) );
  837.  
  838.     free( pi );
  839. }
  840.  
  841. /*************************************************************************
  842.  *                     E N D     O F     S O U R C E                     *
  843.  *************************************************************************/
  844.