Меню сайта
Категории раздела
PHP [0]
Видео уроки [0]
DELPHI [45]
BASIC [0]
HTML [0]
JAVA [0]
C++ / C# [0]
Радио
ЧАТ
200
Облако тегов
Облако фото
Форум
  • композитная арматура (0)
  • Справедливо ли это???? (1)
  • Недвижимость в Тюмени (1)
  • Качество услуг и обслуживания (2)
  • строительный эксперт (0)
  • гид по Греции (0)
  • винные туры по Италии (0)
  • деревянные лестницы (0)
  • гид по Италии (0)
  • Разные поздравления (1)
  • Главная » Статьи » Программисту » DELPHI

    Запись дисков в Delphi
    Запись дисков в Delphi 

    Доброго времени суток уважаемые любители Delphi. В этой статье я расскажу про запись CD\DVD дисков в среде Delphi. Общие принципы, изложенные в этой статье подойдут не только для языка Delphi, но и для языка С++. Для прочтения этой статьи с максимальной пользой, читателю рекомендуется получить базовые понятия об OLE\COM, впрочем даже незнание этих понятий вряд ли помешает понимаю этой статьи, так как классы и компоненты Delphi (так же как и классы С++), которые мы будет использовать полностью скрывают от нас все тонкости и неудобства использования COM интерфейсов для записи дисков.

      Технология, которая будет описываться в этой статье это технология 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 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. Далее приведу код получения списка доступных нам рекордеров:

    procedure TForm1.UpdateRecordersButtonClick(Sender: TObject);
    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;


    В combobox будут выведены все доступные пишушие рекордеры. Если какой-либо рекордер будет недоступен, то вместо его имени будет выведено «—».

      Едем далее, мы нашли нужный нам рекордер, теперь надо создать образ диска для записи. За создание образа отвечает интерфейс IFileSystemImage. Файлы и папки в этом интерфейсе представляются интерфейсами IFsiFileItem и IFsiDirectoryItem. Для получения корневой папки надо вызвать метод IFileSystemImage::get_Root. Получив интерфейс корневой папки можно спокойно добавлять в образ файлы и папки. Есть несколько методов добавления файлов и папок в образ, я опишу наиболее простые из них. 

      Чтобы добавить папку со всеми её файлами удобно использовать метод IFsiDirectoryItem::AddTree, ему надо передать два параметра. Первый параметр это путь к папке, второй параметр имеет тип Boolean, если он равен true, то в образ будет добавлена сама папка и все содержащиеся в ней файлы и папки, если параметр равен false, то в образ будут добавлены только файлы и папки, содержащиеся в искомой (искомая папка не будет добавлена). 

      Для добавления файла необходимо использовать метод IFsiDirectoryItem::AddFile, первый параметр задаёт имя файла в образе, второй параметр задаёт интерфейс IStream с содержимым искомого файла. Для получения IStream c содержимым нужного файла можно использовать функцию SHCreateStreamOnFileEx. Ни в одном заголовочной файле Delphi нет этой функции (как минимум в Delphi 7), поэтому приведу объявление этой функции 

    Function SHCreateStreamOnFileEx( pszFile: PWChar; grfMode:DWORD; dwAttributes:DWORD; fCreate:BOOL; pstmTemplate:IStream; var ppstm:IStream):DWORD;stdcall; external 'shlwapi.dll' name 'SHCreateStreamOnFileEx';

    В этой функции нам интересно только два параметра, первый и последний. Первый параметр это путь к искомому файлу, в последний параметр будет сохранён поток с содержимым файла. Теперь можно написать код, которые создаёт образ диска из файлов пути, к которым занесены в ListBox 

      DiscRoot:=MsftFileSystemImage.Root;

      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;


      Чуть не забыл, чтобы задать имя диска надо вызвать метод 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.

    procedure TForm1.BurnButtonClick(Sender: TObject);
    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;


      Вроде бы всё. Осталось только выводить текущее состояние записи. Для этого нам надо создать свой интерфейс с методом Update 

    HRESULT Update(
      [in] IDispatch *object,
      [in] IDispatch *progress
    );


    Параметр object указывает на текущий интерфейс IDiscFormat2Data которые осуществляет запись. Параметр progress указывает на интерфейс IDiscFormat2DataEventArgs содержащий текущее состояние записи. Интерфейс IDiscFormat2DataEventArgs является потомком интерфейса IWriteEngine2EventArgs. Перед записью диска, необходимо, созданный нами интерфейс с обработчиком подсоединить его к интерфейсу IDiscFormat2Data. К счастью мастер Delphi избавил нас от этой мороки и создал компоненты со свойствами событиями, таким образом поставить свой обработчик также легко, как и поставить обработчик нажатия кнопки. Приводить полный код обработчика не имеет смысла, поэтому далее приведён только код который выводит текущий прогресс:

    procedure TForm1.MsftDiscFormat2DataUpdate(ASender: TObject; const object_,
      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;

    Для получения текущего количества записанных секторов надо вычесть из адреса последнего записанного сектора, адрес сектора, с которого началась запись.

      Вот, пожалуй, и всё на сегодня. Если нужны ещё какие-то аспекты записи дисков, которые вам хотелось бы, чтобы я осветил в следующих статьях, пожалуйста, оставляем комментарии со своими пожеланиями. Возможны неточности и ошибки, буду рад любой конструктивной критике. В архиве находится исходник программы-примера к этой статье. Так же прилагается архив с обновлением KB932716 для Win XP SP2 Rus.
    Категория: DELPHI | Добавил: SeM (30.04.2011)
    Просмотров: 994 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Поиск по сайту
    Новый Год
    Опрос
    Изменить дизайн?


    Всего ответов: 16
    Всего голосовало: 16
    Обсудить на форуме
    Друзья сайта
    измерьте скорость интернета Яндекс.Метрика
    Проверить тИЦ и PR
    Статистика
    Погода
    Яндекс.Погода
    Коменнтарии

    Извиняюсь, заработал. Спасибо за урок biggrin

    Компонент не работает

    Давайте помогу разобраться ? вы хотите что бы когда выбиралась станция сразу начинала проигрывать? скиньте исходник или как лучше связаться с вами?

    у меня все работает!

    Нифига не робит...
    Кто знает как сделать чтобы на жесткий жертвы сохранял..
    ISQ 606017777

    FSDGHDFJHRG


    Отзывы Фото
    6 микр. Красивое место....

    Ершов ))))

    Старый музей но щас его перенесли...

    Фотография под горы smile

    Красивое фото!!! smile

    Copyright MyCorp © 2024