faqs.org.ru

 Главная > Программирование > Языки Pascal/Delphi >

Dze Pascal FAQ

Секция 2 из 2 - Предыдущая - Следующая

     прямого доступа к оборудованию и т.д.

------------------------------------------------------------------------------
Q:>  2.4.1  Как узнать состояние клавиш Shift, Alt, Ctrl,
            Num Lock, Caps Lock, Scroll Lock и искусственно переключать их?

A:>  Состояние  этих  клавиш  храниться  в памяти по адресу 0:$417.
     Каждой  из  этих клавиш в байте по этому адресу соответствует
     свой  бит.  Следующие  процедуры показывает как можно читать и
     изменять состояния клавиш

        Type
                TKeytype=(ktCaps, ktNum, ktScroll, ktCtrl, ktAlt, ktLShift,
                          ktRShift);

        function GetLock(lock:TKeytype):Boolean;
           var
                   b:byte;
           begin
                   case lock of
                           ktCaps   : b:=$40;
                           ktNum    : b:=$20;
                           ktScroll : b:=$10;
                           ktCtrl   : b:=$04;
                           ktAlt    : b:=$08;
                           ktLShift : b:=$02;
                           ktRShift : b:=$01;
                   end;
                   if (mem[0:$417] and b)<>0 then GetLock:=true
                      else GetLock:=false;
           end;

        procedure SetLock(lock:TKeytype; On:Boolean);
           var
                   b:byte;
           begin
                   case lock of
                           ktCaps   : b:=$40;
                           ktNum    : b:=$20;
                           ktScroll : b:=$10;
                           ktCtrl   : b:=$04;
                           ktAlt    : b:=$08;
                           ktLShift : b:=$02;
                           ktRShift : b:=$01;
                   end;
                   if On then
                      mem[0:$417]:=mem[0:$417] or b
                   Else
                      mem[0:$417]:=mem[0:$417] and not b;
           end;


------------------------------------------------------------------------------
Q:>  2.4.2  Как осуществить холодную перезагрузку?

A:>  Попробуйте вот это

          Procedure ColdBoot;
          Begin
             InLine
               ($B8/$40/$00
               /$8E/$D8
               /$89/$C3
               /$B8/$00/$00
               /$A3/$72/$00
               /$EA/$00/$00/$FF/$FF);
          End;

          или как более "паскалевский" вариант.

          procedure ColdBoolt1;
             Begin
               MemW[$40:$72] := 0;
               Inline($EA/00/00/$FF/$FF);
             End;

     На самом это одно и то же...

------------------------------------------------------------------------------
Q:>  2.4.3  Как скопировать файл?

A:>  Читать его в буфер через BlockRead, а затем записывать через
     BlockWrite. Например:

     procedure FileCopy(fileFrom, fileTo: string);
       var
          f1,f2:file;
          p:pointer;
          rb:word;
       Begin
            Assign(f1,fileFrom); FileMode:=0; Reset(f1,1);
            Assign(f2,fileTo); ReWrite(f2,1);
            GetMem(p,32768);
            If p=nil then begin WriteLn('Not enough memory !'); Halt; end;
            Repeat
                  BlockRead(f1,p^,32768,rb);
                  BlockWrite(f2,p^,rb);
            Until rb<>32768;
            FreeMem(p,32768);
            Close(f2); Close(f1);
     End;

A:>  Есть и более изящный вариант, реализованный в следующей проге:

     Uses Objects;
     Var
         S1, S2: TDosStream;
     Begin
       If ParamCount <> 2 Then Halt(1);
       S1.Init(ParamStr(1), stOpenRead);
       S2.Init(ParamStr(2), stCreate);
       S2.CopyFrom(S1, S1.GetSize);
       S2.Done;
       S1.Done;
     End.


------------------------------------------------------------------------------
Q:>  2.4.4  Как определить под какой операционкой мы
            запустились?

A:>  Методов есть много и нет ни одного 100%-ного.
     Основные методы:
        Анализ фала C:\command.com (в Win9X он на самом деле .exe)
        Анализ версии Дос
        Анализ переменных окружения. (Тут есть одна хитрость.
        В Win9X есть переменная окружения windir. Особенность в том,
        что набрана она маленькими буквами и стандартная GETENV её не
        возвращает. Зато если перебрать все переменные окружения и
        проверить.... можно и масдайку расколоть если она того не
        хочет)
     Дополнительные примеры - см DzeServer.


