auto screen-shots (with auto pauses/continuations) (with special auto saves) Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
adamantine
Posts: 32
Joined: 01 Aug 2020, 00:58
Location: europe

auto screen-shots (with auto pauses/continuations) (with special auto saves)

12 Aug 2020, 09:22

the idea is to get an automatic screen-shot (all screen) (png) every 60 seconds

examples for the titles of files:
2020.08.12   17.36.52.png
2020.12.05   01.46.08.png
2021.01.31   23.20.00.png

examples for the paths:
- each png (from 2020.08.12 00:00:00 to 2020.08.12 23:59:59) should be saved in the folder D:\Images\2020.08.12\
- each png (from 2020.08.13 00:00:00 to 2020.08.13 23:59:59) should be saved in the folder D:\Images\2020.08.13\
and so on

the folder D:\Images\ already exists (the folders like 2020.08.12 should be auto created) (i don't have this multiple auto creation now)

- the auto creation of screen-shots should be auto stopped in 30 minutes of idle period
- (when idle period is over) in 30 seconds: screen-shots should be auto created again

i am planning to add the following code to my main big script (which is the only ahk-script that is constantly running as an exe-file):
(please also read the short comments inside this code: 6 in the beginning and 3 in the end)

Code: Select all

SetTimer, MyAutoScreenShot, 30000 ; for some reason i only get the desired 60 seconds if i write 30000 in this line (and also 30000 in the next line)
SetTimer, MyIdle, 30000
return

MyIdle:
if (A_TimeIdle > 1800000) ; 30 minutes
{
SetTimer, MyAutoScreenShot, off
}

if (A_TimeIdle < 1800000) ; is this number correct here?
{
SetTimer, MyAutoScreenShot, on
}
return

q::run C:\WINDOWS\system32\calc.exe ; this line is only for the test (no need in #persistent)

MyAutoScreenShot:
{ ; is this line necessary?
pToken := Gdip_Startup()
OnExit, my-auto-ss-shutdown

folderPath := "D:\Images\Auto\" ; i tried something like "D:\Images\%A_YYYY%.%A_MM%.%A_DD%\" but unsuccessfully
fileName :=  A_YYYY "." A_MM "." A_DD "   " A_Hour "." A_Min "." A_Sec ".png"

CaptureScreen:
	pBitmap := Gdip_BitmapFromScreen()
	saveFileTo := folderPath fileName                   
	Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
	Gdip_DisposeImage(pBitmap)
	return

my-auto-ss-shutdown:
	Gdip_Shutdown(pToken)
	Exitapp
	return


Gdip_BitmapFromScreen(Screen=0, Raster="")
{
	if (Screen = 0)
	{
		Sysget, x, 76
		Sysget, y, 77	
		Sysget, w, 78
		Sysget, h, 79
	}
	else if (SubStr(Screen, 1, 5) = "hwnd:")
	{
		Screen := SubStr(Screen, 6)
		if !WinExist( "ahk_id " Screen)
			return -2
		WinGetPos,,, w, h, ahk_id %Screen%
		x := y := 0
		hhdc := GetDCEx(Screen, 3)
	}
	else if (Screen&1 != "")
	{
		Sysget, M, Monitor, %Screen%
		x := MLeft, y := MTop, w := MRight-MLeft, h := MBottom-MTop
	}
	else
	{
		StringSplit, S, Screen, |
		x := S1, y := S2, w := S3, h := S4
	}

	if (x = "") || (y = "") || (w = "") || (h = "")
		return -1

	chdc := CreateCompatibleDC(), hbm := CreateDIBSection(w, h, chdc), obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC()
	BitBlt(chdc, 0, 0, w, h, hhdc, x, y, Raster)
	ReleaseDC(hhdc)
	
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc)
	return pBitmap
}


Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, "uint", &ci)
	if !(nCount && nSize)
		return -2
   
	Loop, %nCount%
	{
		Location := NumGet(ci, 76*(A_Index-1)+44)
		if !A_IsUnicode
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
		}
		else
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			sString := ""
			Loop, %nSize%
				sString .= Chr(NumGet(Location+0, 2*(A_Index-1), "char"))
			if !InStr(sString, "*" Extension)
				continue
		}
		pCodec := &ci+76*(A_Index-1)
		break
	}
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", "uint", pBitmap, "uint", pCodec, "uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", "uint", pBitmap, "uint", pCodec, "uint", nSize, "uint", &EncoderParameters)
			Loop, % NumGet(EncoderParameters)      ;%
			{
				if (NumGet(EncoderParameters, (28*(A_Index-1))+20) = 1) && (NumGet(EncoderParameters, (28*(A_Index-1))+24) = 6)
				{
				   p := (28*(A_Index-1))+&EncoderParameters
				   NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20)))
				   break
				}
			}      
	  }
	}

	if !A_IsUnicode
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", &wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &wOutput, "uint", pCodec, "uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &sOutput, "uint", pCodec, "uint", p ? p : 0)
	return E ? -5 : 0
}


Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", "uint", pBitmap)
}


