Blog. Just Blog

Образ мышления: Assembler

То, что не удается запрограммировать на Ассемблере, приходится паять
Образ мышления: Assembler - RSS-канал Образ мышления: Assembler - Карта сайта

Перехват ввода и вывода консольных программ

13.04.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Перехват ввода и вывода консольных программ бывает нужен, когда требуется получить результат их работы для обработки в нашем приложении. Также мы получаем возможность передавать консольным программам собственные данные. Как обычно в FASM'е готовых решений нет, пришлось разбираться самому и портировать с языков высокого уровня. Технически перехват ввода и вывода консоли выполняется с использованием специальных структур, называемых "Pipe". По принципу действия они и вправду похожи на трубы: в один конец информация "вливается", из другого "выливается", а перехват является просто подключением нашего "крана" к тому или иному концу трубы. Для перехвата требуется переопределить стандартные дескрипторы ввода и вывода консольного приложения на наши. Создать новые дескрипторы можно при помощи функции CreatePipe, а затем прописать в структуру STARTUPINFO запускаемого приложения. После этого новые дескрипторы будут доступны для чтения и записи как обычный файл.

В сегменте данных родительского приложения требуется определить следующие переменные и структуры:
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. ; Данные для перехвата консоли
  5. newstdin      dd ?  ; Новый дескриптор стандартного ввода
  6. newstdout     dd ?  ; Новый дескриптор стандартного вывода
  7. read_stdout   dd ?  ; Дескриптор для использования ReadFile
  8. write_stdin   dd ?  ; Дескриптор для использования WriteFile
  9. bytestoread   dd ?  ; Всего байт в буфере консоли
  10. available     dd ?  ; Счетчик байт, доступных для чтения из консоли
  11.  
  12. ; Эта структура по умолчанию не определена, сделаем это сами
  13. struct SECURITY_ATTRIBUTES
  14.        nLength               dd ?
  15.        lpSecurityDescriptor  dd ?
  16.        bInheritHandle        dd ?
  17. ends
  18.  
  19. ; Описание структур для запуска консольной программы и настройки дескрипторов
  20. sinfo      STARTUPINFO
  21. sattr      SECURITY_ATTRIBUTES
  22. pinfo      PROCESS_INFORMATION
  23.  
  24. ; Дополнительно зарезервируем буфер для чтения информации
  25. buff   rb 1024
Буфер большого размера для чтения данных лучше не использовать, вполне достаточно 1 килобайта. Количество байт, доступных для чтения из консоли, можно получить при помощи функции PeekNamedPipe. Обратите внимание, что фактически данные из консоли при этом не забираются, это надо будет сделать при помощи функции чтения файла ReadFile. Вот пример кода перехватчика вывода консоли.

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

Воспроизведение музыки в программах на Ассемблере

24.03.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Использование музыки в ваших программах несомненно добавит им привлекательности. Особенно если речь идет о компьютерных играх или кейгенах :) Для различных форматов музыки используются различные библиотеки, в том числе и самописные. Самописные, как правило, приватные и доступны только ограниченному кругу лиц, а качественных и удобных из числа публичных всего две - BASS и uFMOD.

Для качественной музыки используется внешняя библиотека BASS, последняя версия 2.4.2. Это кроссплатформенная библиотека для воспроизведения потоковой музыки (MP3, MP2, MP1, OGG, WAV, AIFF), трекерной (XM, IT, S3M, MOD, MTM, UMX), Internet-вещания (HTTP, FTP), а также некоторых других форматов через внешние модули расширения. При всем богатстве функционала библиотека занимает всего около 100 килобайт на диске. Библиотека обычно используется в аудиоплеерах и компьютерных играх. Скачать последнюю версию можно с офсайта, в архиве имеется подробнейшая документация по всем API библиотеки. Дополнительные модули расширения можно скачать оттуда же с офсайта. Для нас особый интерес представляет пример использования API библиотеки BASS на Flat Assembler'е, скачать его можно также с офсайта. Это плеер с минимальными функциями, но в архиве содержатся необходимые inc-файлы, которые надо будет поместить в соответствующие папки FASM для использования в других проектах. Минусы использования библиотеки BASS в том, что в любом случае приходится таскать за собой 100-килобайтный файл bass.dll. Для больших проектов это погоды не сделает, а для небольших может оказаться критичным. Конечно, можно хранить файл bass.dll внутри исполняемого файла и записывать в системную директорию по мере надобности (именно так и поступает патчер dUP2), но многие антивирусы расценят подобную активность как подозрительную. Со всеми вытекающими. Также к недостаткам можно отнести закрытый код библиотеки и навешанный на нее протектор.

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

Разбор параметров командной строки

03.03.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Наконец-то добрался до полезной практической задачи по корректному разбору параметров командной строки. На языках высокого уровня это делается чуть ли не одной командой, а на Ассемблере как обычно приходится все делать самостоятельно. Решение получилось универсальным, подходит как для консольных, так и для GUI-приложений. Для использования функции ParseCmdLine в сегменте данных надо предварительно определить следующую структуру:
  1. ; Структура для командной строки
  2. struct  CMDLINE
  3.         nCount   dd ?   ; Количество аргументов
  4.         lpArgs   dd ?   ; Указатель на массив адресов строк
  5.         lpArgStr dd ?   ; Указатель на массив строк
  6. ends
