1

Тема: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток. Есть задумка сделать скриншот выделенной части экрана по горячей клавише и показать его поверх всех окон . Помогите реализовать пожалуйста.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

2

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Начинайте, поможем.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3 (изменено: Ядрён, 2015-01-15 02:58:30)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Вот мои задумки по поводу готовой программы , которая на F9 фотографирует выделенную часть экрана.

#NoEnv
#Persistent
WS_EX_TRANSPARENT := 0x20
WS_EX_LAYERED := 0x80000

*~F9::
IfExist, C:\Users\roma\Pictures\GameCenter\WEQ\Desktop\*.jpeg
Gui, -Caption +AlwaysOnTop +Lastfound +ToolWindow 
Gui, Color, EEAA99
WinSet TransColor, EEAA99
Gui, Add, Picture, AltSubmit , C:\Users\roma\Pictures\GameCenter\WEQ\Desktop\*.jpeg
Gui, Show, NA
Return

*~F7::
FileDelete, C:\Users\roma\Pictures\GameCenter\WEQ\Desktop\*.jpeg


GuiClose:
ExitApp

Но вот как всё это подогнать что бы работало . Я весь измучился. Мне кажется легче на "AHK" всё написать чем всё это подгонять.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

4

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Честно говоря, задумку не понял. Как скрипт должен работать?

Если что, в коллекции есть мой скрипт для снятия скриншотов (правда, только под 32-bit, и скриншот не показывает). Для того, чтобы разобраться, в принципе сойдёт.
Кроме того, есть не совсем доделанный подобный код, который может показывать (опционально) скриншот перед сохранением и даже менять его размеры. Если нужно, могу выложить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker пишет:

Честно говоря, задумку не понял. Как скрипт должен работать?

Если что, в коллекции есть мой скрипт для снятия скриншотов (правда, только под 32-bit, и скриншот не показывает). Для того, чтобы разобраться, в принципе сойдёт.
Кроме того, есть не совсем доделанный подобный код, который может показывать (опционально) скриншот перед сохранением и даже менять его размеры. Если нужно, могу выложить.


Ну скрипт из коллекции я нашёл своими силами,за старание всё равно спасибо но подогнать его я не смог. Задумка такая в браузере нужно списать информацию с одного сайта на другой . Вот  ссылка на "Мас" приложение , там всё описано.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

6 (изменено: teadrinker, 2015-01-17 00:29:50)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Вот простенький скрипт:

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
OnExit, Exit
oGuiData := []
OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
Return 

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow([X, Y, W, H])
   Return
   
Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      (v != 0 && DllCall("DeleteObject", Ptr, v))
   ExitApp

CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(oCoords)
{
   global oGuiData
   static SS_BITMAP := 0xE
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen(oCoords[1] "|" oCoords[2] "|" oCoords[3] "|" oCoords[4])
   Gdip_GetImageDimensions(pBitmap, W, H)
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   Gdip_DisposeImage(pBitmap)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := k)
         break
      
   nGui := IsEmpty ? IsEmpty : (k = "" || k = 99) ? 1 : k + 1
   oGuiData[nGui] := hBitmap

   Gui, %nGui%:New
   Gui, %nGui%:Default
   Gui, -Caption +ToolWindow +AlwaysOnTop +LastFound +Border -DPIScale
   Gui, Margin, 0, 0
   Gui, Add, Pic, hwndhPic w%W% h%H% %SS_BITMAP%
   SetImage(hPic, hBitmap)
   Gui, Show, % "x" oCoords[1] " y" oCoords[2]
   
   Gdip_Shutdown(pToken)
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_RBUTTONUP()
{
   global oGuiData
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData[A_Gui] := 0
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   global oGuiData
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData[A_Gui] := 0
}

Нужна библиотека Gdip.ahk.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, закрыть — щелчком правой.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7 (изменено: Ядрён, 2015-01-16 14:03:41)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Огромное вам спасибо teadrinker , то что надо. Хотя и есть небольшая ошибка ,что то связанное с выделением там поле выделения опережает крестик крестик .

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

8

Re: AHK: Скриншот выделенной части экрана поверх всех окон

У меня, вроде, нормально всё. CoordMode, Mouse не забыли?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker пишет:

У меня, вроде, нормально всё. CoordMode, Mouse не забыли?

Попробуйте сделать скрин где нибудь на тёмном фоне и там будет видна белая полоса справа от скриншота сантиметров на 8 и снизу сантиметра на 3.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

10

Re: AHK: Скриншот выделенной части экрана поверх всех окон

У меня никаких полосок нет:

https://cloclo27.cloud.mail.ru/weblink/thumb/w3/c336b62d4dc1/2015.01.16-18.04.40.5.jpg


https://cloclo15.cloud.mail.ru/weblink/thumb/w3/cc542cfe6206/2015.01.16-18.05.02.5.jpg

У кого-нибудь ещё есть полоски?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: Скриншот выделенной части экрана поверх всех окон

У меня тоже самое, потому всегда добавляю:

Gui, -DPIScale
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

12

Re: AHK: Скриншот выделенной части экрана поверх всех окон

С этим ошибка пропадает? Никогда не мог понять, что это даёт?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

13

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ну это если в винде увеличенный шрифт, то по умолчанию (+DPIScale) размер окна увеличивается на столько же процентов.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

14

Re: AHK: Скриншот выделенной части экрана поверх всех окон

С этим нормально работает?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

15

Re: AHK: Скриншот выделенной части экрана поверх всех окон

+ Так
CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
OnExit, Exit
oGuiData := []
OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
Return 

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow([X, Y, W, H])
   Return
   
Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      (v != 0 && DllCall("DeleteObject", Ptr, v))
   ExitApp

CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(oCoords)
{
   global oGuiData
   static SS_BITMAP := 0xE
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen(oCoords[1] "|" oCoords[2] "|" oCoords[3] "|" oCoords[4])
   Gdip_GetImageDimensions(pBitmap, W, H)
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   Gdip_DisposeImage(pBitmap)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := k)
         break
      
   nGui := IsEmpty ? IsEmpty : (k = "" || k = 99) ? 1 : k + 1
   oGuiData[nGui] := hBitmap

   Gui, %nGui%:New
   Gui, %nGui%:Default
   Gui, -Caption +ToolWindow +AlwaysOnTop +LastFound +Border -DPIScale
   Gui, Margin, 0, 0
   Gui, Add, Pic, hwndhPic w%W% h%H% %SS_BITMAP%
   SetImage(hPic, hBitmap)
   Gui, Show, % "x" oCoords[1] " y" oCoords[2]
   
   Gdip_Shutdown(pToken)
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_RBUTTONUP()
{
   global oGuiData
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData[A_Gui] := 0
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   global oGuiData
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData[A_Gui] := 0
}

это решается:

там поле выделения опережает крестик

но вот полосы я у себя не наблюдал и до этого.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

16

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А нет, полосы всё таки были.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

17

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А, ок, добавлю тогда.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18 (изменено: serzh82saratov, 2015-01-17 00:43:36)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Заметил, что когда несколько скринов на экране, то не понятно в какие моменты (чаще в момент нового снимка) может появится пустое (белое) окно скрипта с заголовком.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

19

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Появляется когда резко отводишь мышь и отпускаешь LButton, а окно выделения ещё не "догнало" курсор.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

20 (изменено: Ядрён, 2015-01-17 01:18:35)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Большое спасибо вам serzh82saratov ваш скрипт работае так как надо без лишних полосок.
А можно узнать что вы поменяли что бы всё заработало.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

21

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ядрён Пожалуйста, Вы тут первый с увеличенным шрифтом, а я второй и последний.
teadrinker полоски убрал, а вот про выделение забыл.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

22

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Всё спасибо разобрался "-DPIScale"  в двух местах добавили.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

23

Re: AHK: Скриншот выделенной части экрана поверх всех окон

serzh82saratov пишет:

Заметил, что когда несколько скринов на экране, то не понятно в какие моменты (чаще в момент нового снимка) может появится пустое (белое) окно скрипта с заголовком.

А скриншот можно?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

24

Re: AHK: Скриншот выделенной части экрана поверх всех окон

https://cloud.mail.ru/public/0f9d54cd90 … %D0%BA.PNG

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

25

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Не представляю. В скрипте все окна создаются изначально с опцией -Caption. Если только эта самая -DPIScale с ней как-нибудь не конфликтует.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

