home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / io / filer / drvproc.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  78KB  |  2,422 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples.
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved.
  6. *       This source code is only intended as a supplement to
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /******************************Module*Header*******************************\
  13. * Module Name:  drvproc.c
  14. *
  15. * Filer : SDK sample
  16. *   +   Simple File Management program with GUI front end.
  17. *       Demonstrates Win32 File I/O API and various User algorithms.
  18. *
  19. * DRVPROC.C : Contains procedures relating to child window management.
  20. *               In this sample, the Drive children handle the directory
  21. *               and file enumeration, as well as the file I/O operations.
  22. *
  23. \**************************************************************************/
  24.  
  25. #define  STRICT
  26. #include <windows.h>
  27. #include <string.h>
  28. #define _MBCS
  29. #include <mbstring.h>
  30. #include "globals.h"
  31. #include "filer.h"
  32. #include "expdir.h"
  33. #include "drvproc.h"
  34.  
  35. extern HANDLE   ghModule;
  36. extern HANDLE   ghHeap;
  37. extern HFONT    ghFont;
  38. extern HANDLE   ghDrvThread;
  39. extern HANDLE   ghMenu;
  40.  
  41. extern HWND     ghwndCommand;
  42. extern HWND     ghwndDrives;
  43. extern HWND     ghActiveChild;
  44. extern HWND     ghwndDrv1;
  45. extern HWND     ghwndDrv2;
  46. extern HWND     ghFocusWnd;
  47.  
  48. extern LPDINFO  glpDrives;
  49.  
  50. extern CRITICAL_SECTION    gHeapCS;  // Global heap critical section var.
  51. extern CRITICAL_SECTION    gDrvCS;   // Drive list critical section var.
  52.  
  53. extern TCHAR    gszEditor[DIRECTORY_STRING_SIZE];
  54. extern TCHAR    gszCommandLine[DIRECTORY_STRING_SIZE * 2];
  55.  
  56. extern TCHAR    gszExtensions[NUM_EXTENSION_STRINGS][EXTENSION_LENGTH];
  57.  
  58. extern VKINFO   gVKArray[NUM_VERSION_INFO_KEYS];  // .EXE version info array.
  59.  
  60.  
  61. /***************************************************************************\
  62. * DrvWndProc()
  63. *
  64. * History:
  65. * 05-1-92  Created
  66. \***************************************************************************/
  67.  
  68. LRESULT  WINAPI DrvWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  69. {
  70.     TCHAR lpBuffer[128];
  71.     DWORD dwDirStyle = WS_BORDER | WS_CHILD | WS_VISIBLE |
  72.                               LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
  73.                               LBS_HASSTRINGS | LBS_WANTKEYBOARDINPUT |
  74.                               LBS_DISABLENOSCROLL | WS_HSCROLL |
  75.                               WS_VSCROLL |LBS_USETABSTOPS;
  76.  
  77.     DWORD dwFileStyle = WS_BORDER | WS_CHILD | WS_VISIBLE |
  78.                                LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
  79.                                LBS_HASSTRINGS | LBS_WANTKEYBOARDINPUT |
  80.                                LBS_DISABLENOSCROLL | WS_HSCROLL |
  81.                                LBS_EXTENDEDSEL | LBS_MULTIPLESEL |
  82.                                LBS_MULTICOLUMN | LBS_SORT;
  83.  
  84.     switch (message){
  85.  
  86.         //
  87.         // Creates the text and listbox windows for this Drv child and
  88.         //  saves its handle in the per Drv child DRVCHILDINFO data structure.
  89.         //
  90.         case WM_CREATE: {
  91.             LPCINFO lpCInfo;
  92.  
  93.             DWORD   dwLoop;
  94.  
  95.             LPDINFO lpWalk;
  96.  
  97.             LONG    lTabs = LISTBOX_TAB_SIZE;
  98.  
  99.  
  100.             //
  101.             // Initialize DRVCHILDINFO structure
  102.             //
  103.             lpCInfo = (LPCINFO) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  104.  
  105.             lpCInfo->hwnd = hwnd;
  106.  
  107.             // Create text window
  108.             lpCInfo->hTextWnd = CreateWindow(TEXT("TextClass"), NULL,
  109.                                     SS_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,
  110.                                     0, 0, 0, 0,
  111.                                     lpCInfo->hwnd,
  112.                                     (HMENU) TEXT_WINDOW_ID,
  113.                                     ghModule,
  114.                                     NULL);
  115.  
  116.             // Create Directory and File List boxes
  117.             lpCInfo->hDirLB = CreateWindow(TEXT("LISTBOX"), NULL,
  118.                                     dwDirStyle,
  119.                                     0, 0, 0, 0,
  120.                                     lpCInfo->hwnd,
  121.                                     (HMENU) LISTDIR_ID,
  122.                                     ghModule,
  123.                                     NULL);
  124.  
  125.             lpCInfo->hFileLB = CreateWindow(TEXT("LISTBOX"), NULL,
  126.                                     dwFileStyle,
  127.                                     0, 0, 0, 0,
  128.                                     lpCInfo->hwnd,
  129.                                     (HMENU) LISTFILE_ID,
  130.                                     ghModule,
  131.                                     NULL);
  132.  
  133.             //
  134.             // fDirLeft indicates whether the Directory ListBox defaults to
  135.             //  the left side of each of the two drive windows.
  136.             // fDirExpand indicates whether the Directory Listbox defaults
  137.             //  to full expansion.
  138.             //
  139.             lpCInfo->fDirLeft = TRUE;
  140.             lpCInfo->fDirExpand = FALSE;
  141.             lpCInfo->fSuicide = FALSE;
  142.  
  143.             //
  144.             // Create Mutex associated with each list box
  145.             //
  146.             lpCInfo->hDirMutex = CreateMutex(NULL, FALSE, NULL);
  147.             lpCInfo->hFileMutex = CreateMutex(NULL, FALSE, NULL);
  148.  
  149.             //
  150.             // Associate window with the current directory LPDINFO structure
  151.             //   from the Drives linked list
  152.             //
  153.             dwLoop = GetCurrentDirectory( DIRECTORY_STRING_SIZE,
  154.                                           lpCInfo->CaptionBarText );
  155.             CharUpper(lpCInfo->CaptionBarText);
  156.  
  157.             WaitForSingleObject(ghDrvThread, INFINITE);
  158.             EnterCriticalSection(&gDrvCS);
  159.  
  160.             lpWalk = glpDrives;
  161.  
  162.             if( dwLoop && dwLoop <= DIRECTORY_STRING_SIZE ){
  163.                 while( lpWalk && lpWalk->DriveName[0] !=
  164.                        (lpCInfo->CaptionBarText)[0] )
  165.                     lpWalk = lpWalk->next;
  166.                 if( !lpWalk ){
  167.                     LoadString(ghModule, IDS_DCCDRVLST, lpBuffer, sizeof(lpBuffer)); 
  168.                     ErrorMsg(lpBuffer);
  169.                     LeaveCriticalSection(&gDrvCS);
  170.                     return(-1);
  171.                 }
  172.             }
  173.             else{
  174.                 LoadString(ghModule, IDS_DCCCURDIR, lpBuffer, sizeof(lpBuffer)); 
  175.                 ErrorMsg(lpBuffer);
  176.                 LeaveCriticalSection(&gDrvCS);
  177.                 return(-1);
  178.             }
  179.  
  180.             LeaveCriticalSection(&gDrvCS);
  181.  
  182.             lpCInfo->lpDriveInfo = lpWalk;
  183.  
  184.             //
  185.             // Save the handle to DRVCHILDINFO in our window structure
  186.             //
  187.             SetWindowLong(hwnd, GWL_USERDATA, (LONG) lpCInfo);
  188.  
  189.             //
  190.             // Initialize child windows
  191.             //
  192.             if( !SendMessage(lpCInfo->hDirLB, LB_SETTABSTOPS, (WPARAM)1,
  193.                             (LPARAM)&lTabs) ) {
  194.                 LoadString(ghModule, IDS_DCCTABSTP, lpBuffer, sizeof(lpBuffer)); 
  195.                 ErrorMsg(lpBuffer);
  196.             }
  197.  
  198.             //
  199.             // Set default font.
  200.             //
  201.             SendMessage(lpCInfo->hDirLB, WM_SETFONT, (WPARAM)ghFont, (LPARAM)FALSE);
  202.             SendMessage(lpCInfo->hFileLB, WM_SETFONT, (WPARAM)ghFont, (LPARAM)FALSE);
  203.  
  204.             SendMessage(hwnd, WM_COMMAND, (WPARAM)MM_REFRESH, (LPARAM)NULL);
  205.  
  206.             return(1);
  207.         }
  208.  
  209.         case WM_COMMAND: {
  210.           static LPCINFO     lpCInfo;
  211.           static SELECTINFO  Select;
  212.  
  213.           //
  214.           // Retrieving this child window's DRVCHILDINFO data for displaying
  215.           //    messages in the text window
  216.           //
  217.           lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);
  218.  
  219.           switch (LOWORD(wParam)){
  220.  
  221.             case MM_TAB:{
  222.                 HWND    hFocus;
  223.  
  224.                 hFocus = GetFocus();
  225.  
  226.                 if( hFocus == lpCInfo->hDirLB )
  227.                     ghFocusWnd = lpCInfo->hFileLB;
  228.                 else
  229.                     if( hFocus == lpCInfo->hFileLB )
  230.                         ghFocusWnd = ghwndCommand;
  231.                     else
  232.                         if( hFocus == ghwndCommand)
  233.                             ghFocusWnd = lpCInfo->hDirLB;
  234.  
  235.                 SetFocus( ghFocusWnd );
  236.                 return(1);
  237.             }
  238.  
  239.             //
  240.             //  Clears the selection in the active window.
  241.             //  Sent when user hits escape key.
  242.             //
  243.             case MM_ESCAPE:{
  244.                 //
  245.                 // If there is a directory expand in process, kill the
  246.                 //  thread, and leave the listbox in a semi-expanded state.
  247.                 //  Else, clear file selection, and switch to command window.
  248.                 //
  249.                 if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
  250.                         == WAIT_TIMEOUT ){
  251.                     lpCInfo->fSuicide = TRUE;
  252.                     lpCInfo->fEscape = TRUE;
  253.                 }
  254.                 else
  255.                     ReleaseMutex( lpCInfo->hDirMutex );
  256.  
  257.                 SendMessage(lpCInfo->hFileLB, LB_SETCURSEL, (WPARAM)-1,
  258.                                (LPARAM)0);
  259.  
  260.                 SetFocus( ghwndCommand );
  261.                 ghFocusWnd = ghwndCommand;
  262.                 SendMessage(ghwndCommand, LB_SETCURSEL, (WPARAM)0,
  263.                                (LPARAM)-1);
  264.                 return(1);
  265.             }
  266.  
  267.             case MM_OPEN:{
  268.                 if( ghFocusWnd == lpCInfo->hFileLB )
  269.                     OpenListBoxItem(lpCInfo);
  270.                 else
  271.                     if( ghFocusWnd == lpCInfo->hDirLB ){
  272.                         if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
  273.                                          (LPARAM)0) ){
  274.                             LoadString(ghModule, IDS_MMOPENERR, lpBuffer, sizeof(lpBuffer)); 
  275.                             ErrorMsg(lpBuffer);
  276.                             return(0);
  277.                         }
  278.                     }
  279.                     else
  280.                         RunCommandItem(lpCInfo);
  281.  
  282.                 return(1);
  283.             }
  284.  
  285.             case MM_COPY:{
  286.  
  287.                 Select.hwnd = hwnd;
  288.                 Select.dwAction = MM_COPY;
  289.                 LoadString(ghModule, IDS_COPYING, lpBuffer, sizeof(lpBuffer)); 
  290.                 Select.szAction = lpBuffer;
  291.                 LoadString(ghModule, IDS_COPYINGTO, lpBuffer, sizeof(lpBuffer));
  292.                 Select.szToFrom = lpBuffer;
  293.  
  294.                 ExecuteFileAction(&Select);
  295.  
  296.                 return(1);
  297.             }
  298.  
  299.             case MM_DELETE:{
  300.  
  301.                 Select.hwnd = hwnd;
  302.                 Select.dwAction = MM_DELETE;
  303.                 LoadString(ghModule, IDS_DELETING, lpBuffer, sizeof(lpBuffer));
  304.                 Select.szAction = lpBuffer;
  305.                 LoadString(ghModule, IDS_DELETINGFRM, lpBuffer, sizeof(lpBuffer));
  306.                 Select.szToFrom = lpBuffer;
  307.  
  308.                 ExecuteFileAction(&Select);
  309.  
  310.                 return(1);
  311.             }
  312.  
  313.             case MM_MOVE:{
  314.  
  315.                 Select.hwnd = hwnd;
  316.                 Select.dwAction = MM_MOVE;
  317.                 LoadString(ghModule, IDS_MOVING, lpBuffer, sizeof(lpBuffer));
  318.                 Select.szAction = lpBuffer;
  319.                 LoadString(ghModule, IDS_COPYINGTO, lpBuffer, sizeof(lpBuffer));
  320.                 Select.szToFrom = lpBuffer;
  321.  
  322.                 ExecuteFileAction(&Select);
  323.  
  324.                 return(1);
  325.             }
  326.  
  327.             case MM_RENAME:{
  328.  
  329.                 if( DialogBoxParam(ghModule, TEXT("RenameDlg"), hwnd,
  330.                               (DLGPROC)RenameProc, (LPARAM)lpCInfo) == -1 ){
  331.                     LoadString(ghModule, IDS_RENAMEERR, lpBuffer, sizeof(lpBuffer));
  332.                     ErrorMsg(lpBuffer);
  333.                     return(0);
  334.                 }
  335.  
  336.                 return(1);
  337.             }
  338.  
  339.             case MM_MKDIR:{
  340.  
  341.                 if( DialogBoxParam(ghModule, TEXT("MkDirDlg"), hwnd,
  342.                               (DLGPROC)MkDirProc, (LPARAM)lpCInfo) == -1 ){
  343.                     LoadString(ghModule, IDS_MKDIRERR, lpBuffer, sizeof(lpBuffer));
  344.                     ErrorMsg(lpBuffer);
  345.                     return(0);
  346.                 }
  347.  
  348.                 return(1);
  349.             }
  350.  
  351.             case MM_VERSION:{
  352.  
  353.                 if( DialogBoxParam(ghModule, TEXT("VersionInfoDlg"), hwnd,
  354.                               (DLGPROC)VersionProc, (LPARAM)lpCInfo) == -1 ){
  355.                     LoadString(ghModule, IDS_VERDLGERR, lpBuffer, sizeof(lpBuffer));
  356.                     ErrorMsg(lpBuffer);
  357.                     return(0);
  358.                 }
  359.  
  360.                 return(1);
  361.             }
  362.  
  363.             case MM_EXPAND:{
  364.  
  365.                 lpCInfo->fDirExpand = !lpCInfo->fDirExpand;
  366.  
  367.                 if( lpCInfo->fDirExpand )
  368.                     CheckMenuItem( ghMenu, MM_EXPAND,
  369.                                     MF_BYCOMMAND | MF_CHECKED);
  370.                 else
  371.                     CheckMenuItem( ghMenu, MM_EXPAND,
  372.                                 MF_BYCOMMAND | MF_UNCHECKED);
  373.  
  374.                 if( !SendMessage( (HWND)lpCInfo->hwnd, WM_COMMAND,
  375.                                  (WPARAM)MM_REFRESH, (LPARAM)0 ) ){
  376.                     LoadString(ghModule, IDS_MMEXPAND, lpBuffer, sizeof(lpBuffer));
  377.                     ErrorMsg(lpBuffer);
  378.                     return(0);
  379.                 }
  380.                 return(1);
  381.             }
  382.  
  383.             //
  384.             // refreshes contents of directory and file ListBoxes.
  385.             //
  386.             case MM_REFRESH:{
  387.  
  388.                 DWORD   dwThreadID;
  389.  
  390.                 if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
  391.                         == WAIT_TIMEOUT )
  392.                     //
  393.                     // If the full directory expand has been cancled, kill the
  394.                     //  existing thread.
  395.                     //
  396.                     if( !lpCInfo->fDirExpand && !lpCInfo->fSuicide){
  397.                         lpCInfo->fSuicide = TRUE;
  398.                         return(1);
  399.                     }
  400.                     else{
  401.                         return(0);
  402.                     }
  403.  
  404.                 // if set, clear the expand dir. user abort (escape key) flag.
  405.                 if( lpCInfo->fEscape ){
  406.                     lpCInfo->fEscape = FALSE;
  407.                     ReleaseMutex( lpCInfo->hDirMutex );
  408.                     return(1);
  409.                 }
  410.  
  411.                 // At this point, the Dir LB mutex has been grabbed.
  412.  
  413.                 // Clear directory LB.  If expand flag is set, expand all
  414.                 //  directories.  Refill File LB.
  415.                 //
  416.                 if( SendMessage( lpCInfo->hDirLB, LB_RESETCONTENT,
  417.                                  (WPARAM)0, (LPARAM)0 ) < 0 ){
  418.                     LoadString(ghModule, IDS_REFRESH1, lpBuffer, sizeof(lpBuffer));
  419.                     ErrorMsg(lpBuffer);
  420.                     ReleaseMutex( lpCInfo->hDirMutex );
  421.                     return(0);
  422.                 }
  423.  
  424.                 //
  425.                 // This call puts the default root entry back into the empty
  426.                 //  LB.  Set suicide flag to false to ensure it will complete.
  427.                 //
  428.                 lpCInfo->fSuicide = FALSE;
  429.                 ExpDir( lpCInfo );
  430.  
  431.                 //
  432.                 // All the Dir LB work is done.  Release Dir LB Mutex.
  433.                 //
  434.                 ReleaseMutex( lpCInfo->hDirMutex );
  435.  
  436.                 if( lpCInfo->fDirExpand ){
  437.  
  438.                     CloseHandle( lpCInfo->hDirThread );
  439.  
  440.                     lpCInfo->hDirThread = CreateThread( NULL, 0,
  441.                                   (LPTHREAD_START_ROUTINE)FullExpand,
  442.                                   (LPVOID)lpCInfo, 0, &dwThreadID);
  443.  
  444.                     if( !lpCInfo->hDirThread ){
  445.                         LoadString(ghModule, IDS_REFRESH2, lpBuffer, sizeof(lpBuffer));
  446.                         ErrorMsg(lpBuffer);
  447.                         return(0);
  448.                     }
  449.                 }
  450.                 else
  451.                     ExpDir( lpCInfo );
  452.  
  453.                 if( !PostMessage(hwnd, WM_COMMAND, MM_FILLFILE,
  454.                                  (LPARAM)0) ){
  455.                     LoadString(ghModule, IDS_REFRESH3, lpBuffer, sizeof(lpBuffer));
  456.                     ErrorMsg(lpBuffer);
  457.                     return(0);
  458.                 }
  459.  
  460.                 return(1);
  461.             }
  462.  
  463.             //
  464.             //  Fill listbox in lParam with directory from Drv child's drive.
  465.             //  Sent by MM_REFRESH.
  466.             //
  467.             //  lParam == 0
  468.             //
  469.             case MM_FILLDIR:{
  470.  
  471.                 DWORD   dwThreadID;
  472.  
  473.                 lpCInfo->fSuicide = FALSE;
  474.  
  475.                 CloseHandle( lpCInfo->hDirThread );
  476.  
  477.                 lpCInfo->hDirThread = CreateThread( NULL, 0,
  478.                               (LPTHREAD_START_ROUTINE)ExpDir,
  479.                               (LPVOID)lpCInfo, 0, &dwThreadID);
  480.  
  481.                 if( !(lpCInfo->hDirThread) ){
  482.                     LoadString(ghModule, IDS_FILDIRERR, lpBuffer, sizeof(lpBuffer));
  483.                     ErrorMsg(lpBuffer);
  484.                     return(0);
  485.                 }
  486.  
  487.                 return(1);
  488.             }
  489.  
  490.             //
  491.             //  Fill listbox in lParam with files from current directory.
  492.             //  Sent by MM_REFRESH & LBN_DBLCLK in DrvWndProc, as well as
  493.             //  DoFileIO. and HandleIOError().
  494.             //
  495.             //  lParam == 0
  496.             //
  497.             case MM_FILLFILE:{
  498.                 TCHAR               szFiles[DIRECTORY_STRING_SIZE + 20];
  499.                 LPTSTR              lpHold;
  500.  
  501.                 if( WaitForSingleObject( lpCInfo->hFileMutex, MUTEX_TIMEOUT)
  502.                         == WAIT_TIMEOUT ){
  503.                     LoadString(ghModule, IDS_FILDIRERR2, lpBuffer, sizeof(lpBuffer));
  504.                     ErrorMsg(lpBuffer);
  505.                     return(0);
  506.                 }
  507.  
  508.  
  509.                 //
  510.                 // Not checking for errors here, as LB_RESETCONTENT always
  511.                 //  returns true, and LB_DIR returns an error if the directory
  512.                 //  is empty.
  513.                 //
  514.                 SendMessage(lpCInfo->hFileLB, LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL);
  515.  
  516.                 lstrcpy( szFiles, lpCInfo->CaptionBarText );
  517.                 lpHold = TStrChr(szFiles, TEXT('\0'));
  518.                 lpHold--;
  519.                 if( *lpHold != TEXT('\\') ){
  520.                     lpHold++;
  521.                     *lpHold = TEXT('\\');
  522.                 }
  523.  
  524.                 lpHold++;
  525.                 lstrcpy( lpHold, TEXT("*.*"));
  526.  
  527.                 if( SendMessage( lpCInfo->hFileLB, LB_DIR, (WPARAM)0x10,
  528.                                  (LPARAM)szFiles ) == LB_ERR ){
  529.                     LoadString(ghModule, IDS_FILDIRERR3, lpBuffer, sizeof(lpBuffer));
  530.                     ErrorMsg(lpBuffer);
  531.                     ReleaseMutex( lpCInfo->hFileMutex );
  532.                     return(0);
  533.                 }
  534.  
  535.                 //
  536.                 //  Set selection to first file.
  537.                 //
  538.                 if( SendMessage( lpCInfo->hFileLB, LB_SETSEL, (WPARAM)TRUE,
  539.                                  (LPARAM)0 ) == LB_ERR ){
  540.                     LoadString(ghModule, IDS_FILDIRERR4, lpBuffer, sizeof(lpBuffer));
  541.                     ErrorMsg(lpBuffer);
  542.                     ReleaseMutex( lpCInfo->hFileMutex );
  543.                     return(0);
  544.                 }
  545.  
  546.                 SetWindowText(lpCInfo->hTextWnd, lpCInfo->CaptionBarText);
  547.  
  548.                 ReleaseMutex( lpCInfo->hFileMutex );
  549.  
  550.                 return(1);
  551.             }
  552.  
  553.             //
  554.             //  Toggle active status of drive child.
  555.             //
  556.             case MM_TOGGLE:{
  557.  
  558.                 SetWindowText(lpCInfo->hTextWnd, lpCInfo->CaptionBarText);
  559.                 return(1);
  560.             }
  561.  
  562.             //
  563.             // The following WM_COMMAND messages are sent by the listboxes
  564.             //
  565.             // HIWORD(wParam) = LB notification message
  566.             // lParam = LB window handle
  567.             //
  568.             case LISTFILE_ID:{
  569.               switch( HIWORD(wParam) ){
  570.                 //
  571.                 // In case of double click on a directory, expand the file
  572.                 // Listbox. if on a file name, run or edit file.
  573.                 //
  574.                 case LBN_DBLCLK:{
  575.                     OpenListBoxItem(lpCInfo);
  576.                     return(1);
  577.                 }
  578.                 break;
  579.  
  580.                 case LBN_SETFOCUS:{
  581.                     ghFocusWnd = lpCInfo->hFileLB;
  582.                 }
  583.                 break;
  584.  
  585.                 default:
  586.                     return(1);
  587.               }
  588.             } // LISTFILE_ID
  589.             break;
  590.  
  591.             //
  592.             // Notification from the Directory ListBox
  593.             //
  594.             case LISTDIR_ID:{
  595.               switch( HIWORD(wParam) ){
  596.  
  597.                 case LBN_SETFOCUS:{
  598.                     ghFocusWnd = lpCInfo->hDirLB;
  599.                 }
  600.                 break;
  601.  
  602.                 //
  603.                 // Expand subdirectories in dir listbox
  604.                 //
  605.                 case LBN_DBLCLK:{
  606.  
  607.                     if( !PostMessage(hwnd, WM_COMMAND, MM_FILLDIR,
  608.                                      (LPARAM)0) ){
  609.                         LoadString(ghModule, IDS_DBLCLKERR, lpBuffer, sizeof(lpBuffer));
  610.                         ErrorMsg(lpBuffer);
  611.                         return(0);
  612.                     }
  613.                     return(1);
  614.                 }
  615.                 break;
  616.  
  617.                 case LBN_SELCHANGE:{
  618.                     //
  619.                     // for the Directory LB, fill the
  620.                     // corresp. File LB with items in the newly selected dir.
  621.                     //
  622.                     LONG lIndex;
  623.  
  624.  
  625.                     if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT)
  626.                             == WAIT_TIMEOUT ){
  627.                         LoadString(ghModule, IDS_SELCNGERR, lpBuffer, sizeof(lpBuffer));
  628.                         ErrorMsg(lpBuffer);
  629.                         return(0);
  630.                     }
  631.  
  632.                     //
  633.                     // Retrieve selected (careted) item.
  634.                     //
  635.                     lIndex = SendMessage( (HWND)lParam, LB_GETCARETINDEX,
  636.                                         (WPARAM)NULL, (LPARAM)NULL );
  637.  
  638.                     if( !ConstructDirName(lpCInfo, lIndex,
  639.                                           lpCInfo->CaptionBarText) ){
  640.                         LoadString(ghModule, IDS_CONDIRERR, lpBuffer, sizeof(lpBuffer));
  641.                         ErrorMsg(lpBuffer);
  642.                         ReleaseMutex( lpCInfo->hDirMutex );
  643.                         return(0);
  644.                     }
  645.  
  646.                     ReleaseMutex( lpCInfo->hDirMutex );
  647.  
  648.                     if( !PostMessage(hwnd, WM_COMMAND, MM_FILLFILE,
  649.                                      (LPARAM)0) ){
  650.                         LoadString(ghModule, IDS_LBNOTFYERR, lpBuffer, sizeof(lpBuffer));
  651.                         ErrorMsg(lpBuffer);
  652.                         return(0);
  653.                     }
  654.                 } // LBN_SELCHANGE
  655.                 break;
  656.  
  657.                 default:
  658.                     return(1);
  659.               }
  660.             } //  LISTDIR_ID
  661.             break;
  662.  
  663.             default:
  664.                return(1);
  665.           }
  666.         }
  667.         break;
  668.  
  669.         //
  670.         // Whenever the Drv child window is resized, its children has to be
  671.         //  resized accordingly.  The GetWindowLong GWL_USERDATA values
  672.         //  contain the height of the windows queried, set in their respective
  673.         //  WM_CREATE cases.
  674.         //
  675.         case WM_SIZE: {
  676.             LPCINFO     lpCInfo;
  677.  
  678.             int         nListHeight,
  679.                         nListWidth;
  680.  
  681.             HWND        hLeftLB,
  682.                         hRightLB;
  683.  
  684.             //
  685.             // First, get the text window's handle from the per Drv child
  686.             //  DRVCHILDINFO data structure
  687.             //
  688.             lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);
  689.  
  690.             nListHeight = HIWORD(lParam) -
  691.                           GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA)
  692.                           - LIST_BORDER * 2;
  693.  
  694.             nListWidth = (LOWORD(lParam) - LIST_BORDER) / 2 - LIST_BORDER;
  695.  
  696.             //
  697.             // Always, put the text window at the top of the Drv window.
  698.             // Increasing sides and bottom extents by 1 to overlap border
  699.             //   with Drv child border
  700.             //
  701.             MoveWindow(lpCInfo->hTextWnd,
  702.                        -1,
  703.                        0,
  704.                        LOWORD(lParam) + 2,
  705.                        GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1,
  706.                        TRUE);
  707.  
  708.             if( lpCInfo->fDirLeft ){
  709.                 hLeftLB = lpCInfo->hDirLB;
  710.                 hRightLB = lpCInfo->hFileLB;
  711.             }
  712.             else{
  713.                 hLeftLB = lpCInfo->hFileLB;
  714.                 hRightLB = lpCInfo->hDirLB;
  715.             }
  716.  
  717.             MoveWindow(hLeftLB,
  718.                        LIST_BORDER,
  719.                        GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1
  720.                          + LIST_BORDER,
  721.                        nListWidth,
  722.                        nListHeight,
  723.                        TRUE);
  724.  
  725.             MoveWindow(hRightLB,
  726.                        (LOWORD(lParam) + LIST_BORDER) / 2,
  727.                        GetWindowLong(lpCInfo->hTextWnd, GWL_USERDATA) + 1
  728.                          + LIST_BORDER,
  729.                        nListWidth,
  730.                        nListHeight,
  731.                        TRUE);
  732.  
  733.         break;
  734.         }
  735.  
  736.         case WM_PARENTNOTIFY:{
  737.             LPCINFO lpCInfo;
  738.  
  739.             if(wParam == WM_LBUTTONDOWN){
  740.                 lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);
  741.                 if(lpCInfo == NULL){
  742.                     LoadString(ghModule, IDS_PARNTFYERR, lpBuffer, sizeof(lpBuffer));
  743.                     ErrorMsg(lpBuffer);
  744.                     return(1);
  745.                 }
  746.                 if(HIWORD(wParam) == LISTDIR_ID)
  747.                     SetFocus(lpCInfo->hDirLB);
  748.                 else
  749.                     if(HIWORD(wParam) == LISTFILE_ID)
  750.                         SetFocus(lpCInfo->hFileLB);
  751.                     else
  752.                         if(HIWORD(wParam) == TEXT_WINDOW_ID)
  753.                             SetFocus(lpCInfo->hTextWnd);
  754.             }
  755.  
  756.             break;
  757.         }
  758.  
  759.         //
  760.         // Same as MainWndProc's MM_ACTIVEDRV case.  The initial PostMessage
  761.         //   is so the currently active Drv child will not process the message
  762.         //   until it is no longer in focus.
  763.         //
  764.         case WM_MOUSEACTIVATE:{
  765.             LPCINFO lpCInfo;
  766.  
  767.             PostMessage(ghActiveChild, WM_COMMAND, (WPARAM)MM_TOGGLE,
  768.                         (LPARAM)NULL);
  769.             ghActiveChild = hwnd;
  770.             SendMessage(ghActiveChild, WM_COMMAND, (WPARAM)MM_TOGGLE,
  771.                         (LPARAM)NULL);
  772.  
  773.             lpCInfo = (LPCINFO) GetWindowLong(hwnd, GWL_USERDATA);
  774.             SendMessage(ghwndDrives, WM_COMMAND, MM_ACTIVEDRV,
  775.                         (LPARAM)lpCInfo->lpDriveInfo);
  776.  
  777.             break;
  778.         }
  779.  
  780.         //
  781.         // Free the DRVCHILDINFO data that associates with this window
  782.         //  also, reset the menu.
  783.         //
  784.         case WM_CLOSE: {
  785.             LPCINFO lpCInfo;
  786.  
  787.             lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);
  788.  
  789.             CloseHandle(lpCInfo->hDirMutex );
  790.             CloseHandle(lpCInfo->hFileMutex );
  791.  
  792.             EnterCriticalSection(&gHeapCS);
  793.             HeapFree(ghHeap, 0, (LPVOID)lpCInfo);
  794.             LeaveCriticalSection(&gHeapCS);
  795.  
  796.             break;
  797.         }
  798.  
  799.         default:
  800.             return DefWindowProc(hwnd, message, wParam, lParam);
  801.  
  802.     } //switch
  803.     return DefWindowProc(hwnd, message, wParam, lParam);
  804. }
  805.  
  806.  
  807. /***************************************************************************\
  808. *
  809. * GetLBText()
  810. *
  811. * Gets the text of the currently selected (careted) item in the given
  812. *   listbox.
  813. *
  814. * Returns:  Index of selected item if successful, -1 on failure
  815. *
  816. * History:
  817. * 4/26/93
  818. *   Created.
  819. *
  820. \***************************************************************************/
  821. LONG GetLBText(HWND hActiveLB, PTCHAR szItemBuff)
  822. {
  823.     LONG    lIndex;
  824.     TCHAR   lpBuffer[128];
  825.  
  826.     //
  827.     // Retrieve selected (careted) item.
  828.     //
  829.     lIndex = SendMessage( hActiveLB, LB_GETCARETINDEX,
  830.                           (WPARAM)NULL, (LPARAM)NULL );
  831.  
  832.     if( SendMessage( hActiveLB, LB_GETTEXT, (WPARAM)lIndex,
  833.                      (LPARAM)szItemBuff) == LB_ERR ){
  834.         LoadString(ghModule, IDS_GETLBTXTERR, lpBuffer, sizeof(lpBuffer));
  835.         ErrorMsg(lpBuffer);
  836.         return(-1);
  837.     }
  838.  
  839.     return( lIndex );
  840. }
  841.  
  842.  
  843. /***************************************************************************\
  844. *
  845. * UpdateFileLB()
  846. *
  847. * Updates the file listbox of the drive child given by sending an MM_FILLFILE
  848. *   message to it.
  849. *
  850. *  input:   hwnd    -   Handle of drive child to update file listbox of.
  851. *
  852. * History:
  853. * 6/3/92
  854. *   Created.
  855. *
  856. \***************************************************************************/
  857. void UpdateFileLB(HWND hwnd)
  858. {
  859.     LPCINFO lpCInfo;
  860.  
  861.     lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);
  862.  
  863.     SendMessage(hwnd, WM_COMMAND, (WPARAM)MM_FILLFILE,
  864.                 (LPARAM)0);
  865. }
  866.  
  867.  
  868. /***************************************************************************\
  869. *
  870. * OpenListBoxItem()
  871. *
  872. * Attempts to expand a selected File list box directory entry into an available
  873. *  file listbox, or spawn a selected list box file.
  874. *
  875. *  input:   lpCInfo   -   pointer to Drv child's LPCINFO structure
  876. *
  877. * History:
  878. * 5/27/92
  879. *   Created.
  880. *
  881. \***************************************************************************/
  882. BOOL OpenListBoxItem(LPCINFO lpCInfo)
  883. {
  884.     TCHAR   szItemBuff[DIRECTORY_STRING_SIZE];
  885.     TCHAR   lpBuffer[128];
  886.  
  887.     //
  888.     // Retrieve selected (careted) item.
  889.     //
  890.     GetLBText(lpCInfo->hFileLB, szItemBuff);
  891.  
  892.     //
  893.     // Determine whether the item is a directory or a file.
  894.     //   If file, Run if possible.
  895.     //
  896.     if( !IsDirectory(lpCInfo->CaptionBarText, szItemBuff) ){
  897.         RunListBoxItem(lpCInfo);
  898.         return(1);
  899.         }
  900.  
  901.     //
  902.     // It is a directory.  Set the new caption text, and expand files.
  903.     //
  904.     lstrcpy( lpCInfo->CaptionBarText, szItemBuff);
  905.  
  906.     if( !PostMessage(lpCInfo->hwnd, WM_COMMAND, MM_FILLFILE,
  907.                         (LPARAM)0) ){
  908.         LoadString(ghModule, IDS_OPENLBERR, lpBuffer, sizeof(lpBuffer));
  909.         ErrorMsg(lpBuffer);
  910.         return(0);
  911.     }
  912.  
  913.     return(1);
  914. }
  915.  
  916. /***************************************************************************\
  917. *
  918. * RunListBoxItem()
  919. *
  920. * Attempts to spawn the selected list box file. If the file is not executable,
  921. *   attempts to spawn an editor to edit the file.
  922. *
  923. *  input:   lpCInfo   -   pointer to Drv child's LPCINFO structure
  924. *
  925. * History:
  926. * 5/27/92
  927. *   Created.
  928. *
  929. * 5/12/93
  930. *   Modified.
  931. *
  932. \***************************************************************************/
  933. BOOL RunListBoxItem(LPCINFO lpCInfo)
  934. {
  935.     LONG        lIndex;
  936.     TCHAR       szFileBuff[DIRECTORY_STRING_SIZE];
  937.     TCHAR       szCmdLine[DIRECTORY_STRING_SIZE * 2];
  938.     LPTSTR      szHold;
  939.     TCHAR       lpBuffer[128];
  940.  
  941.     STARTUPINFO si;
  942.     PROCESS_INFORMATION pi;
  943.  
  944.  
  945.     lstrcpy(szCmdLine, lpCInfo->CaptionBarText);
  946.  
  947.     lstrcat(szCmdLine, TEXT("\\"));
  948.  
  949.     //
  950.     // Get file that was opened, and attempt to spawn. If fails, attempt to
  951.     // edit it.
  952.     //
  953.  
  954.     //
  955.     // Retrieve selected (careted) item.
  956.     //
  957.     lIndex = GetLBText(lpCInfo->hFileLB, szFileBuff);
  958.     if( lIndex == LB_ERR)
  959.         return(0);
  960.  
  961.     //
  962.     // Don't assume the file has an extension. if no '.', insert one at end
  963.     //  of file, so spawned editor will not assume any default extension.
  964.     //  (i.e. Notepad assumes a .TXT if no extension is given.)
  965.     //
  966.     szHold = TStrChr(szFileBuff, TEXT('.'));
  967.     if( !szHold ){
  968.         szHold = TStrChr(szFileBuff, TEXT('\0'));
  969.         *szHold = TEXT('.');
  970.         *(szHold + sizeof(TCHAR)) = TEXT('\0');
  971.     }
  972.  
  973.     si.cb = sizeof(STARTUPINFO);
  974.     si.lpReserved = NULL;
  975.     si.lpDesktop = NULL;
  976.     si.lpTitle = NULL;
  977.     si.dwFlags = 0;
  978.     si.cbReserved2 = 0;
  979.     si.lpReserved2 = NULL;
  980.  
  981.     //
  982.     // Convert file to uppercase for extension comparison.  Raise the
  983.     //   priority of this thread for the duration of the create process code.
  984.     //   This is so the CreateProcess will not be held up by the directory
  985.     //   fill threads.
  986.     //   If an executable extension, spawn, else edit.
  987.     //
  988.     CharUpper(szFileBuff);
  989.  
  990.     SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  991.  
  992.     for(lIndex = 0; lIndex < NUM_EXTENSION_STRINGS; lIndex++)
  993.         if( !lstrcmp(szHold, &gszExtensions[lIndex][0]) ){
  994.  
  995.             lstrcat(szCmdLine, szFileBuff);
  996.  
  997.             if( !CreateProcess(NULL, (LPTSTR)szCmdLine, NULL, NULL, FALSE,
  998.                                CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
  999.                                NULL, lpCInfo->CaptionBarText, &si, &pi) ){
  1000.                 LoadString(ghModule, IDS_CANTSPAWN, lpBuffer, sizeof(lpBuffer));
  1001.                 ErrorMsg(lpBuffer);
  1002.                 return(0);
  1003.             }
  1004.  
  1005.             CloseHandle( pi.hProcess );
  1006.             CloseHandle( pi.hThread );
  1007.  
  1008.             return(1);
  1009.         }
  1010.  
  1011.     LoadString(ghModule, STR_DEF_EDITOR, szCmdLine,
  1012.                DIRECTORY_STRING_SIZE * 2);
  1013.     lstrcat(szCmdLine, TEXT(" "));
  1014.     lstrcat(szCmdLine, szFileBuff);
  1015.  
  1016.     if( !CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
  1017.                        CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
  1018.                        NULL, lpCInfo->CaptionBarText, &si, &pi) ){
  1019.         LoadString(ghModule, IDS_CANTEDIT, lpBuffer, sizeof(lpBuffer));
  1020.         ErrorMsg(lpBuffer);
  1021.         return(0);
  1022.     }
  1023.  
  1024.     CloseHandle( pi.hProcess );
  1025.     CloseHandle( pi.hThread );
  1026.  
  1027.     SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  1028.  
  1029.     return(1);
  1030. }
  1031.  
  1032.  
  1033. /***************************************************************************\
  1034. *
  1035. * FilerGetVersion()
  1036. *
  1037. *  Given an item from a File ListBox, GetVersion retrieves the version
  1038. *    information from the specified file.
  1039. *
  1040. *  input:   lpszFileName   -   the name of the file.
  1041. *           dwBuffSize     -   > 0 size of buffer to hold version info
  1042. *           szBuff         -   buffer to hold version info
  1043. *
  1044. *  returns: TRUE if successful, FALSE otherwise.
  1045. *
  1046. *  comments:  gVKArray would need a critical section if this function were
  1047. *             to be called by more than one thread.
  1048. *
  1049. * History:
  1050. * 2/23/93
  1051. *   Created.
  1052. *
  1053. \***************************************************************************/
  1054. BOOL FilerGetVersion(LPTSTR lpszFileName, DWORD dwBuffSize, LPTSTR szBuff)
  1055. {
  1056.     //
  1057.     // NUM_VERSION_INFO_KEYS in GLOBALS.H should be set to the number of entries in
  1058.     //   VersionKeys[].
  1059.     //
  1060.     CONST static TCHAR   *VersionKeys[] = {
  1061.             TEXT("ProductName"),
  1062.             TEXT("ProductVersion"),
  1063.             TEXT("OriginalFilename"),
  1064.             TEXT("FileDescription"),
  1065.             TEXT("FileVersion"),
  1066.             TEXT("CompanyName"),
  1067.             TEXT("LegalCopyright"),
  1068.             TEXT("LegalTrademarks"),
  1069.             TEXT("InternalName"),
  1070.             TEXT("PrivateBuild"),
  1071.             TEXT("SpecialBuild"),
  1072.             TEXT("Comments")
  1073.     };
  1074.  
  1075.     static TCHAR szNull[1] = TEXT("");
  1076.     LPVOID  lpInfo;
  1077.     DWORD   cch;
  1078.     UINT    i;
  1079.     TCHAR   key[80];
  1080.     TCHAR   lpBuffer[10];
  1081.  
  1082.     GetFileVersionInfo(lpszFileName, 0, dwBuffSize, (LPVOID)szBuff );
  1083.     wsprintf(lpBuffer, "%04X", GetUserDefaultLangID());
  1084.     strcat(lpBuffer,TEXT("04B0"));
  1085.     for (i = 0; i < NUM_VERSION_INFO_KEYS; i++) {
  1086.         lstrcpy(key, VERSION_INFO_KEY_ROOT);
  1087.         lstrcat(key, lpBuffer);
  1088.         lstrcat(key, "\\");
  1089.         lstrcat(key, VersionKeys[i]);
  1090.         gVKArray[i].szKey = VersionKeys[i];
  1091.  
  1092.         //
  1093.         // If version info exists, and the key query is successful, add
  1094.         //  the value.  Otherwise, the value for the key is NULL.
  1095.         //
  1096.         if( dwBuffSize && VerQueryValue(szBuff, key, &lpInfo, &cch) )
  1097.             gVKArray[i].szValue = lpInfo;
  1098.         else
  1099.             gVKArray[i].szValue = szNull;
  1100.     }
  1101.  
  1102.     return TRUE;
  1103. }
  1104.  
  1105.  
  1106. /***************************************************************************\
  1107. * VersionProc()
  1108. *
  1109. * .EXE Version Info Dialog Box
  1110. *
  1111. * History:
  1112. * 2/24/93  2am
  1113. *   Created.
  1114. \***************************************************************************/
  1115. LRESULT WINAPI VersionProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1116. {
  1117.     static LPTSTR   lpszBuff;
  1118.     TCHAR   lpBuffer[128];
  1119.  
  1120.     switch (message){
  1121.       case WM_INITDIALOG:{
  1122.  
  1123.         LPCINFO lpCInfo;
  1124.         DWORD   dwLength;
  1125.         DWORD   dwCount;
  1126.         DWORD   dwHandle;
  1127.         TCHAR   szFile[DIRECTORY_STRING_SIZE];
  1128.         TCHAR   szDir[DIRECTORY_STRING_SIZE];
  1129.         TCHAR   szFullName[DIRECTORY_STRING_SIZE];
  1130.         LPTSTR  lpszHold;
  1131.         TCHAR   lpBuffer[128];
  1132.  
  1133.  
  1134.         lpCInfo = (LPCINFO)lParam;
  1135.         LoadString(ghModule, IDS_FILE, lpBuffer, sizeof(lpBuffer));
  1136.         strcpy(szFile, lpBuffer);
  1137.         LoadString(ghModule, IDS_DIR, lpBuffer, sizeof(lpBuffer));
  1138.         strcpy(szDir, lpBuffer);
  1139.  
  1140.         //
  1141.         // Concatenate path to szDir text-control string.
  1142.         //
  1143.         lstrcat(szDir, lpCInfo->CaptionBarText);
  1144.         SendDlgItemMessage( hDlg, SB_DEST, WM_SETTEXT,
  1145.                             (WPARAM)0, (LPARAM)szDir);
  1146.  
  1147.         //
  1148.         // Concatenate File name to szFile text-control string.
  1149.         //
  1150.         dwLength = lstrlen(szFile);
  1151.  
  1152.         //
  1153.         // Get selected (careted) ListBox item
  1154.         //
  1155.         GetLBText(lpCInfo->hFileLB, (PTCHAR)&szFile[dwLength]);
  1156.  
  1157.         SendDlgItemMessage( hDlg, SB_SOURCE, WM_SETTEXT,
  1158.                             (WPARAM)0, (LPARAM)szFile);
  1159.  
  1160.         //
  1161.         // Fill Version Key and Value edit boxes.
  1162.         //
  1163.         lstrcpy( szFullName, lpCInfo->CaptionBarText );
  1164.  
  1165.         //
  1166.         // a file under some file systems may have [] characters.
  1167.         //   Prepend path, adding a delimiting backslash unless we're in the root.
  1168.         //   If the attribute check is successful, it's a file, so leave.
  1169.         //
  1170.         lpszHold = TStrChr(szFullName, TEXT('\0'));
  1171.  
  1172.         lpszHold--;
  1173.         if( *lpszHold != TEXT('\\') ){
  1174.             lpszHold++;
  1175.             *lpszHold = TEXT('\\');
  1176.         }
  1177.         lpszHold++;
  1178.  
  1179.         lstrcpy(lpszHold, &szFile[dwLength]); // File name past 'File:' prefix
  1180.  
  1181.         dwLength = GetFileVersionInfoSize( szFullName, &dwHandle);
  1182.         if( !dwLength ){
  1183.             LoadString(ghModule, IDS_GETVERERR, lpBuffer, sizeof(lpBuffer));
  1184.             ErrorMsg(lpBuffer);
  1185.             return(1);
  1186.         }
  1187.  
  1188.         // Allocate Version Info buffer
  1189.         EnterCriticalSection(&gHeapCS);
  1190.         lpszBuff = (LPTSTR)HeapAlloc( ghHeap, HEAP_ZERO_MEMORY, dwLength * sizeof(TCHAR) );
  1191.         LeaveCriticalSection(&gHeapCS);
  1192.  
  1193.         FilerGetVersion( szFullName, dwLength, lpszBuff );
  1194.  
  1195.         for( dwCount = 0; dwCount < NUM_VERSION_INFO_KEYS; dwCount++){
  1196.             if( SendDlgItemMessage( hDlg, SB_KEY, LB_ADDSTRING, 0,
  1197.                                     (LPARAM)gVKArray[dwCount].szKey)
  1198.                                     == LB_ERR ){
  1199.                 LoadString(ghModule, IDS_GETVERERR2, lpBuffer, sizeof(lpBuffer));
  1200.                 ErrorMsg(lpBuffer);
  1201.                 return(0);
  1202.             }
  1203.             if( SendDlgItemMessage( hDlg, SB_VALUE, LB_ADDSTRING, 0,
  1204.                                     (LPARAM)gVKArray[dwCount].szValue)
  1205.                                     == LB_ERR ){
  1206.                 LoadString(ghModule, IDS_GETVERERR3, lpBuffer, sizeof(lpBuffer));
  1207.                 ErrorMsg(lpBuffer);
  1208.                 return(0);
  1209.             }
  1210.         }
  1211.  
  1212.         //  Set selection in listboxes to first item.
  1213.         if( SendDlgItemMessage( hDlg, SB_KEY, LB_SETCURSEL,
  1214.                                (WPARAM)0,
  1215.                                (LPARAM)0 )
  1216.                                == LB_ERR ){
  1217.             LoadString(ghModule, IDS_GETVERERR4, lpBuffer, sizeof(lpBuffer));
  1218.             ErrorMsg(lpBuffer);
  1219.             return(0);
  1220.         }
  1221.         if( SendDlgItemMessage( hDlg, SB_VALUE, LB_SETCURSEL,
  1222.                                (WPARAM)0,
  1223.                                (LPARAM)0 )
  1224.                                == LB_ERR ){
  1225.             LoadString(ghModule, IDS_GETVERERR5, lpBuffer, sizeof(lpBuffer));
  1226.             ErrorMsg(lpBuffer);
  1227.             return(0);
  1228.         }
  1229.  
  1230.         //  Initialize Scroll Bar
  1231.         //  Check to see if a scroll bar is needed. See GLOBALS.H and FILER.DLG
  1232.         if( NUM_VERSION_INFO_KEYS - VERSION_DLG_LB_HEIGHT > 0 )
  1233.             SendDlgItemMessage( hDlg, SB_SCROLL, SBM_SETRANGE,
  1234.                                (WPARAM)0,
  1235.                                (LPARAM)NUM_VERSION_INFO_KEYS -1);
  1236.         SendDlgItemMessage( hDlg, SB_SCROLL, SBM_SETPOS,
  1237.                            (WPARAM)0,
  1238.                            (LPARAM)TRUE );
  1239.  
  1240.         return(1);
  1241.       }
  1242.  
  1243.       case WM_VSCROLL:{
  1244.         int nPos;
  1245.  
  1246.         nPos = SendDlgItemMessage( hDlg, SB_SCROLL, SBM_GETPOS,
  1247.                                   (WPARAM)0,
  1248.                                   (LPARAM)0 );
  1249.  
  1250.         switch( LOWORD(wParam) ){
  1251.  
  1252.             case SB_PAGEDOWN:{
  1253.                 nPos += VERSION_DLG_LB_HEIGHT;
  1254.                 if( nPos > NUM_VERSION_INFO_KEYS )
  1255.                     nPos = NUM_VERSION_INFO_KEYS;
  1256.                 break;
  1257.             }
  1258.             case SB_LINEDOWN:{
  1259.                 nPos++;
  1260.                 if( nPos > NUM_VERSION_INFO_KEYS )
  1261.                     nPos = NUM_VERSION_INFO_KEYS;
  1262.                 break;
  1263.             }
  1264.             case SB_PAGEUP:{
  1265.                 nPos -= VERSION_DLG_LB_HEIGHT;
  1266.                 if( nPos < 0 )
  1267.                     nPos = 0;
  1268.                 break;
  1269.             }
  1270.             case SB_LINEUP:{
  1271.                 nPos--;
  1272.                 if( nPos < 0 )
  1273.                     nPos = 0;
  1274.                 break;
  1275.             }
  1276.             default:
  1277.                 return(1);
  1278.         }
  1279.  
  1280.         //  Set Scroll Bar position
  1281.         SendDlgItemMessage( hDlg, SB_SCROLL, SBM_SETPOS,
  1282.                             (WPARAM)nPos,
  1283.                             (LPARAM)TRUE );
  1284.         //  Set selection in listboxes
  1285.         if( SendDlgItemMessage( hDlg, SB_KEY, LB_SETCURSEL,
  1286.                                 (WPARAM)nPos,
  1287.                                 (LPARAM)0 )
  1288.                                 == LB_ERR ){
  1289.             LoadString(ghModule, IDS_GETVERERR6, lpBuffer, sizeof(lpBuffer));
  1290.             ErrorMsg(lpBuffer);
  1291.             return(0);
  1292.         }
  1293.         if( SendDlgItemMessage( hDlg, SB_VALUE, LB_SETCURSEL,
  1294.                                 (WPARAM)nPos,
  1295.                                 (LPARAM)0 )
  1296.                                 == LB_ERR ){
  1297.             LoadString(ghModule, IDS_GETVERERR6, lpBuffer, sizeof(lpBuffer));
  1298.             ErrorMsg(lpBuffer);
  1299.             return(0);
  1300.         }
  1301.  
  1302.         return(0);
  1303.       }
  1304.  
  1305.       case WM_CLOSE:
  1306.           // Free allocated buffer
  1307.           EnterCriticalSection(&gHeapCS);
  1308.           HeapFree( ghHeap, 0, lpszBuff);
  1309.           LeaveCriticalSection(&gHeapCS);
  1310.  
  1311.           EndDialog(hDlg, wParam);
  1312.           return(1);
  1313.  
  1314.       case WM_COMMAND:{
  1315.             int nLBid = 0;  // holds ID of listbox other than one sending LBN msg.
  1316.  
  1317.         switch( LOWORD(wParam) ){
  1318.             case SB_OK:
  1319.             case SB_CANCEL:{
  1320.                 // Free allocated buffer
  1321.                 EnterCriticalSection(&gHeapCS);
  1322.                 HeapFree( ghHeap, 0, lpszBuff);
  1323.                 LeaveCriticalSection(&gHeapCS);
  1324.  
  1325.                 EndDialog(hDlg, wParam);
  1326.                 return(1);
  1327.             }
  1328.  
  1329.             // SB_VALUE and SB_KEY are the ListBox IDs. Below are LB notifications.
  1330.             case SB_VALUE:
  1331.                 nLBid = SB_KEY;
  1332.                 // we slip through to the SB_KEY case on purpose!!
  1333.             case SB_KEY:{
  1334.                 int nSelect;    // Holds selected item
  1335.  
  1336.                 if( HIWORD(wParam) == LBN_SELCHANGE ){
  1337.  
  1338.                     if( !nLBid )    // If nLBid wasn't set by the SB_VALUE case above...
  1339.                         nLBid = SB_VALUE;
  1340.  
  1341.                     //  Get current listbox selection.
  1342.                     nSelect = SendDlgItemMessage( hDlg, LOWORD(wParam), LB_GETCURSEL,
  1343.                                         (WPARAM)0,
  1344.                                         (LPARAM)0 );
  1345.                     if( nSelect == LB_ERR ){
  1346.                         LoadString(ghModule, IDS_GETVERERR7, lpBuffer, sizeof(lpBuffer));
  1347.                         ErrorMsg(lpBuffer);
  1348.                         return(0);
  1349.                     }
  1350.  
  1351.                     //  Set similar selection in corresponding listbox.
  1352.                     if( SendDlgItemMessage( hDlg, nLBid, LB_SETCURSEL,
  1353.                                             (WPARAM)nSelect,
  1354.                                             (LPARAM)0 )
  1355.                                             == LB_ERR ){
  1356.                         LoadString(ghModule, IDS_GETVERERR8, lpBuffer, sizeof(lpBuffer));
  1357.                         ErrorMsg(lpBuffer);
  1358.                         return(0);
  1359.                     }
  1360.  
  1361.  
  1362.                     //  Set Scroll Bar position
  1363.                     SendDlgItemMessage( hDlg, SB_SCROLL, SBM_SETPOS,
  1364.                                         (WPARAM)nSelect,
  1365.                                         (LPARAM)TRUE );
  1366.                 }
  1367.             }
  1368.         }
  1369.         return(1);
  1370.       }
  1371.     }
  1372.  
  1373.     return(0);
  1374. }
  1375.  
  1376.  
  1377. /***************************************************************************\
  1378. *
  1379. * IsDirectory()
  1380. *
  1381. *  Given an item from a ListBox filled from an LB_DIR call, IsDirectory
  1382. *    verifies whether or not the item is a directory, and if so, returns
  1383. *    true, and places the full directory path in lpszFile.
  1384. *
  1385. *  input:   lpszDir     -   Holds current directory
  1386. *           lpszFile    -   Holds item of dubious directoryness.
  1387. *
  1388. * History:
  1389. * 5/30/92
  1390. *   Created.
  1391. *
  1392. \***************************************************************************/
  1393. BOOL IsDirectory(LPTSTR lpszDir, LPTSTR lpszFile)
  1394. {
  1395.     DWORD   dwAttrib;
  1396.     LPTSTR  lpszHold;
  1397.     TCHAR   szItem[DIRECTORY_STRING_SIZE * 2];
  1398.     TCHAR   lpBuffer[128];
  1399.  
  1400.  
  1401.     //
  1402.     // if it's '..', go up one directory
  1403.     //
  1404.     if( !lstrcmp(lpszFile, TEXT("[..]")) ){
  1405.         lstrcpy(lpszFile, lpszDir);
  1406.         lpszHold = TStrChr(lpszFile, TEXT('\0'));
  1407.         while( lpszHold > lpszFile ){
  1408.             if(*lpszHold == TEXT('\\')){
  1409.                 break;
  1410.             }
  1411.             lpszHold = CharPrev(lpszFile, lpszHold);
  1412.         }
  1413.         if(lpszHold <= lpszFile){
  1414.             LoadString(ghModule, IDS_ISDIRERR, lpBuffer, sizeof(lpBuffer));
  1415.             ErrorMsg(lpBuffer);
  1416.             return(0);
  1417.         }
  1418.         else{
  1419.             if( TStrChr(lpszFile, TEXT('\\')) == lpszHold )
  1420.                 lpszHold++;
  1421.             *lpszHold = TEXT('\0');
  1422.             return(1);
  1423.         }
  1424.     }
  1425.  
  1426.     //
  1427.     // A directory will have [] around it in the listbox. Check for it.
  1428.     //
  1429.     if( *lpszFile != TEXT('[') )
  1430.         return(0);
  1431.  
  1432.     //
  1433.     // A file under some file systems may have [] characters.
  1434.     //   Prepend path, adding a delimiting backslash unless we're in the root.
  1435.     //   If the attribute check is successful, it's a file, so leave.
  1436.     //
  1437.     // NOTE:  This is a hack.  If there is a file called '[foo]' and a
  1438.     //   Directory called 'foo', they will appear identical in the listbox.
  1439.     //   Rather than check for this rare case, if it happens, Filer will
  1440.     //   assume it is a file first, as the directory may be changed from
  1441.     //   the Directory Listbox.
  1442.     //
  1443.     lstrcpy(szItem, lpszDir);
  1444.     lpszHold = TStrChr(szItem, TEXT('\0'));
  1445.  
  1446.     lpszHold--;
  1447.     if( *lpszHold != TEXT('\\') ){
  1448.         lpszHold++;
  1449.         *lpszHold = TEXT('\\');
  1450.     }
  1451.     lpszHold++;
  1452.  
  1453.     lstrcpy(lpszHold, lpszFile);
  1454.  
  1455.     dwAttrib = GetFileAttributes(szItem);
  1456.  
  1457.     if( dwAttrib != 0xFFFFFFFF )             // there really is a file called
  1458.         return(0);                           //  '[foo]'.  Exit.
  1459.  
  1460.     //
  1461.     // remove the [], and check if valid directory.
  1462.     //   if it fails, or it's not a directory, leave.
  1463.     //
  1464.     lstrcpy(lpszHold, &lpszFile[1]);
  1465.     lpszHold = TStrChr(lpszHold, TEXT('\0'));
  1466.  
  1467.     lpszHold--;
  1468.     if( *lpszHold != TEXT(']') )
  1469.         return(0);
  1470.     *lpszHold = TEXT('\0');
  1471.  
  1472.     dwAttrib = GetFileAttributes(szItem);
  1473.  
  1474.     if( (dwAttrib == 0xFFFFFFFF) || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) )
  1475.         return(0);
  1476.  
  1477.     //
  1478.     // OK, it's a directory, and szItem now holds the fully qualified path.
  1479.     // copy this to the filename buffer sent in, and return true.
  1480.     //
  1481.     CharUpper(szItem);
  1482.     lstrcpy(lpszFile, szItem);
  1483.     return(1);
  1484. }
  1485.  
  1486.  
  1487. /***************************************************************************\
  1488. *
  1489. * ExecuteFileAction()
  1490. *
  1491. * Creates a dialog box verifying a file action, and carries out the action.
  1492. *
  1493. *  input:   hwnd    -   handle to Drv child.
  1494. *           lpSelect    -   pointer to SELECTINFO structure, containing
  1495. *                           info on the file i/o action to be performed.
  1496. *
  1497. * History:
  1498. * 5/28/92
  1499. *   Created.
  1500. *
  1501. \***************************************************************************/
  1502. BOOL ExecuteFileAction(LPSINFO lpSelect)
  1503. {
  1504.     TCHAR   lpBuffer[128];
  1505.  
  1506.     if( DialogBoxParam(ghModule, TEXT("SelectDlg"), lpSelect->hwnd,
  1507.                   (DLGPROC)SelectProc, (LPARAM)lpSelect) == -1 ){
  1508.         LoadString(ghModule, IDS_EXEFILEERR, lpBuffer, sizeof(lpBuffer));
  1509.         ErrorMsg(lpBuffer);
  1510.         return(0);
  1511.     }
  1512.     return(1);
  1513. }
  1514.  
  1515.  
  1516. /***************************************************************************\
  1517. * SelectProc()
  1518. *
  1519. * File I/O selection dialog proc.
  1520. *
  1521. * History:
  1522. * 5/28/92
  1523. *   Created.
  1524. \***************************************************************************/
  1525. LRESULT WINAPI SelectProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1526. {
  1527.     static LPSINFO lpSelect;
  1528.     TCHAR   lpBuffer[128];
  1529.  
  1530.     switch (message) {
  1531.       case WM_INITDIALOG:{
  1532.  
  1533.         lpSelect = (LPSINFO)lParam;
  1534.  
  1535.         //
  1536.         // Fill source and destination fields of Select dialog.
  1537.         //
  1538.         if( !FillSelectDlg(hDlg, lpSelect) ){
  1539.             EndDialog(hDlg, wParam);
  1540.             return(1);
  1541.         }
  1542.  
  1543.         //
  1544.         // Set the TEXT('action') text (i.e. TEXT("COPYING:"), TEXT("MOVING:"), etc.)
  1545.         //
  1546.         if( !SetDlgItemText(hDlg, SB_ACTION, lpSelect->szAction) ){
  1547.             LoadString(ghModule, IDS_SELPROCERR, lpBuffer, sizeof(lpBuffer));
  1548.             ErrorMsg(lpBuffer);
  1549.             EndDialog(hDlg, wParam);
  1550.             return(1);
  1551.         }
  1552.  
  1553.         //
  1554.         // Set the TEXT("TO:") or TEXT("FROM:") text.
  1555.         //
  1556.         if( !SetDlgItemText(hDlg, SB_TOFROM, lpSelect->szToFrom) ){
  1557.             LoadString(ghModule, IDS_SELPROCERR, lpBuffer, sizeof(lpBuffer));
  1558.             ErrorMsg(lpBuffer);
  1559.             EndDialog(hDlg, wParam);
  1560.             return(1);
  1561.         }
  1562.  
  1563.         break;
  1564.       }
  1565.       case WM_CLOSE:
  1566.         EndDialog(hDlg, wParam);
  1567.         return(1);
  1568.       
  1569.       case WM_COMMAND:{
  1570.         switch(LOWORD(wParam)){
  1571.             case SB_OK:{
  1572.                 DoFileIO(hDlg, lpSelect);
  1573.                 EndDialog(hDlg, wParam);
  1574.                 return(1);
  1575.             }
  1576.             case SB_CANCEL:{
  1577.                 EndDialog(hDlg, wParam);
  1578.                 return(1);
  1579.             }
  1580.         }
  1581.         return(1);
  1582.       }
  1583.     }
  1584.  
  1585.     return(0);
  1586. }
  1587.  
  1588.  
  1589. /***************************************************************************\
  1590. *
  1591. * FillSelectDlg()
  1592. *
  1593. * Fills the Select Dialog box with the files selected in the active Drv Child
  1594. *  for a file i/o action.  Destination defaults to directory selection in
  1595. *  inactive Drv Child.
  1596. *
  1597. *  input:   hDlg    -   handle to Select dialog box.
  1598. *           hwnd    -   handle to Drv child.
  1599. *
  1600. * History:
  1601. * 5/28/92
  1602. *   Created.
  1603. *
  1604. \***************************************************************************/
  1605. BOOL FillSelectDlg(HWND hDlg, LPSINFO lpSelect)
  1606. {
  1607.     LONG    lCount;         // Number of items selected in ListBox
  1608.     LONG    lSize;          // Holds size of a string
  1609.     LONG    lLargest = 0;   // Holds largest string encountered.
  1610.     UINT    *lpnIndex;      // ptr to array of selected ListBox items' indeces
  1611.     int     i;              // counter
  1612.     TCHAR   lpBuffer[128];  // Buffer for string retrieved from resources
  1613.  
  1614.     LPCINFO lpCInfo;
  1615.     HWND    hDest;          // dir of files if delete, else inactive Drv dir.
  1616.  
  1617.     HDC     hDC;
  1618.     TEXTMETRIC  Metrics;
  1619.  
  1620.     LPTSTR  lpszHold;       // marks end of directory path in szName.
  1621.     TCHAR   szName[DIRECTORY_STRING_SIZE * 2];  // holds ListBox strings.
  1622.  
  1623.  
  1624.     lpCInfo = (LPCINFO)GetWindowLong(lpSelect->hwnd, GWL_USERDATA);
  1625.  
  1626.     lCount = SendMessage( lpCInfo->hFileLB, LB_GETSELCOUNT,
  1627.                           (WPARAM)NULL, (LPARAM)NULL );
  1628.  
  1629.     //
  1630.     // if no items selected, leave.
  1631.     //
  1632.     if( !lCount )
  1633.         return(0);
  1634.  
  1635.     //
  1636.     // Allocate array of lCount listbox indexes, and fill it.
  1637.     //
  1638.     EnterCriticalSection(&gHeapCS);
  1639.     lpnIndex = (UINT*)HeapAlloc( ghHeap, HEAP_ZERO_MEMORY, lCount * sizeof(UINT) );
  1640.     LeaveCriticalSection(&gHeapCS);
  1641.     if( !lpnIndex ){
  1642.         LoadString(ghModule, IDS_SELDLGERR, lpBuffer, sizeof(lpBuffer));
  1643.         ErrorMsg(lpBuffer);
  1644.         return(0);
  1645.     }
  1646.  
  1647.     if( SendMessage( lpCInfo->hFileLB, LB_GETSELITEMS, (WPARAM)lCount,
  1648.                      (LPARAM)lpnIndex) != lCount ){
  1649.         LoadString(ghModule, IDS_SELDLGERR2, lpBuffer, sizeof(lpBuffer));
  1650.         ErrorMsg(lpBuffer);
  1651.         return(0);
  1652.     }
  1653.  
  1654.     //
  1655.     // Check if each selected entry is a valid file.
  1656.     //
  1657.     // Check to see if there is a terminating backslash, by decrementing
  1658.     //  pointer, checking, adding a '\' if necessary, then re-incrementing
  1659.     //  the pointer.
  1660.     //
  1661.     lstrcpy(szName, lpCInfo->CaptionBarText);
  1662.  
  1663.     lpszHold = TStrChr(szName, TEXT('\0'));
  1664.  
  1665.     lpszHold--;
  1666.     if( *lpszHold != TEXT('\\') ){
  1667.         lpszHold++;
  1668.         *lpszHold = TEXT('\\');
  1669.     }
  1670.     lpszHold++;
  1671.  
  1672.     //
  1673.     // Fill Dlg ListBox with selected strings from Drv child's ListBox,
  1674.     //   noting size of largest entry.
  1675.     //
  1676.     for( i = 0; i < lCount; i++){
  1677.         if( SendMessage( lpCInfo->hFileLB, LB_GETTEXT, (WPARAM)lpnIndex[i],
  1678.                         (LPARAM)lpszHold) == LB_ERR ){
  1679.             LoadString(ghModule, IDS_SELDLGERR3, lpBuffer, sizeof(lpBuffer));
  1680.             ErrorMsg(lpBuffer);
  1681.             return(0);
  1682.         }
  1683.  
  1684.         if( GetFileAttributes(szName) == 0xFFFFFFFF ){    //Error
  1685.             LoadString(ghModule, IDS_SELDLGERR4, lpBuffer, sizeof(lpBuffer));
  1686.             lstrcat(lpszHold, lpBuffer);
  1687.             ErrorMsg(lpszHold);
  1688.         }
  1689.         else{
  1690.             lSize = lstrlen(lpszHold);
  1691.             if( lSize > lLargest )
  1692.                 lLargest = lSize;
  1693.  
  1694.             if( SendDlgItemMessage( hDlg, SB_SOURCE, LB_ADDSTRING, 0,
  1695.                                     (LPARAM)lpszHold) == LB_ERR ){
  1696.                 LoadString(ghModule, IDS_SELDLGERR5, lpBuffer, sizeof(lpBuffer));
  1697.                 ErrorMsg(lpBuffer);
  1698.                 return(0);
  1699.             }
  1700.         }
  1701.     }
  1702.  
  1703.     //
  1704.     // Get the average char width of current font,
  1705.     // We then set the dialog listbox column width to
  1706.     // (longest string + arbitrary column spacing) * ave width.
  1707.     //
  1708.     hDC = GetDC(lpSelect->hwnd);
  1709.     if( !GetTextMetrics(hDC, &Metrics) ){
  1710.         LoadString(ghModule, IDS_SELDLGERR6, lpBuffer, sizeof(lpBuffer));
  1711.         ErrorMsg(lpBuffer);
  1712.         return(0);
  1713.     }
  1714.  
  1715.     ReleaseDC(lpSelect->hwnd, hDC);
  1716.  
  1717.     SendDlgItemMessage( hDlg, SB_SOURCE, LB_SETCOLUMNWIDTH,
  1718.                         (WPARAM)((lLargest + 8) * Metrics.tmAveCharWidth),
  1719.                         (LPARAM)NULL );
  1720.  
  1721.     EnterCriticalSection(&gHeapCS);
  1722.     HeapFree( ghHeap, 0, (LPVOID)lpnIndex);
  1723.     LeaveCriticalSection(&gHeapCS);
  1724.  
  1725.  
  1726.     //
  1727.     // Fill SB_DEST with directory.
  1728.     // If deleteing, default to the directory of the files.
  1729.     //
  1730.     if( lpSelect->dwAction != MM_DELETE ){
  1731.         //
  1732.         // Not Deleting.  Default to selected directory (titlebar)
  1733.         //   of the inactive Drive child.
  1734.         //
  1735.         if( lpSelect->hwnd == ghwndDrv1 )
  1736.             hDest = ghwndDrv2;
  1737.         else
  1738.             hDest = ghwndDrv1;
  1739.  
  1740.         lpCInfo = (LPCINFO)GetWindowLong(hDest, GWL_USERDATA);
  1741.     }
  1742.  
  1743.    SendDlgItemMessage( hDlg, SB_DEST, EM_LIMITTEXT,
  1744.                             (WPARAM)DIRECTORY_STRING_SIZE, (LPARAM)0);
  1745.  
  1746.    if( SendDlgItemMessage( hDlg, SB_DEST, WM_SETTEXT, 0,
  1747.                             (LPARAM)lpCInfo->CaptionBarText) == CB_ERR ){
  1748.         LoadString(ghModule, IDS_SELDLGERR7, lpBuffer, sizeof(lpBuffer));
  1749.         ErrorMsg(lpBuffer);
  1750.         return(0);
  1751.     }
  1752.  
  1753.     return(1);
  1754. }
  1755.  
  1756.  
  1757. /***************************************************************************\
  1758. *
  1759. * DoFileIO()
  1760. *
  1761. * Called by SelectProc.  Carries out the chosed file operations verified
  1762. *   in the Select Dialog Box.
  1763. *
  1764. *  input:   hDlg    -   handle to Select dialog box.
  1765. *           lpSelect    -   ptr to SELECTINFO structure.
  1766. *
  1767. *  returns: 1 if successful
  1768. *           0 if unsuccessful
  1769. * History:
  1770. * 6/3/92
  1771. *   Created.
  1772. *
  1773. \***************************************************************************/
  1774. BOOL DoFileIO( HWND hDlg, LPSINFO lpSelect)
  1775. {
  1776.     LONG    lCount;
  1777.     LONG    lFile;
  1778.     LPCINFO lpCInfo;
  1779.     LPTSTR  lpEndDest;
  1780.     LPTSTR  lpEndSource;
  1781.     BOOL    fError = FALSE;
  1782.     TCHAR   lpBuffer[128];
  1783.  
  1784.     TCHAR   szSource[DIRECTORY_STRING_SIZE];
  1785.     TCHAR   szDest[DIRECTORY_STRING_SIZE * 2];
  1786.  
  1787.  
  1788.     //
  1789.     // Find number of files to copy
  1790.     //
  1791.     lCount = SendDlgItemMessage( hDlg, SB_SOURCE, LB_GETCOUNT, (WPARAM)NULL,
  1792.                                  (LPARAM)NULL);
  1793.  
  1794.     if( (lCount == LB_ERR) || (lCount == 0) ){
  1795.         LoadString(ghModule, IDS_FILEIOERR, lpBuffer, sizeof(lpBuffer));
  1796.         ErrorMsg(lpBuffer);
  1797.         return(0);
  1798.     }
  1799.  
  1800.     //
  1801.     // Get source directory path. Add a \ to the end, set pointer to end.
  1802.     //
  1803.     lpCInfo = (LPCINFO)GetWindowLong( lpSelect->hwnd, GWL_USERDATA);
  1804.  
  1805.     lstrcpy(szSource, lpCInfo->CaptionBarText);
  1806.  
  1807.     lpEndSource = TStrChr(szSource, TEXT('\0'));
  1808.     *lpEndSource++ = TEXT('\\');
  1809.  
  1810.     //
  1811.     // Get destination directory path. Add a \ to the end, set pointer to end.
  1812.     //
  1813.     if( SendDlgItemMessage( hDlg, SB_DEST, WM_GETTEXT,
  1814.             (WPARAM)DIRECTORY_STRING_SIZE * 2, (LPARAM)szDest) == CB_ERR ){
  1815.         LoadString(ghModule, IDS_FILEIOERR2, lpBuffer, sizeof(lpBuffer));
  1816.         ErrorMsg(lpBuffer);
  1817.         return(0);
  1818.     }
  1819.  
  1820.     lpEndDest = TStrChr(szDest, TEXT('\0'));
  1821.     *lpEndDest++ = TEXT('\\');
  1822.  
  1823.     //
  1824.     // for each file, do appropriate I/O.
  1825.     //
  1826.     while( lCount ){
  1827.  
  1828.         lCount--;
  1829.  
  1830.         lFile = SendDlgItemMessage( hDlg, SB_SOURCE, LB_GETTEXT,
  1831.                                     (WPARAM)0, (LPARAM)lpEndSource);
  1832.         if( lFile == LB_ERR){
  1833.             LoadString(ghModule, IDS_FILEIOERR3, lpBuffer, sizeof(lpBuffer));
  1834.             ErrorMsg(lpBuffer);
  1835.             fError = TRUE;
  1836.         }
  1837.  
  1838.         SendDlgItemMessage( hDlg, SB_SOURCE, LB_DELETESTRING,
  1839.                             (WPARAM)0, (LPARAM)NULL);
  1840.  
  1841.         switch( lpSelect->dwAction ){
  1842.           case MM_COPY:{
  1843.  
  1844.             lstrcpy(lpEndDest, lpEndSource);
  1845.  
  1846.             if( !CopyFile( szSource, szDest, TRUE) )
  1847.                 if( !HandleIOError(lpSelect->hwnd, lpSelect->dwAction,
  1848.                                    szSource, szDest) )
  1849.                     fError = TRUE;
  1850.             break;
  1851.           }
  1852.  
  1853.           case MM_MOVE:{
  1854.  
  1855.             lstrcpy(lpEndDest, lpEndSource);
  1856.  
  1857.             if( !MoveFileEx( szSource, szDest,
  1858.                             MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED) )
  1859.                 if( !HandleIOError(lpSelect->hwnd, lpSelect->dwAction,
  1860.                                    szSource, szDest) )
  1861.                     fError = TRUE;
  1862.             break;
  1863.           }
  1864.           case MM_DELETE:{
  1865.  
  1866.             if(GetFileAttributes(szSource) & FILE_ATTRIBUTE_DIRECTORY) {
  1867.                 if(!RemoveDirectory(szSource))
  1868.                     if( !HandleIOError(lpSelect->hwnd, lpSelect->dwAction,
  1869.                                    szSource, szDest) )
  1870.                         fError = TRUE;
  1871.             }
  1872.             else {
  1873.                 if( !DeleteFile(szSource) )
  1874.                     if( !HandleIOError(lpSelect->hwnd, lpSelect->dwAction,
  1875.                                    szSource, szDest) )
  1876.                         fError = TRUE;
  1877.             }
  1878.           }
  1879.           break;  
  1880.         }
  1881.         if( fError )
  1882.             break;
  1883.     }
  1884.  
  1885.     //
  1886.     //  Update file listboxes.
  1887.     //
  1888.     if( fError )
  1889.         return(0);
  1890.     else{
  1891.         UpdateFileLB(ghwndDrv1);
  1892.         UpdateFileLB(ghwndDrv2);
  1893.     }
  1894.  
  1895.     return(1);
  1896. }
  1897.  
  1898.  
  1899. /***************************************************************************\
  1900. *
  1901. * HandleIOError()
  1902. *
  1903. * Called by DoFileIO. Handles errors arising from File IO operations
  1904. *
  1905. *  input:   hwnd        -   handle to Drv child window
  1906. *           dwAction    -   File I/O Action.  Window message.
  1907. *           szSource    -   ptr to Source string
  1908. *           szDest      -   ptr to Destination string
  1909. *
  1910. *  returns: 1 if successful
  1911. *           0 if unsuccessful
  1912. *
  1913. * History:
  1914. * 6/3/92
  1915. *   Created.
  1916. *
  1917. \***************************************************************************/
  1918. BOOL HandleIOError(HWND hwnd, DWORD dwAction, LPTSTR szSource, LPTSTR szDest)
  1919. {
  1920.     DWORD   dwError;
  1921.     int     nReply;
  1922.     LPCINFO lpCInfo;
  1923.     TCHAR   buff[50];
  1924.     TCHAR   lpBuffer[128];
  1925.  
  1926.     dwError = GetLastError();
  1927.  
  1928.     CharUpper(szDest);
  1929.  
  1930.     switch( dwError ){
  1931.         case ERROR_ALREADY_EXISTS:
  1932.         case ERROR_FILE_EXISTS:{
  1933.           //
  1934.           // MoveFile file already exists. We can CopyFile & DeleteFile source.
  1935.           //
  1936.           LoadString(ghModule, IDS_HNDIOMSG, lpBuffer, sizeof(lpBuffer));
  1937.           nReply = MessageBox(hwnd,
  1938.                               lpBuffer,
  1939.                               szDest, MB_YESNOCANCEL);
  1940.           switch( nReply ){
  1941.             case IDYES:{
  1942.  
  1943.               lpCInfo = (LPCINFO)GetWindowLong(hwnd, GWL_USERDATA);
  1944.  
  1945.               if( !CopyFile( szSource, szDest, FALSE) )
  1946.                   if( HandleIOError(hwnd, dwAction, szSource, szDest) )
  1947.                       return(1);
  1948.                   else
  1949.                       return(0);
  1950.               if( dwAction == MM_MOVE )
  1951.                   if( !DeleteFile( szSource) )
  1952.                       if( HandleIOError(hwnd, dwAction, szSource, szDest) )
  1953.                           return(1);
  1954.                       else
  1955.                           return(0);
  1956.  
  1957.               UpdateFileLB(ghwndDrv1);
  1958.               UpdateFileLB(ghwndDrv2);
  1959.  
  1960.               return(1);
  1961.             }
  1962.             case IDNO:{
  1963.               return(1);
  1964.             }
  1965.             case IDCANCEL:{
  1966.               return(0);
  1967.             }
  1968.           }
  1969.           break;
  1970.         }
  1971.  
  1972.         case ERROR_ACCESS_DENIED:
  1973.         case ERROR_FILE_NOT_FOUND:
  1974.         case ERROR_INVALID_PARAMETER:{
  1975.             LoadString(ghModule, IDS_HNDIOMSG2, lpBuffer, sizeof(lpBuffer));
  1976.             wsprintf(buff,
  1977.                      lpBuffer,
  1978.                      dwError);
  1979.             MessageBox( hwnd, buff, szDest, MB_OK);
  1980.  
  1981.             return(1);
  1982.         }
  1983.  
  1984.         case ERROR_DISK_FULL:{
  1985.             LoadString(ghModule, IDS_HNDIOMSG3, lpBuffer, sizeof(lpBuffer));
  1986.             MessageBox( hwnd,
  1987.             lpBuffer,
  1988.             szDest, MB_OK);
  1989.             return(0);
  1990.         }
  1991.  
  1992.         case ERROR_INVALID_NAME:
  1993.         case ERROR_DIRECTORY:
  1994.         case ERROR_PATH_NOT_FOUND:{
  1995.             LoadString(ghModule, IDS_HNDIOMSG4, lpBuffer, sizeof(lpBuffer));
  1996.             MessageBox( hwnd,
  1997.             lpBuffer,
  1998.             szDest, MB_OK);
  1999.             return(0);
  2000.         }
  2001.  
  2002.         default:{
  2003.             LoadString(ghModule, IDS_HNDIOMSG5, lpBuffer, sizeof(lpBuffer));
  2004.             wsprintf(buff, lpBuffer, dwError);
  2005.             ErrorMsg(buff);
  2006.             return(1);
  2007.         }
  2008.     }
  2009.  
  2010.     return(1);
  2011. }
  2012.  
  2013.  
  2014. /***************************************************************************\
  2015. * RenameProc()
  2016. *
  2017. * File I/O rename Dialog Box
  2018. *
  2019. * History:
  2020. * 6/5/92  2am
  2021. *   Created.
  2022. \***************************************************************************/
  2023. LRESULT WINAPI RenameProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2024. {
  2025.     static TCHAR   szName[DIRECTORY_STRING_SIZE];
  2026.     static LPTSTR  lpszHold;
  2027.     static LPCINFO lpCInfo;
  2028.     TCHAR   lpBuffer[128];
  2029.     TCHAR   lpBuffer2[128];
  2030.  
  2031.     switch (message){
  2032.       case WM_INITDIALOG:{
  2033.  
  2034.         LONG    lIndex;
  2035.  
  2036.         lpCInfo = (LPCINFO)lParam;
  2037.  
  2038.         //
  2039.         // Check to see if there is a terminating backslash, by decrementing
  2040.         //  pointer, checking, adding a '\' if necessary, then re-incrementing
  2041.         //  the pointer.
  2042.         //
  2043.         lstrcpy(szName, lpCInfo->CaptionBarText);
  2044.         lpszHold = TStrChr(szName, TEXT('\0'));
  2045.  
  2046.         lpszHold--;
  2047.         if( *lpszHold != TEXT('\\') ){
  2048.             lpszHold++;
  2049.             *lpszHold = TEXT('\\');
  2050.         }
  2051.         lpszHold++;
  2052.  
  2053.         lIndex = GetLBText(lpCInfo->hFileLB, lpszHold);
  2054.         if( lIndex == LB_ERR )
  2055.             return(1);
  2056.  
  2057.         //
  2058.         // if not a valid file (i.e. listbox directory entry in []s), fail.
  2059.         //
  2060.         if( GetFileAttributes(szName) == 0xFFFFFFFF ){    //Error
  2061.             LoadString(ghModule, IDS_SELDLGERR4, lpBuffer, sizeof(lpBuffer));
  2062.             lstrcat(lpszHold, lpBuffer);
  2063.             ErrorMsg(lpszHold);
  2064.             return(1);
  2065.         }
  2066.  
  2067.         //
  2068.         // Place name in both source and destination edit controls.
  2069.         //
  2070.         CharUpper(szName);
  2071.  
  2072.         SendDlgItemMessage( hDlg, SB_SOURCE, EM_LIMITTEXT,
  2073.                             (WPARAM)DIRECTORY_STRING_SIZE, (LPARAM)0);
  2074.  
  2075.         SendDlgItemMessage( hDlg, SB_DEST, EM_LIMITTEXT,
  2076.                             (WPARAM)DIRECTORY_STRING_SIZE, (LPARAM)0);
  2077.  
  2078.         if( SendDlgItemMessage( hDlg, SB_SOURCE, WM_SETTEXT, 0,
  2079.                                 (LPARAM)lpszHold) == LB_ERR ){
  2080.             LoadString(ghModule, IDS_RENMEMSG, lpBuffer, sizeof(lpBuffer));
  2081.             ErrorMsg(lpBuffer);
  2082.             return(1);
  2083.         }
  2084.         if( SendDlgItemMessage( hDlg, SB_DEST, WM_SETTEXT, 0,
  2085.                                 (LPARAM)lpszHold) == LB_ERR ){
  2086.             LoadString(ghModule, IDS_RENMEMSG2, lpBuffer, sizeof(lpBuffer));
  2087.             ErrorMsg(lpBuffer);
  2088.             return(1);
  2089.         }
  2090.         return(1);
  2091.       }
  2092.       case WM_COMMAND:{
  2093.         switch(LOWORD(wParam)){
  2094.             case SB_OK:{
  2095.                 TCHAR   szDest[DIRECTORY_STRING_SIZE];
  2096.                 LPTSTR  lpszCheck;
  2097.  
  2098.                 //
  2099.                 // the entire source dir\file is still in static szName.
  2100.                 // static lpszHold points to the end of the dir
  2101.                 //
  2102.                 *lpszHold = TEXT('\0');
  2103.  
  2104.                 lstrcpy(szDest, szName);
  2105.  
  2106.                 if( SendDlgItemMessage( hDlg, SB_SOURCE, WM_GETTEXT,
  2107.                                         DIRECTORY_STRING_SIZE,
  2108.                                         (LPARAM)lpszHold) == LB_ERR ){
  2109.                     LoadString(ghModule, IDS_RENMEMSG3, lpBuffer, sizeof(lpBuffer));
  2110.                     ErrorMsg(lpBuffer);
  2111.                     EndDialog(hDlg, wParam);
  2112.                     return(1);
  2113.                 }
  2114.  
  2115.                 //
  2116.                 // If there are any \s in the new filename, fail.
  2117.                 //
  2118.                 lpszCheck = TStrChr(lpszHold, TEXT('\\'));
  2119.  
  2120.                 if( lpszCheck ){
  2121.                     LoadString(ghModule, IDS_RENMEMSG4, lpBuffer, sizeof(lpBuffer));
  2122.                     LoadString(ghModule, IDS_RENMEMSG5, lpBuffer2, sizeof(lpBuffer2));
  2123.                     MessageBox(lpCInfo->hwnd,
  2124.                                lpBuffer,
  2125.                                lpBuffer2, MB_OK );
  2126.                     return(1);
  2127.                 }
  2128.  
  2129.                 lpszHold = TStrChr(szDest, TEXT('\0'));
  2130.  
  2131.                 if( SendDlgItemMessage( hDlg, SB_DEST, WM_GETTEXT,
  2132.                                         DIRECTORY_STRING_SIZE,
  2133.                                         (LPARAM)lpszHold) == LB_ERR ){
  2134.                     LoadString(ghModule, IDS_RENMEMSG6, lpBuffer, sizeof(lpBuffer));
  2135.                     ErrorMsg(lpBuffer);
  2136.                     EndDialog(hDlg, wParam);
  2137.                     return(1);
  2138.                 }
  2139.  
  2140.                 //
  2141.                 // If there are any \s in the destination filename, fail.
  2142.                 //
  2143.                 lpszCheck = TStrChr(lpszHold, TEXT('\\'));
  2144.  
  2145.                 if( lpszCheck ){
  2146.                     LoadString(ghModule, IDS_RENMEMSG4, lpBuffer, sizeof(lpBuffer));
  2147.                     LoadString(ghModule, IDS_RENMEMSG5, lpBuffer2, sizeof(lpBuffer2));
  2148.                     MessageBox(lpCInfo->hwnd,
  2149.                                lpBuffer,
  2150.                                lpBuffer2, MB_OK );
  2151.                     return(1);
  2152.                 }
  2153.  
  2154.                 //
  2155.                 // if strings are identical, leave.
  2156.                 //
  2157.                 if( !lstrcmpi(szName, szDest) ){
  2158.                     EndDialog(hDlg, wParam);
  2159.                     return(1);
  2160.                 }
  2161.  
  2162.                 if( !MoveFile( szName, szDest) )
  2163.                     if( !HandleIOError(lpCInfo->hwnd,
  2164.                                        (DWORD)MM_RENAME, szName, szDest) ){
  2165.                         EndDialog(hDlg, wParam);
  2166.                         return(1);
  2167.                     }
  2168.  
  2169.                 if( !PostMessage(lpCInfo->hwnd, WM_COMMAND, MM_FILLFILE,
  2170.                                  (LPARAM)0) ) {
  2171.                     LoadString(ghModule, IDS_RENMEMSG7, lpBuffer, sizeof(lpBuffer));
  2172.                     ErrorMsg(lpBuffer);
  2173.                 }
  2174.                 EndDialog(hDlg, wParam);
  2175.                 return(1);
  2176.             }
  2177.             case SB_CANCEL:{
  2178.                 EndDialog(hDlg, wParam);
  2179.                 return(1);
  2180.             }
  2181.         }
  2182.         return(1);
  2183.       } // WM_COMMAND
  2184.     }
  2185.  
  2186.     return(0);
  2187. }
  2188.  
  2189.  
  2190. /***************************************************************************\
  2191. * MkDirProc()
  2192. *
  2193. * File I/O Make Directory Dialog Box
  2194. *
  2195. * History:
  2196. * 6/5/92  2am
  2197. *   Created.
  2198. \***************************************************************************/
  2199. LRESULT WINAPI MkDirProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2200. {
  2201.     TCHAR   lpBuffer[128];
  2202.  
  2203.     switch (message){
  2204.       case WM_INITDIALOG:{
  2205.         LPCINFO lpCInfo;
  2206.         TCHAR   szDest[DIRECTORY_STRING_SIZE];
  2207.         LPTSTR  lpszHold;
  2208.  
  2209.  
  2210.         lpCInfo = (LPCINFO)lParam;
  2211.  
  2212.         //
  2213.         // Check to see if there is a terminating backslash, by decrementing
  2214.         //  pointer, checking, adding a '\' if necessary.
  2215.         //
  2216.         lstrcpy(szDest, lpCInfo->CaptionBarText);
  2217.         lpszHold = TStrChr(szDest, TEXT('\0'));
  2218.  
  2219.         lpszHold--;
  2220.         if( *lpszHold != TEXT('\\') ){
  2221.             lpszHold++;
  2222.             *lpszHold = TEXT('\\');
  2223.             lpszHold++;
  2224.             *lpszHold = TEXT('\0');
  2225.         }
  2226.  
  2227.         SendDlgItemMessage( hDlg, SB_DEST, EM_LIMITTEXT,
  2228.                             (WPARAM)DIRECTORY_STRING_SIZE, (LPARAM)0);
  2229.  
  2230.         //
  2231.         // Place name in directory name edit control.
  2232.         //
  2233.         if( SendDlgItemMessage( hDlg, SB_DEST, WM_SETTEXT, 0,
  2234.                                 (LPARAM)szDest) == LB_ERR ){
  2235.             LoadString(ghModule, IDS_MKDIRMSG, lpBuffer, sizeof(lpBuffer));
  2236.             ErrorMsg(lpBuffer);
  2237.             return(1);
  2238.         }
  2239.  
  2240.         SendDlgItemMessage( hDlg, SB_DEST, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
  2241.  
  2242.         return(1);
  2243.       }
  2244.       case WM_COMMAND:{
  2245.         switch(wParam){
  2246.             case SB_OK:{
  2247.                 TCHAR    szDest[DIRECTORY_STRING_SIZE];
  2248.  
  2249.                 if( SendDlgItemMessage( hDlg, SB_DEST, WM_GETTEXT,
  2250.                                         DIRECTORY_STRING_SIZE,
  2251.                                         (LPARAM)szDest) == LB_ERR ){
  2252.                     LoadString(ghModule, IDS_MKDIRMSG2, lpBuffer, sizeof(lpBuffer));
  2253.                     ErrorMsg(lpBuffer);
  2254.                     EndDialog(hDlg, wParam);
  2255.                     return(1);
  2256.                 }
  2257.  
  2258.                 //
  2259.                 // If loacation of subdir is invalid, leave.
  2260.                 //
  2261.                 if( !CreateDirectory(szDest, NULL) ){
  2262.                     LoadString(ghModule, IDS_MKDIRMSG3, lpBuffer, sizeof(lpBuffer));
  2263.                     ErrorMsg(lpBuffer);
  2264.                     EndDialog(hDlg, wParam);
  2265.                     return(1);
  2266.                 }
  2267.  
  2268.                 SendMessage( ghwndDrv1, WM_COMMAND, MM_REFRESH, (LPARAM)0);
  2269.                 SendMessage( ghwndDrv2, WM_COMMAND, MM_REFRESH, (LPARAM)0);
  2270.             }
  2271.             case SB_CANCEL:{
  2272.                 EndDialog(hDlg, wParam);
  2273.                 return(1);
  2274.             }
  2275.         }
  2276.         return(1);
  2277.       }
  2278.     }
  2279.  
  2280.     return(0);
  2281. }
  2282.  
  2283.  
  2284. /***************************************************************************\
  2285. *
  2286. * TextWndProc()
  2287. *
  2288. * Text Window procedure for displaying miscellaneous messages to user.
  2289. *
  2290. * History:
  2291. * 5/25/92
  2292. *   Created.
  2293. *
  2294. \***************************************************************************/
  2295.  
  2296. LRESULT WINAPI TextWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2297. {
  2298.  
  2299.     TCHAR   lpBuffer[128];
  2300.     
  2301.     switch (message)
  2302.     {
  2303.     case WM_CREATE:
  2304.         {
  2305.         HDC        hDC;
  2306.         HGDIOBJ    hOldFont;
  2307.         TEXTMETRIC tm;
  2308.         LONG       lHeight;
  2309.  
  2310.         hDC = GetDC(hwnd);
  2311.  
  2312.         hOldFont = SelectObject(hDC, ghFont);
  2313.         GetTextMetrics(hDC, &tm);
  2314.  
  2315.         //
  2316.         // base the height of the window on size of text
  2317.         //
  2318.         lHeight = tm.tmHeight + GetSystemMetrics(SM_CYBORDER) + 6;
  2319.  
  2320.         //
  2321.         // saved the height for later reference
  2322.         //
  2323.         SetWindowLong(hwnd, GWL_USERDATA, lHeight);
  2324.  
  2325.             if(hOldFont)
  2326.                 SelectObject(hDC, hOldFont);
  2327.  
  2328.             ReleaseDC(hwnd, hDC);
  2329.             break;
  2330.         }
  2331.  
  2332.     case WM_SETTEXT:
  2333.             DefWindowProc(hwnd, message, wParam, lParam);
  2334.             if( !InvalidateRect(hwnd, NULL, TRUE) ){
  2335.                 LoadString(ghModule, IDS_TXTMSG, lpBuffer, sizeof(lpBuffer));
  2336.                 ErrorMsg(lpBuffer);
  2337.                 return(1);
  2338.             }
  2339.             UpdateWindow(hwnd);
  2340.             return(1);
  2341.  
  2342.     case WM_PAINT:
  2343.         {
  2344.             PAINTSTRUCT ps;
  2345.             RECT        rc;
  2346.             TCHAR       ach[128];
  2347.             int         len, nxBorder, nyBorder;
  2348.             HFONT       hOldFont = NULL;
  2349.             HBRUSH      hBrush;
  2350.  
  2351.             BeginPaint(hwnd, &ps);
  2352.  
  2353.             GetClientRect(hwnd,&rc);
  2354.  
  2355.             len = GetWindowText(hwnd, ach, sizeof(ach));
  2356.  
  2357.             SetBkMode(ps.hdc, TRANSPARENT);
  2358.  
  2359.             if( GetParent(hwnd) == ghActiveChild ){
  2360.                 hBrush = CreateSolidBrush( GetSysColor(COLOR_ACTIVECAPTION) );
  2361.                 SetTextColor( ps.hdc, GetSysColor(COLOR_CAPTIONTEXT) );
  2362.             }
  2363.             else{
  2364.                 hBrush = CreateSolidBrush( GetSysColor(COLOR_INACTIVECAPTION) );
  2365.                 SetTextColor( ps.hdc, GetSysColor(COLOR_INACTIVECAPTIONTEXT) );
  2366.             }
  2367.  
  2368.             hOldFont = SelectObject(ps.hdc, ghFont);
  2369.  
  2370.             FillRect(ps.hdc, &rc, hBrush);
  2371.  
  2372.             nxBorder = GetSystemMetrics(SM_CXBORDER);
  2373.             rc.left  += 9*nxBorder;
  2374.             rc.right -= 9*nxBorder;
  2375.  
  2376.             nyBorder = GetSystemMetrics(SM_CYBORDER);
  2377.             rc.top    += 3*nyBorder;
  2378.             rc.bottom -= 3*nyBorder;
  2379.  
  2380.             ExtTextOut(ps.hdc, rc.left+2*nxBorder, rc.top, ETO_CLIPPED,
  2381.                     &rc, ach, len, NULL);
  2382.  
  2383.             SetBkMode(ps.hdc, OPAQUE);
  2384.  
  2385.             if (hOldFont)
  2386.                 SelectObject(ps.hdc, hOldFont);
  2387.  
  2388.             DeleteObject(hBrush);
  2389.  
  2390.             EndPaint(hwnd, &ps);
  2391.             return(1);
  2392.         }
  2393.     }
  2394.     return DefWindowProc(hwnd, message, wParam, lParam);
  2395. }
  2396.  
  2397. /***************************************************************************\
  2398. *
  2399. * TStrChr()
  2400. *
  2401. * A strchr() function which is ASCII or UNICODE.
  2402. *
  2403. * History:
  2404. * 2/25/93
  2405. *   Created.
  2406. *
  2407. \***************************************************************************/
  2408. PTCHAR TStrChr(const PTCHAR string, UINT c)
  2409. {
  2410. #ifdef UNICODE
  2411.     return wcschr((wchar_t*)string, (wchar_t)c);
  2412. #else
  2413.     PTCHAR  psz;
  2414.     for (psz = string; *psz; psz = CharNext(psz)) {
  2415.         if (*psz == (TCHAR)c) {
  2416.             break;
  2417.         }
  2418.     }
  2419.     return psz;
  2420. #endif
  2421. }
  2422.