Blog. Just Blog

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

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

Создание прозрачных окон в Windows

29.10.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Еще один простой в реализации, но красивый эффект для ваших программ - прозрачные диалоговые окна. Для этого надо, чтобы диалоговое окно было прописано в ресурсах или создавалось с расширенным стилем WS_EX_LAYERED, а при его инициализации вызывалась функция SetLayeredWindowAttributes. Значение коэффициента прозрачности может быть от 0 (полностью прозрачное окно) до 255 (непрозрачное окно). Рекомендуется значение 240-245, при этом эффект прозрачности уже заметен, а содержимое окна еще легко читается и не сливается с перекрываемыми окнами. Этой же функцией можно динамически менять прозрачность уже созданного окна, например чтобы создать эффект его плавного появления или исчезновения.
  1. ; Сегмент кода
  2. section '.code' code readable executable
  3. ...
  4. ; Процедура обработчика окна
  5. proc DialogProc hwnddlg,msg,wparam,lparam
  6.         ...
  7.         ; Инициализация окна?
  8.         cmp     [msg], WM_INITDIALOG
  9.         je      wminitdialog
  10.         ; Закрытие окна?
  11.         cmp     [msg], WM_CLOSE
  12.         je      wmclose
  13.         ...
  14. wminitdialog:
  15.         ; Установить первоначальную прозрачность окна 245
  16.         invoke  SetLayeredWindowAttributes, [hwnddlg], 0, 245, LWA_ALPHA
  17.         ...
  18. wmclose:
  19.         ; Плавное исчезновение окна при его закрытии
  20.         mov     ecx,245
  21. fade_dialog:
  22.         push    ecx
  23.         ; Установка нового атрибта прозрачности
  24.         invoke  SetLayeredWindowAttributes, [hwnddlg], 0, ecx, LWA_ALPHA
  25.         ; Небольшая пауза
  26.         invoke  Sleep,2
  27.         pop     ecx
  28.         loop    fade_dialog
  29.         ...
  30.  
  31. ; Секция ресурсов
  32. section '.rsrc' resource data readable
  33.  
  34. ; Описание диалогового окна в ресурсах.
  35. ; В расширенных стилях должен быть прописан атрибут "WS_EX_LAYERED"
  36. dialog demo, 'Demo', 70, 70, 190, 175,\
  37.         WS_CAPTION + WS_POPUP + WS_SYSMENU + DS_MODALFRAME,\
  38.         WS_EX_LAYERED
  39.         ...
Не забывайте вызывать функцию SetLayeredWindowAttributes при инициализации диалогового окна со стилем WS_EX_LAYERED, иначе после открытия его вообще не будет видно. Также помните, что эффект прозрачности не поддерживается в Windows 9x. Пример программы с плавным появлением и исчезновением окна прилагается.

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

Вывод QWORD в виде десятичного числа

05.10.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Для преобразования и форматированного вывода 32-битных значений в ассемблере используется стандартная API-функция wsprintf, но она бесполезна при работе с большими числами, например QWORD (64 бита). Значит обойдемся совсем без использования API.
  1. ;---------------------------------------------------
  2. ; Преобразование QWORD в десятичное число
  3. ; Параметры вызова:
  4. ; dwHigh - Старшее двойное слово
  5. ; dwLow  - Младшее двойное слово
  6. ; lpBuff - указатель на буфер-приемник
  7. ;---------------------------------------------------
  8. proc    bignum dwHigh:DWORD, dwLow:DWORD, lpBuff:DWORD
  9.         pushad                   ; Сохранить все регистры
  10.         mov     eax,[dwLow]      ; Младшее двойное слово
  11.         mov     edx,[dwHigh]     ; Старшее двойное слово
  12.         mov     edi,[lpBuff]     ; Указатель на буфер-приемник
  13.  
  14.         xchg    esi,edx          ; Сохранить старший dword
  15.         mov     ebx,10           ; Основание системы счисления
  16.         xor     ecx,ecx          ; Счетчик десятичных цифр
  17. .bignum_1:
  18.         xchg    eax,esi          ; Расчитать десятичную цифру
  19.         xor     edx,edx
  20.         div     ebx
  21.         xchg    esi,eax
  22.         div     ebx
  23.         or      dl,'0'           ; Преобразовать результат в символ цифры
  24.         push    edx              ; Сохранить цифру в стеке
  25.         inc     ecx              ; Увеличить счетчик цифр
  26.         or      eax,eax          ; Все преобразовали?
  27.         jnz     .bignum_1
  28.  
  29. .bignum_2:
  30.         pop     eax              ; Записать все цифры из стека в буфер
  31.         stosb
  32.         loop    .bignum_2
  33.         xor     eax,eax          ; Признак окончания строки
  34.         stosb
  35.         popad                    ; Восстановить все регистры
  36.         ret                      ; Ворзврат из процедуры
  37. endp
Пример использования:

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

Время непрерывной работы (Uptime) Windows

01.10.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Для получения времени непрерывной работы системы обычно используется функция API GetTickCount. Она возвращает количество миллисекунд, прошедших с момента последнего старта системы. Проблема в том, что счетчик имеет тип dword, и по прошествии примерно 50 дней (49,7 если быть точным) достигает предельного значения и обнуляется. Конечно, продержать систему без перезагрузки почти два месяца трудно, но не значит что невозможно. Поэтому для получения гарантированно точного времени работы системы воспользуемся функцией NtQuerySystemInformation. Достаточно долго эта функция относилась к разряду недокументированных, теперь же на MSDN по ней имеется описание с примечанием, что ее использование в прикладных программах все равно нежелательно.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. ; По умолчанию структура в FASM не определена, сделаем это самостоятельно
  5. ; Для получения необходимой информации нужны только два первых значения
  6. struct SYSTEM_TIME_INFORMATION
  7.        liKeBootTime       dq ?  ; Время старта системы
  8.        liKeSystemTime     dq ?  ; Текущее время
  9.        liExpTimeZoneBias  dq ?
  10.        uCurrentTimeZoneId dd ?
  11.        dwReserved         dw ?
  12. ends
  13.  
  14. SystemTime   SYSTEM_TIME_INFORMATION  ; Наша структура с данными
  15.  
  16. ; Константа нужного класса информации тоже не определена, сделаем это сами
  17. GET_SYSTEM_TIME_INFORMATION = 3 
  18.  
  19. ; Сегмент кода
  20. section '.code' code readable executable
  21. ...
  22.         invoke  NtQuerySystemInformation, GET_SYSTEM_TIME_INFORMATION,\
  23.                 SystemTime, sizeof.SYSTEM_TIME_INFORMATION, 0
  24.         ; Записать в регистры EDX:EAX текущее время в миллисекундах
  25.         mov     eax, dword [SystemTime.liKeSystemTime]
  26.         mov     edx, dword [SystemTime.liKeSystemTime+4]
  27.         ; Вычесть время старта системы
  28.         sub     eax, dword [SystemTime.liKeBootTime]
  29.         sbb     edx, dword [SystemTime.liKeBootTime+4]
  30.         ; Теперь в регистры EDX:EAX записано реальное количество миллисекунд,
  31.         ; прошедшее с момента старта системы
  32. ...
Преобразовать миллисекунды в обычный вид даты и времени можно при помощи пары стандартных функций FileTimeToLocalFileTime и FileTimeToSystemTime.

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

Поиск строки в памяти с использованием маски

