Экранная лупа на Ассемблере

Алгоритм реализации экранной лупы достаточно простой. Надо получить часть изображения рабочего стола и скопировать его с масштабированием в нужную область вашего приложения. Сделать это можно при помощи функции StretchBlt. Если посмотрите описание, то увидите, что для работы этой функции требуются следующие параметры: размеры результирующей области, размеры исходной области и контексты устройств (окон), в которых находятся области. А поскольку мы сейчас разрабатываем лупу, значит она должна увеличивать, то есть размеры исходного окна должны быть пропорционально меньше результирующего. Коэффициент пропорциональности и есть коэффициент увеличения лупы. При инициализации окна выполним предварительные расчеты:
        ...
        ; Получить контекст окна лупы
        invoke  GetDlgItem,[hwnddlg],ID_ZOOM
        mov     ebx,eax
        invoke  GetDC,eax
        mov     [wDC],eax
 
        ; Получить размеры окна лупы
        invoke  GetClientRect,ebx,coord
        mov     eax,[coord.right]
        sub     eax,[coord.left]
        mov     [dWidth],eax
        mov     eax,[coord.bottom]
        sub     eax,[coord.top]
        mov     [dHeight],eax
 
        ; Получить контекст десктопа
        invoke  GetDesktopWindow
        mov     [hDesktop],eax
        invoke  GetDC,eax
        mov     [dDC],eax
        ...

Как теперь запустить экранную лупу? Здесь есть два варианта: при получении сообщения от мыши и по таймеру. У каждого способа свои достоинства и недостатки. Если обрабатывать сообщения мыши, то требуется инжект вспомогательной dll во все процессы, а экран лупы будет обновляться только при движении мыши. Это существенно снизит нагрузку на систему, но если окно под курсором будет обновляться, а курсор останется неподвижным, то лупа получит только тот кадр, который был при последнем движении курсора. Обновление по таймеру создаст дополнительную нагрузку на систему, но при этом изображение в лупе будет в точности соответствовать текущему состоянию окна под курсором. Оба способа имеют место быть, каждый под свои задачи.

Еще один важный момент. Координаты курсора соответствуют левому верхнему углу копируемой части экрана. Но для большего эффекта надо копировать фрагмент вокруг курсора, так что потребуется небольшая корректировка координат. Итак, код основной процедуры экранной лупы:
        ; Получить позицию курсора
        invoke  GetCursorPos,curs
 
        ; Расчитать координаты и размер копируемой
        ; области рабочего стола
        mov     edx,[dWidth]    ; Ширина / 4
        shr     edx,2           ; EDX - ширина копируемой области
        mov     eax,edx
        shr     eax,1
        sub     [curs.x],eax    ; Координата Х левого угла
 
        mov     ecx,[dHeight]   ; Высота / 4
        shr     ecx,2           ; ECX - высота копируемой области
        mov     eax,ecx
        shr     eax,1
        sub     [curs.y],eax    ; Координата Y левого угла
 
        ; Флаг в FASM не определен
        CAPTUREBLT = 0x40000000
 
        ; Скопировать участок экрана с увеличением в окно лупы
        invoke  StretchBlt, [wDC], 0, 0, [dWidth], [dHeight],\
                            [dDC], [curs.x], [curs.y], edx, ecx,\
                            CAPTUREBLT+MERGECOPY

В этом примере для удобства используется коэффициент увеличения равный 4, вы можете использовать другой коэффициент или менять его динамически по мере необходимости. Флаг CAPTUREBLT используется в случае, если требуется захватывать полупрозрачные окна. Но это может вызвать неприятный эффект мерцания курсора, причем программно это мерцание никак не подавить. Без флага CAPTUREBLT лупа будет просто игнорировать layered-окна, показывая информацию под ними.

В приложении исходный код программы и исполняемый файл экранной лупы, работающей по таймеру. Прозрачные окна захватываются.
Теги:
Экранная лупа
Добавлено: 10 Апреля 2018 20:33:04 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...