Главная > Программирование > Языки 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" - Обсудить эту статью на Форуме |
Главная - Поиск по сайту - О проекте - Форум - Обратная связь |