Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Управление лотком CD-ROM на Ассемблере

06.02.2011 | Категория: Образ мышления: Assembler | Автор: ManHunter
Открывать и закрывать лоток CD-ROM можно программными способами. Это может оказаться полезным в случаях, когда системный блок стоит в труднодоступном месте или по каким-либо иным причинам нет возможности управлять им при помощи механической кнопки. Также я читал истории, когда на лоток CD-ROM возлагались полезные функции, например, при выдвижении он замыкал контакты питания и отправлял сервер в перезагрузку, а администратор таким образом удаленно управлял им. Так что программное управление лотком CD-ROM имеет место быть, и наша задача научиться его делать. Чаще всего в разных интернетах описывается способ управления при помощи MCI (Media Control Interface). Кстати, именно этот способ приводится в качестве одного из примеров программ в пакете FASM.
  1.         ...
  2.         ; Открыть лоток CD-ROM
  3.         invoke  mciSendString,cmd_open,0,0,0
  4.         invoke  mciSendString,cmd_eject,0,0,0
  5.         invoke  mciSendString,cmd_close,0,0,0
  6.         ...
  7.         ; Закрыть лоток CD-ROM
  8.         invoke  mciSendString,cmd_open,0,0,0
  9.         invoke  mciSendString,cmd_load,0,0,0
  10.         invoke  mciSendString,cmd_close,0,0,0
  11.         ...
  12. cmd_open   db 'open cdaudio',0
  13. cmd_eject  db 'set cdaudio door open',0
  14. cmd_load   db 'set cdaudio door closed',0
  15. cmd_close  db 'close cdaudio',0
У данного метода есть недостатки. Главный заключается в том, что при наличии в системе нескольких приводов CD-ROM нет возможности указать, лоток которого из них необходимо выдвигать, всегда открывается первый по счету. Второй существенный недостаток - некоторые антивирусы считают наличие таких функций в программах потенциально опасными. Видимо из-за того, что иногда несанкционированное открытие лотка CD-ROM используется в различных программах-шутках для окошмаривания доверчивых пользователей.

Читать статью целиком »
Просмотров: 10092 | Комментариев: 6

Проверка баланса скобок на Ассемблере

28.01.2011 | Категория: Образ мышления: Assembler | Автор: ManHunter
Есть такая классическая задача по программированию: проверка правильности расстановки скобок в строке, или иначе проверка баланса скобок. Суть задачи заключается в том, что есть произвольное математическое выражение, записанное в строку, в этом выражении используется три вида скобок "( )", "[ ]" и "{ }", последовательность и вложенность может быть любая. Требуется проверить, все ли скобки закрыты, соответствует ли каждая закрывающая скобка открывающей и нет ли лишних закрывающих скобок. В разных интернетах есть решения на различных языках программирования, я решил добавить свое решение на Ассемблере, тем более, что он идеально подходит для реализации этого алгоритма.