26

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Без DPIScale тоже самое:

Появляется когда резко отводишь мышь и отпускаешь LButton, а окно выделения ещё не "догнало" курсор.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

27

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ага, тоже получилось, подумаю.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

28

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Вот так у меня выглядело.

http://i003.radikal.ru/1501/6e/c6575719e382.jpg

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

29

Re: AHK: Скриншот выделенной части экрана поверх всех окон

serzh82saratov пишет:

Появляется когда резко отводишь мышь и отпускаешь LButton, а окно выделения ещё не "догнало" курсор.

Нужно после KeyWait, LButton добавить SetTimer, EventHandling, Off.

/*
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, закрыть — щелчком правой.
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
OnExit, Exit
oGuiData := []
OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
Return

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow([X, Y, W, H])
   Return
   
Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      (v != 0 && DllCall("DeleteObject", Ptr, v))
   ExitApp

CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(oCoords)
{
   global oGuiData
   static SS_BITMAP := 0xE
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen(oCoords[1] "|" oCoords[2] "|" oCoords[3] "|" oCoords[4])
   Gdip_GetImageDimensions(pBitmap, W, H)
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   Gdip_DisposeImage(pBitmap)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := k)
         break
      
   nGui := IsEmpty ? IsEmpty : (k = "" || k = 99) ? 1 : k + 1
   oGuiData[nGui] := hBitmap

   Gui, %nGui%:New
   Gui, %nGui%:Default
   Gui, -Caption +ToolWindow +AlwaysOnTop +LastFound +Border -DPIScale
   Gui, Margin, 0, 0
   Gui, Add, Pic, hwndhPic w%W% h%H% %SS_BITMAP%
   SetImage(hPic, hBitmap)
   Gui, Show, % "x" oCoords[1] - 1 " y" oCoords[2] - 1
   
   Gdip_Shutdown(pToken)
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_RBUTTONUP()
{
   global oGuiData
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData[A_Gui] := 0
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   global oGuiData
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData[A_Gui] := 0
}

Для работы скрипта нужна библиотека Gdip.ahk.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

30

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А можно ли добавить увеличение скрина внутри окна по горячей клавише .

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

31 (изменено: teadrinker, 2017-03-18 08:02:42)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Так можно менять размер колесом мыши:

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

32

Re: AHK: Скриншот выделенной части экрана поверх всех окон

К вопросу о скриншотах - кому-нибудь встречалась задача по созданию скрина свернутого окна приложения без использования внешнего софта (Paint и т.д.), а так же снятия скринов при разлогиненном компьютере (хм, вообще возможно ли такое)? Перелопатил несколько веток на англоязычном форуме, но к сожалению примеры не заработали.

33

Re: AHK: Скриншот выделенной части экрана поверх всех окон

emmetoya пишет:

кому-нибудь встречалась задача по созданию скрина свернутого окна приложения без использования внешнего софта

Встречалась.

emmetoya пишет:

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

Нет, такая точно не встречалась.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

34

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker
Удалось снимать скрины со свернутых окон, поделитесь знанием)?

По второму вопросу я некорректно описал задачу - пользователь залогинен на рабочей станции, но система заблокирована.

35

Re: AHK: Скриншот выделенной части экрана поверх всех окон

emmetoya пишет:

Удалось снимать скрины со свернутых окон, поделитесь знанием)?

Со свёрнутых пока никому не удавалось, но можно временно развернуть за экраном.
И просьба, старайтесь не цитировать предыдущий пост целиком, пользуйтесь кнопкой «Ответить» или формой быстрого ответа.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

36 (изменено: Ядрён, 2017-03-16 15:35:53)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток . Подскажите пожалуйста как добавить сохранение скриншота выделенной части экрана .

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

37

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Подскажите в какую сторону хоть смотреть.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

38

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Завтра попробую, пока некогда.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

39

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Смотреть нужно в сторону туториалов:
https://autohotkey.com/board/topic/2944 … 45-by-tic/
За сохранение файла отвечает функция: Gdip_SaveBitmapToFile(pBitmap, "File.png").
Соответственно вставьте ее в скрипте teadrinkerа после создания объекта pBitmap и до освобождения его ресурсов Gdip_DisposeImage(pBitmap).

40

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Уважаемый Malcev всё получилось как вы говорили , правда  выделяешь часть экрана и сразу происходит сохраняет . А подскажите пожалуйста как сделать сохранение по горячей клавише.

+ открыть спойлер

Сегодня пол ночи мучился , так и не одолел "сохранение по горячей клавише".

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

41 (изменено: Malcev, 2017-03-17 15:59:22)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Нужно объявить глобальными переменные pBitmap и pToken и стереть Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken) из конца функции CreateScreenshotWindow(X, Y, W, H).
Вставить  в начало функции:

if pBitmap
   Gdip_DisposeImage(pBitmap)
if pToken
   Gdip_Shutdown(pToken)

И тоже самое вставить в метку OnExit, чтобы при выходе из скрипта тоже подчищалось, хотя я читал, что винда сама должна подчищать.

42 (изменено: Ядрён, 2017-03-18 04:19:10)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Что то не получается помогите пожалуйста. Как сделать например нажал "F10" скрин сохранился.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

43 (изменено: teadrinker, 2017-03-18 08:26:08)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ядрён пишет:

Подскажите пожалуйста как добавить сохранение скриншота выделенной части экрана

Если речь идёт о вышеприведённом скрипте, то там можно выделять несколько областей экрана сразу. Как скрипт узнает, какую именно сохранять по горячей клавише? Кроме того, там можно менять размер окна со скриншотом. В каком размере должно сохраняться, в первоначальном, или в текущем?

Malcev пишет:

Нужно объявить глобальными переменные pBitmap и pToken и стереть Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken) из конца функции CreateScreenshotWindow(X, Y, W, H).

Нет, ничего такого не нужно. В скрипте есть объект oGuiData с хэндлами hBitmap существующих окон. Скрипт немного подправил.
Вот сохранение по двойному клику:

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
   res := Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . A_Now . ".png")
   
   DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
   oGuiData.Delete(A_Gui)
   Gui, %A_Gui%:Destroy
   Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
   
   if (res = 0)
      MsgBox, Файл успешно создан по адресу:`n%A_ScriptDir%\%A_Now%.png
   else
      MsgBox, Не удалось создать файл. Ошибка: %res%
}

WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

44

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Спасибо огромное вам teadrinker то что нужно , всё работает.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

45

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А где брать ф-ию Gdip_Startup() ? Без нее скрипт из 43-го поста не работает.

46

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Там же написано:

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1

47

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток. Решил добавить выборочное сохранение файла , но файл не сохраняется. Подскажите где ошибка.

WM_LBUTTONDBLCLK()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])

res := Gdip_SaveBitmapToFile(pBitmap, OutFile "\" A_Now ".png")

 FileSelectFile, res, S3, %OutFile%\%A_Now%.png, Сохранить скриншот, All Files(*.*)

 DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
   oGuiData.Delete(A_Gui)
   Gui, %A_Gui%:Destroy
   Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

}
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

48

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А чему переменная OutFile в шестой строке равна?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

49

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Как написано в справке. OutFile: Корневой (начальный) каталог, который предположительно является папкой нижележащего уровня в %A_WorkingDir% в том случае, если абсолютный путь точно не определен. Может я чего то недопонимаю. Но по идее всё ведь должно работать.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

50

Re: AHK: Скриншот выделенной части экрана поверх всех окон

А причём тут справка к  FileSelectFile? Я про шестую строку спросил, ещё до неё.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

51 (изменено: Ядрён, 2017-03-21 15:40:44)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Я думал "OutFile" из шестой строки, это третий параметр из "FileSelectFile".Ну как то так наверное.Но скорее всего я ошибаюсь.Подскажите как правильно.

OutFile := %OutFile% 

Ну никак не пойму если из встроенной переменной "A_Now" дата и время переходит в стандартное диалоговое окно(название файла),то почему "OutFile" не переходит как путь("OutFile" это конечно не путь)но даже если поставить вместо "OutFile" "A_ScriptDir"- а это уже путь, и почему нельзя его изменить из 3 -го параметра  "FileSelectFile".

 res := Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . A_Now . ".png")

 FileSelectFile, res, S3, %A_ScriptDir%\%A_Now%.png, Сохранить скриншот, All Files(*.*)
+ открыть спойлер

Я наверное я как всегда перемудрил.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

52

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Сперва попытайтесь объяснить, зачем вы сначала сохраняете картинку в файл, а после этого выбираете ещё какой-то файл?
Функция Gdip_SaveBitmapToFile() как раз сохраняет файл по указанному пути. Может, сначала стоит выбрать путь с помощью FileSelectFile, а уже потом сохранять?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

53

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Верно но как это сделать.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

54

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ваша задача сейчас получить нужный путь из FileSelectFile в переменную, и подставить его в Gdip_SaveBitmapToFile(). Почитайте справку по FileSelectFile.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

55

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Если только так но так тоже не работает. У меня закончились идеи .

Gdip_SaveBitmapToFile(pBitmap, %SelectFile% . "\" . A_Now . ".png")
 FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
+ открыть спойлер

Ну где же ошибка.Никак не получается , капец в 2-х строках разобраться не могу.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

56

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker пишет:

получить нужный путь из FileSelectFile в переменную, и подставить его в Gdip_SaveBitmapToFile().

teadrinker пишет:

Может, сначала стоит выбрать путь с помощью FileSelectFile, а уже потом сохранять?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

57

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Не понимаю: Если параметр RootDir опущен или пуст, то начальным будет каталог по умолчанию, который, возможно, будет зависеть от версии операционной системы.

FileSelectFile, SelectFile, S3, RootDir\%A_Now%.png , Сохранить скриншот, All Files(*.*)

Я его и оставил пустым , значит  путь должен быть по умолчанию.

FileSelectFile, SelectFile, S3,%A_Now%.png , Сохранить скриншот, All Files(*.*)
+ открыть спойлер

Нет всё сдаюсь.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

58

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Этот код

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)

написан корректно. Можно проверить:

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
MsgBox, % SelectFile
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

59 (изменено: Ядрён, 2017-03-22 19:59:22)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Почему же так не работает.

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)

Gdip_SaveBitmapToFile(pBitmap, %SelectFile% . "\" . A_Now . ".png")

Получается "SelectFile" это путь.

SelectFile := %SelectFile% 


И почему путь из "SelectFile" не переходит в "%SelectFile%" для последующего сохранения.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

60

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ему никуда переходить не надо, он уже там. В функцию переменные подставляются без знаков процента.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

61 (изменено: Ядрён, 2017-03-22 21:31:36)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Так тоже не работает.

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
 Gdip_SaveBitmapToFile(pBitmap, "SelectFile" . "\" . A_Now . ".png")
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

62

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ядрён, так посмотрите чему у вас равна переменная сохранения файла и поймёте почему у вас не сохраняется:

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
msgbox % "SelectFile" . "\" . A_Now . ".png"

63

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Я действительно в ступоре . Я не понимаю почему.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

64 (изменено: Ядрён, 2017-03-22 22:19:15)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

stealzy он не долже быть сохранён . При таком пути.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

65 (изменено: Ядрён, 2017-03-22 22:25:48)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Так фишка в том что в "FileSelectFile" можно выбрать любой путь.А так то пожалуйста.

Gdip_SaveBitmapToFile(pBitmap, "C:\Users\Public\Pictures\Sample Pictures" . "\" . A_Now . ".png")
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

66 (изменено: teadrinker, 2017-03-22 23:02:44)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker пишет:

В функцию переменные подставляются без знаков процента.

Ядрён пишет:
Gdip_SaveBitmapToFile(pBitmap, "SelectFile" . "\" . A_Now . ".png")

Ядрён, а вы изобретательны! Кавычками обрамлять тоже не надо. Кавычками переменные не обрамляются никогда.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

67

Re: AHK: Скриншот выделенной части экрана поверх всех окон

stealzy пишет:

Запомните, что функции всегда ждут от вас переменную

Нет, функции ждут выражение, а в них переменные пишутся без знака процента, а строки в кавычках.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

68

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Так тоже не работает .

Gdip_SaveBitmapToFile(pBitmap, SelectFile . "\" . A_Now . ".png")
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

69

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ядрён, ну так опять же, посмотрите путь в который вы сохраняете:

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
msgbox % SelectFile . "\" . A_Now . ".png"

70

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Всем огромное спасибо разобрался.

FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
 Gdip_SaveBitmapToFile(pBitmap, SelectFile)
+ открыть спойлер

Ну я и тугой .Хотя ребёнок малениький 2.5 месяца отходишь то и дело и сосредоточиться нереально.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

71

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток. Помогите пожалуйста сделать кнопки на окне поделиться скриншотом в Telegram и WhatsApp .

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

*~$vk2C::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])

Gui, %A_Gui%:Hide
FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)

   
 res := Gdip_SaveBitmapToFile(pBitmap, SelectFile )




 DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
   oGuiData.Delete(A_Gui)
   Gui, %A_Gui%:Destroy
   Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

  ; if (res = 0)  

      ;MsgBox, Скриншот успешно сохранён: `n%SelectFile%\%A_Now%.png
  ;else

      ;MsgBox, Не удалось сохранить скриншот. Ошибка: %res%
}



WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

72

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток. Подскажите как сделать при исчезании окна копирование выделенной части в буфер.

WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

Где то здесь я думаю.

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

*~$vk2C::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])

Gui, %A_Gui%:Hide
FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)

   
 res := Gdip_SaveBitmapToFile(pBitmap, SelectFile )




 DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
   oGuiData.Delete(A_Gui)
   Gui, %A_Gui%:Destroy
   Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

  ; if (res = 0)  

      ;MsgBox, Скриншот успешно сохранён: `n%SelectFile%\%A_Now%.png
  ;else

      ;MsgBox, Не удалось сохранить скриншот. Ошибка: %res%
}



WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

73

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Используйте Gdip_SetBitmapToClipboard().

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

74

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Уважаемый teadrinker что то не получается.

WM_RBUTTONUP()
{

 pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

Вот так помещает в буфер скрин полного экрана а не выделенной части экрана.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

75

Re: AHK: Скриншот выделенной части экрана поверх всех окон

teadrinker пишет:

Используйте Gdip_SetBitmapToClipboard().

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

76

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Уважаемый teadrinker большое спасибо за подсказку .

WM_RBUTTONUP()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])

   res := Gdip_SetBitmapToClipboard(pBitmap)

   if (A_Gui != "Select")  {
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

Так всё получилось.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

77

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Отлично, лучше так:

WM_RBUTTONUP()
{
   if (A_Gui != "Select")  {
      pToken := Gdip_Startup()
      pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
      Gdip_SetBitmapToClipboard(pBitmap)
      Gdip_DisposeImage(pBitmap)
      Gdip_Shutdown(pToken)
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

78 (изменено: Ядрён, 2022-10-17 23:10:12)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Доброго времени суток. Обнаружил в работе скрипта баг. Если выделенную часть экрана заскролить
"WheelDown" "WheelUp"(увеличить или уменьшить окно) а потом сохранить или копировать картинку в буфер то сохраняется картинка изначального размера т.е(без увеличения или уменьшения окна). Помогите пожалуйста разобраться.

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

*~$vk2C::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
    if (A_Gui != "Select")  {
     pToken := Gdip_Startup()
     pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
     Gui, %A_Gui%:Hide
     FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
     Gdip_SaveBitmapToFile(pBitmap, SelectFile )
     DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
     oGuiData.Delete(A_Gui)
     Gui, %A_Gui%:Destroy
     Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
    }
}

WM_RBUTTONUP()
{
     if (A_Gui != "Select")  {
      pToken := Gdip_Startup()
      pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
      Gdip_SetBitmapToClipboard(pBitmap)
      Gdip_DisposeImage(pBitmap)
      Gdip_Shutdown(pToken)
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

79

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Почему баг, изначально функционал для сохранения в буфер обмена не предполагался. Версия, которую вы выложили, не сохраняет даже изначальный размер. Проверяйте код, перед тем как выкладывать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

80 (изменено: Ядрён, 2022-10-17 23:11:51)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Уважаемый teadrinker я всё исправил.
Был не прав.

OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

81

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Ядрён пишет:

WM_RBUTTONUP -удаление окна

Понял.

WM_RBUTTONUP()
{
      if (A_Gui != "Select")  {
     Gdip_SetBitmapToClipboard(pBitmap)
     DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
     Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
      Gui, %A_Gui%:Destroy
   }

}

А что там делает строка

Gdip_SetBitmapToClipboard(pBitmap)

? Она явно лишняя. А в коде

WM_MBUTTONDOWN()
{
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])

Gui, %A_Gui%:Hide
   FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
      res := Gdip_SaveBitmapToFile(pBitmap, SelectFile )

   DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
   oGuiData.Delete(A_Gui)
   Gui, %A_Gui%:Destroy
   Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}

не сохранён приведённый мной алгоритм, там

if (A_Gui != "Select")

совсем не напрасно было.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

82

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Уважаемый teadrinker я исправил код алгоритм соблюдён.

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

*~$vk2C::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE)  {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
    if (A_Gui != "Select")  {
     pToken := Gdip_Startup()
     pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
     Gui, %A_Gui%:Hide
     FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
     Gdip_SaveBitmapToFile(pBitmap, SelectFile )
     DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
     oGuiData.Delete(A_Gui)
     Gui, %A_Gui%:Destroy
     Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
    }
}

WM_RBUTTONUP()
{
     if (A_Gui != "Select")  {
      pToken := Gdip_Startup()
      pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
      Gdip_SetBitmapToClipboard(pBitmap)
      Gdip_DisposeImage(pBitmap)
      Gdip_Shutdown(pToken)
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

83 (изменено: teadrinker, 2022-10-18 03:02:01)

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Так будет в размере окна сохранять:

/*
Скрипт снимает скриншот выделенной области экрана и показывает его поверх всех окон.
Скрипт также позволяет изменять размеры скриншота при вращении над ним колеса мыши.
Ctrl + Space — начать выделение (отпустив Ctrl + Space).
Двигать окно со скриншотом левой кнопкой, менять размер вращая колесо, закрыть — щелчком правой.
При закрытии окна скриншот сохраняется в буфер обмена.

Для работы скрипта необходима библиотека Gdip.ahk
https://www.dropbox.com/s/73vpu9xdzn5ys13/Gdip.ahk?dl=1
*/