GetDCEx(hwnd, flags=0, hrgnClip=0)
{
    return DllCall("GetDCEx", "uint", hwnd, "uint", hrgnClip, "int", flags)
}


CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", "uint", hdc)
}


CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4), NumPut(h, bi, 8), NumPut(40, bi, 0), NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16), NumPut(bpp, bi, 14, "ushort")
	hbm := DllCall("CreateDIBSection", "uint" , hdc2, "uint" , &bi, "uint" , 0, "uint*", ppvBits, "uint" , 0, "uint" , 0)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}


SelectObject(hdc, hgdiobj)
{
   return DllCall("SelectObject", "uint", hdc, "uint", hgdiobj)
}


GetDC(hwnd=0)
{
	return DllCall("GetDC", "uint", hwnd)
}


BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
	return DllCall("gdi32\BitBlt", "uint", dDC, "int", dx, "int", dy, "int", dw, "int", dh
	, "uint", sDC, "int", sx, "int", sy, "uint", Raster ? Raster : 0x00CC0020)
}


ReleaseDC(hdc, hwnd=0)
{
   return DllCall("ReleaseDC", "uint", hwnd, "uint", hdc)
}


Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "uint", hBitmap, "uint", Palette, "uint*", pBitmap)
	return pBitmap
}


DeleteObject(hObject)
{
   return DllCall("DeleteObject", "uint", hObject)
}


DeleteDC(hdc)
{
   return DllCall("DeleteDC", "uint", hdc)
}


Gdip_Startup()
{
	if !DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "uint*", pToken, "uint", &si, "uint", 0)
	return pToken
}


Gdip_Shutdown(pToken)
{
	DllCall("gdiplus\GdiplusShutdown", "uint", pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("FreeLibrary", "uint", hModule)
	return 0
}

return ; is this line necessary?
} ; is this line necessary?
return ; is this line necessary?
at the moment this code saves a png-file to already existing folder only
the code also cannot create folders (depending on the date) and save the png-files inside folders (which have a corresponding dates in their titles)

i'm also not sure that everything is correct concerning the timers
so if you see any disadvantages (and if you know how to make this code perform all parts of my idea), feel free to post the correct/improved variant
User avatar
littlegandhi1199
Posts: 195
Joined: 29 Aug 2016, 23:58

Re: auto screen-shots (with auto pauses/continuations) (with special auto saves)  Topic is solved

12 Aug 2020, 16:46

Gdip should be in a seperate file. This is chaos to read through. I've uploaded the newest gdip version before gdip2 under attatchments to this post.
Gdip.ahk
(95.54 KiB) Downloaded 35 times
I've done it all for you I think as well. No need for 2 timers when it can check for idle activity right before saving.
Gdip doesn't automatically create folders that don't exist for you. Doubt FileMove does either but maybe that's why you're assuming that.
You use FileCreateDir for that.

You don't need to create a new token everytime you save a screenshot and it's probably a bad idea. Moved all one time lines to the start of the script. I also doubt you still need the hotkey to make the script persistent now either.

Code: Select all

#Include, Gdip.ahk
If !pToken := Gdip_Startup()
{
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}
msgbox, Started succesfully!

OnExit, my-auto-ss-shutdown
folderPath := "D:\Images\Auto"

SetTimer, MyAutoScreenShot, 30000
return


q::run C:\WINDOWS\system32\calc.exe ; this line is only for the test (no need in #persistent)


MyAutoScreenShot:
If (A_TimeIdle < 1800000)
{
TargetDir = %folderPath%\%A_YYYY%.%A_MM%.%A_DD%\
FileCreateDir, %TargetDir%
fileName :=  A_YYYY "." A_MM "." A_DD "   " A_Hour "." A_Min "." A_Sec ".png"
saveFileTo = %TargetDir%%fileName%

CaptureScreen:
pBitmap := Gdip_BitmapFromScreen()
If !pBitmap
{
	MsgBox, 48, Error!, Could not grab screen
	ExitApp
}
;;Gdip_GetImageDimensions(pBitmap, Width, Height)
;;msgbox, %Width% and %Height%
Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
Gdip_DisposeImage(pBitmap)
}
return

my-auto-ss-shutdown:
Gdip_Shutdown(pToken)
Exitapp
return
Script Backups on every Execution :mrgreen:
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=75767&p=328155#p328155

Scrabble Solver 4-15 letter word outputs ( :crazy: # of inputs)
https://www.autohotkey.com/boards/viewtopic.php?f=19&t=34285
adamantine
Posts: 32
Joined: 01 Aug 2020, 00:58
Location: europe

Re: auto screen-shots (with auto pauses/continuations) (with special auto saves)

13 Aug 2020, 07:06

thank you, littlegandhi1199
i ask you not to be angry at me but at the present time i prefer to continue not using this huge gdip.ahk (2715 lines)
because i only need those parts of it (~215 lines) that are related to creation of screen-shots
here's a topic where the author speaks exactly about it

i still don't have any #include's in my only ahk-script, and i don't really want to have them at all (as long as it's possible)
i may reconsider this my attitude in the future but now it's easier for me to manage my big but very modest script this way

at the moment i have this version of the code, and seemingly it works as intended:
(any kinds of msgbox are not acceptable for me (in this code at least))

Code: Select all

pToken := Gdip_Startup()
OnExit, my-auto-ss-shutdown
FolderPath := "D:\Images\Auto"

SetTimer, MyAutoScreenShot, 60000
return

q::run C:\WINDOWS\system32\calc.exe ; this line is still needed during the test (but it will be removed later)

MyAutoScreenShot:
If (A_TimeIdle < 1800000)
{
TargetDir = %FolderPath%\%A_YYYY%.%A_MM%.%A_DD%\
FileCreateDir, %TargetDir%
fileName :=  A_YYYY "." A_MM "." A_DD "   " A_Hour "." A_Min "." A_Sec ".png"
saveFileTo = %TargetDir%%fileName%

CaptureScreen:
pBitmap := Gdip_BitmapFromScreen()
Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
Gdip_DisposeImage(pBitmap)
}
return

my-auto-ss-shutdown:
Gdip_Shutdown(pToken)
Exitapp
return

;*********************************************************************************************************************************
;*********************************************************************************************************************************start of excerpt from gdip.ahk
;*********************************************************************************************************************************
Gdip_BitmapFromScreen(Screen=0, Raster="")
{
	if (Screen = 0)
	{
		Sysget, x, 76
		Sysget, y, 77	
		Sysget, w, 78
		Sysget, h, 79
	}
	else if (SubStr(Screen, 1, 5) = "hwnd:")
	{
		Screen := SubStr(Screen, 6)
		if !WinExist( "ahk_id " Screen)
			return -2
		WinGetPos,,, w, h, ahk_id %Screen%
		x := y := 0
		hhdc := GetDCEx(Screen, 3)
	}
	else if (Screen&1 != "")
	{
		Sysget, M, Monitor, %Screen%
		x := MLeft, y := MTop, w := MRight-MLeft, h := MBottom-MTop
	}
	else
	{
		StringSplit, S, Screen, |
		x := S1, y := S2, w := S3, h := S4
	}

	if (x = "") || (y = "") || (w = "") || (h = "")
		return -1

	chdc := CreateCompatibleDC(), hbm := CreateDIBSection(w, h, chdc), obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC()
	BitBlt(chdc, 0, 0, w, h, hhdc, x, y, Raster)
	ReleaseDC(hhdc)
	
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc)
	return pBitmap
}

Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, "uint", &ci)
	if !(nCount && nSize)
		return -2
   
	Loop, %nCount%
	{
		Location := NumGet(ci, 76*(A_Index-1)+44)
		if !A_IsUnicode
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
		}
		else
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			sString := ""
			Loop, %nSize%
				sString .= Chr(NumGet(Location+0, 2*(A_Index-1), "char"))
			if !InStr(sString, "*" Extension)
				continue
		}
		pCodec := &ci+76*(A_Index-1)
		break
	}
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", "uint", pBitmap, "uint", pCodec, "uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", "uint", pBitmap, "uint", pCodec, "uint", nSize, "uint", &EncoderParameters)
			Loop, % NumGet(EncoderParameters)      ;%
			{
				if (NumGet(EncoderParameters, (28*(A_Index-1))+20) = 1) && (NumGet(EncoderParameters, (28*(A_Index-1))+24) = 6)
				{
				   p := (28*(A_Index-1))+&EncoderParameters
				   NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20)))
				   break
				}
			}      
	  }
	}

	if !A_IsUnicode
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", &wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &wOutput, "uint", pCodec, "uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &sOutput, "uint", pCodec, "uint", p ? p : 0)
	return E ? -5 : 0
}

Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", "uint", pBitmap)
}