29.09.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Для поиска произвольной строки в блоке памяти с использованием бинарной маски я написал следующую процедуру:
  1. ; ---------------------------------------------
  2. ; Процедура поиска строки в блоке памяти
  3. ; (C) ManHunter / PCL
  4. ; ---------------------------------------------
  5. ; SRCdata - блок памяти в котором выполняется поиск
  6. ; SRCsize - размер блока в котором выполняется поиск
  7. ; PTRdata - строка для поиска
  8. ; PTRsize - длина строки для поиска
  9. ; MSKdata - бинарная маска для поиска или 0 если не используется
  10. ;
  11. ; Возврат: EAX = offset найденной строки
  12. ;          EAX = -1 если ничего не найдено
  13. ; ---------------------------------------------
  14.  
  15. proc scanmem SRCdata:dword, SRCsize:dword, PTRdata:dword,\
  16.              PTRsize:dword, MSKdata:dword
  17.  
  18.         push    esi edi ebx ecx edx
  19.  
  20.         ; Длина паттерна больше длины данных?
  21.         mov     eax,[PTRsize]
  22.         cmp     eax,[SRCsize]
  23.         ; Да, возврат -1
  24.         ja      .scanmem_not_found
  25.  
  26.         mov     esi,[SRCdata]
  27.         mov     edi,[PTRdata]
  28.         mov     edx,[MSKdata]
  29.         mov     ebx,esi
  30.         add     ebx,[SRCsize]
  31.         sub     ebx,[PTRsize]
  32. .scanmem_loop:
  33.         xor     ecx,ecx
  34. .scanmem_test_char:
  35.         or      edx,edx
  36.         jz      .scanmem_no_mask
  37.         cmp     byte [edx+ecx],0
  38.         jz      .scanmem_char_equal
  39.  
  40. .scanmem_no_mask:
  41.         mov     al,[esi+ecx]
  42.         cmp     al,[edi+ecx]
  43.         jne     .scanmem_next_pattern
  44. .scanmem_char_equal:
  45.         inc     ecx
  46.         cmp     ecx,[PTRsize]
  47.         jb      .scanmem_test_char
  48.         jmp     .scanmem_found
  49. .scanmem_next_pattern:
  50.         inc     esi
  51.         cmp     esi,ebx
  52.         jbe     .scanmem_loop
  53.  
  54. .scanmem_not_found:
  55.         ; Строка не найдена
  56.         mov     eax,-1
  57.         jmp     .scanmem_ret
  58.  
  59. .scanmem_found:
  60.         ; Строка найдена
  61.         mov     eax,esi
  62.  
  63. .scanmem_ret:
  64.         pop    edx ecx ebx edi esi
  65.  
  66.         ret
  67. endp
Пример использования процедуры:

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

Вывод лога на Ассемблере

19.09.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Если при работе вашей программы требуется вывод лога неопределенной длины, то это удобно делать в многострочном поле Edit. Преимущества такого способа налицо: можно мышкой выделить и скопировать любой кусок текста, средствами API получить весь текст целиком и сохранить в файл, быстро очистить окно лога и многое другое. Удобно делать все, кроме главного: добавление новых строчек в лог. Конечно, можно получать текст, в памяти добавлять к нему новые строчки и вставлять обратно. Но это долго, неудобно и требует дополнительных ресурсов, а для очень больших логов и вовсе неприемлемо. Поэтому воспользуемся следующей функцией:
  1. ;---------------------------------------------
  2. ; procedure AddLog
  3. ; void AddLog(hWnd:dword,CtrlID:dword,pStr:&string)
  4. ;---------------------------------------------
  5. proc    AddLog  hWnd:dword,CtrlID:dword,pStr:dword
  6.         push    eax
  7.         invoke  GetDlgItem,[hWnd],[CtrlID]
  8.         or      eax,eax
  9.         jz      .AddLog_1
  10.         mov     [CtrlID],eax
  11.         invoke  SendMessage,[CtrlID],EM_GETLINECOUNT,0,0
  12.         dec     eax
  13.         invoke  SendMessage,[CtrlID],EM_LINEINDEX,eax,0
  14.         invoke  SendMessage,[CtrlID],EM_SETSEL,eax,eax
  15.         invoke  SendMessage,[CtrlID],EM_REPLACESEL,FALSE,[pStr]
  16. .AddLog_1:
  17.         pop     eax
  18.         ret
  19. endp  
Парметры вызова: hWnd - хэндл окна, которому принадлежит дочернее окно логом, CtrlID - идентификатор окна Edit в ресурсах, pStr - указатель на строку ASCIIZ, которую надо записать в лог.

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

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