CoordMode, Mouse
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir, % A_ScriptDir
OnExit, Exit
global oGuiData := []

OnMessage(0x112, "WM_SYSCOMMAND")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x205, "WM_RBUTTONUP")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
Return

Exit:
   (CrossHair && CrossHair())
   (hHookMouse && DllCall("UnhookWindowsHookEx", Ptr, hHookMouse))
   for k, v in oGuiData
      DllCall("DeleteObject", Ptr, v)
   ExitApp

^Space::CrossHair(CrossHair := 1)

#If CrossHair = 1
LButton::
   MouseGetPos, mouse_x_start, mouse_y_start
   
   Gui, Select:Default
   Gui, -Caption +ToolWindow +LastFound +AlwaysOnTop -DPIScale
   Gui, Color, Grey
   WinSet, Transparent, 150
   
   hHookMouse := DllCall("SetWindowsHookEx"
      , Int, WH_MOUSE_LL := 14
      , Int, RegisterCallback("LowLevelMouseProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
      
   KeyWait, LButton
   SetTimer, EventHandling, Off
   DllCall("UnhookWindowsHookEx", Ptr, hHookMouse), hHookMouse := ""
   CrossHair(CrossHair := "")
   WinGetPos, X, Y, W, H
   Gui, Destroy
   CreateScreenshotWindow(X, Y, W, H)
   Return

#If hGui := ScreenWindowUnderCursor()
WheelDown::
WheelUp:: WM_WHEEL(A_ThisHotkey = "WheelUp" ? 0 : 1, hGui)
   
CrossHair(OnOff = "")
{
   static IDC_CROSS := 32515, SPI_SETCURSORS := 0x57
      , hCursor := DllCall("LoadCursor", Ptr, 0, UInt, IDC_CROSS, Ptr)
      , sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
   
   if !OnOff
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
   else
      for k, cursor in sys_cursors
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, 2, Int, 0, Int, 0, UInt, 0)
         , DllCall("SetSystemCursor", Ptr, hCopy, UInt, cursor)
}
       
LowLevelMouseProc(nCode, wParam, lParam)
{
   static mouse_x, mouse_y, WM_MOUSEMOVE := 0x200
   global mouse_x_start, mouse_y_start

   if (wParam = WM_MOUSEMOVE) {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      SetTimer, EventHandling, -10
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)

EventHandling:
   x := mouse_x_start < mouse_x ? mouse_x_start : mouse_x
   y := mouse_y_start < mouse_y ? mouse_y_start : mouse_y
   w := Abs(mouse_x - mouse_x_start)
   h := Abs(mouse_y - mouse_y_start)
   Gui, Select:Show, x%x% y%y% w%w% h%h% NA
   Return
}

CreateScreenshotWindow(X, Y, W, H)
{
   static WS_EX_LAYERED := 0x80000
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen( X "|" Y "|" W "|" H )
   
   hbm := CreateDIBSection(W, H)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
   
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, W - 2, H - 2)
   Gdip_DeletePen(pPen)
   
   for k, v in oGuiData
      if (v = 0 && IsEmpty := 1)
         break
      
   Gui, New, -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +hwndhGui -DPIScale
   Gui, Show, NA
   oGuiData[hGui] := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   UpdateLayeredWindow(hGui, hdc, X, Y, W, H)
   
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}

