• Иллюстрированный самоучитель по Delphi 7 для профессионалов

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

    Приведем из большого разнообразия несколько приемов использования функции 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. О роли этих изменений – в следующем разделе.

    Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.