Последние записи
- Рандомное слайдшоу
- Событие для произвольной области внутри TImage
- Удаление папки с файлами
- Распечатка файла
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
25th
Фев
Запись дисков в Delphi средствами IMAPI
Posted by Chas under Журнал, Статьи
Доброго времени суток уважаемые любители Delphi. В этой статье я расскажу про запись CD/DVD дисков в среде Delphi. Общие принципы, изложенные в этой статье подойдут не только для языка Delphi, но и для языка С++. Для прочтения этой статьи с максимальной пользой, читателю рекомендуется получить базовые понятия об OLE/COM, впрочем даже незнание этих понятий вряд ли помешает понимаю этой статьи, так как классы и компоненты Delphi (так же как и классы С++), которые мы будет использовать полностью скрывают от нас все тонкости и неудобства использования COM интерфейсов для записи дисков.
Руслан Аблязов
by rpy3uH www.programmersforum.ru
Технология, которая будет описываться в этой статье это технология IMAPI v2.0. Одной статьей эту технологию описать не представляется возможным, поэтому в этой статье будут описаны только основы работы с IMAPI2. Эта технология довольно-таки новая, и поддерживается операционными системами Windows XP SP2, 2003 Server, Vista и т.д. Т.е. перед тем как использовать технологию IMAPI2, следует убедиться, в том, что операционная система на компьютере, на котором будет работать программа, является как минимум одной из вышеперечисленных или более новая (например, Windows 7 ). «Олицетворением» IMAPI2 являются две библиотеки imapi2.dll и imapi2fs.dll. Перед тем как использовать эту технологию вы или программа, которая будет работать на компьютере, должны убедиться, что эти две DLL существуют. Если их нет, то следует установить обновление KB932716 с узла Microsoft.com (ссылки на скачку обновления, а также обновление для Win XP смотрите в конце статьи) [1, 2].
Что нам понадобится?
Итак, мы убедились, что IMAPI v2 поддерживается операционной системой. Теперь нам нужны заголовочные файлы, вернее нам надо установить компоненты для записи дисков. Программистам С++ по этой части проще, так как в Platform SDK есть заголовочные файлы и их надо только подключить, чтобы воспользоваться классами для записи дисков. Но в Delphi тоже не очень сложно, в Delphi надо импортировать библиотеку типов. После импорта библиотеки типов Delphi сама создаст компоненты и классы для записи дисков и установит их в палитру. Что нам надо для этого сделать. Объясняю, как импортировать библиотеку типов для пользователей Delphi 7 (англ). Выбираем меню Project -> Import Type Library. В открывшемся окне в списке находим «Microsoft IMAPI2 Base Functionality (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. Далее приведу код получения списка доступных нам рекордеров:
var
i:integer;
begin
RecordersComboBox.Clear;
for i:=0 to MsftDiscMaster.Count-1 do
begin
try
MsftDiscRecorder.InitializeDiscRecorder(MsftDiscMaster.Item);
RecordersComboBox.Items.Add(MsftDiscRecorder.VendorId+‘ ‘+MsftDiscRecorder.ProductId);
MsftDiscRecorder.Disconnect;
except
RecordersComboBox.Items.Add(‘—‘);
end;
end;
RecordersComboBox.ItemIndex:=0;
end;Syhi-подсветка кода
В combobox будут выведены все доступные пишушие рекордеры. Если какой-либо рекордер будет недоступен, то вместо его имени будет выведено «—».
Едем далее. Мы нашли нужный нам рекордер, теперь надо создать образ диска для записи. За создание образа отвечает интерфейс IFileSystemImage. Файлы и папки в этом интерфейсе представляются интерфейсами IFsiFileItem и IFsiDirectoryItem. Для получения корневой папки надо вызвать метод IFileSystemImage::get_Root. Получив интерфейс корневой папки можно спокойно добавлять в образ файлы и папки. Есть несколько методов добавления файлов и папок в образ, я опишу наиболее простые из них.
Чтобы добавить папку со всеми ее файлами удобно использовать метод IFsiDirectoryItem::AddTree, ему надо передать два параметра. Первый параметр это путь к папке, второй параметр имеет тип Boolean, если он равен true, то в образ будет добавлена сама папка и все содержащиеся в ней файлы и папки, если параметр равен false, то в образ будут добавлены только файлы и папки, содержащиеся в искомой (искомая папка не будет добавлена).
Для добавления файла необходимо использовать метод IFsiDirectoryItem::AddFile, первый параметр задает имя файла в образе, второй параметр задает интерфейс IStream с содержимым искомого файла. Для получения IStream c содержимым нужного файла можно использовать функцию SHCreateStreamOnFileEx. Ни в одном заголовочной файле Delphi нет этой функции (как минимум в Delphi 7), поэтому приведу объявление этой функции
pstmTemplate:IStream; var ppstm:IStream):DWORD;stdcall;
external ‘shlwapi.dll’ name ‘SHCreateStreamOnFileEx’;Syhi-подсветка кода
В этой функции нам интересно только два параметра, первый и последний. Первый параметр это путь к искомому файлу, в последний параметр будет сохранен поток с содержимым файла. Теперь можно написать код, которые создает образ диска из файлов пути, к которым занесены в ListBox
for i:=0 to FilesListBox.Count-1 do
begin
if DirectoryExists(FilesListBox.Items) then
DiscRoot.AddTree(FilesListBox.Items,true);
if FileExists(FilesListBox.Items) then
begin
wstr:=FilesListBox.Items;
SHCreateStreamOnFileEx(PWideChar(wstr) ,0, 0, False ,nil, IStream(fstream));
DiscRoot.AddFile(ExtractFileName(FilesListBox.Items),IMAPI2FS_TLB.IStream(fstream));
end;
end;Syhi-подсветка кода
Чуть не забыл, чтобы задать имя диска надо вызвать метод 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:
var
wstr:WideString;
i:integer;
DiscRoot:IFsiDirectoryItem;
resimage:IFileSystemImageResult;
DiscStream,fstream:IMAPI2_TLB.IStream;
DR:IDiscRecorder2;
begin
if RecordersComboBox.Items[RecordersComboBox.ItemIndex]=‘—‘ then exit;
if FilesListBox.Count=0 then exit;
MsftDiscRecorder.InitializeDiscRecorder(MsftDiscMaster.Item[RecordersComboBox.ItemIndex]);
DiscRoot:=MsftFileSystemImage.Root;
MsftDiscFormat2Data.Recorder:=MsftDiscRecorder.DefaultInterface;
MsftDiscFormat2Data.ClientName:=‘IMAPI’;
DR:=IDiscRecorder2(MsftDiscRecorder.DefaultInterface);
MsftFileSystemImage.ChooseImageDefaults(DR);
MsftFileSystemImage.VolumeName:= DiscVolumeNameEdit.Text;
for i:=0 to FilesListBox.Count-1 do
begin
if DirectoryExists(FilesListBox.Items) then
DiscRoot.AddTree(FilesListBox.Items,true);
if FileExists(FilesListBox.Items) then
begin
wstr:=FilesListBox.Items;
SHCreateStreamOnFileEx(PWideChar(wstr),0,0,False,nil,IStream(fstream));
DiscRoot.AddFile(ExtractFileName(FilesListBox.Items),IMAPI2FS_TLB.IStream(fstream));
end;
end;
resimage:=MsftFileSystemImage.CreateResultImage;
DiscStream:=IMAPI2_TLB.IStream(resimage.ImageStream);
LogListBox.Clear;
LogListBox.Items.Add(‘запись началась’);
MsftDiscFormat2Data.Write(DiscStream);
MsftDiscRecorder.EjectMedia;
MsftDiscRecorder.Disconnect;
BurnButton.Enabled:=false;
ShowMessage(‘запись закончилась’);
end;Syhi-подсветка кода
Вроде бы все. Осталось только выводить текущее состояние записи. Для этого нам надо создать свой интерфейс с методом Update:
Параметр object указывает на текущий интерфейс IDiscFormat2Data которые осуществляет запись. Параметр progress указывает на интерфейс IDiscFormat2DataEventArgs содержащий текущее состояние записи. Интерфейс IDiscFormat2DataEventArgs является потомком интерфейса IWriteEngine2EventArgs
Перед записью диска, необходимо, созданный нами интерфейс с обработчиком подсоединить его к интерфейсу IDiscFormat2Data. К счастью, мастер Delphi избавил нас от этой мороки и создал компоненты со свойствами событиями, таким образом поставить свой обработчик так же легко, как и поставить обработчик нажатия кнопки. Приводить полный код обработчика не имеет смысла, поэтому далее приведен только код который выводит текущий прогресс:
progress: IDispatch);
var
CurProgress: IDiscFormat2DataEventArgs;
CurDiscF2D:IDiscFormat2Data;
writtensectors:int64;
begin
CurProgress:= progress as IDiscFormat2DataEventArgs;
CurDiscF2D:=object_ as IDiscFormat2Data;
………….
if CurProgress.CurrentAction = IMAPI_FORMAT2_DATA_WRITE_ACTION_WRITING_DATA then
begin
writtensectors :=CurProgress.LastWrittenLba -CurProgress.StartLba;
ProgressBar1.Position :=round((writtensectors/ CurProgress.SectorCount )*100);
end;
………………
end;Syhi-подсветка кода
Для получения текущего количества записанных секторов надо вычесть из адреса последнего записанного сектора, адрес сектора, с которого началась запись.
Через IMAPI2 доступны все возможности необходимые при записи дисков, в том числе и скорость записи.
Заключение
Вот, пожалуй, и все на сегодня. Если нужны еще какие-то аспекты записи дисков, которые вам хотелось бы, чтобы я осветил в следующих статьях, пожалуйста, оставляем комментарии со своими пожеланиями. Возможны неточности и ошибки, буду рад любой конструктивной критике. В архиве [3] находится исходник программы-примера к этой статье. Так же прилагается архив с обновлением KB932716 для Win XP SP2 Rus.
Все упомянутые в статье исходные коды приведены в виде ресурсов непосредственно в архиве с журналом.
Ресурсы
- Официальная страница IMAPI на узле MSDN http://msdn.microsoft.com/en-us/library/aa366450(VS.85).aspx
- Официальная страница с обновлением KB932716 на узле Microsoft.com http://support.microsoft.com/kb/932716
- Скачать архив с исходником на Delphi http://pblog.ru/wp-content/uploads/burncdsample.zip
- Скачать обновление KB932716 для Win XP SP2 Rus http://pblog.ru/wp-content/uploads/windowsxp-kb932716-v2-x86-rus.zip
Статья из девятого выпуска журнала «ПРОграммист».
Обсудить на форуме — Запись дисков в Delphi средствами IMAPI
Похожие статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)