Solved

Directory Listing

Posted on 1997-09-22
6
426 Views
Last Modified: 2013-12-03
I am developing a 16-bit application using MS Visual C++ 1.5. No C++ code is implemented in the app.

Q: I would like a combo box which would allow the user to select any available drive (including network). I do not want to use the DlgDirListComboBox function because it displays the directory listing as brackets. I would like the directory listing exactly as shown when selecting 'File' and 'Open' of most 16-bit applications.
0
Comment
Question by:stevetr
  • 4
  • 2
6 Comments
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
You will have to do it yourself.

Use _findfirst/_findnext to get ths directory names only _A_SUBDIR

Then fill your combo box.

If you want to show the tree structure, you will need to make the combo owner drawn and do this work yourself (attach some data to each item that has dir name and nesting level and display approripately).
0
 

Author Comment

by:stevetr
Comment Utility
How do I include or create the bitmaps (floppy, HD, CD, network, etc.) that go along with the drive locations?
0
 
LVL 10

Accepted Solution

by:
RONSLOW earned 50 total points
Comment Utility
Make it owner draw.

I have sample code that fills a combo box with folders and drives and includes the bitmaps.  I can send it to you if you want.  Just send mailto:Roger_Onslow@compsys.com.au

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
I have sent you the code -- I hope it is useful.
0
 

Author Comment

by:stevetr
Comment Utility
My original question stated that there's no C++ code implemented in the app. I will probably use DlgDirListComboBox.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Soory about that - I did tell you I could send you C code if you wanted.

Anyway ,I've emailed you the C code version.

Here is the .c file for you to read (zip I e-mailed includes .h, bmp files .rc etc)

This is C source code
I've included DDLIST.C (but not header files) here for your persual

/*
* DDLIST.C
*
* Main entry code for application demonstrating owner-drawn listbox
* code to emulate the Common Dialogs drive and directory listboxes.
* The code uses bitmaps provided in the Windows 3.1 Software Development
* Kit that come directly from the Common Dialogs themselves.
*
* Copyright (c)1992 Kraig Brockschmidt, All Right Reserved
* Compuserve:  70750,2344
* Internet  :  kraigb@microsoft.com
*/


#include <windows.h>
#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <direct.h>
#include <string.h>
#include "ddlist.h"


//Caches of the bitmaps in our resources.
HBITMAP rghBmpDrives[5];
HBITMAP rghBmpFolders[3];


/*
* WinMain
*
* Purpose:
*  Main entry point of application.   Should register the app class
*  if a previous instance has not done so and do any other one-time
*  initializations.
*
* Parameters:
*  Standard
*
* Return Value:
*  Value to return to Windows--termination code.
*/

int PASCAL WinMain (HANDLE hInst, HANDLE hPrevInst, LPSTR pszCmd, int nCmdShow)
{
    WNDCLASS        wc;
    HWND            hWnd;
    MSG             msg;
      
    if (!hPrevInst)
      {
        //Main window class
        wc.style          = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc    = DDListWndProc;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hInstance      = hInst;
        wc.hIcon          = LoadIcon(hInst, "Icon");
        wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground  = COLOR_WINDOW+1;
        wc.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU);
        wc.lpszClassName  = "DDLIST";
            
        if (!RegisterClass(&wc))
            return FALSE;
      }
      
      
    hWnd=CreateWindow("DDLIST", "Common Dialogs Owner-Drawn Listboxes"
            , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW
            , 35, 35, 350, 150
            , NULL, NULL, hInst, NULL);
      
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
      
    while (GetMessage(&msg, NULL, 0,0 ))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      
    return msg.wParam;
}






/*
* DDListWndProc
*
* Purpose:
*  Window class procedure.  Standard callback.
*
* Parameters:
*  Standard.
*
* Return Value:
*  Standard.
*/