Формат структуры: nCount - количество параметров командной строки, в случае успешного вызова функции это значение обязательно будет ненулевым, так как самый первый параметр - полный путь запуска программы, а остальные аргументы из хвоста командной строки будут расположены, начиная со второго элемента массива. lpArgStr - указатель на массив параметров командной строки. Все строки в этот массив записываются последовательно одна за другой в формате ASCIIZ, если строки были не в кавычках, то с начала и конца строки удаляются избыточные пробелы и символы табуляции. lpArgs - указатель на массив адресов разобранных параметров командной строки. Какого-то отдельного признака окончания массива не предусмотрено, количество элементов берется из значения nCount.

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

Использование иконок разных размеров в ресурсах

12.02.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Большим плюсом Flat Assembler является то, что при разработке создается минимальное количество файлов. Описания ресурсов хранятся прямо в исходнике ASM, что тоже очень удобно. Например, в официальной документации и исходниках описание главной иконки в ресурсах исполняемого файла выглядит примерно так:
  1. section '.rsrc' resource data readable
  2.  
  3.   directory RT_ICON, icons,\
  4.             RT_GROUP_ICON, group_icons
  5.  
  6.   resource icons,\
  7.            1, LANG_NEUTRAL, icon_data
  8.  
  9.   resource group_icons,\
  10.            1, LANG_NEUTRAL, main_icon
  11.  
  12.   ; Описание одиночной иконки
  13.   icon main_icon, icon_data, 'main_icon.ico'
Проблема в том, что одиночной иконки в приложениях часто бывает недостаточно. Система Windows в разных ситуациях отображает разные иконки файлов. Например, при просмотре папки Проводником в режиме "Таблица" или "Значки" иконки исполняемых файлов будут разного размера. Если в исполняемом файле только одна маленькая иконка, то она будет растянута до нужного размера. Аналогично, при компактном режиме просмотра одиночная большая иконка будет сжата. Качество изображения после масштабирования в большинстве случаев оставляет желать лучшего. После усиленных поисков было найдено такое вот простое, но неочевидное решение. Почему оно не описано в документации и не реализовано ни в одном примере, непонятно. Создаете несколько файлов иконок нужных размеров и описываете их в ресурсах следующим образом:
  1. section '.rsrc' resource data readable
  2.  
  3.   directory RT_ICON, icons,\
  4.             RT_GROUP_ICON, group_icons
  5.  
  6.   resource icons,\
  7.            1, LANG_NEUTRAL, icon_data1,\
  8.            2, LANG_NEUTRAL, icon_data2,\
  9.            3, LANG_NEUTRAL, icon_data3
  10.  
  11.   resource group_icons,\
  12.            1, LANG_NEUTRAL, main_icon
  13.  
  14.   ; Описание иконок разных размеров, объединенных в одну
  15.   icon main_icon,\
  16.            icon_data1, 'icon_16x16_32bit.ico',\
  17.            icon_data2, 'icon_32x32_32bit.ico',\
  18.            icon_data3, 'icon_48x48_32bit.ico'
Теперь наше приложение будет красиво отображаться в разных режимах просмотра. Количество иконок не ограничено, и вы можете использовать даже монохромные или 16-цветные иконки. Но лично я считаю, что для программ на Ассемблере вполне достаточно двух полноцветных иконок размерами 16х16 и 32х32 пикселов.

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

Программное выключение монитора

08.02.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Выключить монитор из программы можно, но только если он совместим со стандартом EnergyStar. Об этом можно не беспокоиться, все современные мониторы удовлетворяют этому условию. Беспокоиться надо о другом. По непонятной причине с сайта на сайт упорно копируют один и тот же код на разных языках программирования, который якобы должен выключить монитор. Вот его вариант на Ассемблере:
  1. ; ВНИМАНИЕ! Это НЕПРАВИЛЬНЫЙ код!!!
  2. invoke  GetDesktopWindow
  3. invoke  SendMessage, eax, WM_SYSCOMMAND, SC_MONITORPOWER, 0
Во-первых, через хэндл из функции GetDesktopWindow достучаться до монитора не получится, причем ни в обычном Explorer'e, ни в альтернативных шеллах типа Aston Desktop. Чтобы сообщение дошло до нужного адресата, надо использовать широковещательную рассылку через HWND_BROADCAST. Во-вторых, непонятно откуда взялся последний параметр - 0. В MSDN четко прописано, что для выключения монитора через SC_MONITORPOWER значение lParam должно быть равно 2. Более того, нулевого значения параметра для этого сообщения вообще не предусмотрено. В двух строчках кода две принципиальные ошибки! И это уже далеко не первый случай, когда код из различных популярных источников является заведомо нерабочим. Всем любителям бездумного копипаста очень рекомендую сперва сверяться с первоисточниками, а перед публикацией проверять весь код на практике.

Но хватит о грустном. Правильный код программного выключения монитора будет таким:
  1. ;-------------------------------------------------
  2. ; Правильный код выключения монитора
  3. ;-------------------------------------------------
  4. ; В FASM не определена константа HWND_BROADCAST, сделаем это самостоятельно
  5. HWND_BROADCAST = 0FFFFh
  6. ; Выключить монитор
  7. invoke  SendMessage, HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, 2
Для включения монитора обратно достаточно пошевелить мышкой или нажать любую кнопку на клавиатуре. А можно также сделать это из нашей программы. У копипастеров этот код также содержит ошибку, потому что для включения монитора значение lParam должно быть равно -1, а не 1.

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

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2023
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 3 (0.005 сек.) / Память: 5 Mb
Наверх