Решение заключается в том, что мы двигаемся по строке с самого начала, перебирая все символы по одному. Если символ является открывающей скобкой любого типа, то мы помещаем его в стек. Если символ является закрывающей скобкой, то берем из стека последнюю сохраненную открывающую скобку и проверяем на соответствие. Если не совпадают - ошибка несоответствия скобок, если стек пустой, то ошибка лишней закрывающей скобки. Если конец строки достигнут, но стек не пустой, то ошибка незакрытых скобок. Как видите, решение целиком построено на работе со стеком, а Ассемблер предоставляет для этого все возможности. Переходим к программированию.
  1. ;------------------------------------------------------------------------
  2. ; Функция проверки правильности расстановки скобок в выражении
  3. ; На входе: указатель на строку ASCIIZ
  4. ; На выходе: EAX - результат проверки выражения
  5. ;    0 - скобки расставлены правильно
  6. ;    1 - ОШИБКА: скобки не совпадают
  7. ;    2 - ОШИБКА: закрывающая скобка без открывающей
  8. ;    3 - ОШИБКА: открывающая скобка без закрывающей
  9. ;------------------------------------------------------------------------
  10. proc    CheckBrackets str:DWORD
  11.         local res:DWORD ; Результат
  12.  
  13.         pusha                   ; Сохранить все регистры
  14.  
  15.         mov     esi,[str]       ; Указатель на строку
  16.         cld
  17.         xor     ecx,ecx         ; Глубина стека
  18.         mov     [res],0         ; Результат проверки
  19.  
  20. .scan_expr:
  21.         lodsb                   ; Прочитать символ из строки
  22.         or      al,al           ; Конец строки достигнут?
  23.         jz      .finish
  24.  
  25.         ; Проверить открывающие скобки
  26.         cmp     al,'['
  27.         je      .push_bracket
  28.         cmp     al,'('
  29.         je      .push_bracket
  30.         cmp     al,'{'
  31.         je      .push_bracket
  32.  
  33.         ; Проверить закрывающие скобки
  34.         cmp     al,']'
  35.         je      .pop_bracket
  36.         cmp     al,')'
  37.         je      .pop_bracket
  38.         cmp     al,'}'
  39.         je      .pop_bracket
  40.  
  41.         jmp     .scan_expr      ; Следующий символ
  42.  
  43.         ; Занести скобку в стек
  44. .push_bracket:
  45.         inc     ecx             ; Увеличить счетчик
  46.         movzx   eax,al          ; Записать скобку в стек
  47.         push    eax
  48.         jmp     .scan_expr      ; Следующий символ
  49.  
  50.         ; Извлечь скобку из стека
  51. .pop_bracket:
  52.         or      ecx,ecx         ; В стеке ничего нет?
  53.         jne     @f
  54.  
  55.         ; ОШИБКА: закрывающая скобка без открывающей
  56.         mov     [res],2
  57.         jmp     .finish
  58. @@:
  59.         dec     ecx             ; Уменьшить счетчик
  60.         pop     ebx             ; Извлечь из стека скобку
  61.  
  62.         ; Проверить закрывающие скобки
  63.         cmp     bl,'['
  64.         jne     @f
  65.  
  66.         cmp     al,']'          ; Скобки совпадают?
  67.         je      .scan_expr      ; Да, следующий символ
  68. @@:
  69.         cmp     bl,'('
  70.         jne     @f
  71.  
  72.         cmp     al,')'          ; Скобки совпадают?
  73.         je      .scan_expr      ; Да, следующий символ
  74. @@:
  75.         cmp     bl,'{'
  76.         jne     @f
  77.  
  78.         cmp     al,'}'          ; Скобки совпадают?
  79.         je      .scan_expr      ; Да, следующий символ
  80. @@:
  81.         ; ОШИБКА: скобки не совпадают
  82.         mov     [res],1
  83.         or      ecx,ecx         ; В стеке пусто?
  84.         jz      .exit           ; Да, просто на выход
  85.         jmp     .clean_stack    ; Надо почистить стек
  86. .finish:
  87.         or      ecx,ecx         ; Все проверили и в стеке пусто?
  88.         jz      .exit           ; Да, скобки расставлены правильно
  89.  
  90.         ; ОШИБКА: открывающая скобка без закрывающей
  91.         mov     [res],3
  92.  
  93.         ; Почистить стек от оставшихся скобок
  94. .clean_stack:
  95.         pop     eax
  96.         loop    .clean_stack
  97. .exit:
  98.         popa                    ; Восстановить все регистры
  99.         mov     eax,[res]
  100.  
  101.         ret
  102. endp
Текст функции проверки подробно прокомментирован, так что в дополнительных пояснениях не нуждается. Тем более, что алгоритм был расписан словами выше. Где это можно использовать? Кроме различных калькуляторов подобные решения можно применять для валидации xml-подобных документов, при проверке синтаксиса каких-либо скриптов и т.п., так что главное уяснить принцип.

Читать статью целиком »
Просмотров: 7130 | Комментариев: 4

Эффект плавного открытия окна