LONG FAR PASCAL DDListWndProc(HWND hWnd, UINT iMsg, UINT wParam, LONG lParam)
{
    static HINSTANCE    hInst;
    FARPROC             pfn;
    UINT                i;
      
    /*
      * These three variables and the unpacking code below compiles correctly
      * for both Windows 3.x and Windows NT
      */
    WORD            wID;
    WORD            wCode;
    HWND            hWndMsg;
      
    hWndMsg=(HWND)(UINT)lParam;
    wID=LOWORD(wParam);
#ifdef WIN32
      wCode=HIWORD(wParam);
#else
      wCode=HIWORD(lParam);
#endif
      
      
    switch (iMsg)
      {
      case WM_CREATE:
            //Save the instance handle for creating the dialog box
            hInst=((LPCREATESTRUCT)lParam)->hInstance;
            
            //Load the drive and folder bitmaps for the lists.
            for (i=IDB_DRIVEMIN; i<=IDB_DRIVEMAX; i++)
                  rghBmpDrives[i-IDB_DRIVEMIN]=LoadBitmap(hInst, MAKEINTRESOURCE(i));
            
            for (i=IDB_FOLDERMIN; i<=IDB_FOLDERMAX; i++)
                  rghBmpFolders[i-IDB_FOLDERMIN]=LoadBitmap(hInst, MAKEINTRESOURCE(i));
            
            return 0L;
            
      case WM_DESTROY:
            //Free up our allocated resources.
            for (i=IDB_DRIVEMIN; i<=IDB_DRIVEMAX; i++)
                  DeleteObject(rghBmpDrives[i-IDB_DRIVEMIN]);
            
            for (i=IDB_FOLDERMIN; i<=IDB_FOLDERMAX; i++)
                  DeleteObject(rghBmpFolders[i-IDB_FOLDERMIN]);
            
            PostQuitMessage(0);
            break;
            
      case WM_COMMAND:
            switch (wID)
            {
            case IDM_DIALOG:
                  pfn=MakeProcInstance(DDListDialogProc, hInst);
                  DialogBox(hInst, MAKEINTRESOURCE(IDD_DDLIST), hWnd, pfn);
                  FreeProcInstance(pfn);
                  break;
            }
            
        default:
            return (DefWindowProc(hWnd, iMsg, wParam, lParam));
      }
      
    return 0L;
}





/*
* DDListDialogProc
*
* Purpose:
*  Handles the dialog that displays a drive and directory owner-draw
*  combobox and listbox, respectiviely.  This procedure handles only
*  the WM_INITDIALOG and WM_DRAWITEM messages,dispatching them to
*  alternate functions that handle each message for each list.
*
* Parameters:
*  Standard
*
* Return Value:
*  Standard
*/