GetDCEx(hwnd, flags=0, hrgnClip=0)
{
    return DllCall("GetDCEx", "uint", hwnd, "uint", hrgnClip, "int", flags)
}

CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", "uint", hdc)
}

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4), NumPut(h, bi, 8), NumPut(40, bi, 0), NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16), NumPut(bpp, bi, 14, "ushort")
	hbm := DllCall("CreateDIBSection", "uint" , hdc2, "uint" , &bi, "uint" , 0, "uint*", ppvBits, "uint" , 0, "uint" , 0)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}

SelectObject(hdc, hgdiobj)
{
   return DllCall("SelectObject", "uint", hdc, "uint", hgdiobj)
}

GetDC(hwnd=0)
{
	return DllCall("GetDC", "uint", hwnd)
}

BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
	return DllCall("gdi32\BitBlt", "uint", dDC, "int", dx, "int", dy, "int", dw, "int", dh
	, "uint", sDC, "int", sx, "int", sy, "uint", Raster ? Raster : 0x00CC0020)
}

ReleaseDC(hdc, hwnd=0)
{
   return DllCall("ReleaseDC", "uint", hwnd, "uint", hdc)
}

Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "uint", hBitmap, "uint", Palette, "uint*", pBitmap)
	return pBitmap
}

DeleteObject(hObject)
{
   return DllCall("DeleteObject", "uint", hObject)
}

DeleteDC(hdc)
{
   return DllCall("DeleteDC", "uint", hdc)
}

Gdip_Startup()
{
	if !DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "uint*", pToken, "uint", &si, "uint", 0)
	return pToken
}

