Pár tipů pro práci s CD mechanikou v C++

V tomto článku si ukážeme pár možností pro ovládání a detekci různých událostí CD mechaniky.

Ukážeme si, jak zjistit jednotky CD v počítači, jak vybranou jednotku programově otevřít a zavřít, jak detekovat otevření a zavření dvířek uživatelem nebo jiným programem a jak detekovat automatické spuštění programu z CD mechaniky. Ukázková aplikace je MFC aplikace založená na dialogovém okně.

Klepněte pro větší obrázek

Zjištění přítomných CD mechanik

Nejprve si ukážeme, jak zjistit písmenné označení mechanik přítomných v počítači. Vytvoříme si funkci, která nám (při inicializaci dialogu) naplní list-box označením nalezených jednotek. Použijeme funkci

DWORD GetLogicalDrives(VOID);

která nám vrátí bitovou masku reprezentující dostupné CD mechaniky, a dále funkci

UINT GetDriveType(
  LPCTSTR lpRootPathName  // kořenový adrersář
);

Její návratová hodnota určuje typ zařízení. Pro jednotky CD (ale i DVD nebo CD-RW) nám funkce vrátí hodnotu DRIVE_CDROM. Celá naše zmíněná funkce vypadá potom takto:

int CUkazkaDlg::GetCDDrives()
{
  int pos = 0;
  DWORD dwList = GetLogicalDrives();
  int index = 0;
  TCHAR chDrive[4];
  lstrcpy(chDrive, "x:\\");
  while ( dwList )
  {
    if ( dwList & 1 )
    {
      chDrive[0] = 0x41 + pos;
      if ( GetDriveType(chDrive) == DRIVE_CDROM )
      {
        SendDlgItemMessage(IDC_LIST_CD, LB_ADDSTRING, 0, (LPARAM)chDrive);
        index++;
      }
    }
    dwList >>= 1;
    pos++;
  }
  return index;
}

Otevírání a zavírání CD mechaniky

Nyní se podívejme, jak programově otvírat a zavírat vybranou mechaniku. Použijeme příkazů MCI (Media Kontrol Interface), konkrétně funkci

MCIERROR mciSendCommand(
  MCIDEVICEID IDDevice,
  UINT uMsg,
  DWORD fdwCommand,
  DWORD dwParam
);

Podrobný popis této funkce a jejích parametrů a možností naleznete v nápovědě, podívejme se na její použití v případě otevření CD mechaniky:

BOOL CUkazkaDlg::OpenCD(LPCTSTR lpDrive)
{
  TCHAR chDrive[4];
  MCI_OPEN_PARMS mop;
  DWORD dwFlags;
  strcpy(chDrive, "D:");
  ZeroMemory(&mop, sizeof(MCI_OPEN_PARMS));
  mop.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
  chDrive[0] = lpDrive[0];
  dwFlags = MCI_OPEN_TYPE |  MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE | MCI_OPEN_ELEMENT;
  mop.lpstrElementName = chDrive;
  if ( mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD)&mop) == 0 )
  {
    mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0);
    mciSendCommand(mop.wDeviceID, MCI_CLOSE, MCI_WAIT, 0);
  }
  return TRUE;
}

Pro případ, že požadujeme zavření CD mechaniky, se celá funkce bude lišit pouze v jediném řádku

// …..
  if ( mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD)&mop) == 0 )
  {
    mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0);
    mciSendCommand(mop.wDeviceID, MCI_CLOSE, MCI_WAIT, 0);
  }
  return TRUE;

Jak tyto funkce použít? Jako parametr, který zadáme do prvku struktury MCI_OPEN_PARAMS, musíme zadat písmenné označeni jednotky CD. Naší funkci tedy v našem případě předáme obsah vybraného řádku list-boxu:

void CUkazkaDlg::OnOpenCD()
{
  TCHAR chDrive[6];
  SendDlgItemMessage(IDC_LIST_CD, LB_GETTEXT,
    SendDlgItemMessage(IDC_LIST_CD, LB_GETCURSEL, 0,0), (LPARAM)chDrive);
  OpenCD(chDrive);
}

Detekce otevření a zavření

Nyní si ukažme, jak zachytávat některé události CD mechaniky. Pro tento účel je důležité zachycení zprávy WM_DEVICECHANGE. Tato zpráva je posílána všem aplikacím jako oznámení o změně na některém zařízení v počítači. Parametr wParam této zprávy určuje, o jakou událost se jedná. Nás budou zajímat 2 hodnoty tohoto parametru:
  • DBT_DEVICEARRIVAL – došlo k vložení zařízení, tedy v našem případě CD disku do mechaniky
  • DBT_DEVICEREMOVECOMPLETE – zařízení (CD disk) bylo vyjmuto z mechaniky
Parametr lParam této zprávy je adresa struktury

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

která obsahuje další informace o události na zařízení. Pokud prvek dbch_devicetype je roven DBT_DEVTYP_VOLUME (což je i v případě CD disku), tato struktura je pak

typedef struct _DEV_BROADCAST_VOLUME {
  DWORD dbcv_size;
  DWORD dbcv_devicetype;
  DWORD dbcv_reserved;
  DWORD dbcv_unitmask;
  WORD dbcv_flags;
} DEV_BROADCAST_VOLUME;
typedef DEV_BROADCAST_VOLUME *PDEV_BROADCAST_VOLUME;

Pokud pak prvek dbcv_flags obsahuje DBTF_MEDIA, jde o médium (v našem případě CD disk) v mechanice. Podívejme se nyní konkrétně, jak lze tuto zprávu zpracovat. Když přímo v proceduře okna vytvoříme „switch“ na zprávy, bude příslušná část funkce WindowProc vypadat třeba takto:

// …..
  switch ( message )
  {
    case WM_DEVICECHANGE:
      lpdb = (PDEV_BROADCAST_HDR)lParam;
      switch ( wParam )
      {
        case DBT_DEVICEARRIVAL:
          if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
          {
            lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
            if (lpdbv->dbcv_flags & DBTF_MEDIA)
            {
              if ( SendDlgItemMessage(IDC_NOTIFY_INSERT, BM_GETCHECK, 0, 0) == BST_CHECKED)
              {
                wsprintf(chMessage, "Do jednotky %c: byl vložen disk\n",
                  GetDriveFromMask(lpdbv->dbcv_unitmask));
                MessageBox(chMessage);
              }
            }
          }
          break;
        case DBT_DEVICEREMOVECOMPLETE:
          if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
          {
            lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
            if (lpdbv->dbcv_flags & DBTF_MEDIA)
            {
              if ( SendDlgItemMessage(IDC_NOTIFY_REMOVE, BM_GETCHECK, 0, 0) == BST_CHECKED)
              {
                wsprintf(chMessage, "Z jednotky %c: byl vyjmut disk\n",
                  GetDriveFromMask(lpdbv->dbcv_unitmask));
                MessageBox(chMessage);
              }
            }
          }
          break;
      }
      break;
// …..
  }

Funkce, která převádí získanou bitovou masku, určující zařízení, na písmenné označení CD mechaniky, vypadá takto:

TCHAR CUkazkaDlg::GetDriveFromMask(ULONG mask)
{
  CHAR i;
  for (i = 0; i < 26; ++i)
  {
    if (mask & 0x1)
      break;
    mask = mask >> 1;
  }
  return (i + `A`);
 
}

Detekce automatického spuštění

Nyní si ještě ukážeme, jak detekovat automatické spuštění programu z CD disku. Pro tento účel musíme nejdříve registrovat zprávu "QueryCancelAutoPlay" pomocí funkce

UINT RegisterWindowMessage(
  LPCTSTR lpString  // message string
);

Tuto zprávu pak systém posílá aplikaci na popředí. Znamená to tedy, že tímto způsobem můžeme autoplay detekovat pouze tehdy, když je naše aplikace na popředí.

Vytvoříme si tedy členskou proměnnou

UINT m_AutoPlayMessage;

a ve funkci InitDialog zaregistrujeme zprávu:

  m_AutoPlayMessage = RegisterWindowMessage(LPCTSTR("QueryCancelAutoPlay"));

Zbytek již zařídíme opět v proceduře okna WindowProc:

switch ( message )
{
// ….  Tady jsou handlery ostatních zpráv

  default:
    if ( message == m_AutoPlayMessage )
      if ( SendDlgItemMessage(IDC_NOTIFY_AUTORUN, BM_GETCHECK, 0, 0) == BST_CHECKED)
          MessageBox("CD disk byl automaticky spuštěn.");
    break;
}

Zde si můžete stáhnout ukázkový projekt cd_drive.zip (30 kB).

Diskuze (10) Další článek: Transmeta vyhodila svého CEO

Témata článku: Software, Programování, Code, Switch, Písmenné označení, Pár, Message, Pár tipů


Určitě si přečtěte

16 tipů a vychytávek, se kterými dokonale ovládnete komunitní navigaci Waze

16 tipů a vychytávek, se kterými dokonale ovládnete komunitní navigaci Waze

** Waze není jen navigace – je to i sociální síť s dopravními informacemi ** Mobilní aplikace skýtá široké možnosti nastavení ** Vybrali jsme pro vás 16 nejzajímavějších tipů a triků

Karel Kilián | 48

20 tipů a triků pro Gmail: Užitečné maličkosti, které zefektivní práci s e-maily

20 tipů a triků pro Gmail: Užitečné maličkosti, které zefektivní práci s e-maily

** V Gmailu je řada užitečných funkcí, které možná všechny neznáte ** Odeslání mailu můžete například pozdržet či naplánovat na později ** Nad Gmailem můžete mít s několika triky daleko lepší kontrolu

Karel Kilián | 25

Pojďme programovat elektroniku: Postavíme bezpečnostní systém za 30 Kč

Pojďme programovat elektroniku: Postavíme bezpečnostní systém za 30 Kč

** Před pár týdny jste si mohli v akci koupit Wi-Fi desku za jeden dolar ** Nám už TTGO T-Display dorazila do redakce ** Připojíme k ní jazýčkový kontakt a vyrobíme bezpečnostní systém

Jakub Čížek | 30

Antivir zdarma: 8 bezplatných řešení, která zatočí s havětí v počítači

Antivir zdarma: 8 bezplatných řešení, která zatočí s havětí v počítači

** Součástí Windows 10 je integrovaný antivirový program. Stačí to? ** Představíme vám sedm aplikací na boj proti virům a malwaru ** Všechny jsou k dispozici zdarma a některé ani nemusíte instalovat

Karel Kilián | 26

Co zabírá nejvíce místa na disku? Těchto 10 nástrojů odhalí největší žrouty dat

Co zabírá nejvíce místa na disku? Těchto 10 nástrojů odhalí největší žrouty dat

** Je vhodné jednou za čas zanalyzovat, co vám leží na disku ** Poradíme vám nástroje, kterými zjistíte, jaká data uchováváte ** Podle výsledků můžete optimalizovat svá data či úložiště

Karel Kilián | 49



Aktuální číslo časopisu Computer

Speciál o přechodu na DVB-T2

Velký test herních myší

Super fotky i z levného mobilu

Jak snadno upravit PDF