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í, Switch, Pár, Písmenné označení, Pár tipů, Message, Code


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

Lidl buduje chytrou domácnost, propojí všechno se vším
Lukáš Václavík
LidlChytrá domácnostIoT
Micro:bit V2: Tuto destičku plnou čipů dokáže naprogramovat i vaše babička

Micro:bit V2: Tuto destičku plnou čipů dokáže naprogramovat i vaše babička

** Chcete se teď hned naučit programovat čipy? ** Nechcete nic instalovat a číst zdlouhavé manuály? ** Naprogramujeme si Micro:bit, který zahraje Tichou noc

Jakub Čížek | 33

Jakub Čížek
Pojďme programovat elektronikuProgramování pro děti
Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

** Kvalita GPS ve městech občas stojí za starou bačkoru ** Mohou za to odrazy signálu od okolních budov ** Google má jejich 3D model, a tak spolupracuje s výrobci GPS čipů

Jakub Čížek | 40

Jakub Čížek
NavigaceTechnologieGoogle
Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

** Kde jsou ty doby, kdy měl skoro každý doma Photoshop ** Photoshop a Premiere Pro od kamaráda nebo z warezu ** Dnes už to nemá smysl, existuje totiž hromada laciných alternativ

Jakub Čížek | 90

Jakub Čížek
Grafický editorStřih videa
Pozor na tyto doplňky pro Chrome a Edge. Mohou obsahovat malware, varuje Avast
Jakub Čížek
MalwareProhlížeče
Šéf Spotify: Budeme zdražovat. Náš obsah se zlepšil
Markéta Mikešová
PředplatnéSpotify
Air Bank, Fio banka a MONETA zakládají alianci pro bankovní identitu
Jakub Čížek
BankaČeskoeGovernment

Aktuální číslo časopisu Computer

Jak prodloužit výdrž notebooku

Velké testy: gamepady a inkoustové tiskárny

Důkladný test Sony Playstation 5