08.12.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
Разберем еще один красивый эффект для ваших приложений - плавное сворачивание и разворачивание окна. Для этого используются те же функции, что и для создания окон нестандартной формы, так как по сути это такая же работа с прямоугольными регионами, но только в цикле с заданными параметрами. Алгоритм простой: прямоугольный регион окна увеличивается от центра до полного размера или уменьшается со всех сторон до центра. Для этого надо сперва надо вычислить шаг, на который будет увеличиваться или уменьшаться горизонтальная и вертикальная координата.
  1.         ; Обработчик инициализации окна
  2.         ...
  3.         ; Получить размер окна
  4.         invoke  GetClientRect,[hwnddlg],coord
  5.  
  6.         ; Вычислить размеры окна для создания основного региона
  7.         mov     eax,[coord.bottom]
  8.         sub     eax,[coord.top]
  9.         mov     [height],eax
  10.  
  11.         mov     eax,[coord.right]
  12.         sub     eax,[coord.left]
  13.         mov     [width],eax
  14.  
  15.         SPEED   = 4     ; Скорость анимации
  16.  
  17.         ; Вычислить коэффициент соотношения сторон в зависимости от
  18.         ; размеров ширины и высоты окна
  19.         cmp     eax,[height]
  20.         ja      @f
  21.  
  22.         ; Высота/ширина
  23.         xor     edx,edx
  24.         mov     eax,[height]
  25.         mov     ecx,[width]
  26.         div     ecx
  27.         shl     eax,SPEED
  28.         mov     [delta_x],(1 shl SPEED) ; Шаг изменения ширины
  29.         mov     [delta_y],eax           ; Шаг изменения высоты
  30.         jmp     @1
  31. @@:
  32.         ; Ширина/высота
  33.         xor     edx,edx
  34.         mov     eax,[width]
  35.         mov     ecx,[height]
  36.         div     ecx
  37.         shl     eax,SPEED
  38.         mov     [delta_x],eax           ; Шаг изменения ширины
  39.         mov     [delta_y],(1 shl SPEED) ; Шаг изменения высоты
  40. @1:
Поскольку коэффициенты получаются целочисленные, то наиболее красивый эффект будет на окнах квадратной формы или на окнах с кратным соотношением размеров сторон.

Читать статью целиком »
Просмотров: 6413 | Комментариев: 6

Расчет CRC16 на Ассемблере

30.11.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
CRC (Cyclic Redundancy Code - циклический избыточный код) - алгоритм расчета контрольной суммы для передаваемого сообщения, основанный на полиномиальной арифметике. Основная идея алгоритма CRC состоит в представлении сообщения в виде огромного двоичного числа, делении его на другое фиксированное двоичное число и использовании остатка от этого деления в качестве контрольной суммы. Получив сообщение, приемник должен выполнить аналогичное действие и сравнить полученный результат с принятой контрольной суммой. Сообщение считается достоверным, выполняется это равенство. Классический алгоритм CRC16 часто используется в архиваторах для контроля целостности данных служебных заголовков архивов, также его удобно использовать для сравнения строки с каким-либо значением, когда по соображениям безопасности сравниваемое значение не хранится в открытом виде. Для контроля целостности файлов функцию CRC16 лучше не использовать, так как из-за небольшой длины ее научились подделывать. Чтобы выполнить расчет CRC16 требуется сперва подготовить так называемую таблицу инициализации. В сегменте данных таблица резервируется как 256 слов, по одному word на каждый возможный байт:
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. ; Таблица инициализации для расчета CRC16
  5. crc16table rw 256
