CD Insert Notification in WinXP

Tim Golden tim.golden at iname.com
Wed Jan 21 15:20:44 EST 2004


"Tim Golden" <tim.golden at viacom-outdoor.co.uk> wrote in message
news:mailman.575.1074679049.12720.python-list at python.org...
> >Hi,
> >
> >I'm using Python 2.3 on a Win XP box, and I'm trying to find
> >if there's
> >a library of some sort that will give you a callback (or something
> >comparable) when a new disc is inserted into a CD Rom drive.
> >I've done a
> >little googling and nothing's come up, so I'm not holding my breath. :)
> >
>
> Initial response, prior to further investigation:
> [... snip PyGame suggestion ...]

OK. After further investigation, what you want to do is trap
the WM_DEVICECHANGED message. From a combination of Googling,
the following article:

http://www.undu.com/Articles/980221b.htm

and MSDN KB Q163503 (HOWTO: Getting Notification of CD-ROM Insertion
 or Removal)

and the oh-so-useful ctypes:

http://starship.python.net/crew/theller/ctypes/

and some example by Itamar Shtull-Trauring of using the win32gui

I've managed to cobble together the following working example.
I'm quite sure it could be improved by someone who knew what
he was talking about, but it does work. (At least on my laptop).

<code>

import win32api, win32con, win32gui
from ctypes import *

#
# Device change events (WM_DEVICECHANGE wParam)
#
DBT_DEVICEARRIVAL = 0x8000
DBT_DEVICEQUERYREMOVE = 0x8001
DBT_DEVICEQUERYREMOVEFAILED = 0x8002
DBT_DEVICEMOVEPENDING = 0x8003
DBT_DEVICEREMOVECOMPLETE = 0x8004
DBT_DEVICETYPESSPECIFIC = 0x8005
DBT_CONFIGCHANGED = 0x0018

#
# type of device in DEV_BROADCAST_HDR
#
DBT_DEVTYP_OEM = 0x00000000
DBT_DEVTYP_DEVNODE = 0x00000001
DBT_DEVTYP_VOLUME = 0x00000002
DBT_DEVTYPE_PORT = 0x00000003
DBT_DEVTYPE_NET = 0x00000004

#
# media types in DBT_DEVTYP_VOLUME
#
DBTF_MEDIA = 0x0001
DBTF_NET = 0x0002

WORD = c_ushort
DWORD = c_ulong

class DEV_BROADCAST_HDR (Structure):
  _fields_ = [
    ("dbch_size", DWORD),
    ("dbch_devicetype", DWORD),
    ("dbch_reserved", DWORD)
  ]

class DEV_BROADCAST_VOLUME (Structure):
  _fields_ = [
    ("dbcv_size", DWORD),
    ("dbcv_devicetype", DWORD),
    ("dbcv_reserved", DWORD),
    ("dbcv_unitmask", DWORD),
    ("dbcv_flags", WORD)
  ]

def drive_from_mask (mask):
  n_drive = 0
  while 1:
    if (mask & (2 ** n_drive)): return n_drive
    else: n_drive += 1

class Notification:

  def __init__(self):
    message_map = {
      win32con.WM_DEVICECHANGE : self.onDeviceChange
    }

    wc = win32gui.WNDCLASS ()
    hinst = wc.hInstance = win32api.GetModuleHandle (None)
    wc.lpszClassName = "DeviceChangeDemo"
    wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
    wc.hCursor = win32gui.LoadCursor (0, win32con.IDC_ARROW)
    wc.hbrBackground = win32con.COLOR_WINDOW
    wc.lpfnWndProc = message_map
    classAtom = win32gui.RegisterClass (wc)
    style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
    self.hwnd = win32gui.CreateWindow (
      classAtom,
      "Device Change Demo",
      style,
      0, 0,
      win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
      0, 0,
      hinst, None
    )

  def onDeviceChange (self, hwnd, msg, wparam, lparam):
    #
    # WM_DEVICECHANGE:
    #  wParam - type of change: arrival, removal etc.
    #  lParam - what's changed?
    #    if it's a volume then...
    #  lParam - what's changed more exactly
    #
    dev_broadcast_hdr = DEV_BROADCAST_HDR.from_address (lparam)

    if wparam == DBT_DEVICEARRIVAL:
      print "Something's arrived"

      if dev_broadcast_hdr.dbch_devicetype == DBT_DEVTYP_VOLUME:
        print "It's a volume!"

        dev_broadcast_volume = DEV_BROADCAST_VOLUME.from_address (lparam)
        if dev_broadcast_volume.dbcv_flags & DBTF_MEDIA:
          print "with some media"
          drive_letter = drive_from_mask
(dev_broadcast_volume.dbcv_unitmask)
          print "in drive", chr (ord ("A") + drive_letter)

    return 1

if __name__=='__main__':
  w = Notification ()
  win32gui.PumpMessages ()

</code>

TJG





More information about the Python-list mailing list