home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / CNRBAS.ZIP / POPULATE.C < prev    next >
Text File  |  1993-01-01  |  25KB  |  549 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  populate.c             AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  10-09-92                                           *
  5.  *                                                                   *
  6.  * DESCRIPTION:                                                      *
  7.  *                                                                   *
  8.  *  This module is part of CNRBASE.EXE. It performs the function of  *
  9.  *  filling a container window with file icons. This processing is   *
  10.  *  taking place in a secondary thread that was started with         *
  11.  *  _beginthread from the CreateContainer function in create.c.      *
  12.  *                                                                   *
  13.  *  Recursion is used to fill the container with all subdirectories  *
  14.  *  from the base directory.  This is done to demonstrate the Tree   *
  15.  *  view.                                                            *
  16.  *                                                                   *
  17.  *  The reason this is in a separate thread is that, if we are       *
  18.  *  traversing the root directory and its subdirectories, it could   *
  19.  *  take a long time to fill the container.                          *
  20.  *                                                                   *
  21.  *  This thread posts a UM_CONTAINER_FILLED message to the client    *
  22.  *  window when the container is filled.                             *
  23.  *                                                                   *
  24.  * CALLABLE FUNCTIONS:                                               *
  25.  *                                                                   *
  26.  *  VOID PopulateContainer( PVOID pThreadParms );                    *
  27.  *                                                                   *
  28.  * HISTORY:                                                          *
  29.  *                                                                   *
  30.  *  10-09-92 - Program coded                                         *
  31.  *  10-18-92 - Fixed error mgmt of PopulateContainer thread so that  *
  32.  *             the correct hab is being passed to WinGetLastError.   *
  33.  *             Reported by Jon Wright on CIS. Added hab to the parm  *
  34.  *             list of most of the static functions.                 *
  35.  *  10-18-92 - Added use of a default icon if WinLoadFileIcon fails. *
  36.  *  10-18-92 - Changed the ProcessDirectory function to load all     *
  37.  *             records for a subdirectory before recursing.          *
  38.  *  10-19-92 - In RecurseSubdirs, if the parent record is NULL, use  *
  39.  *             CMA_FIRST rather than CMA_FIRSTCHILD because of a bug *
  40.  *             that is being fixed in the Service Pack.              *
  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_DOSERRORS
  57. #define  INCL_DOSFILEMGR
  58. #define  INCL_WINDIALOGS
  59. #define  INCL_WINERRORS
  60. #define  INCL_WINFRAMEMGR
  61. #define  INCL_WINPOINTERS
  62. #define  INCL_WINSTDCNR
  63. #define  INCL_WINWINDOWMGR
  64.  
  65. /**********************************************************************/
  66. /*----------------------------- INCLUDES -----------------------------*/
  67. /**********************************************************************/
  68.  
  69. #include <os2.h>
  70. #include <stdarg.h>
  71. #include <stdio.h>
  72. #include <stdlib.h>
  73. #include <string.h>
  74. #include "cnrbase.h"
  75.  
  76. /*********************************************************************/
  77. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  78. /*********************************************************************/
  79.  
  80. #define FILES_TO_GET       100        // Nbr of files to search for at a time
  81. #define FF_BUFFSIZE        (sizeof( FILEFINDBUF3 ) * FILES_TO_GET)
  82.  
  83. /**********************************************************************/
  84. /*---------------------------- STRUCTURES ----------------------------*/
  85. /**********************************************************************/
  86.  
  87. /**********************************************************************/
  88. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  89. /**********************************************************************/
  90.  
  91. static VOID ProcessDirectory ( HAB habThread, HWND hwndCnr, PCNRITEM pciParent,
  92.                                PSZ szDirBase, PSZ szDirectory );
  93. static VOID RecurseSubdirs   ( HAB habThread, HWND hwndCnr, PCNRITEM pciParent,
  94.                                PSZ szDir );
  95. static BOOL InsertRecords    ( HAB habThread, HWND hwndCnr, PCNRITEM pciParent,
  96.                                PSZ szDir, PFILEFINDBUF3 pffb, ULONG cFiles);
  97. static BOOL FillInRecord     ( PCNRITEM pci, PSZ szDir, PFILEFINDBUF3 pffb );
  98.  
  99. /**********************************************************************/
  100. /*------------------------ GLOBAL VARIABLES --------------------------*/
  101. /**********************************************************************/
  102.  
  103. /**********************************************************************/
  104. /*------------------------ PopulateContainer -------------------------*/
  105. /*                                                                    */
  106. /*  THREAD THAT FILLS THE CONTAINER WITH RECORDS.                     */
  107. /*                                                                    */
  108. /*  INPUT: pointer to thread parameters passed by main thread         */
  109. /*                                                                    */
  110. /*  1.                                                                */
  111. /*                                                                    */
  112. /*  OUTPUT: nothing                                                   */
  113. /*                                                                    */
  114. /*--------------------------------------------------------------------*/
  115. /**********************************************************************/
  116. VOID PopulateContainer( PVOID pThreadParms )
  117. {
  118.     HAB         hab;
  119.     HMQ         hmq = NULLHANDLE;
  120.     HWND        hwndClient = ((PTHREADPARMS) pThreadParms)->hwndClient;
  121.     PINSTANCE   pi = INSTDATA( hwndClient );
  122.  
  123.     // We must create a message queue so that this thread can do WinSendMsg's.
  124.     // All contact with the container is done with WinSendMsg.
  125.  
  126.     hab = WinInitialize( 0 );
  127.  
  128.     if( hab )
  129.         hmq = WinCreateMsgQueue( hab, 0 );
  130.     else
  131.         Msg( "PopulateContainer WinInitialize failed!" );
  132.  
  133.     if( hmq )
  134.     {
  135.         if( pi )
  136.         {
  137.             // Insert the container records from the specified directory. Using
  138.             // NULL for the parent record tells ProcessDirectory that it is
  139.             // dealing with the top-level directory should recursion cause
  140.             // subdirectories to be expanded. The last parameter is a pointer
  141.             // to a subdirectory used during recursion and can be NULL here.
  142.  
  143.             ProcessDirectory( hab, WinWindowFromID( hwndClient, CNR_DIRECTORY ),
  144.                               NULL, pi->szDirectory, NULL );
  145.         }
  146.         else
  147.             Msg( "PopulateContainer cant get Inst data. RC(%X)", HABERR( hab ));
  148.     }
  149.     else
  150.         Msg( "PopulateContainer CreateMsgQueue failed! RC(%X)", HABERR( hab ) );
  151.  
  152.     if( hmq )
  153.         (void) WinDestroyMsgQueue( hmq );
  154.  
  155.     if( hab )
  156.         (void) WinTerminate( hab );
  157.  
  158.     free( pThreadParms );
  159.  
  160.     // Let the primary thread know the container is filled
  161.  
  162.     WinPostMsg( hwndClient, UM_CONTAINER_FILLED, NULL, NULL );
  163.  
  164.     _endthread();
  165.  
  166.     return;
  167. }
  168.  
  169. /**********************************************************************/
  170. /*------------------------- ProcessDirectory -------------------------*/
  171. /*                                                                    */
  172. /*  POPULATE THE CONTAINER WITH THE CONTENTS OF A DIRECTORY           */
  173. /*                                                                    */
  174. /*  INPUT: anchor block handle for this thread,                       */
  175. /*         container window handle,                                   */
  176. /*         parent container record,                                   */
  177. /*         base directory name with drive qualifier,                  */
  178. /*         directory to display                                       */
  179. /*                                                                    */
  180. /*  1.                                                                */
  181. /*                                                                    */
  182. /*  OUTPUT: nothing                                                   */
  183. /*                                                                    */
  184. /*--------------------------------------------------------------------*/
  185. /**********************************************************************/
  186. static VOID ProcessDirectory( HAB hab, HWND hwndCnr, PCNRITEM pciParent,
  187.                               PSZ szDirBase, PSZ szDirectory )
  188. {
  189.     // Allocate a buffer big enough to hold FILES_TO_GET files. Then allocate
  190.     // a work buffer to hold the full file spec.
  191.  
  192.     PFILEFINDBUF3 pffb = malloc( FF_BUFFSIZE );
  193.     PSZ           szFileSpec = malloc( CCHMAXPATH + 1 );
  194.  
  195.     if( pffb && szFileSpec )
  196.     {
  197.         HDIR   hdir = HDIR_SYSTEM;
  198.         ULONG  ulMaxFiles = FILES_TO_GET;
  199.         PCH    pchEndPath;
  200.         APIRET rc;
  201.         PINSTANCE pi = INSTDATA( PARENT( hwndCnr ) );
  202.  
  203.         // Combine C:\DIR1\DIR2 and DIR3 to make C:\DIR1\DIR2\DIR3\*.*
  204.         // Keep a placeholder so we can strip the trailing '\*.*' after the
  205.         // DosFindFirst has completed.
  206.  
  207.         (void) strcpy( szFileSpec, szDirBase );
  208.  
  209.         if( szDirectory )
  210.         {
  211.             (void) strcat( szFileSpec, "\\" );
  212.  
  213.             (void) strcat( szFileSpec, szDirectory );
  214.         }
  215.  
  216.         pchEndPath = szFileSpec + strlen( szFileSpec );
  217.  
  218.         (void) strcat( szFileSpec, "\\*.*" );
  219.  
  220.         // Get buffer of files up to the maximum FILES_TO_GET files. Get both
  221.         // normal files and directories.
  222.  
  223.         rc = DosFindFirst( szFileSpec, &hdir, FILE_NORMAL | FILE_DIRECTORY,
  224.                            pffb, FF_BUFFSIZE, &ulMaxFiles, FIL_STANDARD );
  225.  
  226.         *pchEndPath = 0;
  227.  
  228.         // Let the user know what directory we're processing unless we're
  229.         // in the process of shutting down
  230.  
  231.         if( pi && !pi->fShutdown )
  232.             SetWindowTitle( PARENT( hwndCnr ), "%s: Processing %s...",
  233.                             PROGRAM_TITLE, szFileSpec );
  234.  
  235.         while( !rc )
  236.         {
  237.             // If the main thread wants to shutdown, accommodate it
  238.  
  239.             if( pi && pi->fShutdown )
  240.                 break;
  241.  
  242.             // Insert the files into the container
  243.  
  244.             if( InsertRecords( hab, hwndCnr, pciParent, szFileSpec, pffb,
  245.                                ulMaxFiles ) )
  246.                 // Get more files if there are any
  247.  
  248.                 rc = DosFindNext( hdir, pffb, FF_BUFFSIZE, &ulMaxFiles );
  249.             else
  250.                 rc = 1;
  251.         }
  252.  
  253.         DosFindClose( hdir );
  254.  
  255.         // Recursively insert child records into the container for any
  256.         // subdirectories found under this directory
  257.  
  258.         if( pi && !pi->fShutdown )
  259.             RecurseSubdirs( hab, hwndCnr, pciParent, szFileSpec );
  260.     }
  261.     else
  262.         Msg( "ProcessDirectory Out of Memory!" );
  263.  
  264.     if( pffb )
  265.         free( pffb );
  266.  
  267.     if( szFileSpec )
  268.         free( szFileSpec );
  269.  
  270.     return;
  271. }
  272.  
  273. /**********************************************************************/
  274. /*-------------------------- RecurseSubdirs --------------------------*/
  275. /*                                                                    */
  276. /*  CALL ProcessDirectory FOR EACH SUBDIRECTORY OF THE BASE DIRECTORY */
  277. /*                                                                    */
  278. /*  INPUT: anchor block handle for this thread,                       */
  279. /*         container window handle,                                   */
  280. /*         parent container record,                                   */
  281. /*         base directory name with drive qualifier                   */
  282. /*                                                                    */
  283. /*  1.                                                                */
  284. /*                                                                    */
  285. /*  OUTPUT: nothing                                                   */
  286. /*                                                                    */
  287. /*--------------------------------------------------------------------*/
  288. /**********************************************************************/
  289. static VOID RecurseSubdirs( HAB hab, HWND hwndCnr, PCNRITEM pciParent,
  290.                             PSZ szDirBase )
  291. {
  292.     USHORT    usWhatRec = (pciParent == NULL) ? CMA_FIRST : CMA_FIRSTCHILD;
  293.     PCNRITEM  pciPrev = pciParent, pciNext;
  294.     PINSTANCE pi = INSTDATA( PARENT( hwndCnr ) );
  295.  
  296.     // Note that this function is called AFTER a subdirectory's files have
  297.     // been inserted into the container. We traverse those records to see if
  298.     // any are subdirectories themselves.
  299.  
  300.     while( fTrue )
  301.     {
  302.         // If the main thread wants to shutdown, accommodate it
  303.  
  304.         if( pi && pi->fShutdown )
  305.             break;
  306.  
  307.         // Get the next child record. We start with usWhatRec set to
  308.         // CMA_FIRSTCHILD, then use CMA_NEXT after getting the first child.
  309.         // This enumerates the children of pciParent. The docs don't
  310.         // go into it, but my tests show that using CMA_NEXT after a
  311.         // CMA_FIRSTCHILD will return NULL after the last *child* has been
  312.         // enumerated, rather than the last record in the container. Of course
  313.         // that is how it should work but it's not documented.
  314.  
  315.         // BUG NOTE (10/19/92): I had to use CMA_FIRST instead of CMA_FIRSTCHILD
  316.         // if pciParent is NULL (parent is the top container level). This bug
  317.         // is fixed in the Service Pack due any day now
  318.  
  319.         pciNext = WinSendMsg( hwndCnr, CM_QUERYRECORD, MPFROMP( pciPrev ),
  320.                               MPFROM2SHORT( usWhatRec, CMA_ITEMORDER ) );
  321.  
  322.         if( (INT) pciNext == -1 )
  323.         {
  324.             Msg( "RecurseSubdirs CM_QUERYRECORD RC(%X)", HABERR( hab ) );
  325.  
  326.             break;
  327.         }
  328.  
  329.         if( !pciNext )
  330.             break;
  331.  
  332.         // If we found a subdirectory that isn't '.' or '..', recursively
  333.         // call PopulateContainer for that subdirectory (remember, while we're
  334.         // in this function, the parent's ProcessDirectory hasn't completed
  335.         // yet)
  336.  
  337.         if( (pciNext->attrFile & FILE_DIRECTORY) &&
  338.              pciNext->szFileName[0] != '.' )
  339.             ProcessDirectory( hab, hwndCnr, pciNext, szDirBase,
  340.                               pciNext->szFileName );
  341.  
  342.         usWhatRec = CMA_NEXT;
  343.  
  344.         pciPrev = pciNext;
  345.     }
  346.  
  347.     return;
  348. }
  349.  
  350. /**********************************************************************/
  351. /*--------------------------- InsertRecords --------------------------*/
  352. /*                                                                    */
  353. /*  INSERT DIRECTORY ENTRIES INTO THE CONTAINER.                      */
  354. /*                                                                    */
  355. /*  INPUT: anchor block handle for this thread,                       */
  356. /*         container window handle,                                   */
  357. /*         parent container record,                                   */
  358. /*         directory being displayed,                                 */
  359. /*         buffer containing directory entries,                       */
  360. /*         count of files in directory buffer                         */
  361. /*                                                                    */
  362. /*  1.                                                                */
  363. /*                                                                    */
  364. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  365. /*                                                                    */
  366. /*--------------------------------------------------------------------*/
  367. /**********************************************************************/
  368. static BOOL InsertRecords( HAB hab, HWND hwndCnr, PCNRITEM pciParent,
  369.                            PSZ szDirectory, PFILEFINDBUF3 pffb, ULONG cFiles )
  370. {
  371.     BOOL     fSuccess = TRUE;
  372.     PBYTE    pbBuf = (PBYTE) pffb;
  373.     PCNRITEM pci;
  374.  
  375.     // Allocate memory for cFiles container records. EXTRA_RECORD_BYTES refers
  376.     // to the number of bytes per record over and above the MINIRECORDCORE
  377.     // structure size that we need per record. Take a look at the PCNRITEM
  378.     // struct in CNRBASE.H to see what kind of data we are storing. The good
  379.     // thing is that the container will allocate this for us during the
  380.     // CM_ALLOCRECORD message. When we do a CM_REMOVERECORD during WM_DESTROY
  381.     // processing, we can free all this container memory in 1 shot. Note that
  382.     // CM_ALLOCRECORD allocates a linked list of records and sets the
  383.     // MINIRECORDCORE.cb size field for each record. It also appears to
  384.     // zero out all allocated memory besides this .cb field. It knows to
  385.     // allocate enough memory for MINIRECORDCORE rather than RECORDCORE structs
  386.     // due to using CCS_MINIRECORDCORE on the WinCreateWindow of the container.
  387.  
  388.     pci = WinSendMsg( hwndCnr, CM_ALLOCRECORD, MPFROMLONG( EXTRA_RECORD_BYTES ),
  389.                       MPFROMLONG( cFiles ) );
  390.  
  391.     if( pci )
  392.     {
  393.         INT           i;
  394.         PFILEFINDBUF3 pffbFile;
  395.         RECORDINSERT  ri;
  396.         PCNRITEM      pciFirst = pci;
  397.         ULONG         cFilesInserted = cFiles;
  398.  
  399.         // Insert all files into the container in one shot by filling in each
  400.         // linked list node that the container allocated for us.
  401.  
  402.         for( i = 0; i < cFiles; i++ )
  403.         {
  404.             // Get next FILEFINDBUF3 structure that points to a found file.
  405.  
  406.             pffbFile = (PFILEFINDBUF3) pbBuf;
  407.  
  408.             // Fill in the container record with the file info.
  409.  
  410.             if( FillInRecord( pci, szDirectory, pffbFile ) )
  411.  
  412.                 // Get the next container record in the linked list that the
  413.                 // container allocated for us.
  414.  
  415.                 pci = (PCNRITEM) pci->rc.preccNextRecord;
  416.             else
  417.                 cFilesInserted--;
  418.  
  419.             // Point to the next file in the buffer. This is done by adding
  420.             // an offset value to the current location in the buffer. Since
  421.             // the file name is variable length, this offset points to the
  422.             // end of the current file name and the beginning of the next
  423.             // one.
  424.  
  425.             pbBuf += pffbFile->oNextEntryOffset;
  426.         }
  427.  
  428.         // Use the RECORDINSERT structure to tell the container how to
  429.         // insert this batch of records. Here we ask to insert the
  430.         // records at the end of the linked list. The parent record indicates
  431.         // who to stick this batch of records under (if pciParent is NULL, the
  432.         // records are at the top level). (Child records are only displayed in
  433.         // Tree view). The zOrder is used for icon view only and specifies the
  434.         // ZORDER that places one record on top of another. In this case we are
  435.         // placing this batch of records at the top of the ZORDER. Also since
  436.         // fInvalidateRecord is TRUE, we will cause the records to be painted
  437.         // as they are inserted. In a container with a small amount of records
  438.         // you probably want to set this to FALSE and do a CM_INVALIDATERECORD
  439.         // (using 0 for cNumRecord) after all records have been inserted. But
  440.         // here the user needs visual feedback if a large amount of
  441.         // subdirectories are found.
  442.  
  443.         (void) memset( &ri, 0, sizeof( RECORDINSERT ) );
  444.  
  445.         ri.cb                 = sizeof( RECORDINSERT );
  446.         ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  447.         ri.pRecordParent      = (PRECORDCORE) pciParent;
  448.         ri.zOrder             = (USHORT) CMA_TOP;
  449.         ri.cRecordsInsert     = cFilesInserted;
  450.         ri.fInvalidateRecord  = TRUE;
  451.  
  452.         if( !WinSendMsg( hwndCnr, CM_INSERTRECORD, MPFROMP( pciFirst ),
  453.                          MPFROMP( &ri ) ) )
  454.         {
  455.             fSuccess = FALSE;
  456.  
  457.             Msg( "InsertRecords CM_INSERTRECORD RC(%X)", HABERR( hab ) );
  458.         }
  459.     }
  460.     else
  461.     {
  462.         fSuccess = FALSE;
  463.  
  464.         Msg( "InsertRecords CM_ALLOCRECORD RC(%X)", HABERR( hab ) );
  465.     }
  466.  
  467.     return fSuccess;
  468. }
  469.  
  470. /**********************************************************************/
  471. /*-------------------------- FillInRecord ----------------------------*/
  472. /*                                                                    */
  473. /*  POPULATE CONTAINER RECORD WITH FILE INFORMATION                   */
  474. /*                                                                    */
  475. /*  INPUT: pointer to record buffer to fill,                          */
  476. /*         directory path of file,                                    */
  477. /*         pointer to FILEFINDBUF3 that describes the file            */
  478. /*                                                                    */
  479. /*  1.                                                                */
  480. /*                                                                    */
  481. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  482. /*                                                                    */
  483. /*--------------------------------------------------------------------*/
  484. /**********************************************************************/
  485. static BOOL FillInRecord( PCNRITEM pci, PSZ szDirectory, PFILEFINDBUF3 pffb )
  486. {
  487.     BOOL     fSuccess = TRUE;
  488.     CHAR     szFullFileName[ CCHMAXPATH + 1 ];
  489.     HPOINTER hptr;
  490.  
  491.     // Copy the file name into the storage allocated by the container.
  492.  
  493.     (void) memset( pci->szFileName, 0, sizeof( pci->szFileName ) );
  494.     (void) memcpy( pci->szFileName, pffb->achName, pffb->cchName );
  495.  
  496.     // Get the fully qualified path for this file
  497.  
  498.     (void) memset( szFullFileName, 0, sizeof( szFullFileName ) );
  499.  
  500.     (void) strcpy( szFullFileName, szDirectory );
  501.  
  502.     szFullFileName[ strlen( szFullFileName ) ] = '\\';
  503.  
  504.     (void) strcat( szFullFileName, pci->szFileName );
  505.  
  506.     // Let PM get the icon for us by using WinLoadFileIcon. Note that a
  507.     // WinFreeFileIcon for this icon is not necessary because we are getting
  508.     // a shared copy by using FALSE as the last parameter. If you do a
  509.     // WinFreeFileIcon on this hptr you will get a PMERR_INVALID_PROCESS_ID.
  510.  
  511.     hptr = WinLoadFileIcon( szFullFileName, FALSE );
  512.  
  513.     // WinLoadFileIcon doesn't allow for any error investigation
  514.     // (WinGetLastError always returns zero). It seems to fail when a file is
  515.     // opened in write mode since it fails on the CNRBASE debug file and on the
  516.     // .INI files. Use a default icon if it fails.
  517.  
  518.     if( !hptr )
  519.         hptr = WinQuerySysPointer( HWND_DESKTOP, SPTR_QUESICON, FALSE );
  520.  
  521.     // Set up the file name pointer to point to the file name. This is
  522.     // crucial because we instructed the container in the
  523.     // SetContainerColumns function (CREATE.C) to use rc.pszIcon as a pointer
  524.     // to the file name (for reasons explained in that function).
  525.  
  526.     // Fill in all fields of the container record.
  527.  
  528.     pci->date.day       = pffb->fdateLastWrite.day;
  529.     pci->date.month     = pffb->fdateLastWrite.month;
  530.     pci->date.year      = pffb->fdateLastWrite.year;
  531.     pci->time.seconds   = pffb->ftimeLastWrite.twosecs;
  532.     pci->time.minutes   = pffb->ftimeLastWrite.minutes;
  533.     pci->time.hours     = pffb->ftimeLastWrite.hours;
  534.     pci->cbFile         = pffb->cbFile;
  535.     pci->attrFile       = pffb->attrFile;
  536.  
  537.     // Fill in all fields of the MINIRECORDCORE structure. Note that the .cb
  538.     // field of the MINIRECORDCORE struct was filled in by CM_ALLOCRECORD.
  539.  
  540.     pci->rc.pszIcon     = pci->szFileName;
  541.     pci->rc.hptrIcon    = hptr;
  542.  
  543.     return fSuccess;
  544. }
  545.  
  546. /*************************************************************************
  547.  *                     E N D     O F     S O U R C E                     *
  548.  *************************************************************************/
  549.