Gdip_Shutdown(pToken)
{
	DllCall("gdiplus\GdiplusShutdown", "uint", pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("FreeLibrary", "uint", hModule)
	return 0
}
;*********************************************************************************************************************************
;*********************************************************************************************************************************end of excerpt from gdip.ahk
;*********************************************************************************************************************************
is it a normal idea to use this code on a regular basis? (i'm particularly worried about line 1 and also about line 2)
are there any remained disadvantages here?
 
Spoiler
User avatar
littlegandhi1199
Posts: 195
Joined: 29 Aug 2016, 23:58

Re: auto screen-shots (with auto pauses/continuations) (with special auto saves)

13 Aug 2020, 12:53

Yeah! Absolutely not a problem.
I mean I thought it would be an issue to run ptoken startup 1000 times in a script like you were doing before but apparently not lol.

It's just a matter of how much memory the application uses and possibly memory leaks to raise your ram usage probably. (If you run the startup more then once)
So that's just a weird way of starting up GDIP that pretty much doesn't allow you to run it more then once.
And note that it doesn't matter anyways because your startup section isn't run more then once anyways. :P

Just to be safe you could prevent it from opening multiples of this script by adding
#SingleInstance Ignore
which just doesn't even ask if you want to replace the old script if it's already running. It won't allow you to start up another.

I'm gonna ask for the full code on the important thread you mentioned.
I currently already have implemented a core windows feature to a new hotkey binding. That is Ctrl+Escape and Ctrl+Shift+Escape
One press moves the current window to the back of the queue. (Which I rebound to something much easier to press quickly)
Other press moves any windows at the back of the queue to the front in the order they were put back there.
Script Backups on every Execution :mrgreen:
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=75767&p=328155#p328155

Scrabble Solver 4-15 letter word outputs ( :crazy: # of inputs)
https://www.autohotkey.com/boards/viewtopic.php?f=19&t=34285
adamantine
Posts: 32
Joined: 01 Aug 2020, 00:58
Location: europe

Re: auto screen-shots (with auto pauses/continuations) (with special auto saves)

15 Aug 2020, 14:13

in addition to the code from this thread, i have a code for manual creation of screen-shots
so there is always running exe-file that contains (among many other things) this code (in the auto-execute section)...:

Code: Select all

; automatic creation of screen-shots:

pToken := Gdip_Startup()
;OnExit, ShutDown ;-----------------------i'm testing the script with this line in a commented out state (this line, and also the 4 related lines that are lower) (is it safe?)
MyFolderPath := "D:\Images"

SetTimer, MyAutoScreenShot, 60000
return

MyAutoScreenShot:
If (A_TimeIdle < 600000) ; 10 minutes
{
TargetDir = %MyFolderPath%\%A_YYYY%.%A_MM%.%A_DD%\
FileCreateDir, %TargetDir%
fileName :=  A_YYYY "." A_MM "." A_DD "   " A_Hour "." A_Min "." A_Sec ".png"
saveFileTo = %TargetDir%%fileName%

;CaptureScreen: ;------------------------------------------------i decided to comment this line out (if i'm not mistaken, it brings nothing anyway)
pBitmap := Gdip_BitmapFromScreen()
Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
Gdip_DisposeImage(pBitmap)
}
return

;ShutDown: ;-----------------------------------------------------related line 1
;Gdip_Shutdown(pToken) ;-----------------------------------------related line 2
;Exitapp ;-------------------------------------------------------related line 3
;return ;--------------------------------------------------------related line 4
 
...and also this code (in the end):

Code: Select all

; manual creation of a screen-shot:

^+s::
{
pToken := Gdip_Startup()

folderPath := "D:\Images\"
fileName :=  A_YYYY "." A_MM "." A_DD "   " A_Hour "." A_Min "." A_Sec ".png"

pBitmap := Gdip_BitmapFromScreen()
saveFileTo := folderPath fileName                   
Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
Gdip_DisposeImage(pBitmap)
return

sleep 1000
return
}

;*********************************************************************************************************************************
;*********************************************************************************************************************************start of excerpt from gdip.ahk
;*********************************************************************************************************************************
Gdip_BitmapFromScreen(Screen=0, Raster="")
{
	if (Screen = 0)
	{
		Sysget, x, 76
		Sysget, y, 77	
		Sysget, w, 78
		Sysget, h, 79
	}
	else if (SubStr(Screen, 1, 5) = "hwnd:")
	{
		Screen := SubStr(Screen, 6)
		if !WinExist( "ahk_id " Screen)
			return -2
		WinGetPos,,, w, h, ahk_id %Screen%
		x := y := 0
		hhdc := GetDCEx(Screen, 3)
	}
	else if (Screen&1 != "")
	{
		Sysget, M, Monitor, %Screen%
		x := MLeft, y := MTop, w := MRight-MLeft, h := MBottom-MTop
	}
	else
	{
		StringSplit, S, Screen, |
		x := S1, y := S2, w := S3, h := S4
	}

	if (x = "") || (y = "") || (w = "") || (h = "")
		return -1

	chdc := CreateCompatibleDC(), hbm := CreateDIBSection(w, h, chdc), obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC()
	BitBlt(chdc, 0, 0, w, h, hhdc, x, y, Raster)
	ReleaseDC(hhdc)
	
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc)
	return pBitmap
}



Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, "uint", &ci)
	if !(nCount && nSize)
		return -2
   
	Loop, %nCount%
	{
		Location := NumGet(ci, 76*(A_Index-1)+44)
		if !A_IsUnicode
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
		}
		else
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			sString := ""
			Loop, %nSize%
				sString .= Chr(NumGet(Location+0, 2*(A_Index-1), "char"))
			if !InStr(sString, "*" Extension)
				continue
		}
		pCodec := &ci+76*(A_Index-1)
		break
	}
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", "uint", pBitmap, "uint", pCodec, "uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", "uint", pBitmap, "uint", pCodec, "uint", nSize, "uint", &EncoderParameters)
			Loop, % NumGet(EncoderParameters)      ;%
			{
				if (NumGet(EncoderParameters, (28*(A_Index-1))+20) = 1) && (NumGet(EncoderParameters, (28*(A_Index-1))+24) = 6)
				{
				   p := (28*(A_Index-1))+&EncoderParameters
				   NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20)))
				   break
				}
			}      
	  }
	}

	if !A_IsUnicode
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", &wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &wOutput, "uint", pCodec, "uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &sOutput, "uint", pCodec, "uint", p ? p : 0)
	return E ? -5 : 0
}



Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", "uint", pBitmap)
}



