- •Windows -приложение
- •Среда программирования
- •Встроенный отладчик
- •Использование графики
- •Графические данные и палитра
- •Сохранение проекта
- •Структура приложения
- •Структура модуля
- •Простые типы
- •Символьные типы
- •Логические типы
- •Тип перечень
- •Составной оператор
- •Оператор if
- •Оператор цикла for
- •Оператор цикла while
- •Оператор цикла repeat
- •Пример приложения 6
- •Пример приложения 7
- •Статические массивы
- •Динамические массивы
- •Оператор with
- •Идентичность типов
- •Совместимость типов
- •Преобразование типов
- •Операторы обработки исключительных ситуаций
- •Рекурсия
- •Процедура exit
- •Директивы подпрограммы
- •Класс как объектный тип
- •Наследование
- •Операции is и as
- •Типы ссылки на класс
- •Типизированные файлы
- •Файлы без типа
- •Пример приложения 17
- •Компонент tmainmenii
- •Двунаправленные списки
- •Потоки данных
- •Пример приложения 22
- •Интерфейс drag and drop
- •Пример приложения 24
- •С файлами
- •Пример приложения 26
- •Программные потоки
- •Приоритеты потоков
- •Класс tthread
- •Проблемы синхронизации потоков
С файлами
Иногда требуются стандартные функции работы с файлами Windows, тем более что возможности в них расширены. Каждый файл в Windows описывается не переменной, а дескриптором (THandle, можно описывать Cardinal), который представляет собой 32-разрядную величину, идентифицирующую файл в операционной системе. Открывается файл при помощи следующей функции:
function CreateFileA(lpFileName: PAnsiChar;
dwDesiredAccess, dwShareMode: DWORD;
lpSecurityAttributes: PSecurityAttributes;
dwCreationDisposition, dwFlagsAndAttributes: DWORD;
hTemplatePile: THandle): THandle; stdcall;.
Такое большое количество параметров функции связано с тем, что сгеateFileA используется для открытия файлов на диске, устройств, каналов, портов и, вообще, любых источников ввода и вывода. Рассмотрим назначение параметров.
Здесь ipFileName - имя открываемого объекта; dwDesiredAccess -способ доступа к объекту (может иметь значение generic_read-для чтения, generic_write - для записи или комбинация этих значений). Если dwDesiredAccess =0, то можно получить атрибуты файла без фактического его открытия. Параметр dwShareMode открывает режим совместного с другими программами доступа (о - совместный доступ запрещен;
FILE_SHARE_READ – для чтения; FILE_SHARE_WRITE – Для записи; Комбинация этих значений - полный доступ). В рассматриваемой функции можно задавать атрибуты защиты объекта - lpSecurityAttributes (если равно nil, то устанавливаются атрибуты по умолчанию). Следующий параметр dwCreationDisposition отвечает за способ открытия объекта (create_new - создается новый объект, если таковой существует, иначе возвращается Ошибка ERROR_ALREADY_EXISTS; CREATE_ALWAYS - создается
новый объект, если таковой существует, или, если возможно, перезаписыва-202
ется, иначе выдается ошибка; open_exi sting - открывает существующий объект или, если таковой не найден, возвращается ошибка; open_always -открывает существующий объект, если таковой не найден, он создается). Набор атрибутов (скрытый, системный, сжатый) и флагов для открытия объекта задается параметром dwFlagsAndAttributes. Последний параметр hTemplateFile задает файл-шаблон, атрибуты которого используются для открытия объекта.
Функция возвращает дескриптор открытого объекта (некоторое число). Если открыть объект невозможно, то возвращается код ошибки invalid_handle_valoe. Более полные сведения об ошибке можно получить, вызвав функцию GetLastError.
Закрывается объект функцией function CloseHandle(hObject: THandle): BOOL; stdcall;.
Для чтения и записи данных используются следующие функции:
function ReadFile(hFile: THandle; var Buffer; nNumberOf-BytesToRead: DWORD; var lpNumberOfBytesRead: DWORD; lpOver-lapped: POverlapped): BOOL; stdcall;
function WriteFile(hFile: THandle; const Buffer; nNum-berOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
Здесь nNumberOfBytesToRead и nNumberOfBytesToWrite - количество байт, которое нужно прочитать или записать; lpNumberOfBytesRead и lpNumberOfBytesWritten - количество байт, которое фактически прочитано или записано. Параметр lpOverlapped - указатель на некоторый дескриптор структуры (типа TOverlapped) события отложенного ввода или вывода, например, для каких-то относительно "медленных" устройств. Создается событие следующей функцией: function CreateEventA( lpEven-tAttributes: PSecurityAttributes; bManualReset, blnitialState :BOOL; lpName: PAnsiChar): THandle; stdcall;. Эта функция как раз и возвращает указанный выше дескриптор, на который ссылается параметр lpOverlapped. С помощью данного события автоматически включается отложенный ввод или вывод. Время в миллисекундах (параметр dwMilli-seconds), которое разрешается ожидать при отложенном вводе или выводе, указывается в функции function WaitForSingleObject(hHandle : THandle; dwMilliseconds: DWORD): DWORD; stdcall;, которая прерывает отложенную операцию чтения или записи. Можно задать бесконечный интервал infinite.
Функция createFileA полезна при работе с портами, например, следующая программа позволяет успешно открыть порт СОМ1 и выдать минимальные сведения о подключенном к этому порту модеме.
procedure TForm1.Button1Click(Sender: TObject);
203
var CommPort : string;
hDev : THandle;
ModemStat : DWord;
begin
CommPort := 'CCM1';
hDev := CreateFile(PChar(CommPort), GENERIC_READ,O,nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hDev = INVALID_HANDLE_VALUE then begin
ShowMessage('Ошибка открытия порта '+ CommPort); exit;
end;
if GetCommModemStatus(hDev,ModemStat)ofalse then begin
if ModemStat and MS_CTS_ON <> 0 then ShowMessage(
'Управление CTS (clear-to-send) в порядке.');
if ModemStat and MS_DSR_ON <>0 then ShowMessage(
'Управление DSR (data-set-ready) в порядке.'); if ModemStat and MS_RIN6_ON <> Othen ShowMessage(
'Управление ring indicator в порядке.');
if ModemStat and MS_RLSD_ON <> 0 then ShowMessage( 'Управление RLSD (receive-line-signal-detect) в порядке.'); end;
CloseHandle(hDev); end; .
Еще один вариант использования рассматриваемой функции Windows API можно привести, когда требуется посекторное чтение, например, в дисководе А:.
Const SectorSize=512; Var Buffer:Pointer;
FUNCTION TForm1.ReadSector(Head,Track,Sector:integer; Buffer:pointer):boolean;
var
hDev:THandle; DevName:string; nb:cardinal;
begin
DevName: ='\\.\A: ';
hDev:=CreateFile(pChar(DevName),GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
if hDev=INVALID_HANDLE_VALDE then begin
Result:=false;
Expend;
SetFilePointer(hDev,(Sector-1)*SectorSize,nil,FILE_BEGIN); Result:=ReadFile(hDev,Buffer,SectorSize,nb,nil)
and (nb=SectorSize);
204
CloseHandle(hDev);
end;
В данном примере для позиционирования файлового указателя применяется еще одна функция Windows API setFilePointer, объявленная следующим образом: function SetFilePointer(hFile: THandle; lDis-tanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: DWORD): DWORD; stdcall;.
Как следует из примера функции ReadSector, позиционирование файлового указателя не учитывает значений параметров Head и Track (опущено для упрощения). При необходимости можно добавить взаимосвязь всех трех параметров.
Далее рассматривается небольшой пример, чтобы продемонстрировать указанные выше функции в работе.
ПРИМЕР ПРИЛОЖЕНИЯ 25
Пусть имеется текстовый файл, созданный по правилам Delphi. Требуется открыть этот файл указанной выше функцией Windows API и прочитать его содержимое. При выполнении этого примера встретятся некоторые трудности из-за того, что придется читать файл как совокупность байтов, а потом эти байты пытаться интерпретировать. Вариант решения примера приводится на рис. 61.
Рис.61 Ниже приводится текст программы.
unit OMSfile; interface
205
uses Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons type
TForm1 = class(TForm) Button1: TButton;
Memo1: TMemo;
BitBtnl: TBitBtn;
Memo2: TMemo;
Label1: TLabel;
procedure Button1Click(Sender: TObject); procedure FormDeactivate(Sender: TObject); public
hDev:THandle; end;
var Form1: TForm1; Buffer:pointer; FilSize:cardinal; implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); type buf=array of byte; var FilName:string; nb:cardinal; i,r:byte; F:File;
sNumber:string [3]; begin
FilName: ='InpFil.txt' ; Buffer := Nil; FilSize:=0;
AssignFile(F, FilName);
System.Reset(F, 1);
{$1+}
if IOResult<>O then begin
memo1.Lines.Add('Ошибка открытия файла');
Exit; End;
FilSize := FileSize(F); closeFILE(F);
Memo1.Lines.Add('FilSize= '+inttostr(FilSize)); memo2.Lines.LoadFromFile(FilName); hDev:=CreateFileA(pChar(FilName),GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NOPMAL,0);
if hDev=INVALID_HANDLE_VALUE then begin
memo1.Lines.Add(' Ошибка открытия файла Windows');
Exit;
end; try
Getmem(Buffer, FilSize) ;
ReadFile{hDev,Buffer,FilSize,nb,nil);
Memo1.Lines.Add('Прочитано байтов'+inttostr(nb)); Memo1.Lines.Add('Прочитаны числа1); sNumber:='';
FOR I:=0 TO FilSize DO BEGIN r:=buf(@buffer)[I]; if chr(r) in ['0'..'9'] then
sNumber:=sNumber+chr(r) else begin
if length(sNumber)>0 then Memo1.Lines.Add(sNumber); sNumber:=''; end; END; finally
CloseHandle(hDev); end; end;
procedure TForm1.FormDeactivate(Sender: TObject); begin
FreeMem(Buffer,FilSize); end; end.
В данной программе вначале определяется количество байт в исходном файле, которое включает в себя все символы, содержащиеся в файле, в том числе и разделители, т.е. отдельные цифры чисел, пробелы, #13, #10. Далее этот файл открывается как файл Windows. Байты считываются в переменную Buffer и с помощью преобразования типа Pointer в тип Array of byte восстанавливаются в исходные числа. В примере показан один из вариантов работы с типом Pointer.
ИСПОЛЬЗОВАНИЕ ОТОБРАЖАЕМЫХ ФАЙЛОВ
В Windows под памятью подразумевается не только оперативная память (ОЗУ), но также и память, резервируемая операционной системой на жестком диске. Этот вид памяти называется виртуальной памятью. Посредством страничной системы (paging system) подкачки в такую память на жестком диске отображаются код и данные. По мере необходимости требуемый фрагмент виртуальной памяти переносится из страничного файла в ОЗУ и, таким образом, становится доступным для выполнения. Данный механизм отображения можно применить и для любого другого файла, сделав его содержимое частью адресного пространства.
207
Для выделения фрагмента виртуальной памяти должен быть создан специальный системный объект , называемый отображаемым файлом. Отображаемый в адресное пространство дескриптор объекта создается операционной системой при вызове следующей функции Windows API: function CreateFileMappingA(hFile: THandle; lpFileMappingAttributes: PSecurityAttributes; flProtect, dwMaximumSizeHigh, dwMaximum-SizeLow:DWORD; lpName: PAnsiChar): THandle; stdcall;.
Первый параметр соответствует дескриптору открытого при помощи функции createFile файла. Второй параметр является указателем на структуру с данными по защите файла. Посредством параметра f lProtect указывается тип доступа к файлу, например, page_readwritk. С помощью параметров dwMaximumSizeHigh, dwMaximumSizeLow задается выделяемое пространство виртуальной памяти. Если отображается весь файл, то их значения можно задать равными нулю (при условии, что файл намного меньше 4 Гбайт). Последний параметр представляет собой имя объекта файлового отображения (применяется при вызовах из разных, но одновременно использующих созданный объект, программ).
Следующий этап построения отображения - спроецировать данные файла в адресное пространство. Этой цели служит следующая функция: function MapViewOfFile(hFileMappingObject: THandle; dwDesiredAc-cess: DWORD; dwFileOffsetHigh, dwFileOffsetLow, dwNumberOf-BytesToMap: DWORD): Pointer; stdcall;.
Первый параметр является дескриптором созданного объекта файлового отображения. С помощью второго параметра определяется режим доступа к объекту (file_map_write, filb_map_read, file_map_all_access). Посредством третьего и четвертого параметров задается смещение отображаемого участка относительно начала файла (чаще всего оба параметра равны нулю). Пятый параметр определяет количество байт данных файлового отображения - если равен нулю, то отображаются все данные, выделенные при этом функцией CreateFileMappingA.
Функция MapViewOfFile вернет начальный адрес (тип возвращаемого результата - Pointer) данных в памяти. Далее можно работать с исходным файлом как с обычной памятью.
По окончании работы с отображаемым в памяти файлом необходимо вернуть занятое адресное пространство, используя функцию function DnmapViewOfFile(lpBaseAddress: Pointer): BOOL; stdcall;, где lpBaseAddress - используемый выше указатель. Последняя операция, которую надо выполнить, - закрыть полученный выше дескриптор. Эта операция выполняется путем вызова еще одной функции Windows API: function CloseHandle(hObject: THandle): BOOL; stdcall;.