Запис CD-DVD дисків у Delphi - все про IT та програмування
Written on 30 Січня 2009 . Posted in Delphi
Технологія, яка описуватиметься в цій статті, це технологія IMAPI v2.0. Однією статтею цю технологію описати неможливо, тому в цій статті будуть описані тільки основи роботи з IMAPI2. Ця технологія досить нова, і підтримується операційними системами Windows XP SP2, 2003 Server, Vista і т.д. Тобто. Перед тим як використовувати технологію IMAPI2 слід переконатися, що операційна система на комп'ютері, на якому буде працювати програма, є як мінімум однією з перерахованих вище або більше нова (наприклад, Windows 7). "Уособленням" IMAPI2 є дві бібліотеки imapi2.dll і imapi2fs.dll. Перед використанням цієї технології ви або програма, яка буде працювати на комп'ютері, повинні переконатися, що ці дві DLL існують. Якщо їх немає, слід встановити оновлення KB932716 з вузла Microsoft.com (посилання на скачку оновлення, а також оновлення для Win XP дивіться в кінці статті).
Отже, переконалися, що IMAPI v2 підтримується операційною системою. Тепер нам потрібні файли заголовків, вірніше нам потрібно встановити компоненти для запису дисків. Програмістам С++ по цій частині простіше, так як у Platform SDK є файли заголовків і їх треба тільки підключити щоб скористатися класами для запису дисків. Але у Delphi теж не дуже складно, у Delphi треба імпортувати бібліотеку типів. Після імпорту бібліотеки типів Delphi сама створить компоненти та класи для запису дисків та встановить їх на палітру. Що нам треба для цього зробити. Поясню, як імпортувати бібліотеку типів для користувачів Delphi 7 (англ). Вибираємо меню Project -> Import Type Library. У вікні, що відкрилося, у списку знаходимо «Microsoft IMAPI2 BaseFunctionality (Version 1.0)», внизу ставимо галочку «Generate Component Wrapper» (за умовчанням вона поставлена), натискаємо кнопку «Install». Вибираємо вкладку "Into new package" і вибираємо файл, куди буде збережено пакет, натискаємо кнопку ОК. Після чого майстер відразу запропонує встановити ці компоненти, натискаємо Yes після установки перезавантажуємо Delphi. За промовчанням нові компоненти повинні інсталюватися на вкладці ActiveX. Після цього робимо те саме з пунктом «Microsoft IMAPI2 File System Image Creator (Version 1.0)».
Отже, компоненти встановлені можна програмувати. Як вже було сказано, Delphi сама створює класи та компоненти, які є оболонками навколо відповідних COM інтерфейсів, що максимально спрощує програмування. Але є один мінус. Якщо ми використовуємо інтерфейси безпосередньо, то якщо їхня робота методів закінчується невдало, то вони просто повертають помилку, коли ми використовуємо «дельфійські» класи, то методи класів у разі невдачі генерують винятки, тому рекомендується укладати виклики методів і важливі ділянки коду укладати в блоки try / except. Під час налагодження (коли ми запускаємо програму натисканням кнопки F9) повідомлення про помилки, все одно виводяться, що досить дратівливо. У цій статті будуть описані методи COM інтерфейсів, оскільки знаючи методи і назви COM інтерфейсів, ми зможемо писати програми не тільки на Delphi, але і на С++ та VB. Методи та властивості компонентів Delphi описуватись не будуть, тому що в них і так все інтуїтивно зрозуміло та просто.
Перше що треба зробити - це отримати список приводів, які можуть марнувати диски і до яких можна отримати доступ через IMAPI2. Це можна зробити за допомогою інтерфейсу IDiscMaster2. Перше що нам треба дізнатися це чи підтримує хоча б один привід в системі записдисків і до нього можна звернутись через інтерфейс IMAPI2. Для цього необхідно викликати метод IDiscMaster2::get_IsSupportedEnvironment. Якщо ми отримаємо результат true, то в системі є хоча б один придатний для нас привід. Для отримання загальної кількості приводів у системі потрібно викликати метод IDiscMaster2::get_Count. Для отримання унікального ідентифікатора приводу необхідно викликати метод IDiscMaster2::get_Item.
Наступний пункт – це ініціалізація приводу та отримання від нього інформації, поки нам знадобиться тільки VendorId та ProductId приводу. Саме ці два рядки дають нам назвою приводу, яка виводиться в диспетчері пристроїв. Для отримання цих двох ідентифікаторів необхідно викликати методи IDiscRecorder2::get_VendorId, IDiscRecorder2::get_ProductId. Зрозуміло, що спочатку потрібно викликати метод IDiscRecorder2::InitializeDiscRecorder, який приймає унікальний ідентифікатор приводу, отриманий від методу IDiscMaster2::get_Item.
Отже, займемося «дельфеєю». Ставимо на форму компонентів TMsftDiscMaster2 і TMsftDiscRecorder2. Далі наведу код отримання списку доступних нам рекордерів:
У combobox будуть виведені всі доступні рекордери. Якщо будь-який рекордер буде недоступний, замість його імені буде виведено «—».
Їдемо далі, ми знайшли потрібний рекордер, тепер треба створити образ диска для запису. За створення образу відповідає інтерфейс IFileSystemImage. Файли та папки в цьому інтерфейсі є інтерфейсами IFsiFileItem і IFsiDirectoryItem. Для отримання кореневої папки необхідно викликати метод IFileSystemImage::get_Root. Отримавши інтерфейс кореневої папки, можна спокійно додавати в образ файли і папки. Є кілька методів додавання файлів та папок у образ, я опишу найпростіші з них.
Щоб додати папку з усіма її файламизручно використовувати метод IFsiDirectoryItem::AddTree, йому треба передати два параметри. Перший параметр це шлях до папки, другий параметр має тип Boolean, якщо він дорівнює true, то в образ буде додана сама папка і всі файли і папки, що містяться в ній, якщо параметр дорівнює false, то в образ будуть додані тільки файли і папки, що містяться у шуканій (пошукова папка не буде додана).
У цій функції нам цікаво лише два параметри, перший та останній. Перший параметр - це шлях до шуканого файлу, в останній параметр буде збережено потік із вмістом файлу. Тепер можна написати код, який створює образ диска з файлів шляху, до яких занесені до ListBox
Мало не забув, щоб задати ім'я диска треба викликати метод IFileSystemImage::put_VolumeName. Для того щоб встановити налаштування файлової системи в залежності від того, який диск вставлений в привод, потрібно викликати метод IFileSystemImage::ChooseImageDefaults передавши йому як параметр інтерфейс IDiscRecorder2.\
Йдемо далі, щоб створити результуючий образ треба викликати метод IFileSystemImage::CreateResultImage. Після виклику ми отримаємо інтерфейс IFileSystemImageResult. Для запису нам знадобиться його IStream, для цього потрібно викликати метод IFileSystemImageResult::get_ImageStream.
Ми отримали результуючий образ, нам залишилося лише записати його. За запис образу відповідає інтерфейс IDiscFormat2Data. Також є інтерфейси IDiscFormat2RawCD, IDiscFormat2TrackAtOnce, IDiscFormat2Erase (для стирання дисків), робота з ними аналогічна роботі з IDiscFormat2Data.
Для встановлення приводу, на якому буде здійснюватися запис, потрібно викликати метод IDiscFormat2Data::put_Recorder. Щоб запустити запис диска треба викликати метод IDiscFormat2Data::Write передавши йому як параметрIStream із вмістом образу диска. Тепер можна написати функцію, яка записує на диск файли та папки, зазначені в ListBox.
Начебто все. Залишилося лише виводити поточний стан запису. Для цього нам потрібно створити свій інтерфейс із методом Update
Параметр object вказує на поточний інтерфейс IDiscFormat2Data, який здійснює запис. Параметр progress вказує на інтерфейс IDiscFormat2DataEventArgs, що містить поточний стан запису. Інтерфейс IDiscFormat2DataEventArgs є нащадком інтерфейсу IWriteEngine2EventArgs. Перед записом диска необхідно створений нами інтерфейс з обробником підключити його до інтерфейсу IDiscFormat2Data. На щастя майстер Delphi позбавив нас цієї мороки і створив компоненти з властивостями подіями, таким чином поставити свій обробник так само легко, як і поставити обробник натискання кнопки. Наводити повний код обробника немає сенсу, тому далі наведено лише код який виводить поточний прогрес: