M Y D E L P H I 7 . R U Самоучитель программирования  
 
  • Главная
  •  

     

    Ввод/вывод с использованием функций Windows API

    Для тех, кто переходит на Delphi не с прежних версий Turbo Pascal, а с С, других языков или начинает освоение с "нуля", более привычными будут стандартные функции работы с файлами Windows. Тем более, что возможности ввода/вывода в них расширены. Каждый файл в этом наборе функций описывается не переменной, а дескриптором (Handle) — 32-разрядной величиной, которая идентифицирует файл в операционной системе.

    В Win32 файл открывается при помощи функции, имеющей обманчивое название:

    function CreateFile(IpFileName: PChar; dwDesiredAccess, 

    dwShareMode: DWORD; IpSecurityAttributes: PSecurityAttributes;

     dwCreationDistribution, dwFlagsAndAttributes: DWORD; 

    hTemplateFile: THandle): THandle;

    Хоть ее название и начинается с create, но она позволяет не только создавать, но и открывать уже существующие файлы.

    Такое огромное количество параметров оправдано, т. к. createFile используется для открытия файлов на диске, устройств, каналов, портов и вообще любых источников ввода/вывода. Назначение параметров описано в табл. 9.2.

    Таблица 9.2. Параметры функции CreateFile

    Параметр

    Описание

    IpFileName:pChar

    Имя открываемого объекта. Может представлять собой традиционную строку с путем и именем файла, UNC (для открытия объектов в сети, имя порта, драйвера или устройства)

    dwDesiredAccess,:DWORD

    Способ доступа к объекту. Может быть равен:

    •  GENERIC READ — для чтения; 

    •  GENERIC WRITE — для записи.

    Их комбинация позволяет открыть файл для чтения и записи. Параметр 0 применяется, если нужно получить атрибуты файла без его фактического открытия

    dwShareMode:DWORD

    Режим совместного использования файла: 

    •  0 — совместный доступ запрещен;

    • FILE SHARE READ — для чтения;

    • FILE_SHARE_WRITE -  для записи.

    Их комбинация — для полного совместного доступа

    IpSecurityAttributes :PSecurityAttributes

    Атрибуты защиты файла. В Windows 95/98 не используются (должны быть равны nil). В Windows NT/2000 этот параметр, равный nil, дает объекту атрибуты по умолчанию

    dwCreationDistribution: DWORD;

    Способ открытия файла:

    •  CREATE NEW — создается новый файл, если таковой уже существует, функция возвращает ошибку ERROR_ALREADY_EXISTS;
    •  CREATE ALWAYS — создается новый файл, если таковой уже существует, он перезаписывается;
    •  OPEN EXISTING— открывает существующий файл, если таковой не найден, функция возвращает ошибку;
    •  OPEN ALWAYS — открывает существующий файл, если таковой не найден, он создается

    dwFlagsAndAttributes: DWORD;

    Набор атрибутов (скрытый, системный, сжатый) и флагов для открытия объекта. Подробное описание см. в документации по Win32

    hTemplateFile: THandle

    Файл-шаблон, атрибуты которого используются для открытия. В Windows 95/98 не используется и должен быть равен 0

    Функция createFile возвращает дескриптор открытого объекта ввода/вывода. Если открытие невозможно из-за ошибок, возвращается код INVALID_HANDLE_VALUE, а расширенный код ошибки можно узнать, вызвав функцию GetLastError.

    Закрывается файл в Win32 функцией closeHandie (не closeFile, a closeHandle! Правда, "легко" запомнить? Что поделать, так их назвали разработчики Win32).

    Приведем из большого разнообразия несколько приемов использования функции CreateFile. Часто программисты хотят иметь возможность организовать посекторный доступ к физическим устройствам хранения — например к дискете. Сделать это не так уж сложно, но при этом методы для Windows 98 и Windows 2000 различаются. В Windows 2000 придется открывать устройство ('\\.\A:'), а в Windows 98 — специальный драйвер доступа (обозначается '\\.\vwin32'). И то и другое делается функцией createFile.

     Листинг 9.1  Чтение сектора с дискеты при помощи функции CreateFile 

    type

    pDIOCRegs = ^TDIOCRegs;

    TDIOCRegs = packed record

    rEBX,rEDX,rECX,rEAX,rEDI, rESI, rFlags : DWORD;

    end;

    const VWIN32_DIOC_DOS_IOCTL = 1;

    VWIN32_DIOC_DOS_INT13 = 4; //Прерывание 13

    SectorSize = 512;

    function ReadSector(Head, Track, Sector: Integer; buffer : pointer; 

    Floppy: char):Boolean; 

    var hDevice : THandle; 

    Regs : TDIOCRegs;

     DevName : string; nb : Integer; 

    begin

    if WIN32PLATFORM <> VER_PLATFORM_WIN32_NT then

     begin {win95/98} hDevice := CreateFile('\\.\vwin32', GENERIC_READ, 0, nil, 0,

    FILE_FLAG_DELETE_ON_CLOSE, 0);

    if (hDevice = INVALID_HANDLE_VALUE) then

     begin

    Result := FALSE;

    Exit; end;

    regs.rEDX := Head * $100 + Ord(Floppy in ['b', 'B']);

    regs.rEAX := $201; // KOH onepam-iM read sector

    regs.rEBX := DWORD(buffer); // buffer

    regs.rECX := Track * $100 + Sector;

    regs.rFlags := $0;

    Result := DeviceloControl(hDevice,VWIN32_DIOC_DOS_INT13,

    @regs, sizeof(regs), @regs, sizeof(regs), nb, nil) 

    and ((regs.rFlags and $1)=0); CloseHandle(hDevice); 

    end {win95/98} 

    else

    begin // Windows NT/2000 

    DevName :='\\.\A:';

    if Floppy in ['b', 'B'] then DevName[5] := Floppy;

    hDevice := CreateFile(pChar(Devname), GENERIC_READ, FILE_SHARE_READ 

    or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

    if (hDevice = INVALID_HANDLE_VALUE) then 

    begin 

    Result := FALSE;

    Exit;

    end;

    SetFilePointer(hDevice, (Sector-1)*SectorSize, nil, FILE_BEGIN); // нумерация с 1

    Result := ReadFile(hDevice, buffer';, SectorSize, nb, nil) and (nb=SectorSize);

    CloseHandle(hDevice);

    end; // Windows NT/2000 

    end;

    Для чтения и записи данных в Win32 используются функции:

    function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD; var IpNumberOfBytesRead: DWORD; IpOverlapped: POverlapped): BOOL; function WriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD; var IpNumberOfBytesWritten: DWORD; IpOverlapped: POverlapped): BOOL;

    Здесь все сходно с BlockRead и Blockwrite: hFile — это дескриптор файла, Buffer — адрес, по которому будут читаться (писаться) данные; третий параметр означает требуемое число читаемых (записываемых) байтов, а четвертый — фактически прочитанное (записанное). Последний параметр — IpOverlapped — обсудим чуть позже.

    Функция createFile используется и для доступа к портам ввода/вывода. Часто программисты сталкиваются с задачей: как организовать обмен данными с различными нестандартными устройствами, подключенными к параллельному или последовательному порту? В Turbo Pascal для DOS был очень хороший псевдомассив Ports: пишешь Port[x] := у; и не знаешь проблем. В Win32 прямой доступ к портам запрещен и приходится открывать их как файлы:

    ...

    hCom := CreateFile('COM2', GENERIC_READ or GENERIC_WRITE,

    0, NIL, OPEN_EXISTING, FILE_FLAG__OVERLAPPED, 0) ;

     if hCom = INVALID_HANDLE_VALUE then

    begin

    raise EAbort.CreateFmt('Ошибка открытия порта: %d*,[GetLastError]);

    end;

    Самое большое отличие от предыдущего примера — в скромном флаге FILE_FLAG_OVERLAPPED. О роли этих изменений- в следующем разделе