------------------------------------------------------------------------------
Q:>  2.4.5  Как читать клавиши курсора, F1-F12 и т.д.?

A:>  Эти клавиши кодируются двумя байтами: #0 +<код>
     Есть таблицы для всех этих символов, но можно обойтись и без них
     Откомпилите эту программку и будете знать коды любых клавиш =)

     uses Crt;
      var
        Key: char;
     Begin
      while true do Begin
           Key:=readkey;
           case Key of
                #0: WriteLN('#0 + #', ord(readkey));
                #27: Begin WriteLN('#27 - Esc pressed.'); Halt; End;
                Else WriteLN(ord(key))
           End;
      End;
     End.

     ps  А можно ещё и скан-коды юзать, но это гемор и не всегда
         оправданно.

------------------------------------------------------------------------------
Q:>  2.4.5  Как получить в свое распоряжение больше чем
                640 кило памяти?

A:>  Юзать библиотеки для работы c EMS и XMS
     Компилировать в DPMI или под Винды причем желательно 32-битными
     компиляторами.

------------------------------------------------------------------------------
Q:>  2.4.6  Как в BP юзать 32-разрядный асм?

A:>  Поставить перед командой префикс: db 66h. Например,

        db 66h
        mov ax,bx
     эквивалентно mov eax,ebx в нормальном асме,

        db 66h
        movsw
     эквивалентно movsd. Только если засылается значение, придется
     недостающие байты отдельно задавать, иначе компилер не поймет.
     То есть:

       db 66h
       mov ax,5678h
       dw 1234h
     эквивалентно mov eax,12345678h в нормальном асме.
     Заодно: для 32х битных адресных выражений используется префикс 67h.

     (С)  Alexey Dorohin (2:5022/43.34)

------------------------------------------------------------------------------
Q:>  2.4.7  Как писать TSR'ы?

A:>  Для написания TSR'ов, программ которые остаются в памяти после
     передачи управления операционной системе, используется функция
     keep. Почитать о ней можно в хелпе, там же приведён пример самого
     простого резидента. Естественно для нормального резидента нужно
     активизироваться по каким-то событиям. Для этого обычно перехватывают
     какие-либо прерывания. Например прерывание клавиатуры
     (int 9h) или таймера (int 1Ch или 08h). Как повесить обработчик
     своего прерывания на int 1Ch показано в хелпе по Get/SetIntVec.
     Кроме того для настоящего TSR'а необходима нормальная выгрузка.
     Для этого необходимо создание каких-либо семафоров. Каких именно -
     все зависит только от вашей фантазии. Годиться почти все: начиная
     с файлов и заканчивая указателями прерываний.
     Примеры резидентов на Паскале опять же на DzeServer'е.


------------------------------------------------------------------------------
Q:>  2.4.8  Как осуществить поиск файла по всем директориям?

