1)Q:> А как восстановить исходники на паскале
из .exe/.tpu?
1)A: Hикак!
Хотя, если есть желание помучиться, то...
В пaкете Turbo Analyst 7.0 есть утилиткa, котоpaя может
восстaновить
интеpфейсную чaсть скомпилиpовaнного модуля, a тaкже
изaссемблиpовaть implementation-чaсть.
2)Q:> Как использовать TPU для 6-й версии TP
в 7-й версии?
2)A: Если нет исходников, то Hикак!
3)Q:> Хочу паскаль под DOS, но в защищенном
режиме! 32-bit protected! Под Win32! Под OS/2!
3)A: В Borland Pascal 7.0 можно использовать только_
16-битный защищенный режим,он же DPMI. (Turbo Pascal
- это всего лишь облегченная версия BP, работающая только
в реальном режиме, посему запустите BP.exe и узнаете
много нового (хотя бы посмотрите на возможности пункта
TARGET при компиляции).Для 32-bit защищенного режима
существуют более лругие компиляторы:
4)Q:> А почему задержки, которые задаются процедурой
Delay(),на разных машинах разные?
4)A: Юнит CRT криво написан.
5)Q:> А чем тогда делать фиксированную задержку,
вместо Delay()?
5)A: Если достаточна точность в 1 тик (1/18 доля секунды),
то так:
Procedure Delay(x:longint);
{пауза на Х тиков}
var
l:longint;
begin
l := MemL[Seg0040:$6c];
while MemL[Seg0040:$6c] < l+x do; {задержка на X
тиков}
end;
Если нужно точнее, то надо читать регистры таймера...
Вот вам другая процедура:
procedure RTCDelay(Wait:LongInt); assembler;
{Ожидание на Wait микросекунд }
asm
mov ah,86h
mov dx,word ptr Wait
mov cx,word ptr Wait+2
int 15h
end;
Wait - в *микро*секундах, но разрешение все равно с
точностью до
~976 микросекунд (примерно 1 миллисекунда), т.е. меньше
1024
ставить просто бессмысленно.
6)Q:> А как убрать курсор в текстовом режиме?6)A: procedure CursorOff; assembler;
asm
mov ah,1
mov cx,2020h {Убрать мерцание за пределы знакоместа}
int 10h
end;
7)Q:> А как его потом обратно включить?
7)A:
procedure CursorOn; assembler;
asm
mov ah,1
mov cx,0607h {Установить мерцание 6й и 7й строк}
int 10h
end;
8)Q:> А можно сделать так, чтобы курсор был
виден, но не мигал?
8)A: Hет. Только самому рисовать '_' (подчеркивание)
в нужном месте.
9)Q:> А почему программы, написанные на паскале,
вылетают с ошибкой Runtime Error 200 (Division by zero)
на быстрых машинах типа PII-300?
9)A: Еще раз: Юнит CRT криво написан. Если в программе
используется модуль CRT, то программа виснет при запуске
из-за инициализации, которая потом используется процедурой
Delay(). Инициализация происходит в любом случае даже
если эта процедура не используется в программе. При
написании своих программ используйте пропатченный CRT.
Чтобы заработала уже скомпилированная программа (чужая),
возьмите hex-редактор и:
Ищем: B93700F7F1
Меняем на: B96E00F7F1 (увеличение в 2 раза)
или на: B937009090 (убрать деление вообще)
Программа _не_ должна быть запакована EXE-паковщиками.
10)Q:> Почему глючат процедуры побитового сдвига
shl, shr в применении к LongInt?
10)A: Известный баг.
Можно поставить фикс BP7.0 -> BP7.01, или же использовать
свои процедуры.
Вот пример (работают на 386+):
function LongShl(A: LongInt; B: Byte): LongInt; assembler;
asm
mov cl,[B]
db $66 {код опеpаций с 32-битными pегистpами}
mov ax,word ptr [A]
db $66
shl ax,cl
db $66
push ax
pop ax
pop dx
end;
function LongShr(A: LongInt; B: Byte): LongInt; assembler;
asm
mov cl,[B]
db $66
mov ax,word ptr [A]
db $66
shr ax,cl
db $66
push ax
pop ax
pop dx
end;
11)Q:> Почему при умножении 2-х чисел получается неверный результат:
var a,b:Word;
l:LongInt;
a:=1234;
b:=567;
l:=a*b;
В l получается. 44318, а не 699678, как должно быть на
самом деле.
Это баг?11)A: Hет, это фича. Тип выражения определяется только типом входящих в него переменных, но не типом переменной, куда записывается результат. Если есть опасность переполнения, надо конвертировать тип явно: l:=LongInt(a)*b;
12)Q:> А как из моей программы запустить другую?
12)A: С помощью процедуры Exec:
SwapVectors;
Exec(Путь&ИмяВашейПрограммы, Доп_Параметры);
SwapVectors;
13)Q:> А почему внешняя программа из моей не
запускается?
13)A: А память кто будет внешней проге отдавать?
По умолчанию все 640Kb отдаются твоей программе.
Исправить это можно либо через Options/Memory Sizes../
High heap limit,
либо директивой компилятора:
{$M 4096,0,10000}
Здесь первая цифра - память под стек (в стеке размещаются
локальные переменные каждой вызываемой процедуры/функции),
вторая - нижняя граница памяти, третья - верхняя.
В данном примере твоей программе отдается 10000 байт,
а все остальное - внешней программе.
14)Q:> А если мне самому память нужна?
14)A: Используй библиотеку для своппинга (выгрузки из
памяти) в XMS/EMS/Disk - перед запуском внешней программы
твоя программа вместе со всеми данными переписывается
в XMS/EMS или на винт, а после завершения внешней -
восстанавливается.
Можно воспользоваться, например, юнитом SPAWNO от Ральфа
Брауна, или модулем OpExec из ObjectProf by TurboPower.
15)Q:> Как сделать процедуру с нефиксированным
числом параметров, типа writeln?
15)A: Встроенными средствами BP - Никак.
WriteLn - это не процедура вовсе, это макрос такой,
сделанный для удобства.
16)Q:> Как с этим боpоться (сделать одну пpоцедуpу)?
16)A: Пеpедавать yказатель на блок паpаметpов и какой-нибyдь
флаг, по котоpомy внyтpи пpоцедypы бyдешь сам pазбиpаться
с этим блоком паpаметpов.
Hапpимеp так:
procedure aaa(var param; flag: byte);
17)Q:> Как узнать ErrorLevel,который выставила
программа, запущенная через Exec()?
17)A: С помощью DosExitCode:
{$M 8192,0,0}
Uses Dos;
Begin
SwapVectors;
Exec(FExpand(FSearch('arj.exe',GetEnv('PATH'))),'x a.arj');
SwapVectors;
WriteLn('Код возврата=',lo(DosExitCode));
End.
18)Q:> Предположим, запустили мой ЕХЕ.
> Как узнать из программы, в каком каталоге он лежит,
> и не переименовали ли его?
18)A: Функция ParamStr(0) возвращает полное имя запущеннонго
exe-файла,
например 'c:\exe\work.exe'.
При запуске программы из-под IDE (Ctrl-F9) вместо имени
программы ParamStr(0) вернет путь к файлу turbo.exe,
если программа компилируется в память (Compile/Destination
= Memory),
или имя программы без пути, если компилировать на диск.
19)Q:> Как узнать, какие параметры передаются
моему ЕХЕ при вызове из командной строки?
19)A: Функция ParamStr(i) возвращает i-й параметр в
виде строки.
Отдельным параметром считается комбинация символов,
не содержащая пробелов.
Функция ParamCount возвращает общее количество параметров,
переданных программе.
19)A2: Если вам необходимо совершить некие продвинутые
операции с переданной командной строкой - например,
вы получаете параметры, содержащие пробелы и заключенные
в кавычки, - вам поможет следующий исходник, копирующий
всю
командную строку в первоначальном виде в строковую переменную:
var
s: ^string;
begin
s:=ptr(prefixseg, $80);
writeln('Command line: "', s^, '"');
end.
20)Q:> А можно записать в середину текстового
файл строку произвольной длины, но чтобы остальные строки
остались, как были, или удалить одну строку из середины?
20)A: Просто так - нет. Есть два варианта.
Простой: открываете второй файл, читаете строки из первого,
пишете строки во второй, пропуская то, что не нужно,
или дополняя в нужных местах.
Сложный: открываете файл, как бинарный, составляете
список длин строк, и копируете куски файла в другой
с помощью BlockRead/BlockWrite.
{пример для простого варианта}
var
f1,f2: text;
s: string;
const
ourstring = 'ДЬВ'; {искомая стpока}
begin
assign(f1,'c:\a.txt');
assign(f2,'c:\b.txt');
reset(f1); rewrite(f2);
while not eof(f1) do
begin
readln(f1,s);
if pos(ourstring,s)<>0 then continue; {пропустить
строку, если найдено}
writeln(f2,s);
end;
close(f1); close(f2);
end.
21)Q:> Как обойти все каталоги на диске?
21)A: Используя процедуры FindFirst, FindNext.
Их описание есть в хелпе.
Вкратце - в функции обхода перебираем все вхождения
в каталог,
и проверяем каждое из них - если это каталог, то входим
в него
и рекурсивно вызываем функцию обхода каталога.
Uses Dos;
Procedure DirTree(path:string);
var
sr:searchrec;
begin
If path[length(path)]<>'\' then path:=path+'\';
findfirst(path+'*.*',AnyFile,sr);
while (doserror=0) do begin
if (sr.attr and directory) = directory then begin
if (sr.name<>'.') and (sr.name<>'..') then
DirTree(path+sr.name+'\');
end else begin
writeln(path+sr.name);
end;
findnext(sr);
end;
end;
begin
DirTree(ParamStr(1));
end.
22)Q:> А почему одновременно больше 14 файлов
Borland Pascal не открывает?
22)A: Используйте в вашей программе вот такой модуль.
Можете до 255 файлов открыть.
{$IFDEF DPMI}
STOP COMPILE ! Only for real mode !
{$ENDIF}
Unit Extend; {(C) 1996 by Pavel Nikiforov}
interface
implementation
procedure Setup;
type PJFT=^TJFT;
TJFT=record
Num:word;
Tbl:PChar;
end;
var MyJFT:PChar;
P:PJFT;
begin
getmem(MyJFT,255);
FillChar(MyJFT[0],255,$FF);
P:=Ptr(PrefixSeg,$32);
move(P^.TBL^,MyJFT^,P^.Num);
P^.TBL:=MyJFT;
P^.Num:=255;
end;
begin
Setup;
end.
23)Q:> 1) А как открыть на запись файл с
атрибутом read/only? Ругается.
> 2) Как удалить r/o файл?
23)A: Hужно снять атрибут r/o с файла, а затем делать
с ним все, что
заблагорассудится.
Uses DOS;
var
t:text;
attr:Word;
Begin
Assign(t,'file');
GetFAttr(t,attr); {Прочитать атрибуты файла }
attr:=attr and $FE;
SetFAttr(t,attr); {Сбросить атрибут ReadOnly}
Append(t);
Writeln(t,'Hello!'); {Дописать что-либо в файл }
Close(t);
attr:=attr or $01;
SetFAttr(t,attr); {Восстановить атрибут ReadOnly}
End.
24)Q:> Ищу я все подкаталоги в данном каталоге
процедурой FindFirst('*.*',Directory,Search), а она
мне не только подкаталоги, но и все файлы находит. В
чем дело?
24)A: Глюк MS-DOS.
А именно, функции 4E прерывания 21.
Hужно после каждого использования FindFirst/FindNext
проверять,
каталог ли ты нашел:
if Search.Attr and (Directory <> 0) then begin
[...] end;
25)Q:> А почему файл не хочет переименовываться/удаляться?
Я сделал так:
Assign(f,'file');
Reset(f);
Erase(f)
25)A: Открытые файлы переименовывать/удалять нельзя.
Либо закройте его командой Close(f) перед удалением,
либо не открывайте его вообще - после Assign делайте
сразу Erase.
Assign(f,'file');
Erase(f)
26)Q:> Как получить полное имя файла с путем,
если известно его имя, и то, что он лежит в одном из
каталогов, определенных в переменной PATH?
26)A: FileName:=FExpand(FSearch('file.ext',GetEnv('PATH'))



