Вопрос № 20577: Здравствуйте, помогите, пожалуйста, бедному студенту.
Нужна помощь в написании программы по перехвату прерываний клавиатуры.
В книжках ничего конкретного не почерпнул, копаться в рассылках не охото, нормальные статьи найти немогу, преподовате...Вопрос № 20582: Уважаемые эксперты..... Помогите найти в данных процедурах найти ошибку.... Всё всермя выбрасывает с недопустимой инструкцией...... Очень надо....
Int_1Ch_proc proc far
pushf
call dword ptr cs:[Int_1Ch_vect] ;вызов оригинального о...
Вопрос № 20577
Здравствуйте, помогите, пожалуйста, бедному студенту.
Нужна помощь в написании программы по перехвату прерываний клавиатуры.
В книжках ничего конкретного не почерпнул, копаться в рассылках не охото, нормальные статьи найти немогу, преподователь злой и не помогает - вот к Вам обращаюсь.
Суть программы в том, что при нажатии на клавишу должен происходить перехват этого прерывания, и подмена выходных параметров. В частности, если нажата буква 'a' - на экране должна появиться буква 'b' и наоборот.
Кое-что, конечно, препод подсказал - но все равно ничего не работает. Если раньше прога хоть вешала намертво комп, то сейчас вообще ничего не происходит.
Помогите, пожалуйста. Расскажите, где основная ошибка и что надо откорректировать. Заранее списибо!
Приложение:
Отправлен: 08.05.2005, 15:48
Вопрос задал: Сухоруков Юрий (статус: Посетитель)
Всего ответов отправлено: 3
Отвечает: Евгений Иванов
Здравствуйте, raynor_y!
сохраняй регистры в прерывании!!!!
и не вызывай из своего обработчика то же самое прерывание.
смотри файл
Прикреплённый файл: Загрузить >> Срок хранения файла на сервере RusFAQ.ru составляет 14 суток с момента отправки ответа.
Ответ отправил: Евгений Иванов (статус: Профессор)
Отправлен: 08.05.2005, 23:47
Отвечает: Ayl
Здравствуйте, raynor_y!
Хм... Ошибок много.
Во-первых, у тебя не резидентная программа! Вот трассировка действий твоей программы:
1. Установить сегмент данных - ок.
2. Получить адрес старого обработчика 16-го прерывания - ок.
3. Сохранить адрес в переменных - ок.
4. Установить свой обработчик - ок. Обсуждение написания обработчика - дальше.
5. Установить ds:bx на адрес старого обработчика. Хм. А зачем? Непонятное действие.
6. Комментированные строки. Записать по адресу ds:chr_out значение регистра al. А куда указывает ds? правильно - на сегмент старого обработчика. Интересно, я бы, пожалуй, тоже обиделся на такую запись.
7. Вывести на экран строку, завершающуюся символом '$' и начинающуюся с адреса ds:chr_out. Ну, сегментный регистр по-прежнему указывает на сегмент старого обработчика, а вот будет ли там символ доллара - я не уверен. Кстати, прога вылетает, скорее всего, еще на шаге 6.
8. Завершить программу с выходом в ДОС.
Итак, что ты имеешь:
1. Неправильная установка регистра ds
2. После возможного завершения программы ты теряешь адрес старого обработчика и при запуске следующей программы вызов 16-го прерывания все равно приведет к ошибке
3. Программа не резидентная, т.к. не остается в памяти после завершения.
Теперь по поводу обработчика. Допустим, что его вызвали. Что о делает. А делает он то, что в первой же строке обращается к самому себе! Рекурсия, причем безусловная! Т.е. зацикливание. Очень быстро произойдет переполнение стека - и опаньки! Неправильный алгоритм.
И последнее. Насколько я понял из задания, тебе нужно отлавливать нажатия на клавиши и подменять 'a' на 'b', а 'b' на 'a'. но все дело в том, что 16-е прерывание - программное! И работает только при прямом обращении. Т.е. если программа не будет вызывать 16-е прерывание, то и работать это не будет.
В то же время любое нажатие или отпускание клавиши генерирует на аппаратном уровне прерывание IRQ1, которое соответствует вектору 9. Т.е. любое нажатие клавиши вызывает обработчик 9-го прерывания! Может, с ним лучше поиграть?
И еще два вопроса. Зачем ты при написании резидента создаешь EXE-программу? Да, это не ошибка, но написание резидента в виде EXE-модуля гораздо сложнее написания такого же резидента, но в виде COM-программы.
Второй вопрос - ты используешь 32-разрядные регистры или команды 386-го процессора? Если нет - зачем использовать .386? Достаточно .286, хотя твой код вполне компилируем и на 8088. Это, как ты понимаешь, не ошибка, но если бы я был твоим преподом, то в первую очередь задал бы этот вопрос, чтобы выяснить, а понимаешь ли ты вообще эту директиву.
В общем, см. в приложении резидент на 16-е прерывание в виде COM-программы. Он очень простой, практически не делает никаких действий, только устанавливает новый обработчик прерывания и завершается резидентно. Теперь при любом получении нажатия клавиши через 16-е прерывание будет осуществляться проверка на скен-коды клавиш A и B и их подмена. Вывод на экран также будет формироваться внешней программой.
От этого можешь отталкиваться.
Приложение:
Ответ отправил: Ayl (статус: Профессор)
Отправлен: 11.05.2005, 14:39 Оценка за ответ: 5 Комментарий оценки: Да, свои ошибки понял. БОЛЬШУЩЕЕ !!!спасибо!!!
Отвечает: Стас
Здравствуйте, raynor_y!
1) накой тебе сдался PSP, Chr_out (который ты почему-то 9 функцией 21 прерывания пытаешься вывести)?
2) вызывая Int 16 из Int 16 ты намертво зацикливаешся.
3) mov ax,4C00h int 21h выгружает твою прогу из памяти ПОЛНОСТЬЮ, при этом Int16 yt восстанавливаешь. Тоже ерунда.
4) Вообще в данном случае перехват Int16 не лучший вариант, есть много других способов получить код нажатой клавиши минуя ah=0 int 16h.
Тем не менее вот такой вариант: (COM файл)
.model tiny
386
.code
org 100h
start:
jmp begin
; ф-ция
intproc:
or ah,ah
jnz loc1
pushf
call dword ptr cs:oldint16
cmp ax,1e61h
jnz loc2
mov ax,3062h
loc2:
iret
loc1:
jmp dword ptr cs:oldint16
oldint16:
_off dw ?
_seg dw ?
; ф-ция закончена
begin:
mov ax,3516h
int 21h
mov ax,es
mov _seg,ax ;Запомнить старый Int16
mov _off,bx
mov ax,cs
mov ds,ax
lea dx,intproc
mov ax,2516h
int 21h ;Установить новый
lea dx,begin ;Оставить резидентом!!!
int 27h
end start
А вот более приемлимый вариант перехватывающий INT9:
.model tiny
.386
.code
org 100h
start:
jmp begin
; ф-ция
intproc:
pushf
call dword ptr cs:oldint9 ;пусть отработает оригинальный и положит в буфер клавиатуры код
push ds
push bx
push ax
push 40h
pop ds
mov bx,ds:[1ch] ;какой последний код был положен в буффер
cmp bx,1eh
jnz loc1
add bx,20h; буффер круговой
loc1:
sub bx,2
mov ax,[bx]
cmp ax,1e61h ;только маленькая 'a' !!!! большая будет:1e41 (c ctrl-a =1e01h) и т.д.
jnz loc2
mov ax,3062h ;большая 3042h
mov [bx],ax ;вот собственно и подмена
loc2:
pop ax
pop bx
pop ds
iret
oldint9:
_off dw ?
_seg dw ?
; ф-ция закончена
begin:
mov ax,3509h
int 21h
mov ax,es
mov _seg,ax ;Запомнить старый Int09
mov _off,bx
mov ax,cs
mov ds,ax
lea dx,intproc
mov ax,2509h
int 21h ;Установить новый
lea dx,begin ;Оставить резидентом!!!
int 27h
end start
Есть еще несколько вариантов решения той же проблемы.
Ответ отправил: Стас (статус: Практикант)
Отправлен: 13.05.2005, 00:17
Вопрос № 20582
Уважаемые эксперты..... Помогите найти в данных процедурах найти ошибку.... Всё всермя выбрасывает с недопустимой инструкцией...... Очень надо....
Int_1Ch_proc proc far
pushf
call dword ptr cs:[Int_1Ch_vect] ;вызов оригинального обработчика
test cs:[MyFlags],bActivityFlag ;проверим флаг активизации резидента
jz Not_active
iret ;активирован выходим
Not_active:
test cs:[MyFlags],bCallFlag ;проверим флаг вызова резидента
jnz callVideo
or cs:[MyFlags],bActivityFlag ;установим флаг активации резидента
mov al, 20h ;сбросим контроллер прерываний
out 20h, al
call MyResident ;вызываем резидентную процедуру
and cs:[MyFlags], (not bActivityFlag) ; сбросим флаг активации
iret ;выходим
CallVideo:
test cs:[MyFlags],b10hFlag ;проверим флаг вызова 10-ого прерывания
jz Vid1
iret
Vid1:
or cs:[MyFlags],bActivityFlag ;установим флаг активации резидента
mov al, 20h ;сбросим контроллер прерываний
out 20h, al
pushf
or cs:[MyFlags],bActivityFlag
cmp ax,9889h ;Проверка на повторную загрузку
jne Goo_21h
xchg ah,al ;Если мы уже в перехватывает прерывание, то
popf
and cs:[MyFlags], (not bActivityFlag)
iret ;меняем регистры
Goo_21h:
popf
and cs:[MyFlags], (not bActivityFlag)
jmp dword ptr cs:[Int_21h_vect] ;передаем управление
;оригинальному обработчику 21h
Go_21h:
jmp dword ptr cs:[Int_21h_vect] ;передаем управление
;оригинальному обработчику 21h
Отправлен: 08.05.2005, 19:51
Вопрос задал: edson (статус: Посетитель)
Всего ответов отправлено: 2
Отвечает: Евгений Иванов
Здравствуйте, edson!
отвечаю в жж
http://www.livejournal.com/community/useful_faq/294819.html
впредь будь внимателен
Ответ отправил: Евгений Иванов (статус: Профессор)
Отправлен: 09.05.2005, 21:15
Отвечает: Стас
Здравствуйте, edson!
Была бы прога полностью посмотрел, так не охота.
Могу посоветовать как это сделал бы я:
Отключал бы процедуры одна за другой, и смотрел когда перестает работать.
Или наоборот отключил бы все, а потом постепенно подключал по модулю.
Ответ отправил: Стас (статус: Практикант)
Отправлен: 13.05.2005, 00:24