GetDCEx(hwnd, flags=0, hrgnClip=0)
{
    return DllCall("GetDCEx", "uint", hwnd, "uint", hrgnClip, "int", flags)
}



CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", "uint", hdc)
}



CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4), NumPut(h, bi, 8), NumPut(40, bi, 0), NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16), NumPut(bpp, bi, 14, "ushort")
	hbm := DllCall("CreateDIBSection", "uint" , hdc2, "uint" , &bi, "uint" , 0, "uint*", ppvBits, "uint" , 0, "uint" , 0)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}



SelectObject(hdc, hgdiobj)
{
   return DllCall("SelectObject", "uint", hdc, "uint", hgdiobj)
}



GetDC(hwnd=0)
{
	return DllCall("GetDC", "uint", hwnd)
}



BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
	return DllCall("gdi32\BitBlt", "uint", dDC, "int", dx, "int", dy, "int", dw, "int", dh
	, "uint", sDC, "int", sx, "int", sy, "uint", Raster ? Raster : 0x00CC0020)
}



ReleaseDC(hdc, hwnd=0)
{
   return DllCall("ReleaseDC", "uint", hwnd, "uint", hdc)
}



Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "uint", hBitmap, "uint", Palette, "uint*", pBitmap)
	return pBitmap
}



DeleteObject(hObject)
{
   return DllCall("DeleteObject", "uint", hObject)
}



DeleteDC(hdc)
{
   return DllCall("DeleteDC", "uint", hdc)
}



Gdip_Startup()
{
	if !DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "uint*", pToken, "uint", &si, "uint", 0)
	return pToken
}



Gdip_Shutdown(pToken)
{
	DllCall("gdiplus\GdiplusShutdown", "uint", pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("FreeLibrary", "uint", hModule)
	return 0
}
;*********************************************************************************************************************************
;*********************************************************************************************************************************end of excerpt from gdip.ahk
;*********************************************************************************************************************************
^+s is just a forced intermediary between ahk and my keyboard's software (i only press the convenient "MX5" button to create a screen-shot)

 
these 4 lines are present twice in the script:

Code: Select all

pToken := Gdip_Startup()

pBitmap := Gdip_BitmapFromScreen()
Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
Gdip_DisposeImage(pBitmap)
i didn't notice any problems so far, even in the case when 2 screen-shots were created during the same second: the 1st was manual, the 2nd was automatic
but i would like to specify anyway: is it all safe?
User avatar
littlegandhi1199
Posts: 195
Joined: 29 Aug 2016, 23:58

Re: auto screen-shots (with auto pauses/continuations) (with special auto saves)

15 Aug 2020, 15:50

I don't know but once per script is safe and easy. Might as well do it at the start one time and be done with it.
Script Backups on every Execution :mrgreen:
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=75767&p=328155#p328155

Scrabble Solver 4-15 letter word outputs ( :crazy: # of inputs)
https://www.autohotkey.com/boards/viewtopic.php?f=19&t=34285

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 138 guests