
Экранная лупа на Ассемблере
Алгоритм реализации экранной лупы достаточно простой. Надо получить часть изображения рабочего стола и скопировать его с масштабированием в нужную область вашего приложения. Сделать это можно при помощи функции StretchBlt. Если посмотрите описание, то увидите, что для работы этой функции требуются следующие параметры: размеры результирующей области, размеры исходной области и контексты устройств (окон), в которых находятся области. А поскольку мы сейчас разрабатываем лупу, значит она должна увеличивать, то есть размеры исходного окна должны быть пропорционально меньше результирующего. Коэффициент пропорциональности и есть коэффициент увеличения лупы. При инициализации окна выполним предварительные расчеты:Code (Assembler) : Убрать нумерацию
- ...
- ; Получить контекст окна лупы
- 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
- ...
Еще один важный момент. Координаты курсора соответствуют левому верхнему углу копируемой части экрана. Но для большего эффекта надо копировать фрагмент вокруг курсора, так что потребуется небольшая корректировка координат. Итак, код основной процедуры экранной лупы:
Code (Assembler) : Убрать нумерацию
- ; Получить позицию курсора
- 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
В приложении исходный код программы и исполняемый файл экранной лупы, работающей по таймеру. Прозрачные окна захватываются.
Просмотров: 6309 | Комментариев: 6

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ND
(06.10.2015 в 11:02):
То ли я гуглем не умею пользоваться, то ли запросы у меня специфические, но в качестве незамороченной экранной лупы - лучший вариант.

Павел
(28.05.2013 в 10:36):
а если надо все время увеличивать фиксированноую область экрана?

brute
(09.01.2012 в 00:00):
понял, я не использовал 'STATIC', а сразу выводил в диалоговое окно..

ManHunter
(08.01.2012 в 22:22):
GetDlgItem,[hwnddlg],ID_ZOOM возвращает хэндл окна лупы, а не всего окна приложения. Для прозрачных окон ставишь флаги CAPTUREBLT + MERGECOPY + BLACKNESS, но это очень сильно влияет на производительность.

brute
(08.01.2012 в 22:15):
повторить на PB удалось, всего 30 строк:http://webfile.ru/5760396
Остались вопросы:
1. зачем invoke GetDlgItem,[hwnddlg],ID_ZOOM, если уже есть hwnddlg?
2. прозрачные окна не ловятся; например, NetMeter,YzDock
3. можно ли htimer=settimer_(hwnddlg,0,50,@ZoomProc()) и затем killtimer_(hwnddlg,htimer)?
Остались вопросы:
1. зачем invoke GetDlgItem,[hwnddlg],ID_ZOOM, если уже есть hwnddlg?
2. прозрачные окна не ловятся; например, NetMeter,YzDock
3. можно ли htimer=settimer_(hwnddlg,0,50,@ZoomProc()) и затем killtimer_(hwnddlg,htimer)?

Grey
(05.01.2012 в 06:04):
В общем хотел поблагодарить Вас, я ранее пытался делать, что-то подобное, но другими средствами (GDI+). Так как WinAPI не сказать, чтобы часто пользуюсь, про такую функцию, чесно не знал. :) Вот реализация этой идеи на АХК:
#NoEnv
CoordMode, Mouse
Width:=159, Value:=15
Gui, +AlwaysOnTop -Caption +Resize +ToolWindow HwndGUIhWnd
Gui, Show, % "w"Width " h"Width, Magnifier
OnMessage(0x201, "WM_NCLBUTTONDOWN") ; WM_LBUTTONDOWN
hDCgui:=DllCall("GetDC", "UInt", GUIhWnd)
hDCdesk:=DllCall("GetDC", "UInt", DllCall("GetDesktopWindow"))
SetTimer, ChaseCursor, 100
^MButton::
^WheelUp::
^WheelDown::
If SubStr(A_ThisHotkey, 2)="MButton"
{
Value:=15, Width:=159
WinMove, % "ahk_id"GUIhWnd,,,, Width, Width
}
Else If SubStr(A_ThisHotkey, 2)="WheelDown"
Value-=4, Value<0 ? Value:=1:Value
Else Value+=4
Return
GuiSize:
If % A_EventInfo=0
{
Width:=A_GuiWidth
WinMove, % "ahk_id"GUIhWnd,,,, Width, Width
}
Return
ChaseCursor:
MouseGetPos, XPos, YPos
DllCall("gdi32\StretchBlt", "UInt", hDCgui
, "Int", 0
, "Int", 0
, "Int", Width
, "Int", Width
, "UInt", hDCdesk
, "Int", XPos-(Value/2)+1
, "Int", YPos-(Value/2)+1
, "Int", Value
, "Int", Value
, "UInt", 0x40C000CA) ; CAPTUREBLT|MERGECOPY
Return
WM_NCLBUTTONDOWN()
{
global
PostMessage, 0xA1, 2,,, % "ahk_id"GUIhWnd ; WM_NCLBUTTONDOWN, HTCAPTION
}
Esc::
GuiClose:
ExitApp
#NoEnv
CoordMode, Mouse
Width:=159, Value:=15
Gui, +AlwaysOnTop -Caption +Resize +ToolWindow HwndGUIhWnd
Gui, Show, % "w"Width " h"Width, Magnifier
OnMessage(0x201, "WM_NCLBUTTONDOWN") ; WM_LBUTTONDOWN
hDCgui:=DllCall("GetDC", "UInt", GUIhWnd)
hDCdesk:=DllCall("GetDC", "UInt", DllCall("GetDesktopWindow"))
SetTimer, ChaseCursor, 100
^MButton::
^WheelUp::
^WheelDown::
If SubStr(A_ThisHotkey, 2)="MButton"
{
Value:=15, Width:=159
WinMove, % "ahk_id"GUIhWnd,,,, Width, Width
}
Else If SubStr(A_ThisHotkey, 2)="WheelDown"
Value-=4, Value<0 ? Value:=1:Value
Else Value+=4
Return
GuiSize:
If % A_EventInfo=0
{
Width:=A_GuiWidth
WinMove, % "ahk_id"GUIhWnd,,,, Width, Width
}
Return
ChaseCursor:
MouseGetPos, XPos, YPos
DllCall("gdi32\StretchBlt", "UInt", hDCgui
, "Int", 0
, "Int", 0
, "Int", Width
, "Int", Width
, "UInt", hDCdesk
, "Int", XPos-(Value/2)+1
, "Int", YPos-(Value/2)+1
, "Int", Value
, "Int", Value
, "UInt", 0x40C000CA) ; CAPTUREBLT|MERGECOPY
Return
WM_NCLBUTTONDOWN()
{
global
PostMessage, 0xA1, 2,,, % "ahk_id"GUIhWnd ; WM_NCLBUTTONDOWN, HTCAPTION
}
Esc::
GuiClose:
ExitApp

Добавить комментарий
Заполните форму для добавления комментария