В классическом варианте для расчета CRC16 используется полином 0a001h, на его основе таблица слов заполняется значениями. Для этого используется следующая вспомогательная функция:
  1. ;-----------------------------------------------------------------------
  2. ; Функция создания таблицы инициализации для расчета CRC16
  3. ;-----------------------------------------------------------------------
  4. proc init_CRC16
  5.         push    eax ebx ecx edi
  6.  
  7.         ; Указатель на выделенную под таблицу память
  8.         mov     edi,crc16table
  9.         ; Расчитать значения для всех 256 слов
  10.         xor     edx,edx
  11. CRC16_Polynom:
  12.         mov     eax,edx
  13.         mov     ecx,8
  14. CRC16_NL:
  15.         shr     ax,1
  16.         jae     CRC16_NoXOR
  17.         ; Magic Number!
  18.         xor     ax,0a001h
  19. CRC16_NoXOR:
  20.         loop    CRC16_NL
  21.         ; Записать значение в таблицу полиномов
  22.         stosw
  23.         inc     edx            ; Счетчик +1
  24.         cmp     edx,256        ; Всю таблицу сгенерировали?
  25.         jne     CRC16_Polynom  ; Нет, работаем дальше
  26.  
  27.         ; Восстановить измененные регистры
  28.         pop     edi ecx ebx eax
  29.         ret
  30. endp
Таблица инициализации получается всегда одинаковой (при условии неизменности полинома), так что ее можно даже не раcчитывать, а хранить в виде массива констант. Если требуется таблица инициализации CRC16 отдельно для использования в других проектах или языках программирования, то она приведена ниже. Для некоторых других разновидностей алгоритма CRC16, например, CRC-CCITT или CRC16-IBM, полином будет другим, и, соответственно, таблица также будет другой.

Читать статью целиком »
Просмотров: 11065 | Комментариев: 2

Как запретить Windows переходить в спящий режим

26.10.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
В некоторых случаях требуется, чтобы на время работы вашего приложения компьютер постоянно оставался в активном состоянии, то есть не включался скринсейвер, не отключался монитор, система не переходила в спящий режим. Для этого надо "убедить" Windows, что за клавиатурой сидит реальный пользователь и проявляет какую-то активность, в этом случае все счетчики времени бездействия будут сбрасываться. Для программной имитации действий пользователя используются две функции: mouse_event для симуляции работы с мышкой мышки и, соответственно, keybd_event для клавиатуры. Также можно использовать более универсальную функцию SendInput, она позволяет симулировать не только мышку и клавиатуру, но и хардварные события. Есть еще более суровые варианты, связанные с ковырянием в реестре, изменением профилей электропитания, но их я рассматривать не буду.

В прикладном приложении для имитации действий пользователя надо установить таймер, например, на секундный интервал, и в его функции-обработчике симулировать движение мыши. Нажатия кнопок мыши и клавиш на клавиатуре симулировать не надо, так как эти действия могут наложиться с действиями реального пользователя, а вот перемещение мышки на какое-нибудь незаметное расстояние будет в самый раз. Почитаем повнимательнее документацию к функции mouse_event. Координаты перемещения задаются в условных единицах - микки, которые высчитываются по формуле: 1 микки = (ширина или высота разрешения монитора) / 65535. Если не указан флаг MOUSEEVENTF_ABSOLUTE, то координаты считаются относительные, то есть от текущего положения курсора. Первоначальный вариант решения был в перемещении курсора на 1 микки от текущего положения курсора, а затем в возвращении его обратно. Но, к сожалению, на Windows XP этот способ все-таки двигал курсор (спасибо ezfalc0n за подсказку). Следующий вариант, вообще без движения, также сбрасывает счетчик времени бездействия системы, так что будем использовать именно его:
  1.         ; Симулировать событие от мышки, оставляя ее на месте
  2.         invoke  mouse_event,MOUSEEVENTF_MOVE,0,0,0,0
Вот и все решение. Теперь Windows будет бодрствовать ровно столько, сколько вам нужно. Можете убедиться в этом, запустив одновременно программу для определения времени бездействия системы и пример из приложения к статье. Вы увидите, что даже когда вы сами не прикасаетесь к мышке и клавиатуре, таймер бездействия системы (функция GetLastInputInfo) остается на нулевой отметке.

Читать статью целиком »
Просмотров: 12877 | Комментариев: 25

01 ... 58 59 60 61 62 63 64 ... 72
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 3 (0.0143 сек.) / Память: 4.5 Mb
Наверх