이번글은 USB 장치를 연결할 때 연결/해제를 감지하기 위한 방법을 정리합니다. Dialog 기반 App에서 검증된 방법입니다.

1. 메인 윈도우에서 디바이스 감지

먼저 메인 Dialog에 메시지 맵을 추가합니다. (SDI/MDI에서는 MainFrame에 등록하면 됩니다.)

Class Wizard에서는 찾을 수 없으니 수동 드록하면 됩니다.

1. header 정의

// DialogBasedDlg.h
class CDialogBasedDlg {
  ...

  // Generated message map functions
protected:
  afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData);
};

2. cpp 메시지 함수 등록

메시지 맵에는 기존 등록된 메시지 함수 ON_WM_DEVICECHANGE()를 사용합니다. 아래의 예처럼 DBT_DEVICEARRIVAL 또는 DBT_DEVICEARRIVAL 이벤트를 통해 연결/해제를 감지 할 수 있습니다.

// DialogBasedDlg.cpp
BEGIN_MESSAGE_MAP(CDialogBasedDlg, CDialogEx)
  ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()

BOOL CDialogBasedDlg::OnDeviceChange(UINT nEventType, DWORD_PTR dwData)
{
  switch(nEventType)
  {
    case DBT_DEVICEARRIVAL:
      AfxMessageBox(_T("USB Device Connected"));
      break;
    case DBT_DEVICEREMOVECOMPLETE:
      AfxMessageBox(_T("USB Device Disconnected"));
      break;
  }
  return TRUE;
}

2. 메인 윈도우 외에서 디바이스 이벤트 받기

Toolbar나 다른 dialog등에서는 위와 같이 ON_WM_DEVICECHANGE()를 등록하여 사용할 수 없습니다. 그러나 기능적인 분리를 위해선 Toolbar나 기타 dialog에서 필요할 때가 있습니다. 가령 Device 연결을 위한 Toolbar를 제작할 때처럼요.

먼저 RegisterDeviceNotification 함수를 통해 이벤트를 받을 장치를 등록합니다.

1. header 정의

// DialogBasedDlg.h
class CDialogBasedDlg {
  ...

  // Generated message map functions
protected:
  afx_msg LRESULT OnMsgDeviceChange(WPARAM wParam, LPARAM lParam);
};

2. cpp 디바이스 메시지 등록

각 디바이스의 GUID를 참고하여 필요한 GUID list만을 만들어 사용하시면 됩니다. 저는 GUID_DEVINTERFACE_USB_DEVICE에 해당하는 USB 부분만 사용했습니다.

// DialogBasedDlg.cpp
static const GUID GUID_DEVINTERFACE_LIST[] =
{
    // GUID_DEVINTERFACE_USB_DEVICE
    { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },

    //// GUID_DEVINTERFACE_DISK
    //{ 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, //0x8b } },

    //// GUID_DEVINTERFACE_HID,
    //{ 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, //0x30 } },
    //         
    //// GUID_NDIS_LAN_CLASS
    //{ 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, //0x8c } }

    //// GUID_DEVINTERFACE_COMPORT
    //{ 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, //0x73 } },

    //// GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
    //{ 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, //0x18 } },

    //// GUID_DEVINTERFACE_PARALLEL
    //{ 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, //0x5C } },

    //// GUID_DEVINTERFACE_PARCLASS
    //{ 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } }
};

BOOL CDialogBasedDlg::OnInitDialog()
{
  ...
  DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
  ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
  NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  for (INT i=0; i<_countof(GUID_DEVINTERFACE_LIST); i++)
  {
    NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];
    RegisterDeviceNotification(GetSafeHwnd(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
  }
}

WM_DEVICECHANGE 메시지를 맵에 등록합니다. 이제 wParam의 값으로 1장에서와 같이 연결/해제를 감지 할 수 있습니다.

BEGIN_MESSAGE_MAP(CDialogBasedDlg, CDialogEx)
  ON_MESSAGE(WM_DEVICECHANGE, &CDialogBasedDlg::OnMsgDeviceChange)
END_MESSAGE_MAP()

LRESULT CDialogBasedDlg::OnMsgDeviceChange(WPARAM wParam, LPARAM lParam)
{
  PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
  if ( pHdr->dbch_devicetype==DBT_DEVTYP_DEVICEINTERFACE )
  {
    switch(wParam)
    {
      case DBT_DEVICEARRIVAL:
        AfxMessageBox(_T("USB Device Connected"));
        break;
      case DBT_DEVICEREMOVECOMPLETE:
        AfxMessageBox(_T("USB Device Disconnected"));
        break;
    }
  }
  return 0;
}

댓글남기기