Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Intercept the insertion/removal of a CD/DVD

0.00/5 (No votes)
8 Apr 2005 1  
How to intercept a new media in the drive, using WM_DEVICECHANGE message.

Introduction

While working (with Borland C++), I've found myself in the trouble of wiritng write an application that reacts to the insertion/removal of a media (CD/DVD) in one of the PC's drives.

The Event

After some surfing on the web, I found that the best way to do this was to use a handler to a specific Windows message, WM_DEVICECHANGE, that is sent by the system when a medium is inserted or removed, as specified in an MSDN page.

The Handler

I've used the WindosProc function to override the default message handler of the application, WndProc, to manage the WM_DEVICECHANGE message. The first thing to do is to redirect the WindowProc function to our message handler, called FormWndProc.

WindowProc=FormWndProc;

The function is defined as:

void __fastcall TFormSpyMsg::FormWndProc(Messages::TMessage &Message)
{
    switch (Message.Msg)
    {
        case WM_DEVICECHANGE:
            handle_WM_DEVICECHANGE(Message);
            break;
        default:
            WndProc(Message);
  }
}

It writes down the handler and is used to handle the WM_DEVICEMESSAGE message. To manage both cases, insertion and removal, we have to understand the parameters of the message we receive, specified in TMessage.LParam. This is a pointer to a DEV_BROADCAST_HDR structure:

typedef struct DEV_BROADCAST_HDR 
{
    DWORD dbch_size;
    DWORD dbch_devicetype;
    DWORD dbch_reserved;
} 
DEV_BROADCAST_HDR, 
*PDEV_BROADCAST_HDR;

The media type is defined in dbch_devicetype. With another cast, from PDEV_BROADCAST_HDR to PDEV_BROADCAST_VOLUME, we could retrieve the flags that identify the media, lpdbv -> dbcv_flags. The identifier of the drive that has been changed is specified in lpdbv ->dbcv_unitmask. To decode this value, I've used a function found on the MSDN page:

char FirstDriveFromMask (ULONG unitmask)
{
    char i;
    for (i = 0; i < 26; ++i)
    {
        if (unitmask & 0x1) break;
        unitmask = unitmask >> 1;
    }
    return (i + 'A');
}

The handler is coded below:

void TFormSpyMsg::handle_WM_DEVICECHANGE(TMessage Msg)
{
    PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)Msg.LParam;
    AnsiString smsg;
    char drive;

    switch(Msg.WParam)
    {
        case DBT_DEVICEARRIVAL:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
            {
                PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
                if (lpdbv -> dbcv_flags & DBTF_MEDIA)
                {
                    drive = FirstDriveFromMask(lpdbv ->dbcv_unitmask);
                    smsg = "Device inserte in drive " + 
                        AnsiString(drive);
                    Memo1->Lines->Add(smsg);
                }
            }
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
            {
                PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
                if (lpdbv -> dbcv_flags & DBTF_MEDIA)
                {
                    drive = FirstDriveFromMask(lpdbv ->dbcv_unitmask);
                    smsg = "Device removed from drive " + 
                    AnsiString(drive);
                    Memo1->Lines->Add(smsg);
                }
            }
            break;
        default: ;
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here