В завершение главы рассмотрим три несложных примера работы с файлами: копирование файла (с отображением хода копирования в ProgressBar), определение значков, ассоциированных с файлами, и извлечение значков из ЕХЕ– и DLL-файлов.
Красивое копирование файла
Казалось бы, что особенного в организации копирования большого файла с отображением процесса: читай файл порциями, записывай прочитанные данные в файл назначения, попутно показывая в ProgressBar или где-то еще отношение объема переписанной информации к размеру файла. Однако зачем такие сложности? Ведь у API-функции CopyFi 1е, осуществляющей простое копирование файла, есть расширенный вариант – функция CopyFileEx, в которую встроена поддержка отображения процесса копирования (и не только это). Вот прототип функции CopyFileEx:
...
function CopyFileEx(lpExistingFileName, lpNewFileName: PChar;
lpProgressRoutine: TFNProgressRoutine; lpData: Pointer;
pbCancel: PBool; dwCopyFlags: DWORD): BOOL; stdcall;
Итак, кроме пути исходного и конечного файлов, а также флагов (последний параметр), функция принимает ряд дополнительных параметров: адрес функции обратного вызова (IpProgressRoutine), указатель на данные, передаваемые в функцию обратного вызова (lpData), а также адрес переменной типа BOOL (pbCancel), при установке значения которой в True копирование прерывается.
Пример использования функции CopyFileEx в программе приведен в листинге 4.32. Здесь подразумевается, что кнопка cmbCopy используется как для запуска, так и для остановки процесса копирования. Также на форме присутствуют следующие элементы управления:
• индикатор pbCopyProgress, диапазон значений которого от 0 до 100;
• текстовое поле txtFrom с именем копируемого файла;
• текстовое поле txtTo с именем файла назначения.
...
Листинг 4.32.
Использование функции CopyFileEx
procedure TForm1.cmbCopyClick(Sender: TObject);
begin
if cmbCopy.Caption = \'Копировать\' then
begin
//Запускаем копирование
progress := pbCopyProgress; //Настроен от 0 до 100 %
bCancelCopy := False;
cmbCopy.Caption := \'Отмена\
if CopyFileEx(PAnsiChar(txtFrom.Text), PAnsiChar(txtTo.Text),
Addr(CopyProgressFunc), nil, Addr(bCancelCopy),
COPY_FILE_FAIL_IF_EXISTS) = False
then
MessageBox(Handle, \'Не удается скопировать файл\',
\'Копирование\', MB_ICONEXCLAMATION);
end
else
begin
//Останавливаем процесс копирования
bCancelCopy := True;
cmbCopy.Caption := \'Копировать\
end;
end;
Из листинга 4.32 можно увидеть, что в качестве значения последнего параметра функции CopyFileEx можно передавать константу COPY_FILE_FAIL_IF_EXISTS (функция вернет False, если файл назначения уже существует, и не будет осуществлять копирование).
На самом деле значение параметра dwCopyFlags функции CopyFileEx может быть комбинацией значений COPY_FILE_FAIL_IF_EXISTS И COPY_FILE_RES TARTABLE, то есть представляет собой битовый флаг. Последнее значение используется для того, чтобы в случае прерывания копирование файла можно было возобновить. Функция CopyFileEx в этом случае сохраняет в файле назначения информацию, достаточную для возобновления процесса копирования.
В листинге 4.32 изменяется переменная progress – глобальная переменная-ссылка на TProgressBar, которая используется в функции обратного вызова. Переменная bCancelCopy, адрес которой передается в функцию CopyFileEx, также объявлена глобальной (в пределах модуля).
Теперь, наконец, рассмотрим функцию обратного вызова, осуществляющую в нашем случае отображение хода копирования на индикаторе (листинг 4.33).
...
Листинг 4.33.
Функция, показывающая ход копирования файла
function CopyProgressFunc( TotalFileSize: Int64;
TotalBytesTransferred: Int64;
StreamSize: Int64;
StreamBytesTransferred: Int64;
dwStreamNumber: DWORD;
dwCallbackReason: DWORD;
hSourceFile: THandle;
hDestinationFile: THandle;
lpData: Pointer): DWORD; stdcall;
begin
progress.Position := 100 * TotalBytesTransferred div
TotalFileSize;
Application.ProcessMessages; //Чтобы не «зависал»
//интерфейс приложения
CopyProgressFunc := PROGRESS_CONTINUE;
end;
Пусть вас не смущает большое количество параметров функцииСоруРгодгеззЕипс. Применять их все далеко не обязательно (но они должны быть объявлены), хотя ничего сложного здесь нет. В листинге 4.33 использование параметров реализовано наиболее простым (на наш взгляд) и очевидным образом: значения параметров TotalBytesTransferred и TotalFileSize применяются для определения доли скопированной информации.