ScreenWindowUnderCursor()
{
   MouseGetPos,,, hGui
   WinGet, PID, Pid, ahk_id %hGui%
   if DllCall("GetCurrentProcessId") = PID
      Return hGui
}

WM_LBUTTONDOWN()
{
   if (A_Gui != "Select")
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_LBUTTONDBLCLK()
{
   if (A_Gui != "Select") {
      pToken := Gdip_Startup()
      pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
      Gui, %A_Gui%:Hide
      FileSelectFile, SelectFile, S3, %A_Now%.png , Сохранить скриншот, All Files(*.*)
      Gdip_SaveBitmapToFile(pBitmap, SelectFile )
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
      Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
   }
}

WM_RBUTTONUP()
{
   if (A_Gui != "Select") {
      pToken := Gdip_Startup()
      pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[A_Gui])
      pBitmap := ScaleImage(pBitmap, A_Gui)
      Gdip_SetBitmapToClipboard(pBitmap)
      Gdip_DisposeImage(pBitmap)
      Gdip_Shutdown(pToken)
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui])
      oGuiData.Delete(A_Gui)
      Gui, %A_Gui%:Destroy
   }
}

ScaleImage(pBitmap, hGui) {
   WinGetPos,,, W, H, ahk_id %hGui%
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   if (W = WidthBM)
      Return pBitmap
   pNewBitmap := Gdip_CreateBitmap(W, H)
   G := Gdip_GraphicsFromImage(pNewBitmap)
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, WidthBM, HeightBM)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap)
   Return pNewBitmap
}

