home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / winsock / wvnsc926 / rcs / wvpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  26.2 KB  |  848 lines

  1. head     1.1;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.1
  10. date     94.09.18.22.36.45;  author jcooper;  state Exp;
  11. branches ;
  12. next     ;
  13.  
  14.  
  15. desc
  16. @Dialog handler for WinVNSelectPath with folder/disk bitmaps, etc
  17. @
  18.  
  19.  
  20.  
  21. 1.1
  22. log
  23. @Initial revision
  24. @
  25. text
  26. @/*
  27.  * wvpath.c
  28.  *
  29.  * based on ddlist example is MSDN (Copyright (c)1992 Kraig Brockschmidt)
  30.  *
  31.  * John S. Cooper
  32.  * 9/10/94
  33.  */
  34.  
  35. #include <windows.h>
  36. #include <windowsx.h>
  37. #include "wvglob.h"
  38. #include "winvn.h"
  39. #pragma hdrstop
  40. #include <dos.h>
  41. #include <io.h>            // for _access
  42. #include <stdlib.h>
  43. #include <stdio.h>
  44. #include <direct.h>
  45. #include <string.h>
  46.  
  47. /* forward declarations */
  48.  
  49. void DriveListInitialize(HWND, HWND);
  50. UINT DriveType(UINT);
  51. void DirectoryListInitialize(HWND, HWND, LPSTR);
  52. void DriveDirDrawItem(LPDRAWITEMSTRUCT, BOOL);
  53. void TransparentBlt(HDC, UINT, UINT, HBITMAP, COLORREF);
  54.  
  55. //Special ROP code for TransparentBlt.
  56. #define ROP_DSPDxax  0x00E20746
  57.  
  58. /*
  59.  * DriveListInitialize
  60.  *
  61.  * Purpose:
  62.  *  Resets and fills the given combobox with a list of current
  63.  *  drives.  The type of drive is stored with the item data.
  64.  *
  65.  * Parameters:
  66.  *  hList           HWND of the combobox to fill.
  67.  *  hTempList       HWND to use for finding drives.
  68.  *
  69.  * Return Value:
  70.  *  None
  71.  */
  72.  
  73. void DriveListInitialize(HWND hList, HWND hTempList)
  74.     {
  75.     struct find_t   fi;
  76.     char            ch;
  77.     UINT            i, iItem;
  78.     UINT            cch, cItems;
  79.     UINT            iDrive, iType;
  80.     UINT            iCurDrive;
  81.     char            szDrive[10];
  82.     char            szNet[64];
  83.     char            szItem[26];
  84.  
  85.     if (NULL==hList)
  86.         return;
  87.  
  88.     //Clear out all the lists.
  89.     SendMessage(hList,     CB_RESETCONTENT, 0, 0L);
  90.     SendMessage(hTempList, LB_RESETCONTENT, 0, 0L);
  91.  
  92.     //Get available drive letters in the temp list
  93.     SendMessage(hTempList, LB_DIR, DDL_DRIVES | DDL_EXCLUSIVE, (LONG)(LPSTR)"*");
  94.  
  95.     iCurDrive=_getdrive()-1;       //Fix for zero-based drive indexing
  96.  
  97.     /*
  98.      * Walk through the list of drives, parsing off the "[-" and "-]"
  99.      * For each drive letter parsed, add a string to the combobox
  100.      * composed of the drive letter and the volume label.  We then
  101.      * determine the drive type and add that information as the item data.
  102.      */
  103.     cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
  104.  
  105.     for (i=0; i<cItems;  i++)
  106.         {
  107.         SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDrive);
  108.  
  109.         //Insure lowercase drive letters
  110.         AnsiLower(szDrive);
  111.         iDrive=szDrive[2]-'a';
  112.         iType=DriveType(iDrive);        //See Below
  113.  
  114.         if (iType < 2)                  //Skip non-existent drive B's
  115.             continue;
  116.  
  117.         //Start the item string with the drive letter, color, and two spaces
  118.         wsprintf(szItem, "%c%s", szDrive[2], (LPSTR)":  ");
  119.  
  120.         /*
  121.          * For fixed or ram disks, append the volume label which we find
  122.          * using _dos_findfirst and attribute _A_VOLID.
  123.          */
  124.         if (DRIVE_FIXED==iType || DRIVE_RAM==iType)
  125.             {
  126.             wsprintf(szDrive, "%c:\\*.*", szDrive[2]);
  127.  
  128.             if (0==_dos_findfirst(szDrive, _A_VOLID, &fi))
  129.                 {
  130.                 //Convert volume to lowercase and strip any . in the name.
  131.                 AnsiLower(fi.name);
  132.  
  133.                 //If a period exists, it has to be in position 8, so clear it.
  134.                 ch=fi.name[8];
  135.                 fi.name[8]=0;
  136.                 lstrcat(szItem, fi.name);
  137.  
  138.                 //If we did have a broken volume name, append the last 3 chars
  139.                 if ('.'==ch)
  140.                     lstrcat(szItem, &fi.name[9]);
  141.                 }
  142.             }
  143.  
  144.         //For network drives, go grab the \\server\share for it.
  145.         if (DRIVE_REMOTE==iType)
  146.             {
  147.             szNet[0]=0;
  148.             cch=sizeof(szNet);
  149.  
  150.             wsprintf(szDrive, "%c:", szDrive[2]);
  151.             AnsiUpper(szDrive);
  152.  
  153.             WNetGetConnection((LPSTR)szDrive, (LPSTR)szNet, &cch);
  154.             AnsiLower(szNet);
  155.  
  156.             lstrcat(szItem, szNet);
  157.             }
  158.  
  159.         iItem=(int)SendMessage(hList, CB_ADDSTRING, 0, (LONG)(LPSTR)szItem);
  160.         SendMessage(hList, CB_SETITEMDATA, iItem, MAKELONG(iDrive, iType));
  161.  
  162.         if (iDrive==iCurDrive)
  163.             SendMessage(hList, CB_SETCURSEL, iItem, 0L);
  164.         }
  165.  
  166.     return;
  167.     }
  168.  
  169. /*
  170.  * DriveType
  171.  *
  172.  * Purpose:
  173.  *  Augments the Windows API GetDriveType with a call to the CD-ROM
  174.  *  extensions to determine if a drive is a floppy, hard disk, CD-ROM,
  175.  *  RAM-drive, or networked  drive.
  176.  *
  177.  * Parameters:
  178.  *  iDrive          UINT containing the zero-based drive index
  179.  *
  180.  * Return Value:
  181.  *  UINT            One of the following values describing the drive:
  182.  *                  DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAM,
  183.  *                  DRIVE_NETWORK.
  184.  */
  185.  
  186. UINT DriveType(UINT iDrive)
  187.     {
  188.     int     iType;
  189.     BOOL    fCDROM=FALSE;
  190.     BOOL    fRAM=FALSE;
  191.  
  192.  
  193.     //Validate possible drive indices
  194.     if (0 > iDrive  || 25 < iDrive)
  195.         return 0xFFFF;
  196.  
  197.     iType=GetDriveType(iDrive);
  198.  
  199.     /*
  200.      * Under Windows NT, GetDriveType returns complete information
  201.      * not provided under Windows 3.x which we now get through other
  202.      * means.
  203.      */
  204.    #ifdef WIN32
  205.     return iType;
  206.    #else
  207.     //Check for CDROM on FIXED and REMOTE drives only
  208.     if (DRIVE_FIXED==iType || DRIVE_REMOTE==iType)
  209.         {
  210.         _asm
  211.             {
  212.             mov     ax,1500h        //Check if MSCDEX exists
  213.             xor     bx,bx
  214.             int     2fh
  215.  
  216.             or      bx,bx           //BX unchanged if MSCDEX is not around
  217.             jz      CheckRAMDrive   //No?  Go check for RAM drive.
  218.  
  219.             mov     ax,150Bh        //Check if drive is using CD driver
  220.             mov     cx,iDrive
  221.             int     2fh
  222.  
  223.             mov     fCDROM,ax       //AX if the CD-ROM flag
  224.             or      ax,ax
  225.             jnz     Exit            //Leave if we found a CD-ROM drive.
  226.  
  227.             CheckRAMDrive:
  228.             }
  229.         }
  230.  
  231.     //Check for RAM drives on FIXED disks only.
  232.     if (DRIVE_FIXED==iType)
  233.         {
  234.         /*
  235.          * Check for RAM drive is done by reading the boot sector and
  236.          * looking at the number of FATs.  Ramdisks only have 1 while
  237.          * all others have 2.
  238.          */
  239.         _asm
  240.             {
  241.             push    ds
  242.  
  243.             mov     bx,ss
  244.             mov     ds,bx
  245.  
  246.             sub     sp,0200h            //Reserve 512 bytes to read a sector
  247.             mov     bx,sp               //and point BX there.
  248.  
  249.             mov     ax,iDrive           //Read the boot sector of the drive
  250.             mov     cx,1
  251.             xor     dx,dx
  252.  
  253.             int     25h
  254.             add     sp,2                //Int 25h requires our stack cleanup.
  255.             jc      DriveNotRAM
  256.  
  257.             mov     bx,sp
  258.             cmp     ss:[bx+15h],0f8h    //Reverify fixed disk
  259.             jne     DriveNotRAM
  260.             cmp     ss:[bx+10h],1       //Check if there's only one FATs
  261.             jne     DriveNotRAM
  262.             mov     fRAM,1
  263.  
  264.             DriveNotRAM:
  265.             add     sp,0200h
  266.             pop     ds
  267.  
  268.             Exit:
  269.             //Leave fRAM untouched  it's FALSE by default.
  270.             }
  271.         }
  272.  
  273.     /*
  274.      * If either CD-ROM or RAM drive flags are set, return privately
  275.      * defined flags for them (outside of Win32).  Otherwise return
  276.      * the type given from GetDriveType.
  277.      */
  278.  
  279.     if (fCDROM)
  280.         return DRIVE_CDROM;
  281.  
  282.     if (fRAM)
  283.         return DRIVE_RAM;
  284.  
  285.     //Drive B on a one drive system returns < 2 from GetDriveType.
  286.     return iType;
  287.    #endif
  288.     }
  289.  
  290. /*
  291.  * DirectoryListInitialize
  292.  *
  293.  * Purpose:
  294.  *  Initializes strings in a listbox given a directory path.  The first
  295.  *  string in the listbox is the drive letter.  The remaining items are
  296.  *  each directory in the path completed with a listing of all sub-
  297.  *  directories under the last directory in the path.
  298.  *
  299.  * Parameters:
  300.  *  hList           HWND of the listbox to fill.
  301.  *  hTempList       HWND of a listbox to use for  directory enumerations.
  302.  *  pszDir          LPSTR of the path to use in initialization assumed
  303.  *                  to be at least _MAX_DIR long.
  304.  *
  305.  * Return Value:
  306.  *  None
  307.  */
  308.  
  309. void DirectoryListInitialize(HWND hList, HWND hTempList, LPSTR pszDir)
  310.     {
  311.     LPSTR       psz, pszLast;
  312.     char        ch;
  313.     char        szDir[_MAX_DIR];
  314.     UINT        cch, cItems;
  315.     UINT        i, iItem, iIndent;
  316.     BOOL        fFirst=TRUE;
  317.  
  318.     if (NULL==hList || NULL==pszDir)
  319.         return;
  320.  
  321.     //If the path ends in a \, strip the '\'
  322.     cch=lstrlen(pszDir);
  323.  
  324.     if ('\\'==pszDir[cch-1])
  325.         pszDir[cch-1]=0;
  326.  
  327.     //Clear out all the lists.
  328.     SendMessage(hList,     WM_SETREDRAW,    FALSE, 0L);
  329.     SendMessage(hList,     LB_RESETCONTENT, 0,     0L);
  330.     SendMessage(hTempList, LB_RESETCONTENT, 0,     0L);
  331.  
  332.     /*
  333.      * Walk through the path one \ at a time.  At each one found,
  334.      * we add the string composed of the characters between it and
  335.      * the last \ found.  We also make sure everything is lower case.
  336.      */
  337.  
  338.     pszLast=AnsiLower(pszDir);
  339.  
  340.     //Save this for changing directories
  341.     SetWindowText(hList, pszDir);
  342.  
  343.     //Save the directory appended with \*.*
  344.     wsprintf(szDir, "%s\\*.*", pszDir);
  345.  
  346.     while (TRUE)
  347.         {
  348.         psz=_fstrchr(pszLast, '\\');
  349.  
  350.         if (NULL!=psz)
  351.             {
  352.             /*
  353.              * Save the character here so we can NULL terminate.  If this
  354.              * if the first entry, it's a drive root, so keep the \
  355.              */
  356.  
  357.             if (fFirst)
  358.                 ch=*(++psz);
  359.             else
  360.                 ch=*psz;
  361.  
  362.             *psz=0;
  363.             }
  364.         else
  365.             {
  366.             //If we're looking at a drive only, then append a backslash
  367.             if (pszLast==pszDir && fFirst)
  368.                 lstrcat(pszLast, "\\");
  369.             }
  370.  
  371.         //Add the drive string--includes the last one where psz==NULL
  372.         iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0, (LONG)pszLast);
  373.  
  374.         /*
  375.          * The item data here has in the HIWORD the bitmap to use for
  376.          * the item with the LOWORD containing the indentation.  The
  377.          * bitmap is IDB_FOLDEROPEN for anything above the current
  378.          * directory (that is, c:\foo is above than c:\foo\bar),
  379.          * IDB_FOLDERCLOSED for anything below the current, and
  380.          * IDB_FOLDEROPENSELECT for the current directory.
  381.          */
  382.  
  383.         i=(NULL!=psz) ? IDB_FOLDEROPEN : IDB_FOLDEROPENSELECT;
  384.         SendMessage(hList, LB_SETITEMDATA, iItem, MAKELONG(iItem, i));
  385.  
  386.         if (NULL==psz)
  387.             break;
  388.  
  389.         //Restore last character.
  390.         *psz=ch;
  391.         psz+=(fFirst) ? 0 : 1;
  392.  
  393.         fFirst=FALSE;
  394.         pszLast=psz;
  395.         }
  396.  
  397.  
  398.     /*
  399.      * Now that we have the path in, enumerate the subdirectories here
  400.      * and place them in the list at the indentation iItem+1 since iItem
  401.      * was the index of the last item in the path added to the list.
  402.      *
  403.      * To enumerate the directories, we send LB_DIR to an alternate
  404.      * listbox.  On return, we have to parse off the brackets around
  405.      * those directory names before bringing them into this listbox.
  406.      */
  407.  
  408.     iIndent=iItem+1;
  409.  
  410.     //Get available directories; szDir is pszDir\*.*
  411.     SendMessage(hTempList, LB_DIR, DDL_DIRECTORY | DDL_EXCLUSIVE
  412.                 , (LONG)(LPSTR)szDir);
  413.  
  414.     cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
  415.  
  416.     for (i=0; i<cItems; i++)
  417.         {
  418.         cch=(UINT)SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDir);
  419.  
  420.         //Skip directories beginning with . (skipping . and ..)
  421.         if ('.'==szDir[1])
  422.             continue;
  423.  
  424.         //Remove the ending ']'
  425.         szDir[cch-1]=0;
  426.  
  427.         //Add the string to the real directory list.
  428.         iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0
  429.                                 , (LONG)(LPSTR)(szDir+1));
  430.         SendMessage(hList, LB_SETITEMDATA, iItem
  431.                     , MAKELONG(iIndent, IDB_FOLDERCLOSED));
  432.         }
  433.  
  434.     //Force a listbox repaint.
  435.     SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
  436.     InvalidateRect(hList, NULL, TRUE);
  437.  
  438.     /*
  439.      * If there's a vertical scrollbar, then we've added more items than
  440.      * are visible at once.  To meet the UI specifications, we're supposed
  441.      * to make the next directory up the top visible one.
  442.      */
  443.     GetScrollRange(hList, SB_VERT, (LPINT)&i, (LPINT)&iItem);
  444.  
  445.     if (!(0==i && 0==iItem))
  446.         SendMessage(hList, LB_SETTOPINDEX, max((int)(iIndent-2), 0), 0L);
  447.  
  448.     //Last thing is to set the current directory as the selection
  449.     SendMessage(hList, LB_SETCURSEL, iIndent-1, 0L);
  450.     return;
  451.     }
  452.  
  453. /*
  454.  * DriveDirDrawItem
  455.  *
  456.  * Purpose:
  457.  *  Handles WM_DRAWITEM for both drive and directory listboxes.
  458.  *
  459.  * Parameters:
  460.  *  pDI             LPDRAWITEMSTRUCT passed with the WM_DRAWITEM message.
  461.  *  fDrive          BOOL TRUE to draw a drive, FALSE to draw directory.
  462.  *
  463.  * Return Value:
  464.  *  None
  465.  */
  466.  
  467. void DriveDirDrawItem(LPDRAWITEMSTRUCT pDI, BOOL fDrive)
  468.     {
  469.     char        szItem[40];
  470.     int         iType=0;
  471.     int         iIndent=0;
  472.     UINT        uMsg;
  473.     DWORD       dw;
  474.     BITMAP      bm;
  475.     COLORREF    crText, crBack;
  476.     HBITMAP     hBmp;
  477.  
  478.     if ((int)pDI->itemID < 0)
  479.         return;
  480.  
  481.     if (fDrive)
  482.         dw=SendMessage(pDI->hwndItem, CB_GETITEMDATA, pDI->itemID, 0L);
  483.  
  484.     //Get the text string for this item (controls have different messages)
  485.     uMsg=(fDrive) ? CB_GETLBTEXT : LB_GETTEXT;
  486.     SendMessage(pDI->hwndItem, uMsg, pDI->itemID, (LONG)(LPSTR)szItem);
  487.  
  488.     if ((ODA_DRAWENTIRE | ODA_SELECT) & pDI->itemAction)
  489.         {
  490.         if (ODS_SELECTED & pDI->itemState)
  491.             {
  492.             //Select the appropriate text colors
  493.             crText=SetTextColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  494.             crBack=SetBkColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
  495.             }
  496.  
  497.         /*
  498.          * References to the two bitmap arrays here are the only external
  499.          * dependencies of this code.  To keep it simple, we didn't use
  500.          * a more complex scheme like putting all the images into one bitmap.
  501.          */
  502.         if (fDrive)
  503.             {
  504.             //For drives, get the type, which determines the bitmap.
  505.             iType=(int)HIWORD(dw);
  506.             hBmp=DiskBitmaps[iType-IDB_DRIVEMIN];
  507.             }
  508.         else
  509.             {
  510.             //For directories, indentation level is 4 pixels per indent.
  511.             iIndent=4*(1+LOWORD(pDI->itemData));
  512.             hBmp=FolderBitmaps[HIWORD(pDI->itemData)-IDB_FOLDERMIN];
  513.             }
  514.  
  515.         GetObject(hBmp, sizeof(bm), &bm);
  516.  
  517.         /*
  518.          * Paint the text and the rectangle in whatever colors.  If
  519.          * we're drawing drives, iIndent is zero so it's ineffective.
  520.          */
  521.         ExtTextOut(pDI->hDC, pDI->rcItem.left+bm.bmWidth+4+iIndent
  522.                    , pDI->rcItem.top, ETO_OPAQUE, &pDI->rcItem, szItem
  523.                    , lstrlen(szItem), (LPINT)NULL);
  524.  
  525.  
  526.         //Go draw the bitmap we want.
  527.         TransparentBlt(pDI->hDC, pDI->rcItem.left+iIndent
  528.                        , pDI->rcItem.top, hBmp, RGB(0,0,255));
  529.  
  530.         //Restore original colors if we changed them above.
  531.         if (ODS_SELECTED & pDI->itemState)
  532.             {
  533.             SetTextColor(pDI->hDC, crText);
  534.             SetBkColor(pDI->hDC,   crBack);
  535.             }
  536.         }
  537.  
  538.     if ((ODA_FOCUS & pDI->itemAction) || (ODS_FOCUS & pDI->itemState))
  539.         DrawFocusRect(pDI->hDC, &pDI->rcItem);
  540.  
  541.     return;
  542.     }
  543.  
  544. /*
  545.  * TransparentBlt
  546.  *
  547.  *  Given a DC, a bitmap, and a color to assume as transparent in that
  548.  *  bitmap, BitBlts the bitmap to the DC letting the existing background
  549.  *  show in place of the transparent color.
  550.  *
  551.  * Parameters:
  552.  *  hDC             HDC on which to draw.
  553.  *  x, y            UINT location at which to draw the bitmap
  554.  *  hBmp            HBITMIP to draw
  555.  *  cr              COLORREF to consider as transparent.
  556.  */
  557.  
  558. void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, COLORREF cr)
  559.     {
  560.     HDC         hDCSrc, hDCMid, hMemDC;
  561.     HBITMAP     hBmpMono, hBmpT;
  562.     HBRUSH      hBr, hBrT;
  563.     COLORREF    crBack, crText;
  564.     BITMAP      bm;
  565.  
  566.     if (NULL==hBmp)
  567.         return;
  568.  
  569.     GetObject(hBmp, sizeof(bm), &bm);
  570.  
  571.     //Get three intermediate DC's
  572.     hDCSrc=CreateCompatibleDC(hDC);
  573.     hDCMid=CreateCompatibleDC(hDC);
  574.     hMemDC=CreateCompatibleDC(hDC);
  575.  
  576.     SelectObject(hDCSrc, hBmp);
  577.  
  578.     //Create a monochrome bitmap for masking
  579.     hBmpMono=CreateCompatibleBitmap(hDCMid, bm.bmWidth, bm.bmHeight);
  580.     SelectObject(hDCMid, hBmpMono);
  581.  
  582.     //Create a middle bitmap
  583.     hBmpT=CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
  584.     SelectObject(hMemDC, hBmpT);
  585.  
  586.  
  587.     //Create a monochrome mask where we have 0's in the image, 1's elsewhere.
  588.     crBack=SetBkColor(hDCSrc, cr);
  589.     BitBlt(hDCMid, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
  590.     SetBkColor(hDCSrc, crBack);
  591.  
  592.     //Put the unmodified image in the temporary bitmap
  593.     BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
  594.  
  595.     //Create an select a brush of the background color
  596.     hBr=CreateSolidBrush(GetBkColor(hDC));
  597.     hBrT=SelectObject(hMemDC, hBr);
  598.  
  599.     //Force conversion of the monochrome to stay black and white.
  600.     crText=SetTextColor(hMemDC, 0L);
  601.     crBack=SetBkColor(hMemDC, RGB(255, 255, 255));
  602.  
  603.     /*
  604.      * Where the monochrome mask is 1, Blt the brush; where the mono mask
  605.      * is 0, leave the destination untouches.  This results in painting
  606.      * around the image with the background brush.  We do this first
  607.      * in the temporary bitmap, then put the whole thing to the screen.
  608.      */
  609.     BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMid, 0, 0, ROP_DSPDxax);
  610.     BitBlt(hDC,    x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
  611.  
  612.  
  613.     SetTextColor(hMemDC, crText);
  614.     SetBkColor(hMemDC, crBack);
  615.  
  616.     SelectObject(hMemDC, hBrT);
  617.     DeleteObject(hBr);
  618.  
  619.     DeleteDC(hMemDC);
  620.     DeleteDC(hDCSrc);
  621.     DeleteDC(hDCMid);
  622.     DeleteObject(hBmpT);
  623.     DeleteObject(hBmpMono);
  624.  
  625.     return;
  626.     }
  627.  
  628. /*
  629.  * WinVnSelectPathDialogDlg
  630.  *
  631.  *  Handles the dialog that displays a drive and directory owner-draw
  632.  *  combobox and listbox, respectiviely.  This procedure handles only
  633.  *  the WM_INITDIALOG and WM_DRAWITEM messages,dispatching them to
  634.  *  alternate functions that handle each message for each list.
  635.  *
  636.  */
  637.  
  638. BOOL FAR PASCAL WinVnSelectPathDlg(HWND hDlg,unsigned iMessage,WPARAM wParam,LPARAM lParam)
  639.     {
  640.  
  641.     char cwd[_MAX_PATH];
  642.  
  643.     WORD            wID;
  644.     WORD            wCode;
  645.     HWND            hWndMsg;
  646.  
  647.     hWndMsg=(HWND)(UINT)lParam;
  648.     wID=LOWORD(wParam);
  649.     #ifdef WIN32
  650.         wCode=HIWORD(wParam);
  651.     #else
  652.         wCode=HIWORD(lParam);
  653.     #endif
  654.  
  655.     switch (iMessage)
  656.         {
  657.         case WM_INITDIALOG:
  658.             ShowWindow(hDlg, SW_SHOW);
  659.             UpdateWindow(hDlg);
  660.  
  661.             DriveListInitialize(GetDlgItem(hDlg, ID_DRIVELIST), GetDlgItem(hDlg, ID_TEMPLIST));
  662.  
  663.             if (lParam    && _access((char *)lParam, 0) >= 0) {
  664.                 strcpy (cwd, (char *)lParam);
  665.                 _chdir(cwd);
  666.             } else
  667.                    _getcwd(cwd, _MAX_PATH);
  668.             
  669.             DirectoryListInitialize(GetDlgItem(hDlg, ID_DIRECTORYLIST), GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  670.             return TRUE;
  671.  
  672.         case WM_MEASUREITEM:
  673.             {
  674.             static int              cyItem=-1;      //Height of a listbox item
  675.             LPMEASUREITEMSTRUCT     pMI;
  676.  
  677.             pMI=(LPMEASUREITEMSTRUCT)lParam;
  678.  
  679.             if (-1==cyItem)
  680.                 {
  681.                 HFONT       hFont;
  682.                 HDC         hDC;
  683.                 TEXTMETRIC  tm;
  684.                 BITMAP      bm;
  685.  
  686.                 /*
  687.                  * Attempt to get the font of the dialog. However,
  688.                  * on the first attempt in the life of the dialog,
  689.                  * this could fail; in that case use the system font.
  690.                  */
  691.                 hFont=(HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
  692.  
  693.                 if (NULL==hFont)
  694.                     hFont=GetStockObject(SYSTEM_FONT);
  695.  
  696.                 hDC=GetDC(hDlg);
  697.                 hFont=SelectObject(hDC, hFont);
  698.  
  699.                 /*
  700.                  * Item height is the maximum of the font height and the
  701.                  * bitmap height.  We know that all bitmaps are the same
  702.                  * size, so we just get information for one of them.
  703.                  */
  704.                 GetTextMetrics(hDC, &tm);
  705.                 GetObject(FolderBitmaps[0], sizeof(bm), &bm);
  706.                 cyItem=max(bm.bmHeight, tm.tmHeight);
  707.  
  708.                 ReleaseDC(hDlg, hDC);
  709.                 }
  710.  
  711.             pMI->itemHeight=cyItem;
  712.             }
  713.             break;
  714.  
  715.  
  716.         case WM_DRAWITEM:
  717.             //Go draw the appropriate item and bitmap.
  718.             DriveDirDrawItem((LPDRAWITEMSTRUCT)lParam, (ID_DRIVELIST==wID));
  719.  
  720.             //Prevent default actions in listboxes (drawing focus rect)
  721.             return TRUE;
  722.  
  723.  
  724.         case WM_COMMAND:
  725.             switch (wID)
  726.                 {
  727.                 case ID_DIRECTORYLIST:
  728.                     if (LBN_DBLCLK==wCode)
  729.                         {
  730.                         UINT        i;
  731.                         DWORD       dw;
  732.                         char        szDir[_MAX_PATH];
  733.                         LPSTR       psz;
  734.  
  735.                         /*
  736.                          * On double-click, change directory and reinit the
  737.                          * listbox.  But all we stored in the string was
  738.                          * the directory's single name, so we use the bitmap
  739.                          * type to tell if we're below the current directory
  740.                          * (in which case we just chdir to our name) or above
  741.                          * (in which case we prepend "..\"'s as necessary.
  742.                          */
  743.                         i=(UINT)SendMessage(hWndMsg, LB_GETCURSEL, 0, 0L);
  744.                         dw=SendMessage(hWndMsg, LB_GETITEMDATA, i, 0L);
  745.  
  746.                         /*
  747.                          * If out bitmap is IDB_FOLDERCLOSED or the root,
  748.                          * then just .  If we're IDB_FOLDEROPENSELECT,
  749.                          * don't do anything.  If we're IDB_FOLDEROPEN then
  750.                          * we get the full current path and truncate it
  751.                          * after the directory to which we're switching.
  752.                          */
  753.                         if (IDB_FOLDEROPENSELECT==HIWORD(dw))
  754.                             break;
  755.  
  756.                         //Get get the directory for sub-directory changes.
  757.                         SendMessage(hWndMsg, LB_GETTEXT, i, (LONG)(LPSTR)cwd);
  758.  
  759.                         if (IDB_FOLDEROPEN==HIWORD(dw) && 0!=i)
  760.                             {
  761.                             //Get the current path and find us in this path
  762.                             GetWindowText(hWndMsg, szDir, sizeof(szDir));
  763.                             psz=_fstrstr(szDir, cwd);
  764.  
  765.                             //Null terminate right after us.
  766.                             *(psz+lstrlen(cwd))=0;
  767.  
  768.                             //Get this new directory in the right place
  769.                             lstrcpy(cwd, szDir);
  770.                             }
  771.  
  772.                         //chdir has a nice way of validating for us.
  773.                         if (0==_chdir(cwd))
  774.                             {
  775.                             //Get the new full path.
  776.                             _getcwd(cwd, _MAX_PATH);
  777.  
  778.                             DirectoryListInitialize(hWndMsg
  779.                                 , GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  780.                             }
  781.                         }
  782.                     break;
  783.  
  784.  
  785.                 case ID_DRIVELIST:
  786.                     if (CBN_SELCHANGE==wCode)
  787.                         {
  788.                         UINT        i, iCurDrive;
  789.                         char        szDrive[18]; //Enough for drive:volume
  790.  
  791.                         //Get the first letter in the current selection
  792.                         i=(UINT)SendMessage(hWndMsg, CB_GETCURSEL, 0, 0L);
  793.                         SendMessage(hWndMsg, CB_GETLBTEXT
  794.                                     , i, (LONG)(LPSTR)szDrive);
  795.  
  796.                         iCurDrive=_getdrive();  //Save in case of restore
  797.  
  798.                         /*
  799.                          * Attempt to set the drive and get the current
  800.                          * directory on it.  Both must work for the change
  801.                          * to be certain.  If we are certain, reinitialize
  802.                          * the directories.  Note that we depend on drives
  803.                          * stored as lower case in the combobox.
  804.                          */
  805.  
  806.                         if (0==_chdrive((int)(szDrive[0]-'a'+1))
  807.                             && NULL!=_getcwd(cwd, _MAX_PATH))
  808.                             {
  809.                             DirectoryListInitialize(
  810.                                 GetDlgItem(hDlg, ID_DIRECTORYLIST),
  811.                                 GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  812.  
  813.                             //Insure that the root is visible (UI guideline)
  814.                             SendDlgItemMessage(hDlg, ID_DIRECTORYLIST
  815.                                                , LB_SETTOPINDEX, 0, 0L);
  816.  
  817.                             break;
  818.                             }
  819.  
  820.                         //Changing drives failed so restore drive and selection
  821.                         _chdrive((int)iCurDrive);
  822.  
  823.                         wsprintf(szDrive, "%c:", (char)(iCurDrive+'a'-1));
  824.                         i=(UINT)SendMessage(hWndMsg, CB_SELECTSTRING
  825.                                             , (WPARAM)-1, (LONG)(LPSTR)szDrive);
  826.                         }
  827.  
  828.                     break;
  829.  
  830.                 case IDOK:
  831.                     _getcwd(DialogString, MAXINTERNALLINE);
  832.                     EndDialog(hDlg, TRUE);
  833.                     break;
  834.                   case IDCANCEL:
  835.                     EndDialog (hDlg, FALSE);
  836.                     break;
  837.                 }
  838.             break;
  839.  
  840.         default:
  841.             break;
  842.         }
  843.  
  844.     return FALSE;
  845.     }
  846.  
  847. @
  848.