BOOL FAR PASCAL DDListDialogProc(HWND hDlg, UINT iMsg, UINT wParam, LONG lParam)
{
      
    char            szCurDir[_MAX_PATH];
      
    /*
      * These three variables and the unpacking code below compiles correctly
      * for both Windows 3.x and Windows   NT
      */
    WORD            wID;
    WORD            wCode;
    HWND            hWndMsg;
      
    hWndMsg=(HWND)(UINT)lParam;
    wID=LOWORD(wParam);
#ifdef WIN32
      wCode=HIWORD(wParam);
#else
      wCode=HIWORD(lParam);
#endif
      
      
    switch (iMsg)
      {
      case WM_INITDIALOG:
            ShowWindow(hDlg, SW_SHOW);
            UpdateWindow(hDlg);
            
            //Initialize the drive combobox with the available drives
            DriveListInitialize(GetDlgItem(hDlg, ID_DRIVELIST)
                  , GetDlgItem(hDlg, ID_TEMPLIST));
            
            /*
                  * Initializethe directory listbox with the current working
                  * directory.  WARNING:  The C Run-Time cwd function is not
                  * always compatible with Windows DLLs.  If  you are placing
                  * this code in a DLL you may need to write your own version
                  * using DOS3Call.  We also trust _getcwd to give us a drive
                  * letter at the front of the string.
            */
            _getcwd(szCurDir, _MAX_PATH);
            DirectoryListInitialize(GetDlgItem(hDlg, ID_DIRECTORYLIST)
                  , GetDlgItem(hDlg, ID_TEMPLIST), szCurDir);
            
            return TRUE;
            
            
      case WM_MEASUREITEM:
            {
            static int              cyItem=-1;      //Height of a listbox item
            LPMEASUREITEMSTRUCT     pMI;
                  
            pMI=(LPMEASUREITEMSTRUCT)lParam;
                  
            if (-1==cyItem)
                  {
                HFONT       hFont;
                HDC         hDC;
                TEXTMETRIC  tm;
                BITMAP      bm;
                        
                /*
                        * Attempt to get the font of the dialog. However,
                        * on the first attempt in the life of the dialog,
                        * this could fail; in that case use the system font.
                        */
                hFont=(HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
                        
                if (NULL==hFont)
                    hFont=GetStockObject(SYSTEM_FONT);
                        
                hDC=GetDC(hDlg);
                hFont=SelectObject(hDC, hFont);
                        
                /*
                        * Item height is the maximum of the font height and the
                        * bitmap height.  We know that all bitmaps are the same
                        * size, so we just get information for one of them.
                        */
                GetTextMetrics(hDC, &tm);
                GetObject(rghBmpFolders[0], sizeof(bm), &bm);
                cyItem=max(bm.bmHeight, tm.tmHeight);
                        
                ReleaseDC(hDlg, hDC);
                  }
                  
            pMI->itemHeight=cyItem;
            }
            break;
            
            
      case WM_DRAWITEM:
            //Go draw the appropriate item and bitmap.
            DriveDirDrawItem((LPDRAWITEMSTRUCT)lParam, (ID_DRIVELIST==wID));
            
            //Prevent default actions in listboxes (drawing focus rect)
            return TRUE;
            
            
      case WM_COMMAND:
            switch (wID)
            {
            case ID_DIRECTORYLIST:
                  if (LBN_DBLCLK==wCode)
                  {
                        UINT        i;
                        DWORD       dw;
                        char        szDir[_MAX_PATH];
                        LPSTR       psz;
                        
                        /*
                        * On double-click, change directory and reinit the
                        * listbox.  But all we stored in the string was
                        * the directory's single name, so we use the bitmap
                        * type to tell if we're below the current directory
                        * (in which case we just chdir to our name) or above
                        * (in which case we prepend "..\"'s as necessary.
                        */
                        i=(UINT)SendMessage(hWndMsg, LB_GETCURSEL, 0, 0L);
                        dw=SendMessage(hWndMsg, LB_GETITEMDATA, i, 0L);
                        
                        /*
                        * If out bitmap is IDB_FOLDERCLOSED or the root,
                        * then just .  If we're IDB_FOLDEROPENSELECT,
                        * don't do anything.  If we're IDB_FOLDEROPEN then
                        * we get the full current path and truncate it
                        * after the directory to which we're switching.
                        */
                        if (IDB_FOLDEROPENSELECT==HIWORD(dw))
                              break;
                        
                        //Get get the directory for sub-directory changes.
                        SendMessage(hWndMsg, LB_GETTEXT, i, (LONG)(LPSTR)szCurDir);
                        
                        if (IDB_FOLDEROPEN==HIWORD(dw) && 0!=i)
                        {
                              //Get the current path and find us in this path
                              GetWindowText(hWndMsg, szDir, sizeof(szDir));
                              psz=_fstrstr(szDir, szCurDir);
                              
                              //Null terminate right after us.
                              *(psz+lstrlen(szCurDir))=0;
                              
                              //Get this new directory in the right place
                              lstrcpy(szCurDir, szDir);
                        }
                        
                        //chdir has a nice way of validating for us.
                        if (0==_chdir(szCurDir))
                        {
                              //Get the new full path.
                              _getcwd(szCurDir, _MAX_PATH);
                              
                              DirectoryListInitialize(hWndMsg
                                    , GetDlgItem(hDlg, ID_TEMPLIST), szCurDir);
                        }
                  }
                  break;
                  
                  
            case ID_DRIVELIST:
                  if (CBN_SELCHANGE==wCode)
                  {
                        UINT        i, iCurDrive;
                        char        szDrive[18]; //Enough for drive:volume
                        
                        //Get the first letter in the current selection
                        i=(UINT)SendMessage(hWndMsg, CB_GETCURSEL, 0, 0L);
                        SendMessage(hWndMsg, CB_GETLBTEXT
                              , i, (LONG)(LPSTR)szDrive);
                        
                        iCurDrive=_getdrive();  //Save in case of restore
                        
                                                            /*
                                                            * Attempt to set the drive and get the current
                                                            * directory on it.  Both must work for the change
                                                            * to be certain.  If we are certain, reinitialize
                                                            * the directories.  Note that we depend on drives
                                                            * stored as lower case in the combobox.
                        */
                        
                        if (0==_chdrive((int)(szDrive[0]-'a'+1))
                              && NULL!=_getcwd(szCurDir, _MAX_PATH))
                        {
                              DirectoryListInitialize(
                                    GetDlgItem(hDlg, ID_DIRECTORYLIST),
                                    GetDlgItem(hDlg, ID_TEMPLIST), szCurDir);
                              
                              //Insure that the root is visible (UI guideline)
                              SendDlgItemMessage(hDlg, ID_DIRECTORYLIST
                                    , LB_SETTOPINDEX, 0, 0L);
                              
                              break;
                        }
                        
                        //Changing drives failed so restore drive and selection
                        _chdrive((int)iCurDrive);
                        
                        wsprintf(szDrive, "%c:", (char)(iCurDrive+'a'-1));
                        i=(UINT)SendMessage(hWndMsg, CB_SELECTSTRING
                              , (WPARAM)-1, (LONG)(LPSTR)szDrive);
                  }
                  
                  break;
                  
            case IDOK:
                  EndDialog(hDlg, TRUE);
                  break;
        }
            break;
                        
    default:
        break;
    }
      
      return FALSE;
}
      






/*
* DriveListInitialize
*
* Purpose:
*  Resets and fills the given combobox with a list of current
*  drives.  The type of drive is stored with the item data.
*
* Parameters:
*  hList           HWND of the combobox to fill.
*  hTempList       HWND to use for finding drives.
*
* Return Value:
*  None
*/

void DriveListInitialize(HWND hList, HWND hTempList)
{
      struct find_t   fi;
      char            ch;
      UINT            i, iItem;
      UINT            cch, cItems;
      UINT            iDrive, iType;
      UINT            iCurDrive;
      char            szDrive[10];
      char            szNet[64];
      char            szItem[26];
      
      if (NULL==hList)
            return;
      
      //Clear out all the lists.
      SendMessage(hList,     CB_RESETCONTENT, 0, 0L);
      SendMessage(hTempList, LB_RESETCONTENT, 0, 0L);
      
      //Get available drive letters in the temp list
      SendMessage(hTempList, LB_DIR, DDL_DRIVES | DDL_EXCLUSIVE, (LONG)(LPSTR)"*");
      
      iCurDrive=_getdrive()-1;       //Fix for zero-based drive indexing
      
                                                   /*
                                                   * Walk through the list of drives, parsing off the "[-" and "-]"
                                                   * For each drive letter parsed, add a string to the combobox
                                                   * composed of the drive letter and the volume label.  We then
                                                   * determine the drive type and add that information as the item data.
      */
      cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
      
      for (i=0; i<cItems;  i++)
    {
            SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDrive);
            
            //Insure lowercase drive letters
            AnsiLower(szDrive);
            iDrive=szDrive[2]-'a';
            iType=DriveType(iDrive);        //See Below
            
            if (iType < 2)                  //Skip non-existent drive B's
                  continue;
            
            //Start the item string with the drive letter, color, and two spaces
            wsprintf(szItem, "%c%s", szDrive[2], (LPSTR)":  ");
            
            /*
            * For fixed or ram disks, append the volume label which we find
            * using _dos_findfirst and attribute _A_VOLID.
            */
            if (DRIVE_FIXED==iType || DRIVE_RAM==iType)
        {
                  wsprintf(szDrive, "%c:\\*.*", szDrive[2]);
                  
                  if (0==_dos_findfirst(szDrive, _A_VOLID, &fi))
            {
                        //Convert volume to lowercase and strip any . in the name.
                        AnsiLower(fi.name);
                        
                        //If a period exists, it has to be in position 8, so clear it.
                        ch=fi.name[8];
                        fi.name[8]=0;
                        lstrcat(szItem, fi.name);
                        
                        //If we did have a broken volume name, append the last 3 chars
                        if ('.'==ch)
                              lstrcat(szItem, &fi.name[9]);
            }
        }
            
            //For network drives, go grab the \\server\share for it.
            if (DRIVE_REMOTE==iType)
        {
                  szNet[0]=0;
                  cch=sizeof(szNet);
                  
                  wsprintf(szDrive, "%c:", szDrive[2]);
                  AnsiUpper(szDrive);
                  
                  WNetGetConnection((LPSTR)szDrive, (LPSTR)szNet, &cch);
                  AnsiLower(szNet);
                  
                  lstrcat(szItem, szNet);
        }
            
            iItem=(int)SendMessage(hList, CB_ADDSTRING, 0, (LONG)(LPSTR)szItem);
            SendMessage(hList, CB_SETITEMDATA, iItem, MAKELONG(iDrive, iType));
            
            if (iDrive==iCurDrive)
                  SendMessage(hList, CB_SETCURSEL, iItem, 0L);
    }
      
      return;
}






/*
* DriveType
*
* Purpose:
*  Augments the Windows API GetDriveType with a call to the CD-ROM
*  extensions to determine if a drive is a floppy, hard disk, CD-ROM,
*  RAM-drive, or networked  drive.
*
* Parameters:
*  iDrive          UINT containing the zero-based drive index
*
* Return Value:
*  UINT            One of the following values describing the drive:
*                  DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAM,
*                  DRIVE_NETWORK.
*/

UINT DriveType(UINT iDrive)
{
      int     iType;
      BOOL    fCDROM=FALSE;
      BOOL    fRAM=FALSE;
      
      
      //Validate possible drive indices
      if (0 > iDrive  || 25 < iDrive)
            return 0xFFFF;
      
      iType=GetDriveType(iDrive);
      
      /*
      * Under Windows NT, GetDriveType returns complete information
      * not provided under Windows 3.x which we now get through other
      * means.
      */
#ifdef WIN32
      return iType;
#else
      //Check for CDROM on FIXED and REMOTE drives only
      if (DRIVE_FIXED==iType || DRIVE_REMOTE==iType)
    {
            _asm
        {
                  mov     ax,1500h        //Check if MSCDEX exists
                        xor     bx,bx
                        int     2fh
                        
                        or      bx,bx           //BX unchanged if MSCDEX is not around
                        jz      CheckRAMDrive   //No?  Go check for RAM drive.
                        
                        mov     ax,150Bh        //Check if drive is using CD driver
                        mov     cx,iDrive
                        int     2fh
                        
                        mov     fCDROM,ax       //AX if the CD-ROM flag
                        or      ax,ax
                        jnz     Exit            //Leave if we found a CD-ROM drive.
                        
CheckRAMDrive:
        }
    }
      
      //Check for RAM drives on FIXED disks only.
      if (DRIVE_FIXED==iType)
    {
    /*
      * Check for RAM drive is done by reading the boot sector and
      * looking at the number of FATs.  Ramdisks only have 1 while
      * all others have 2.
            */
            _asm
        {
                  push    ds
                        
                        mov     bx,ss
                        mov     ds,bx
                        
                        sub     sp,0200h            //Reserve 512 bytes to read a sector
                        mov     bx,sp               //and point BX there.
                        
                        mov     ax,iDrive           //Read the boot sector of the drive
                        mov     cx,1
                        xor     dx,dx
                        
                        int     25h
                        add     sp,2                //Int 25h requires our stack cleanup.
                        jc      DriveNotRAM
                        
                        mov     bx,sp
                        cmp     ss:[bx+15h],0f8h    //Reverify fixed disk
                        jne     DriveNotRAM
                        cmp     ss:[bx+10h],1       //Check if there's only one FATs
                        jne     DriveNotRAM
                        mov     fRAM,1
                        
DriveNotRAM:
                  add     sp,0200h
                        pop     ds
                        
Exit:
                  //Leave fRAM untouched  it's FALSE by default.
        }
    }
      
      /*
      * If either CD-ROM or RAM drive flags are set, return privately
      * defined flags for them (outside of Win32).  Otherwise return
      * the type given from GetDriveType.
      */
      
      if (fCDROM)
            return DRIVE_CDROM;
      
      if (fRAM)
            return DRIVE_RAM;
      
      //Drive B on a one drive system returns < 2 from GetDriveType.
      return iType;
#endif
}






/*
* DirectoryListInitialize
*
* Purpose:
*  Initializes strings in a listbox given a directory path.  The first
*  string in the listbox is the drive letter.  The remaining items are
*  each directory in the path completed with a listing of all sub-
*  directories under the last directory in the path.
*
* Parameters:
*  hList           HWND of the listbox to fill.
*  hTempList       HWND of a listbox to use for  directory enumerations.
*  pszDir          LPSTR of the path to use in initialization assumed
*                  to be at least _MAX_DIR long.
*
* Return Value:
*  None
*/

void DirectoryListInitialize(HWND hList, HWND hTempList, LPSTR pszDir)
{
      LPSTR       psz, pszLast;
      char        ch;
      char        szDir[_MAX_DIR];
      UINT        cch, cItems;
      UINT        i, iItem, iIndent;
      BOOL        fFirst=TRUE;
      
      if (NULL==hList || NULL==pszDir)
            return;
      
      //If the path ends in a \, strip the '\'
      cch=lstrlen(pszDir);
      
      if ('\\'==pszDir[cch-1])
            pszDir[cch-1]=0;
      
      //Clear out all the lists.
      SendMessage(hList,     WM_SETREDRAW,    FALSE, 0L);
      SendMessage(hList,     LB_RESETCONTENT, 0,     0L);
      SendMessage(hTempList, LB_RESETCONTENT, 0,     0L);
      
      /*
      * Walk through the path one \ at a time.  At each one found,
      * we add the string composed of the characters between it and
      * the last \ found.  We also make sure everything is lower case.
      */
      
      pszLast=AnsiLower(pszDir);
      
      //Save this for changing directories
      SetWindowText(hList, pszDir);
      
      //Save the directory appended with \*.*
      wsprintf(szDir, "%s\\*.*", pszDir);
      
      while (TRUE)
    {
            psz=_fstrchr(pszLast, '\\');
            
            if (NULL!=psz)
        {
        /*
            * Save the character here so we can NULL terminate.  If this
            * if the first entry, it's a drive root, so keep the \
                  */
                  
                  if (fFirst)
                        ch=*(++psz);
                  else
                        ch=*psz;
                  
                  *psz=0;
        }
            else
        {
                  //If we're looking at a drive only, then append a backslash
                  if (pszLast==pszDir && fFirst)
                        lstrcat(pszLast, "\\");
        }
            
            //Add the drive string--includes the last one where psz==NULL
            iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0, (LONG)pszLast);
            
            /*
            * The item data here has in the HIWORD the bitmap to use for
            * the item with the LOWORD containing the indentation.  The
            * bitmap is IDB_FOLDEROPEN for anything above the current
            * directory (that is, c:\foo is above than c:\foo\bar),
            * IDB_FOLDERCLOSED for anything below the current, and
            * IDB_FOLDEROPENSELECT for the current directory.
            */
            
            i=(NULL!=psz) ? IDB_FOLDEROPEN : IDB_FOLDEROPENSELECT;
            SendMessage(hList, LB_SETITEMDATA, iItem, MAKELONG(iItem, i));
            
            if (NULL==psz)
                  break;
            
            //Restore last character.
            *psz=ch;
            psz+=(fFirst) ? 0 : 1;
            
            fFirst=FALSE;
            pszLast=psz;
    }
      
      
      /*
      * Now that we have the path in, enumerate the subdirectories here
      * and place them in the list at the indentation iItem+1 since iItem
      * was the index of the last item in the path added to the list.
      *
      * To enumerate the directories, we send LB_DIR to an alternate
      * listbox.  On return, we have to parse off the brackets around
      * those directory names before bringing them into this listbox.
      */
      
      iIndent=iItem+1;
      
      //Get available directories; szDir is pszDir\*.*
      SendMessage(hTempList, LB_DIR, DDL_DIRECTORY | DDL_EXCLUSIVE
            , (LONG)(LPSTR)szDir);
      
      cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
      
      for (i=0; i<cItems; i++)
    {
            cch=(UINT)SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDir);
            
            //Skip directories beginning with . (skipping . and ..)
            if ('.'==szDir[1])
                  continue;
            
            //Remove the ending ']'
            szDir[cch-1]=0;
            
            //Add the string to the real directory list.
            iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0
                  , (LONG)(LPSTR)(szDir+1));
            SendMessage(hList, LB_SETITEMDATA, iItem
                  , MAKELONG(iIndent, IDB_FOLDERCLOSED));
    }
      
      //Force a listbox repaint.
      SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
      InvalidateRect(hList, NULL, TRUE);
      
      /*
      * If there's a vertical scrollbar, then we've added more items than
      * are visible at once.  To meet the UI specifications, we're supposed
      * to make the next directory up the top visible one.
      */
      GetScrollRange(hList, SB_VERT, (LPINT)&i, (LPINT)&iItem);
      
      if (!(0==i && 0==iItem))
            SendMessage(hList, LB_SETTOPINDEX, max((int)(iIndent-2), 0), 0L);
      
      //Last thing is to set the current directory as the selection
      SendMessage(hList, LB_SETCURSEL, iIndent-1, 0L);
      return;
}