A:>  Необходимо воспользоваться процедурами FindFirst/FindNext и
     рекурсией. Например:

     {Вот пример самой простенькой програмки. Алгоритм тут весьма
     прозрачен, так что без комментариев.}

     uses Dos;
     {
      Эта программа ищет все файлы по маске turbo.* в поддиректориях
      папки C:\ и выводит на экран их полные имена =)
      Основа программы - функция SearchDir её параметры -
      fn - маска, Dir -начальная директория.
     }
     procedure SearchDir(fn, Dir:string);
     var
       SRec: SearchRec;
     begin
      if dir[length(dir)]<>'\' then Dir:=Dir+'\';

      FindFirst(Dir+fn, AnyFile, SRec);
      while DosError = 0 do begin
            WriteLN(Dir+SRec.Name);
            FindNext(SRec);
      End;
      FindFirst(Dir+'*.*', Directory, SRec);
      while DosError = 0 do begin
            with SRec do
                 if (Attr and 16 <> 0 ) and (Name[1]<>'.') then
                        SearchDir(fn,Dir+Name);
                 FindNext(SRec);
            end;

     end;

     Begin {program}
          SearchDir('turbo.*', 'C:\');
     End. {program}

Q:> А оно у меня не работает! Зацикливается на одном каталоге и вываливается
  по переполнению стека!
A:> А DOS не умеет работать с путями более 63 символов. Наверняка в этот
A:> каталог
  и ДОСовые NC/VC зайти не смогуь. Так что или выполняйте проверки, или
миритесь
  с этими неудобствами.
------------------------------------------------------------------------------
Q:>  2.4.9  Как организовать нормальную задержку?

A:> Задержка в милисекундах. Совместим по фоpмату с Delay из модуля CRT.

Procedure Delay(TimeMS: Word); Assembler;
Asm
     XOR   DX,DX
     MOV   AX,TimeMS
     MOV   BX,1000
     MUL   BX
     MOV   CX,DX
     MOV   DX,AX
     MOV   AH,86H
     INT   15H
End;

------------------------------------------------------------------------------

Q:> 2.4.10
  > А можно из паскаля работать с длинными именами файлов? А из-под ДОСа?
A:> Под виндой доступны функции для работы с длинными именами файлов.
  Подробнее ищите описание INT21h/AX=71xxh. Довольно популярен модуль LFN,
использующий эти функции. Искать на том же pascal.sources.ru. Для чистого ДОСа
все несколько сложнее. Некоторые клоны DOS'а имеют встроенную поддержку
длинных имен, для других требуются спец. драйвера типа LONGNAME или DOSLFN.
  Для любителей остается возможность ковыряться в оглавлении каталогов на
FAT-разделах (почему это плохо - отдельная песня). Говорят, готовый модуль
для этого случая есть в составе DN OSP. Только по сети этот трюк не сработает.

P.S. Есть еще Odi's LFN Tools (http://odi.webjump.com) - они тоже работают
с диском напрямую.

------------------------------------------------------------------------------

Q:> 2.4.11
  > А почему у меня exec() не работает?
  > Как запустить внешнюю программу?
A:> Прочитать справку по паскалю на темы {$M} и exec().
  Директива {$M } нужна, чтобы программа забрала себе под "кучу" не всю
свободную память, как это делается по умолчанию, а не более чем указанное число
байт. Альтернативный способ - использовать Heap manager из модуля drivers
пакета Turbo Vision.
  Вот простенький пример, который вызывает команду Dir коммандного процессора
(command.com). BTW, программы можно запускать сами по себе (только .com и .exe)
или через коммандный процессор. Во втором случае можно выполнять и .bat файлы,
и команды DOS'а (такие как DIR), но тогда программе достанется чуть меньше
памяти и нельзя будет получить ее код возврата (DosExitCode).

{$M 4096,0,0} {4096 байт под стек, под кучу использовать не менее 0 и
не более 0 байт}
uses dos;
var
  s:string;
begin
  s:=GetEnv('COMSPEC');{получили путь к командному процессору}
  if s='' then s:='C:\COMMAND.COM';{редкий случай - отсутствие пути}
  SwapVectors;
  exec(s,' /c dir /s');{выполнили}
  SwapVectors;
end.

------------------------------------------------------------------------------
Q:>  2.5  Файлы

     Вопросы связанные с типами файлов и доступа к ним.

------------------------------------------------------------------------------
Q:>  2.5.1  Где взять описание <такого-то> формата файлов?

A:>  В программерских эхах, faqServer'ах. Если нигде не нашли
     советую посмотреть на http://www.wotsit.org
     По некоторым отзывам - очень неплохое байтохранилище с
     немереным количеством описаний типов файла.

------------------------------------------------------------------------------
Q:>  2.5.2  Как прочитать mp3 tag?

A:>  MP3-файл заканчивается следующей структурой:

     TagCharRec = Record
       ident    : array [1..03] of char;
       title    : array [1..30] of char;
       artist   : array [1..30] of char;
       album    : array [1..30] of char;
       year     : array [1..04] of char;
       comment  : array [1..30] of char;
       genre    : byte;
     End;

     всего      : 128 bytes

     Причём ident='TAG'. Если это не так, то по-ходу дела нужно
     дописывать эту структуру, а не изменять.
     genre - номер жанра. $FF - не указан.


------------------------------------------------------------------------------
Q:>  2.5.3  Как прочитать файлы с картинками (*.bmp; *.jpg)?

A:>  Стандартных функций для этого нет (если не считать Дельфи)
     Поэтому выход один - брать описания типов и писать самому.
     Хотя нет... есть ещё один. Взять уже написанные кем-либо
     модуле. Где взять? Да полно их. Опять же на DzeServer'е =)

------------------------------------------------------------------------------
Q:>  2.5.4  Как удалить строку из текстового файла?

A:>  Только переписывая его заново, пропуская ненужную строку.
     То же самое относиться и к бинарным файлам. Можно немного
     оптимизировать этот процесс, но принципиально ничего другого
     не остаётся =(

------------------------------------------------------------------------------
Q:>  2.5.5  Как читать .ctl/.cfg -файлы?

A:>  Вот один из вариантов:
     Думаю здесь все до безобразия прозрачно.
     F - файл, откуда читаем
     S, S1 - служебные переменные, строки (зачем s1 - думаю понятно)
     'KEYKODE' - название читаемого параметра (регистр не имеет
                 значения - для этого и S1)
     varKeyCode - собственно переменная куда читать.

        while not eof(F) do Begin
                readLn(F, S);
                if S='' then continue;
                if S[1]=';' then continue;
                if Pos(';', S) <> 0 then    {отсекает то, что не нужно}
                        S:=copy(S, 1, Pos(';', S)-1);
                S1:=UpLine(S);     {Функция перевода в верхний регистр}

                if copy(S1, 1, Lenght('KEYKODE')+1) = 'KEYCODE ' then Begin
                        varKeyCode:=copy(S, Lenght('KEYKODE')+1, 255);
                        Continue
                End;
                [  scip about other KeyCodes =)  ]

                WriteLN('Error in configuration file =) ');
        End;

------------------------------------------------------------------------------
Q:>  2.5.5.1  Как обрабатывать INCLUDE?

A:>  А в чем  проблема, собственно? Просто предыдущий кусок кода выполняется
     в виде процедуры, которая вызывается рекурсивно при нахождении слова
     'INCLUDE'

------------------------------------------------------------------------------
Q:>  2.5.6  Как дописать в конец .exe-файла?

A:>  Так же как и в любой дpугой файл. см Seek и FileSize в хелпе.

------------------------------------------------------------------------------
Q:>  2.5.6.1  свою программу?

A:>  Так же как и любую другую информацию =)

     Ах, вам нужно, небось, чтоб она ещё и управление  получала? Тогда
     огорчу: здесь не пункт подготовки вирус описателей, которые не знают
     даже как заголовок .exe переправить. Читайте книжки и доки - они
     рулез. А когда начнёте все понимать - может и вирусы писать не
     захотите =)

------------------------------------------------------------------------------
Q:>  2.5.6.2  свои настройки, как это делает сам BP/TP

A:>  Дописывать их также. Append'ом. А чтобы перезаписывать и читать нужно
     знать оригинальную длину файла. Или просто помнить сколько байтов вы
     дописывали и читать их, что гораздо проще вычисления ординальной длинны.
     Примеры - на DzeServer'е.


------------------------------------------------------------------------------
  >  2.6 Другое


------------------------------------------------------------------------------
Q:>  2.6.1 Есть 2 юнита. В каждом из них есть процедура с одним и тем же
           именем. Как компилятор узнает какую нужно вызывать?
A:>  Из модуля, который описан позже зарезервированным словом Uses
A:>  Можно явно указывать процедуру:
     program a1;
     uses a2,a3;
       procedure Print;
       begin
        ...
       end;
     ...
     begin
       a1.Print; {будет вызвана процедура, описаная в самой программе}
       a3.Print; {будет вызвана процедура, описаная в модуле a3}
       a2.Print; {будет вызвана процедура, описаная в модуле a2}
     end.


----The End.------------------------------------------------------------------

Секция 2 из 2 - Предыдущая - Следующая

Вернуться в раздел "Языки Pascal/Delphi" - Обсудить эту статью на Форуме
Главная - Поиск по сайту - О проекте - Форум - Обратная связь

© faqs.org.ru