Click here to Skip to main content
15,914,111 members
Articles / Desktop Programming / MFC

Detecting when drives are added or removed

Rate me:
Please Sign up or sign in to vote.
4.30/5 (22 votes)
4 Jul 2007CPOL1 min read 114K   3.2K   57   37
Dealing with the WM_DEVICECHANGE message to detect volumes being added or removed.

Screenshot - Drive_Detect.jpg

Introduction

This is possibly my smallest article, and just shows a method of detecting when drives are added to or removed from the system. What you do with that information is up to you!

Background

I was answering a question from Akin Ocal yesterday, when Matthew Faithful came up with a much deeper answer than mine.

In a fit of pique / curiosity, I thought I'd come up with a different way of doing what he described, using Windows messages to do the heavy lifting. As I had to do a bit of digging from barely remembered details, I thought I'd share the work with others.

Using the code

I created a blank MFC dialog project, and added a handler for WM_DEVICECHANGE. The MFC handler structure exists, but it could not be added with the Class Wizard, so I typed it in manually.

C++
ON_WM_DEVICECHANGE ()

I then added the actual handler, which does nothing except log the fact that a drive has been added or removed.

C++
BOOL CDriveDetectDlg::OnDeviceChange( UINT nEventType, DWORD dwData )
{
    BOOL bReturn = CWnd::OnDeviceChange (nEventType, dwData);

    DEV_BROADCAST_VOLUME *volume = (DEV_BROADCAST_VOLUME *)dwData;
    CString log;

    if (nEventType == DBT_DEVICEARRIVAL)
    {
        if (volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
        {
            for (int n = 0; n < 32; n++)
            {
                if (IsBitSet (volume->dbcv_unitmask, n))
                {
                    log.Format ("Drive %c: Inserted\n", n + 'A');
                    m_DetectLog.AddString (log);
                }
            }
        }
    }

    if (nEventType == DBT_DEVICEREMOVECOMPLETE)
    {
        if (volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
        {
            for (int n = 0; n < 32; n++)
            {
                if (IsBitSet (volume->dbcv_unitmask, n))
                {
                    log.Format ("Drive %c: Removed\n", n + 'A');
                    m_DetectLog.AddString (log);
                }
            }
        }
    }

    return bReturn;
}

As you can see, there's not a vast amount of code for the job.

Updates

  • 27/6/2007 - Little drive icons added next to the drives being added / removed. The credit for steering me in the right direction (and providing some code for me to steal^h^h^h^h^hreuse) goes to dgendreau.
  • 20/6/2007 - Original version posted.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Sweden Sweden
I have now moved to Sweden for love, and recently married a lovely Swede.


-----------------
I started programming on BBC micros (6502) when I was six and never quite stopped even while I was supposed to be studying physics and uni.

I've been working for ~13 years writing software for machine control and data analysis. I now work on financial transaction transformation software, for a Software company in Gamlastan, Stockholm.
Look at my articles to see my excellent coding skills. I'm modest too!

Comments and Discussions

 
QuestionWhat about insert devices Pin
VC Spark3-Jul-07 2:28
VC Spark3-Jul-07 2:28 
AnswerRe: What about insert devices Pin
Iain Clarke, Warrior Programmer3-Jul-07 4:16
Iain Clarke, Warrior Programmer3-Jul-07 4:16 
GeneralRe: What about insert devices Pin
VC Spark4-Jul-07 2:32
VC Spark4-Jul-07 2:32 
GeneralNot bad! Pin
Jon Feider25-Jun-07 13:44
Jon Feider25-Jun-07 13:44 
GeneralRe: Not bad! Pin
Iain Clarke, Warrior Programmer25-Jun-07 22:20
Iain Clarke, Warrior Programmer25-Jun-07 22:20 
GeneralRe: Not bad! Pin
Jon Feider25-Jun-07 22:59
Jon Feider25-Jun-07 22:59 
GeneralRe: Not bad! Pin
Iain Clarke, Warrior Programmer25-Jun-07 23:29
Iain Clarke, Warrior Programmer25-Jun-07 23:29 
GeneralEasy way to use explorer icons. Pin
dgendreau20-Jun-07 11:08
dgendreau20-Jun-07 11:08 
Hi Iain. Nice article. I was just wondering about this topic last week. Smile | :)

Re: Drive Icons
There is no need to make up a bitmap and your own image list. The image list built into Windows Explorer is readily accessible. First though, we need 3 helper functions to make the sample code more readable.



// GetShellImageList() - returns a handle to the shell icon image list
HIMAGELIST GetShellImageList()
{
SHFILEINFO sfi;
return (HIMAGELIST) SHGetFileInfo( "C:\\", 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON );
}

// GetShellIcon() - returns the shell icon subscript associated with a given pathname
// NOTE: I believe a trailing backslash is necessary
int GetShellIcon(LPCTSTR pszPath, UINT uFlags = 0 )
{
SHFILEINFO sfi;
SHGetFileInfo( pszPath, 0, &sfi, sizeof(sfi), uFlags|SHGFI_SYSICONINDEX|SHGFI_SMALLICON );
return sfi.iIcon;
}

// GetVolumeName() - returns the volume name of a drive
// NOTE: I believe a trailing backslash necessary. eg. "C:\\".
CString GetVolumeName(CString sDrive)
{
char pszVolName[MAX_PATH]="";
sDrive=sDrive.Left(1);
GetVolumeInformation( sDrive+":\\", pszVolName, MAX_PATH, 0, 0, 0, 0, 0 );
return CString(pszVolName) + "(" + sDrive + "Smile | :) ";
}



How to use shell icons in your app:

1) After your tree or list control is created (eg. in OnInitDialog), connect your CImageList to the shell icon image list and your tree or list controls:
if ( m_ImageList.Attach( GetShellImageList() ) )
m_Tree.SetImageList( &m_ImageList, TVSIL_NORMAL );

2) When inserting items into your list or tree control, Use GetShellIcon(path) to get an icon id. Eg. if we wanted the icon(s) for "F:", we do this:
int nDriveIcon = GetShellIcon( "F:\\", 0 );
int nDriveIconSelected = GetShellIcon( "F:\\", SHGFI_OPENICON | SHGFI_SELECTED );
m_Tree.InsertItem( GetVolumeName("F:\\"), nDriveIcon, nDriveIconSelected );

3) And while exiting, dont forget to Detach your CImageList from the system image list before it passes out of scope:
CMyDialog::~CMyDialog()
{
if (m_ImageList) m_ImageList.Detach();
}

And thats about it. I hope that helps.
-Dan G.

PS. Hmmm... maybe I should write a CShellImageList class to make this even more compact?

GeneralRe: Easy way to use explorer icons. Pin
Iain Clarke, Warrior Programmer20-Jun-07 22:40
Iain Clarke, Warrior Programmer20-Jun-07 22:40 
GeneralRe: Easy way to use explorer icons. Pin
dgendreau21-Jun-07 7:49
dgendreau21-Jun-07 7:49 
GeneralRe: Easy way to use explorer icons. Pin
dgendreau21-Jun-07 8:09
dgendreau21-Jun-07 8:09 
GeneralRe: Easy way to use explorer icons. Pin
Iain Clarke, Warrior Programmer21-Jun-07 21:56
Iain Clarke, Warrior Programmer21-Jun-07 21:56 
GeneralRe: Easy way to use explorer icons. Pin
AlexEvans26-Jun-07 19:24
AlexEvans26-Jun-07 19:24 
GeneralNice Pin
DaTxomin20-Jun-07 0:10
DaTxomin20-Jun-07 0:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.