CGDipSnapShot - GDI replacement for PixelGetColor

Post your working scripts, libraries and tools for AHK v1.1 and older
liij
Posts: 51
Joined: 23 Apr 2016, 13:25

Re: CGDipSnapShot - GDI replacement for PixelGetColor

06 Jan 2017, 17:43

edit=response to your edit
[quote="evilC"]

Code: Select all

	

[strike]I would advise using a debugger or doing something like chuck a msgbox in there to show you what is in the variable.[/strike] Edit - I see the msgbox at the end now.[/quote]

Not sure why cdig is not working in any way in my script, just thought it could be stupidly stuping thing from my side/incompability something with something. This "incompability" is too hard to me and I will check this several months later...
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

06 Jan 2017, 17:47

see previous post. It is likely to do with flow of control.
Again, would advise using a debugger such as Scite. The "red dot" you place on a line is called a "breakpoint". You can set them for lines you are interested and then let the code run until it hits one of those lines. Can also be useful to tell you if / when it is doing something.
Another useful tool is the debug log (See the OutputDebug command). I think Scite has a built in log viewer, but I use DebugView (Google it, it's MS Technet so safe) so I get a separate window with the log in that I can run even when not editing and see the logging from a script.
So yeah, check that it is actually taking a snapshot before it is checking the contents - that would me my guess as to what is wrong.
Also, with a line such as val:=snap.PixelScreen[1571,890].rgb bear in mind that if snap is empty, then val will be empty and AHK will not throw an error.
Last edited by evilC on 06 Jan 2017, 17:50, edited 1 time in total.
liij
Posts: 51
Joined: 23 Apr 2016, 13:25

Re: CGDipSnapShot - GDI replacement for PixelGetColor

06 Jan 2017, 17:49

Whole code before your advice was looking like that

Code: Select all

spawnlarva:
BlockInput, on
snap := new CGdipSnapshot(300,700,1620,380)
snap.TakeSnapshot()
	settimer scvtimer, %scvtime%
	;settimer guitimer3, %guitime3%
	;settimer guitimer2, %guitime2%
	settimer guitimer1, %guitime1%
sleep 1
if czatbreaktheloop=1
	{
	settimer larvatimer, %injecttime%
	return
	}
Send %savecamera%
sleep 1
if czatbreaktheloop=1
	{
	settimer larvatimer, %injecttime%
	return
	}
Send %savecontrolgroup%					;Save camera location
sleep 1
ccloop:=1
thereisnocc:=1
settimer, thereisnocctimer,-500
if czatbreaktheloop=1
	{
	settimer larvatimer, %injecttime%
	return
	}
send %smallcontrolgroup%
sleep 1
while, ccloop
{
if czatbreaktheloop=1
	{
	settimer larvatimer, %injecttime%
	break
	}
lag:=0
while, lag<=3
	{
val:=snap.PixelScreen[1571,890].rgb
		Ifequal, val, 0x677ec1
			{
			lag:=1000
		 	}
		Ifnotequal, val, 0x677ec1
			{
			lag+=1
			sleep 50
snap.TakeSnapshot()
			}
	}
msgbox, %val%
There is

Code: Select all

snap := new CGdipSnapshot(300,700,1620,380)
snap.TakeSnapshot()
before asking/msgboxing script about val, so I am not sure where to put it. It is already in good place I think...
Edit: computer is freezing and crashing after pressing alt+f5 (hotkey running script with snapshot), never happened to me :? :shock:
Yesterday it was giving with blank/empty msgbox
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

06 Jan 2017, 18:00

It's also entirely possible that I goofed on the "Screen" coordinate mode.
The "Snapshot" coordinate mode is the one that is internally used, so it may be worth seeing what happens if you work out what the snapshot coords you would be referencing are.
ie it may just be possible that you do have a snapshot, but you are requesting pixels from outside it (because either I or you goofed).
A simple test would be to replace snap.PixelScreen[1571,890].rgb with snap.PixelSnap[0,0].rgb and see if you get a value back. PixelSnap[0,0] will always hold something if there is a valid snapshot.
liij
Posts: 51
Joined: 23 Apr 2016, 13:25

Re: CGDipSnapShot - GDI replacement for PixelGetColor

06 Jan 2017, 18:09

I think i exluded this possibility with this script

Code: Select all

#include <CGdipSnapshot>
z::
{
snap := new CGdipSnapshot(300,700,1620,380)
snap.TakeSnapshot()
PixelGetColor, OutputVar, 1571,890,
val:=snap.PixelScreen[1571,890].rgb
sleep 10
lag:=0
while, lag<=3
	{
pgtscv:=snap.PixelScreen[1571,890].rgb
		Ifequal, pgtscv, 0x677ec1
			{
			lag:=1000
			MsgBox  %OutputVar% %pgtscv%
		 	}
		Ifnotequal, pgtscv, 0x677ec1
			{
			lag+=1
			sleep 50
			snap := new CGdipSnapshot(300,700,1620,380)
			}
	}
;		;Ifequal, val, 0x677ec1
;{
;MsgBox  %OutputVar% %val%
;}
}
And this script with your CGDipSnapShot is working perfectly.
This is part of my big script that I run separately from my big script...
Entropy42
Posts: 29
Joined: 11 Dec 2016, 12:34

Re: CGDipSnapShot - GDI replacement for PixelGetColor

23 Jan 2017, 17:13

I just implemented this as a replacement for PixelGetColor in my script, and it is way, way faster, which is great, but it seems like I have a memory leak now. Here's my function that calls CGDSS:

Code: Select all

scanGridInnerLoop(newBoard, gemColorsRGB)
{
	; Loop X then Y: get a full column from the bottom then move to the next
	anaylyzeResolution()
	snap := new CGdipSnapshot(PQ_X,PQ_Y,PQ_W, PQ_H)		; snapshot of active window
	; snap.SaveSnapshot("board.png")     ; PNG format
	Loop, 8
	{
		x := A_Index
		px := xCoordToPixel(A_Index)
		Loop, 8
		{
			y := A_Index
			py := yCoordToPixel(A_Index)
			gemColorsRGB[x, y, 1] := snap.PixelSnap[px,py].r		; somehow this line eats up 4 MB of RAM
			gemColorsRGB[x, y, 2] := snap.PixelSnap[px,py].g
			gemColorsRGB[x, y, 3] := snap.PixelSnap[px,py].b		
			test := gemColorsRGB.GetCapacity()
			sg_c := pixelcolor2Gem(gemColorsRGB[x, y])
			if sg_c = 0		; this did not match any known color pattern, abort and try again
				return false
			newBoard[x,y] := sg_c
		}
	}
	return true
}
I've watched the memory usage of AHK using Windows Task Manager, and every time this function is called, as soon as it hits the "gemColorsRGB[x, y, 1] := snap.PixelSnap[px,py].r" line, the memory usage goes up by 4 MB, and it never comes back down. Do I need to destroy the snapshot when I'm done with it? If so, how do I do that? I read the wiki for this library and couldn't find it.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 07:49

I always see the script as using ~4MB.
I had a little look and I cannot see any memory leaks.
If you can provide me with some short, simple code the reproduces the issue, I will investigate.
It doesn't have to do anything useful, just take a bunch of snapshots or whatever...
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 09:30

@Entropy42:

Code: Select all

gemColorsRGB[x, y, 1] := snap.PixelSnap[px,py].r		; somehow this line eats up 4 MB of RAM
In your function the GDIP bitmap will be created when this line is executed the first time.

@evilC: The bitmap should be deleted when the function returns and the snap object is freed, but the call of __Delete() might be prevented because of the references to the embedded classes.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 09:50

Code: Select all

Loop 100 {
	TakeSnap()
}

TakeSnap(){
	snap1 := new CGdipSnapshot(300,300,200,200)
	snap1.TakeSnapshot()
	r := snap.PixelSnap[1,1].r
}

[...]

; Modify destructor from class...
__Delete(){
	ToolTip % A_TickCount
	[...]
}
Debug the script, every time TakeSnap() runs, the destructor is called.
Entropy42
Posts: 29
Joined: 11 Dec 2016, 12:34

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 10:12

I didn't mean to say that the script above will just eat up 4 MB per loop iteration. As you can see, in that function, the gemColorsRGB[x, y, 1] := snap.PixelSnap[px,py].r line gets called 64 times, but it only goes up by 4 MB the first time it encounters that line after the snap is taken. The scanGridInnerLoop() function gets called inside another loop, and the memory usage is going up every time around THAT loop. I cut it way down and verified that this version eats up 4 MB every time I press F10. I was just calling this with my SciTE4AHK window in focus to test it.

Code: Select all

#NoEnv
#SingleInstance, Force
SetWorkingDir,%A_ScriptDir%  ; Ensures a consistent starting directory.
SetDefaultMouseSpeed, 8
#include <CGdipSnapshot>

; ------Super Globals----------
; Coords within the window for the bottom left of the board (0,0).
global SG_ORIGIN_X=290
global SG_ORIGIN_Y=769
; Offset to measure within the square.
global SG_OFFSET_X=43		; from the left
global SG_OFFSET_Y=72		; from the top
; Size of a single square.
global SG_SIZE_X := 85.5
global SG_SIZE_Y := 85.5
global PQ_X=200
global PQ_Y=200
global PQ_W=1260
global PQ_H=815

F10::
		scanGridInnerLoop(board, boardColorsRGB)
	return	
F11::Reload ; pause/reload the script. stop scripts execution

; ========= FUNCTIONS ============
scanGridInnerLoop(newBoard, gemColorsRGB)
{
	; Loop X then Y: get a full column from the bottom then move to the next
	anaylyzeResolution()
	snap := new CGdipSnapshot(PQ_X,PQ_Y,PQ_W, PQ_H)		; snapshot of active window
	Loop, 8
	{
		x := A_Index
		px := xCoordToPixel(A_Index)
		Loop, 8
		{
			y := A_Index
			py := yCoordToPixel(A_Index)
			gemColorsRGB[x, y, 1] := snap.PixelSnap[px,py].r		; somehow this line eats up 4 MB of RAM
			gemColorsRGB[x, y, 2] := snap.PixelSnap[px,py].g
			gemColorsRGB[x, y, 3] := snap.PixelSnap[px,py].b		
		}
	}
	return true
}
anaylyzeResolution()
{
	WinGetPos, X, Y, W, H, A
	PQ_X := X
	PQ_Y := Y
	scaleFactorX := W/PQ_W
	scaleFactorY := H/PQ_H
	return 1
}
yCoordToPixel(y)
{
	return Round( SG_ORIGIN_Y - (y-1) * SG_SIZE_Y - SG_OFFSET_Y )
}
xCoordToPixel(x)
{
	return Round( (x-1) * SG_SIZE_X + SG_ORIGIN_X + SG_OFFSET_X )
}
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 10:14

This one doesn't call the destructor here:

Code: Select all

#NoEnv
MsgBox, Start!
TestFunc()
MsgBox, End!
ExitApp

TestFunc()
{
	snap := new CGdipSnapshot(0, 0, 800, 800)		; snapshot of active window
   MsgBox, Snap!
	r := snap.PixelSnap[10, 10].r		; somehow this line eats up 4 MB of RAM
   MsgBox, PixelSnap!
	Return true
}

#Include CGDIPSnapshot.ahk
#Include GDIPALL.ahk ; <--- my private version of GDIP_All
I added a MsgBox to__Delete().
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 11:23

OK, it seems that the problem is caused by passing a reference to the CGDipSnapShot class into the _CColor class

ie the problem line is:

Code: Select all

	Class _CColor {
		__New(RGB, parent){
			this._RGB := RGB
			this._parent := parent ; <--- This line causes the problem
		}
It is entirely possible that the system can be re-engineered to automatically fire the destructor, or maybe I could add a method to delete.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 11:32

The only things that seem to use the parent property are:

Code: Select all

		; Returns the Difference between two colors
		Diff(c2){
			return this._parent.Diff(this, c2)
		}
The parent class does not have a Diff() method, so this code seems pointless.

Plus a bunch of checks like this:

Code: Select all

if (!this._parent._SnapshotTaken){
	return -1
}
But I do not see the point in this code. If the class exists, it will have been passed an RGB value, so it can return something.

So I removed this offending code, please try out this version of the library and let me know if it fixes your issues.

Code: Select all

Class CGDipSnapShot {
	; "private" Properties - Do not attempt to Set or Get! ===============
	; Coords of snapshot area relative to screen
	; Access via this.Coords instead!
	_Coords := {x: 0, y: 0, w: 0, h: 0}

	; Cache of RGB value for pixels in the Snapshot.
	; Access via this.PixelSnap[] or this.PixelScreen[] instead!
	_PixelCache := [[],[]]
	
	; Internal - you should not need these at all
	_SnapshotTaken := 0
	_NegativeValue := {rgb: -1, r: -1, g: -1, b: -1}

	; GDI stuff for the snapshot. You are unlikely to need these
	pToken := 0
	pBitmap := 0 								; bitmap image
	hBitmap := 0 								; HWND for bitmap?

	; === User Methods ==================================================================================================================================
	; Intended for use by people using the class.

	; Take a new Snapshot
	TakeSnapshot(){
		this._ResetSnapshot()
		this.pBitmap := GDIP_BitmapFromScreen(this._Coords.x "|" this._Coords.y "|" this._Coords.w "|" this._Coords.h)
		this._SnapshotTaken := 1
		return
	}

	; Show the Snapshot in the specified HWND.
	; Declare a regular AHK GUI Textbox like so:
	; Gui, Add, Text, 0xE x5 y5 w200 h200 hwndSnapshotPreview
	; Then ShowSnapshot(SnapshotPreview) to show the snapshot in that GUI item
	ShowSnapshot(hwnd){
		if (!this._SnapshotTaken){
			this.TakeSnapshot()
		}
		if (this.hBitmap){
			; Delete old hwnd
			DeleteObject(this.hBitmap)
		}
		this.hBitmap := Gdip_CreateHBITMAPFromBitmap(this.pBitmap)
		SendMessage, 0x172, 0, % this.hBitmap, , % "ahk_id " hwnd
		return
	}

	; Save snapshot to file
	; Supported extensions are: .BMP,.DIB,.RLE,.JPG,.JPEG,.JPE,.JFIF,.GIF,.TIF,.TIFF,.PNG
	SaveSnapshot(filename, quality := 100){
		if (!this._SnapshotTaken){
			this.TakeSnapshot()
		}
		return Gdip_SaveBitmapToFile(this.pBitmap, filename, quality)
	}

	; Move / Resize the Snapshot after creation
	; Pass an object containing which properties you wish to set.
	; eg to set only x and h to 0, but leave y and w the same, pass {x: 0, h:0}
	SetCoords(obj){
		was_set := 0
		for key, value in Obj {
			if (key = "x" || key = "y" || key = "w" || key = "h"){
				was_set++
				this._Coords[key] := value
			}
		}
		; If moved or resized, reset the Pixel Cache
		if (was_set){
			this._ResetSnapshot()
		}
	}
	
	; Compares one snapshot with another, with optional tolerance
	Compare(snap, tol := 20){
		if (!this._SnapshotTaken){
			this.TakeSnapshot()
		}
		if (this._Coords.w != snap._Coords.w || this._Coords.h != snap._Coords.h){
			return 0
		}
		Loop % this._Coords.w {
			x := A_Index
			Loop % this._Coords.h {
				y := A_Index
				if (!this.PixelSnap[x,y].Compare(snap.PixelSnap[x,y],tol)){
					return 0
				}
			}
		}
		return 1
	}
	
	; Return the Coords object, for completeness
	GetCoords(){
		return this._Coords
	}
	
	; Converts Screen coords to Snapshot coords
	ScreenToSnap(x,y){
		return {x: x - this._Coords.x, y: y - this._Coords.y}
	}

	; Returns true if the snapshot coordinates are valid (eg x not bigger than width)
	; NOT for telling if a screen coord is inside the snapshot
	IsSnapCoord(xpos,ypos){
		if (xpos < 0 || xpos > this._Coords.w || ypos < 0 || ypos > this._Coords.h){
			return 0
		}
		return 1
	}
	
	; Is a screen coord inside the snapshot area?
	IsInsideSnap(xpos,ypos){
		if (xpos < this._Coords.x || ypos < this._Coords.y || xpos > (this._Coords.x + this._Coords.w) || ypos > (this._Coords.y + this._Coords.h) ){
			return 0
		}
		return 1
	}
	
	; ===== Available for End-user use, but not advised (Use better alternatives) ===================================================
	
	; Gets color of a pixel relative to the screen (As long as it is inside the snapshot)
	; Returns -1 if asked for a pixel outside the snapshot
	; Advise use of PixelScreen[] Array instead of this function, as results are cached
	PixelGetColor(xpos,ypos){
		; Return RGB value of -1 if outside snapshot area
		if (!this.IsInsideSnap(xpos,ypos)){
			return this._NegativeValue
		}
		; Work out which pixel in the Snapshot was requested
		xpos := xpos - this._Coords.x
		ypos := ypos - this._Coords.y
		
		return this.SnapshotGetColor(xpos,ypos)
	}

	; Gets color of a pixel relative to the SnapShot
	; Advise use of PixelSnap[] Array instead of this function, as results are cached.
	SnapshotGetColor(xpos, ypos){
		if (!this._SnapshotTaken){
			this.TakeSnapshot()
		}
		if (!this.IsSnapCoord(xpos, ypos)){
			return this._NegativeValue
		}
		ret := GDIP_GetPixel(this.pBitmap, xpos, ypos)
		ret := this.ARGBtoRGB(ret)
		return new this._CColor(ret)
	}
	
	; ===== Mainly for internal use. ==========================================================================================

	_ResetSnapshot(){
		if (this.pBitmap){
			; delete old bitmap
			Gdip_DisposeImage(this.pBitmap)
		}
		this._SnapshotTaken := 0
		this._PixelCache := [[],[]]
	}
	
	; Converts RGB with Alpha Channel to RGB
	ARGBtoRGB( ARGB ){
		SetFormat, IntegerFast, hex
		ARGB := ARGB & 0x00ffffff
		ARGB .= ""  ; Necessary due to the "fast" mode.
		SetFormat, IntegerFast, d
		return ARGB
	}

	; Constructor
	__New(x,y,w,h){
		this.Coords := new this._CCoords()
		this._Coords := {x: x, y: y, w: w, h: h}
		this.pToken := Gdip_Startup()
	}

	; Destructor
	__Delete(){
		if (this.pBitMap != -1)
			Gdip_DisposeImage(this.pBitmap)
		if (this.hBitmap != 0)
			DeleteObject(this.hBitmap)
		if (this.pToken)
			Gdip_ShutDown(this.pToken)
	}
	
	; Implements Pixel Cache via Dynamic Properties
	__Get(aName, x := "", y := ""){
		if (aName = "Coords"){
			return this._Coords
		} else if (aName = "PixelSnap"){
			if (this._PixelCache[x,y] == ""){
				this._PixelCache[x,y] := this.SnapshotGetColor(x,y)
			}
			return this._PixelCache[x,y]
		}
		if (aName = "PixelScreen"){
			col := this.PixelGetColor(x,y)
			; Convert to snapshot coords for array index
			coords := this.ScreenToSnap(x,y)
			x := coords.x
			y := coords.y
			; Check coords are within snapshot
			if (col.rgb != -1){
				this._PixelCache[x,y] := col
			}
			return col
		}
	}
	
	; Implements snapshot coords Get / Set via Dynamic Properties.
	; Automatically resets snapshot if viewport moved
	Class _CCoords {
		__Get(aName){
			if (aName = "x" || aName = "y" || aName = "w" || aName = "h"){
				return this._Coords[aName]
			}
		}
		
		__Set(aName, aValue){
			if (aName = "x" || aName = "y" || aName = "w" || aName = "h"){
				this._Coords[aName] = aValue
				this._ResetSnapshot()
			}
		}
	}
	
	; color class - provides r/g/b values via Dynamic Properties
	Class _CColor {
		__New(RGB){
			this._RGB := RGB
		}
		
		; Implement RGB and R, G, B as Dynamic Properties
		__Get(aName := ""){
			if (aName = "RGB"){
				; Return RGB in Hexadecimal (eg 0xFF00AA) format
				SetFormat, IntegerFast, hex
				ret := this._RGB
				ret += 0
				ret .= ""
				SetFormat, IntegerFast, d
				return ret
			} else if (aName = "R"){
				; Return red in Decimal format
				return (this._RGB >> 16) & 255
			} else if (aName = "G"){
				return (this._RGB >> 8) & 255
			} else if (aName = "B"){
				return this._RGB & 255
			}
		}
		
		; Compares this pixel to a provided color, with a tolerance
		Compare(c2, tol := 20){
			return PixelCompare(this, c2, tol)
		}
	}

}

; Compares two r/g/b integer objects, with a tolerance
; returns true or false
; Note! NOTHING to do with any pixels in the snapshot - purely compares two hex values.
PixelCompare(c1, c2, tol := 20) {
	return (PixelDiff(c1,c2) <= tol)
}

; Returns the Difference between two colors
PixelDiff(c1,c2){
	diff := Abs( c1.r - c2.r ) "," Abs( c1.g - c2.g ) "," Abs( c1.b - c2.b )
	sort diff,N D,

	StringSplit, diff, diff, `,
	return diff%diff0%
}

; Converts hex ("0xFFFFFF" as a string) to an object of r/g/b integers
HexToRGB(color) {
	return { "r": (color >> 16) & 0xFF, "g": (color >> 8) & 0xFF, "b": color & 0xFF }
}
Entropy42
Posts: 29
Joined: 11 Dec 2016, 12:34

Re: CGDipSnapShot - GDI replacement for PixelGetColor

24 Jan 2017, 12:34

As far as I can tell, this fixed the issue. Thanks!
Entropy42
Posts: 29
Joined: 11 Dec 2016, 12:34

Re: CGDipSnapShot - GDI replacement for PixelGetColor

26 Jan 2017, 11:22

I was trying to use Compare function of this library, but I'm not sure how to make the color object to compare to.
I have a pixel color that I get from
col1 := snap.PixelSnap[x,y].rgb
From the documentation, it sounds like this is going to be a color object, so to compare it I need to make another Color object, but don't know how. My colors are in RGB format, like [115,24,41], so I tried defining it by:
col2 := { r:115, g:24, b:41 }
And then comparing using:
match := col1.Compare(col2, 10)

But that didn't work, presumably because I made the color object wrong.
Entropy42
Posts: 29
Joined: 11 Dec 2016, 12:34

Re: CGDipSnapShot - GDI replacement for PixelGetColor

26 Jan 2017, 14:33

Ah, ok, so it is not possible currently. I will just do a compare manually. Thanks!
+MeleaB+
Posts: 12
Joined: 26 Oct 2017, 18:46

Re: CGDipSnapShot - GDI replacement for PixelGetColor

26 Oct 2017, 19:00

EDIT: I just switched my default version of AHK from Unicode 64-bit to Unicode 32-bit. It looks like this may have stopped the crashing.

------------------------------------------------------

Hello evilC

I taught myself AHK a year ago, and used your CGDipSnapShot library to dramatically speed up the program I wrote. However, I ran into a problem which I am again experiencing now, as I attempt to include it in another program I am writing. The issue seems to be that CGDipSnapShot is causing AHK to crash whenever a GUI is closed. If I run, say, your 'example.ahk" then the program works as it should until I attempt to close it. Then I receive the following message:

"AutoHotKey Unicode 64-bit has stopped working. A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available."

If I remove the GUI lines from your example.ahk, then the program runs as it should. if I use it within my own program with a GUI, then it produces the error if I try and close the GUI (and also leaves the PC with the mouse "stuttering" and only moving very slowly, as it there's a process stealing all the focus.)

CGDipSnapShot is amazing, but unfortunately I'm prevented from using it with my GUI (which is imperative!) Any help would be greatly appreciated!

Cheers!

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: pgeugene and 131 guests