/*
* DriveDirDrawItem
*
* Purpose:
*  Handles WM_DRAWITEM for both drive and directory listboxes.
*
* Parameters:
*  pDI             LPDRAWITEMSTRUCT passed with the WM_DRAWITEM message.
*  fDrive          BOOL TRUE to draw a drive, FALSE to draw directory.
*
* Return Value:
*  None
*/

void DriveDirDrawItem(LPDRAWITEMSTRUCT pDI, BOOL fDrive)
{
      char        szItem[40];
      int         iType=0;
      int         iIndent=0;
      UINT        uMsg;
      DWORD       dw;
      BITMAP      bm;
      COLORREF    crText, crBack;
      HBITMAP     hBmp;
      
      if ((int)pDI->itemID < 0)
            return;
      
      if (fDrive)
            dw=SendMessage(pDI->hwndItem, CB_GETITEMDATA, pDI->itemID, 0L);
      
      //Get the text string for this item (controls have different messages)
      uMsg=(fDrive) ? CB_GETLBTEXT : LB_GETTEXT;
      SendMessage(pDI->hwndItem, uMsg, pDI->itemID, (LONG)(LPSTR)szItem);
      
      if ((ODA_DRAWENTIRE | ODA_SELECT) & pDI->itemAction)
    {
            if (ODS_SELECTED & pDI->itemState)
        {
                  //Select the appropriate text colors
                  crText=SetTextColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
                  crBack=SetBkColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
        }
            
            /*
            * References to the two bitmap arrays here are the only external
            * dependencies of this code.  To keep it simple, we didn't use
            * a more complex scheme like putting all the images into one bitmap.
            */
            if (fDrive)
        {
                  //For drives, get the type, which determines the bitmap.
                  iType=(int)HIWORD(dw);
                  hBmp=rghBmpDrives[iType-IDB_DRIVEMIN];
        }
            else
        {
                  //For directories, indentation level is 4 pixels per indent.
                  iIndent=4*(1+LOWORD(pDI->itemData));
                  hBmp=rghBmpFolders[HIWORD(pDI->itemData)-IDB_FOLDERMIN];
        }
            
            GetObject(hBmp, sizeof(bm), &bm);
            
            /*
            * Paint the text and the rectangle in whatever colors.  If
            * we're drawing drives, iIndent is zero so it's ineffective.
            */
            ExtTextOut(pDI->hDC, pDI->rcItem.left+bm.bmWidth+4+iIndent
                  , pDI->rcItem.top, ETO_OPAQUE, &pDI->rcItem, szItem
                  , lstrlen(szItem), (LPINT)NULL);
            
            
            //Go draw the bitmap we want.
            TransparentBlt(pDI->hDC, pDI->rcItem.left+iIndent
                  , pDI->rcItem.top, hBmp, RGB(0,0,255));
            
            //Restore original colors if we changed them above.
            if (ODS_SELECTED & pDI->itemState)
        {
                  SetTextColor(pDI->hDC, crText);
                  SetBkColor(pDI->hDC,   crBack);
        }
    }
      
      if ((ODA_FOCUS & pDI->itemAction) || (ODS_FOCUS & pDI->itemState))
            DrawFocusRect(pDI->hDC, &pDI->rcItem);
      
      return;
}






/*
* TransparentBlt
*
* Purpose:
*  Given a DC, a bitmap, and a color to assume as transparent in that
*  bitmap, BitBlts the bitmap to the DC letting the existing background
*  show in place of the transparent color.
*
* Parameters:
*  hDC             HDC on which to draw.
*  x, y            UINT location at which to draw the bitmap
*  hBmp            HBITMIP to draw
*  cr              COLORREF to consider as transparent.
*
* Return Value:
*  None
*/

void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, COLORREF cr)
{
      HDC         hDCSrc, hDCMid, hMemDC;
      HBITMAP     hBmpMono, hBmpT;
      HBRUSH      hBr, hBrT;
      COLORREF    crBack, crText;
      BITMAP      bm;
      
      if (NULL==hBmp)
            return;
      
      GetObject(hBmp, sizeof(bm), &bm);
      
      //Get three intermediate DC's
      hDCSrc=CreateCompatibleDC(hDC);
      hDCMid=CreateCompatibleDC(hDC);
      hMemDC=CreateCompatibleDC(hDC);
      
      SelectObject(hDCSrc, hBmp);
      
      //Create a monochrome bitmap for masking
      hBmpMono=CreateCompatibleBitmap(hDCMid, bm.bmWidth, bm.bmHeight);
      SelectObject(hDCMid, hBmpMono);
      
      //Create a middle bitmap
      hBmpT=CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
      SelectObject(hMemDC, hBmpT);
      
      
      //Create a monochrome mask where we have 0's in the image, 1's elsewhere.
      crBack=SetBkColor(hDCSrc, cr);
      BitBlt(hDCMid, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
      SetBkColor(hDCSrc, crBack);
      
      //Put the unmodified image in the temporary bitmap
      BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
      
      //Create an select a brush of the background color
      hBr=CreateSolidBrush(GetBkColor(hDC));
      hBrT=SelectObject(hMemDC, hBr);
      
      //Force conversion of the monochrome to stay black and white.
      crText=SetTextColor(hMemDC, 0L);
      crBack=SetBkColor(hMemDC, RGB(255, 255, 255));
      
      /*
      * Where the monochrome mask is 1, Blt the brush; where the mono mask
      * is 0, leave the destination untouches.  This results in painting
      * around the image with the background brush.  We do this first
      * in the temporary bitmap, then put the whole thing to the screen.
      */
      BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMid, 0, 0, ROP_DSPDxax);
      BitBlt(hDC,    x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
      
      
      SetTextColor(hMemDC, crText);
      SetBkColor(hMemDC, crBack);
      
      SelectObject(hMemDC, hBrT);
      DeleteObject(hBr);
      
      DeleteDC(hMemDC);
      DeleteDC(hDCSrc);
      DeleteDC(hDCMid);
      DeleteObject(hBmpT);
      DeleteObject(hBmpMono);
      
      return;
}
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
This article describes how to add a user-defined command button to the Windows 7 Explorer toolbar.  In the previous article (http://www.experts-exchange.com/A_2172.html), we saw how to put the Delete button back there where it belongs.  "Delete" is …
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now