WM_SYSCOMMAND(wp)
{
   static SC_CLOSE := 0xF060
   if (wp = SC_CLOSE && A_Gui != "Select")
      DllCall("DeleteObject", Ptr, oGuiData[A_Gui]), oGuiData.Delete(A_Gui)
}

WM_WHEEL(wp, hwnd)
{
   Critical
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromHBITMAP(oGuiData[hwnd])
   Gdip_GetImageDimensions(pBitmap, WidthBM, HeightBM)
   RatioBM := WidthBM/HeightBM
   SquareBM := WidthBM*HeightBM
   
   WinGetPos, X, Y, W, H, ahk_id %hwnd%
   
   DeltaW := Round(W/(!wp ? 10 : 11))
   DeltaW := wp ? -DeltaW : DeltaW
   ResultW := W + DeltaW
   ResultH := Round(ResultW/RatioBM)
   ResultX := X - Round(DeltaW/2)
   ResultY := Y - Round((ResultH - H)/2)
   SquareWin := ResultW*ResultH
   if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM)
      Return, "", Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)

   hbm := CreateDIBSection(ResultW, ResultH)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   
   Gdip_SetInterpolationMode(G, 7)
   Gdip_DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
   pPen := Gdip_CreatePen(0xFF808080, 2)
   Gdip_DrawRectangle(G, pPen, 1, 1, ResultW - 2, ResultH - 2)
   
   UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)

   Gdip_DeletePen(pPen), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), Gdip_Shutdown(pToken)
}

Вернул горячую клавишу, чтобы соответствовала описанию — Ctrl + Space.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

84

Re: AHK: Скриншот выделенной части экрана поверх всех окон

Немного подправил код.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder