;---------------------------------------------------------------------------------------------------------------------------------------------------------
;                                                             	collected by IXIKO =>    last change: 11.10.2019
;                                                                	Collection of rare or very useful functions
;                                    	for description have a look at README.md (it can be found in the same folder)
;---------------------------------------------------------------------------------------------------------------------------------------------------------


{ ;Clipboard (09) -                                                                                                                                        	baseID: <01>

;<01.01.000001>
ClipboardGetDropEffect() {																				;-- Clipboard function. Retrieves if files in clipboard comes from an explorer cut or copy operation.

	/*                              	DESCRIPTION

			Parameters	:		explorer copy = 5, explorer cut = 2

	*/


   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str" , "Preferred DropEffect")
   DropEffect := 0
   If DllCall("IsClipboardFormatAvailable", "UInt", PreferredDropEffect) {
      If DllCall("OpenClipboard", "Ptr", 0) {
         hDropEffect := DllCall("GetClipboardData", "UInt", PreferredDropEffect, "UPtr")
         pDropEffect := DllCall("GlobalLock", "Ptr", hDropEffect, "UPtr")
         DropEffect := NumGet(pDropEffect + 0, 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hDropEffect)
         DllCall("CloseClipboard")
      }
   }
   Return DropEffect
} ;</01.01.000001>
;<01.01.000002>
ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {										;-- Explorer function for Drag&Drop and Pasting. Enables the explorer paste context menu option.

   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; -------------------------------------------------------------------------------------------------------------------
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return
   ; -------------------------------------------------------------------------------------------------------------------
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format ---------------------------------------------------------------------------------------------------
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hPath := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pPath := DllCall("GlobalLock", "Ptr" , hPath)
      Offset := 20
      NumPut(Offset, pPath + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pPath + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pPath + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hPath)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hPath) ; 0x0F = CF_HDROP
      ; Preferred DropEffect format ------------------------------------------------------------------------------------
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
   }
   Return
} ;</01.01.000002>
;<01.01.000003>
CopyFilesToClipboard(arrFilepath, bCopy) {													;-- copy files to clipboard

	/*                              	DESCRIPTION

			this works under both ANSI/Unicode build of AHK

	*/


	; set drop effect to determine whether the files are copied or moved.
	uDropEffect := DllCall("RegisterClipboardFormat", "str", "Preferred DropEffect", "uint")
	hGblEffect := DllCall("GlobalAlloc", "uint", 0x42, "ptr", 4, "ptr")
	pGblEffect := DllCall("GlobalLock", "ptr", hGblEffect, "ptr")
	; 0x1=DROPEFFECT_COPY, 0x2=DROPEFFECT_MOVE
	NumPut(bCopy ? 1 : 2, pGblEffect+0)

	; Unlock the moveable memory.
	DllCall("GlobalUnlock", "ptr", hGblEffect)


	charsize := A_IsUnicode ? 2 : 1
	AorW := A_IsUnicode ? "W" : "A"

	; calculate the whole size of arrFilepath
	sizeFilepath := charsize*2 ; double null-terminator
	For k, v in arrFilepath {
		sizeFilepath += (StrLen(v)+1)*charsize
	}

	; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
	hPath := DllCall("GlobalAlloc", "uint", 0x42, "ptr", sizeFilepath + 20, "ptr")
	pPath := DllCall("GlobalLock", "ptr", hPath, "ptr")

	NumPut(20, pPath+0) ;pFiles
	NumPut(A_IsUnicode, pPath+16) ;fWide

	pPath += 20

	; Copy the list of files into moveable memory.
	For k, v in arrFilepath {
		DllCall("lstrcpy" . AorW, "ptr", pPath+0, "str", v)
		pPath += (StrLen(v)+1)*charsize
	}

	; Unlock the moveable memory.
	DllCall("GlobalUnlock", "ptr", hPath)

	DllCall("OpenClipboard", "ptr", 0)
	; Empty the clipboard, otherwise SetClipboardData may fail.
	DllCall("EmptyClipboard")
	; Place the data on the clipboard. CF_HDROP=0xF
	DllCall("SetClipboardData","uint",0xF,"ptr",hPath)
	DllCall("SetClipboardData","uint",uDropEffect,"ptr",hGblEffect)
	DllCall("CloseClipboard")
} ;</01.01.000003>
;<01.01.000004>
FileToClipboard(PathToCopy) {																		;-- copying the path to clipboard

	;https://autohotkey.com/board/topic/23162-how-to-copy-a-file-to-the-clipboard/
    ; Expand to full path:
    Loop, %PathToCopy%, 1
        PathToCopy := A_LoopFileLongPath

    ; Allocate some movable memory to put on the clipboard.
    ; This will hold a DROPFILES struct, the string, and an (extra) null terminator
    ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
    hPath := DllCall("GlobalAlloc","uint",0x42,"uint",StrLen(PathToCopy)+22)

    ; Lock the moveable memory, retrieving a pointer to it.
    pPath := DllCall("GlobalLock","uint",hPath)

    NumPut(20, pPath+0) ; DROPFILES.pFiles = offset of file list

    ; Copy the string into moveable memory.
    DllCall("lstrcpy","uint",pPath+20,"str",PathToCopy)

    ; Unlock the moveable memory.
    DllCall("GlobalUnlock","uint",hPath)

    DllCall("OpenClipboard","uint",0)
    ; Empty the clipboard, otherwise SetClipboardData may fail.
    DllCall("EmptyClipboard")
    ; Place the data on the clipboard. CF_HDROP=0xF
    DllCall("SetClipboardData","uint",0xF,"uint",hPath)
    DllCall("CloseClipboard")
} ;</01.01.000004>
;<01.01.000005>
FileToClipboard(PathToCopy) {																		;-- a second way to copying the path to clipboard
    ; Expand to full paths:
    Loop, Parse, PathToCopy, `n, `r
        Loop, %A_LoopField%, 1
            temp_list .= A_LoopFileLongPath "`n"
    PathToCopy := SubStr(temp_list, 1, -1)

    ; Allocate some movable memory to put on the clipboard.
    ; This will hold a DROPFILES struct and a null-terminated list of
    ; null-terminated strings.
    ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
    hPath := DllCall("GlobalAlloc","uint",0x42,"uint",StrLen(PathToCopy)+22)

    ; Lock the moveable memory, retrieving a pointer to it.
    pPath := DllCall("GlobalLock","uint",hPath)

/
    pPath += 20
    ; Copy the list of files into moveable memory.
    Loop, Parse, PathToCopy, `n, `r
    {
        DllCall("lstrcpy","uint",pPath+0,"str",A_LoopField)
        pPath += StrLen(A_LoopField)+1
    }

    ; Unlock the moveable memory.
    DllCall("GlobalUnlock","uint",hPath)

    DllCall("OpenClipboard","uint",0)
    ; Empty the clipboard, otherwise SetClipboardData may fail.
    DllCall("EmptyClipboard")
    ; Place the data on the clipboard. CF_HDROP=0xF
    DllCall("SetClipboardData","uint",0xF,"uint",hPath)
    DllCall("CloseClipboard")
} ;</01.01.000005>
;<01.01.000006>
ImageToClipboard(Filename) {																		;-- Copies image data from file to the clipboard. (first of three approaches)

	;https://autohotkey.com/board/topic/23162-how-to-copy-a-file-to-the-clipboard/
    hbm := DllCall("LoadImage","uint",0,"str",Filename,"uint",0,"int",0,"int",0,"uint",0x10)
    if !hbm
        return
    DllCall("OpenClipboard","uint",0)
    DllCall("EmptyClipboard")
    ; Place the data on the clipboard. CF_BITMAP=0x2
    if ! DllCall("SetClipboardData","uint",0x2,"uint",hbm)
        DllCall("DeleteObject","uint",hbm)
    DllCall("CloseClipboard")
} ;</01.01.000006>
;<01.01.000007>
Gdip_ImageToClipboard(Filename) {																;-- Copies image data from file to the clipboard. (second approach)

	;https://autohotkey.com/board/topic/23162-how-to-copy-a-file-to-the-clipboard/
    pBitmap := Gdip_CreateBitmapFromFile(Filename)
    if !pBitmap
        return
    hbm := Gdip_CreateHBITMAPFromBitmap(pBitmap)
    Gdip_DisposeImage(pBitmap)
    if !hbm
        return
;     Gui, Add, Picture, hwndpic W800 H600 0xE
;     SendMessage, 0x172, 0, hbm,, ahk_id %pic%
;     Gui, Show
    DllCall("OpenClipboard","uint",0)
    DllCall("EmptyClipboard")
    ; Place the data on the clipboard. CF_BITMAP=0x2
    if ! DllCall("SetClipboardData","uint",0x2,"uint",hbm)
        DllCall("DeleteObject","uint",hbm)
    DllCall("CloseClipboard")
} ;</01.01.000007>
;<01.01.000008>
Gdip_ImageToClipboard(Filename) {																;-- Copies image data from file to the clipboard. (third approach)

	;by Lexikos
	;;https://autohotkey.com/board/topic/23162-how-to-copy-a-file-to-the-clipboard/
    pBitmap := Gdip_CreateBitmapFromFile(Filename)
    if !pBitmap
        return
    hbm := Gdip_CreateHBITMAPFromBitmap(pBitmap)
    Gdip_DisposeImage(pBitmap)
    if !hbm
        return
    if hdc := DllCall("CreateCompatibleDC","uint",0)
    {
        ; Get BITMAPINFO.
        VarSetCapacity(bmi,40,0), NumPut(40,bmi)
        DllCall("GetDIBits","uint",hdc,"uint",hbm,"uint",0
             ,"uint",0,"uint",0,"uint",&bmi,"uint",0)
        ; GetDIBits seems to screw up and give the image the BI_BITFIELDS
        ; (i.e. colour-indexed) compression type when it is in fact BI_RGB.
        NumPut(0,bmi,16)
        ; Get bitmap bits.
        if size := NumGet(bmi,20)
        {
            VarSetCapacity(bits,size)
            DllCall("GetDIBits","uint",hdc,"uint",hbm,"uint",0
                ,"uint",NumGet(bmi,8),"uint",&bits,"uint",&bmi,"uint",0)
            ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
            hMem := DllCall("GlobalAlloc","uint",0x42,"uint",40+size)
            pMem := DllCall("GlobalLock","uint",hMem)
            DllCall("RtlMoveMemory","uint",pMem,"uint",&bmi,"uint",40)
            DllCall("RtlMoveMemory","uint",pMem+40,"uint",&bits,"uint",size)
            DllCall("GlobalUnlock","uint",hMem)
        }
        DllCall("DeleteDC","uint",hdc)
    }
    if hMem
    {
        DllCall("OpenClipboard","uint",0)
        DllCall("EmptyClipboard")
        ; Place the data on the clipboard. CF_DIB=0x8
        if ! DllCall("SetClipboardData","uint",0x8,"uint",hMem)
            DllCall("GlobalFree","uint",hMem)
        DllCall("CloseClipboard")
    }
} ;</01.01.000008>
;<01.01.000009>
AppendToClipboard( files, cut=0) { 																;-- Appends files to CF_HDROP structure in clipboard
	DllCall("OpenClipboard", "Ptr", 0)
	if (DllCall("IsClipboardFormatAvailable", "Uint", 1)) ;If text is stored in clipboard, clear it and consider it empty (even though the clipboard may contain CF_HDROP due to text being copied to a temp file for pasting)
		DllCall("EmptyClipboard")
	DllCall("CloseClipboard")
	txt:=clipboard (clipboard = "" ? "" : "`n") files
	Sort, txt , U ;Remove duplicates
	CopyToClipboard(txt, true, cut)
	return
} ;</01.01.000009>

}
;|                                                  	|                                                   	|                                                   	|                                                   	|
;|   ClipboardGetDropEffect(01)    	|   ClipboardSetFiles(02)               	|   CopyFilesToClipboard(03)        	|   FileToClipboard(04)                 	|
;|   FileToClipboard(05)                 	|   1.ImageToClipboard(06)          	|   2.Gdip_ImageToClipboard(07) 	|   3.Gdip_ImageToClipboard(08) 	|
;|   AppendToClipboard(09)          	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Command line (05) -                                                                                                                                	baseID: <02>
;<02.01.000001>
CMDret_RunReturn(CMDin, WorkingDir=0) {                                                        	        	;--

/*
; ******************************************************************
; CMDret-AHK functions
; Version 1.10 beta
;
; Updated: Dec 5, 2006
; by: corrupt
; Code modifications and/or contributions made by:
; Laszlo, shimanov, toralf, Wdb
; ******************************************************************
; Usage:
; CMDin - command to execute
; WorkingDir - full path to working directory (Optional)
; ******************************************************************
; Known Issues:
; - If using dir be sure to specify a path (example: cmd /c dir c:\)
; or specify a working directory
; - Running 16 bit console applications may not produce output. Use
; a 32 bit application to start the 16 bit process to receive output
; ******************************************************************
; Additional requirements:
; - none
; ******************************************************************
; Code Start
; ******************************************************************

*/

  Global cmdretPID
  tcWrk := WorkingDir=0 ? "Int" : "Str"
  idltm := A_TickCount + 20
  CMsize = 1
  VarSetCapacity(CMDout, 1, 32)
  VarSetCapacity(sui,68, 0)
  VarSetCapacity(pi, 16, 0)
  VarSetCapacity(pa, 12, 0)
  Loop, 4 {
    DllCall("RtlFillMemory", UInt,&pa+A_Index-1, UInt,1, UChar,12 >> 8*A_Index-8)
    DllCall("RtlFillMemory", UInt,&pa+8+A_Index-1, UInt,1, UChar,1 >> 8*A_Index-8)
  }
  IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, "UInt",&pa, "Int",0) <> 0) {
    Loop, 4
      DllCall("RtlFillMemory", UInt,&sui+A_Index-1, UInt,1, UChar,68 >> 8*A_Index-8)
    DllCall("GetStartupInfo", "UInt", &sui)
    Loop, 4 {
      DllCall("RtlFillMemory", UInt,&sui+44+A_Index-1, UInt,1, UChar,257 >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+60+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+64+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+48+A_Index-1, UInt,1, UChar,0 >> 8*A_Index-8)
    }
    IF (DllCall("CreateProcess", Int,0, Str,CMDin, Int,0, Int,0, Int,1, "UInt",0, Int,0, tcWrk, WorkingDir, UInt,&sui, UInt,&pi) <> 0) {
      Loop, 4
        cmdretPID += *(&pi+8+A_Index-1) << 8*A_Index-8
      Loop {
        idltm2 := A_TickCount - idltm
        If (idltm2 < 10) {
          DllCall("Sleep", Int, 10)
          Continue
        }
        IF (DllCall("PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 ) <> 0 ) {
          Process, Exist, %cmdretPID%
          IF (ErrorLevel OR bSize > 0) {
            IF (bSize > 0) {
              VarSetCapacity(lpBuffer, bSize+1)
              IF (DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0) > 0) {
                IF (bRead > 0) {
                  TRead += bRead
                  VarSetCapacity(CMcpy, (bRead+CMsize+1), 0)
                  CMcpy = a
                  DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", &CMDout, "Int", CMsize)
                  DllCall("RtlMoveMemory", "UInt", &CMcpy+CMsize, "UInt", &lpBuffer, "Int", bRead)
                  CMsize += bRead
                  VarSetCapacity(CMDout, (CMsize + 1), 0)
                  CMDout=a
                  DllCall("RtlMoveMemory", "UInt", &CMDout, "UInt", &CMcpy, "Int", CMsize)
                  VarSetCapacity(CMDout, -1)   ; fix required by change in autohotkey v1.0.44.14
                }
              }
            }
          }
          ELSE
            break
        }
        ELSE
          break
        idltm := A_TickCount
      }
      cmdretPID=
      DllCall("CloseHandle", UInt, hWrite)
      DllCall("CloseHandle", UInt, hRead)
    }
  }
  IF (StrLen(CMDout) < TRead) {
    VarSetCapacity(CMcpy, TRead, 32)
    TRead2 = %TRead%
    Loop {
      DllCall("RtlZeroMemory", "UInt", &CMcpy, Int, TRead)
      NULLptr := StrLen(CMDout)
      cpsize := Tread - NULLptr
      DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", (&CMDout + NULLptr + 2), "Int", (cpsize - 1))
      DllCall("RtlZeroMemory", "UInt", (&CMDout + NULLptr), Int, cpsize)
      DllCall("RtlMoveMemory", "UInt", (&CMDout + NULLptr), "UInt", &CMcpy, "Int", cpsize)
      TRead2 --
      IF (StrLen(CMDout) > TRead2)
        break
    }
  }
  StringTrimLeft, CMDout, CMDout, 1
  Return, CMDout
} ;</02.01.000001>
;<02.01.000002>
ConsoleSend(text, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {           		;-- Sends text to a console's input stream

	; Sends text to a console's input stream. WinTitle may specify any window in
	; the target process. Since each process may be attached to only one console,
	; ConsoleSend fails if the script is already attached to a console.

    WinGet, pid, PID, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
    if !pid
        return false, ErrorLevel:="window"
    ; Attach to the console belonging to %WinTitle%'s process.
    if !DllCall("AttachConsole", "uint", pid)
        return false, ErrorLevel:="AttachConsole"
    hConIn := DllCall("CreateFile", "str", "CONIN$", "uint", 0xC0000000
                , "uint", 0x3, "uint", 0, "uint", 0x3, "uint", 0, "uint", 0)
    if hConIn = -1
        return false, ErrorLevel:="CreateFile"

    VarSetCapacity(ir, 24, 0)       ; ir := new INPUT_RECORD
    NumPut(1, ir, 0, "UShort")      ; ir.EventType := KEY_EVENT
    NumPut(1, ir, 8, "UShort")      ; ir.KeyEvent.wRepeatCount := 1
    ; wVirtualKeyCode, wVirtualScanCode and dwControlKeyState are not needed,
    ; so are left at the default value of zero.

    Loop, Parse, text ; for each character in text
    {
        NumPut(Asc(A_LoopField), ir, 14, "UShort")

        NumPut(true, ir, 4, "Int")  ; ir.KeyEvent.bKeyDown := true
        gosub ConsoleSendWrite

        NumPut(false, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := false
        gosub ConsoleSendWrite
    }
    gosub ConsoleSendCleanup
    return true

    ConsoleSendWrite:
        if ! DllCall("WriteConsoleInput", "uint", hconin, "uint", &ir, "uint", 1, "uint*", 0)
        {
            gosub ConsoleSendCleanup
            return false, ErrorLevel:="WriteConsoleInput"
        }
    return

    ConsoleSendCleanup:
        if (hConIn!="" && hConIn!=-1)
            DllCall("CloseHandle", "uint", hConIn)
        ; Detach from %WinTitle%'s console.
        DllCall("FreeConsole")
    return
} ;</02.01.000002>
;<02.01.000003>
ScanCode( wParam, lParam ) {                                                                                        	;--  subfunction for ConsoleSend
 Clipboard := "SC" SubStr((((lParam>>16) & 0xFF)+0xF000),-2)
 GuiControl,, SC, %Clipboard%
} ;</02.01.000003>
;<02.01.000004>
StdOutStream( sCmd, Callback := "", WorkingDir:=0, ByRef ProcessID:=0) {                 		;-- Store command line output in autohotkey variable. Supports both x86 and x64.

	/*				DESCRIPTION FOR UTF-8 support of xpftotext.exe

				Link:							https://autohotkey.com/boards/viewtopic.php?f=5&t=25004&hilit=embedded+pdf
				Description:				I haven't studied your whole script, but I see that you have a variable called XpdfPath that is assigned the value pdftotext.exe in A_ScriptDir.
												That's a good approach (although I'd call the var XpdfEXE). Extend the idea as follows:

												(1) Define another variable called xpdfrcFile in the same folder and assign it the value xpdfrc.ini.
												(2) Create a plain text file called xpdfrc.ini with these lines in it:

												unicodeMap Latin1fixed "D:\path\Latin1.unicodeMap"
												textEncoding Latin1fixed

												where D:\path\ is the script folder. Of course, you may put xpdfrc.ini (and Latin1.unicodeMap) wherever you want,
												but I think the script folder is fine. My scripts always create xpdfrc.ini via FileAppend so I have programmatic control over
												its location and contents, but if you want to keep things simple, hard-code it.

												(3) Put the Latin1.unicodeMap file in the proper place, i.e., D:\path\, as discussed above.
												(4) Call PDFtoText with this additional param:

												-cfg "%xpdfrcFile%"

												That should do it. Works perfectly here in many scripts. Here's an actual call from one of my working scripts.
				Modified:             	maz-1 https://gist.github.com/maz-1/768bf7938e533907d54bff276db80904
												SKAN 31-Aug-2013 http://goo.gl/j8XJXY

				EXAMPLE: 				xpdftotext.exe
												RunWait,%PDFtoTextEXE% -f 1 -l 1 %ConversionType% -cfg "%xpdfrcFile%" "%SourceFolder%%FileNameCurrent%" "%DestFolder%%FileNameCurrentTXT%",,Hide

	*/

  Static StrGet := "StrGet"
                                      ; Thanks to :  HotKeyIt         http://goo.gl/IsH1zs
                                      ; Original  :  Sean 20-Feb-2007 http://goo.gl/mxCdn
  tcWrk := WorkingDir=0 ? "Int" : "Str"
  DllCall( "CreatePipe", UIntP,hPipeRead, UIntP,hPipeWrite, UInt,0, UInt,0 )
  DllCall( "SetHandleInformation", UInt,hPipeWrite, UInt,1, UInt,1 )
  If A_PtrSize = 8
  {
    VarSetCapacity( STARTUPINFO, 104, 0  )           	; STARTUPINFO          ;  http://goo.gl/fZf24
    NumPut( 68,         STARTUPINFO,  0 )              	; cbSize
    NumPut( 0x100,      STARTUPINFO, 60 )           	; dwFlags    =>  STARTF_USESTDHANDLES = 0x100
    NumPut( hPipeWrite, STARTUPINFO, 88 )         	; hStdOutput
    NumPut( hPipeWrite, STARTUPINFO, 96 )        	; hStdError
    VarSetCapacity( PROCESS_INFORMATION, 24 )	; PROCESS_INFORMATION  ;  http://goo.gl/b9BaI
  }
  Else
  {
    VarSetCapacity( STARTUPINFO, 68, 0  )
    NumPut( 68,         STARTUPINFO,  0 )
    NumPut( 0x100,      STARTUPINFO, 44 )
    NumPut( hPipeWrite, STARTUPINFO, 60 )
    NumPut( hPipeWrite, STARTUPINFO, 64 )
    VarSetCapacity( PROCESS_INFORMATION, 16 )
  }

	/* Tip for struct calculation

		  ; Any member should be aligned to multiples of its size
		  ; Full size of structure should be multiples of the largest member size
		  ;============================================================================
		  ;
		  ; x64
		  ; STARTUPINFO
		  ;                             offset    size                    comment
		  ;DWORD  cb;                   0         4
		  ;LPTSTR lpReserved;           8         8(A_PtrSize)            aligned to 8-byte boundary (4 + 4)
		  ;LPTSTR lpDesktop;            16        8(A_PtrSize)
		  ;LPTSTR lpTitle;              24        8(A_PtrSize)
		  ;DWORD  dwX;                  32        4
		  ;DWORD  dwY;                  36        4
		  ;DWORD  dwXSize;              40        4
		  ;DWORD  dwYSize;              44        4
		  ;DWORD  dwXCountChars;        48        4
		  ;DWORD  dwYCountChars;        52        4
		  ;DWORD  dwFillAttribute;      56        4
		  ;DWORD  dwFlags;              60        4
		  ;WORD   wShowWindow;          64        2
		  ;WORD   cbReserved2;          66        2
		  ;LPBYTE lpReserved2;          72        8(A_PtrSize)           aligned to 8-byte boundary (2 + 4)
		  ;HANDLE hStdInput;            80        8(A_PtrSize)
		  ;HANDLE hStdOutput;           88        8(A_PtrSize)
		  ;HANDLE hStdError;            96        8(A_PtrSize)
		  ;
		  ;ALL : 96+8=104=8*13
		  ;
		  ; PROCESS_INFORMATION
		  ;
		  ;HANDLE hProcess              0         8(A_PtrSize)
		  ;HANDLE hThread               8         8(A_PtrSize)
		  ;DWORD  dwProcessId           16        4
		  ;DWORD  dwThreadId            20        4
		  ;
		  ;ALL : 20+4=24=8*3
		  ;============================================================================
		  ; x86
		  ; STARTUPINFO
		  ;                             offset     size
		  ;DWORD  cb;                   0          4
		  ;LPTSTR lpReserved;           4          4(A_PtrSize)
		  ;LPTSTR lpDesktop;            8          4(A_PtrSize)
		  ;LPTSTR lpTitle;              12         4(A_PtrSize)
		  ;DWORD  dwX;                  16         4
		  ;DWORD  dwY;                  20         4
		  ;DWORD  dwXSize;              24         4
		  ;DWORD  dwYSize;              28         4
		  ;DWORD  dwXCountChars;        32         4
		  ;DWORD  dwYCountChars;        36         4
		  ;DWORD  dwFillAttribute;      40         4
		  ;DWORD  dwFlags;              44         4
		  ;WORD   wShowWindow;          48         2
		  ;WORD   cbReserved2;          50         2
		  ;LPBYTE lpReserved2;          52         4(A_PtrSize)
		  ;HANDLE hStdInput;            56         4(A_PtrSize)
		  ;HANDLE hStdOutput;           60         4(A_PtrSize)
		  ;HANDLE hStdError;            64         4(A_PtrSize)
		  ;
		  ;ALL : 64+4=68=4*17
		  ;
		  ; PROCESS_INFORMATION
		  ;
		  ;HANDLE hProcess              0         4(A_PtrSize)
		  ;HANDLE hThread               4         4(A_PtrSize)
		  ;DWORD  dwProcessId           8         4
		  ;DWORD  dwThreadId            12        4
		  ;
		  ;ALL : 12+4=16=4*4

	*/

  If ! DllCall( "CreateProcess", UInt,0, UInt,&sCmd, UInt,0, UInt,0 ;  http://goo.gl/USC5a
              , UInt,1, UInt,0x08000000, UInt,0, tcWrk, WorkingDir, UInt,&STARTUPINFO, UInt,&PROCESS_INFORMATION )
   {
    DllCall( "CloseHandle", UInt,hPipeWrite )
    DllCall( "CloseHandle", UInt,hPipeRead )
    DllCall( "SetLastError", Int,-1 )
    Return ""
   }

  hProcess := NumGet( PROCESS_INFORMATION, 0 )
  hThread  := NumGet( PROCESS_INFORMATION, A_PtrSize )
  ProcessID:= NumGet( PROCESS_INFORMATION, A_PtrSize*2 )

  DllCall( "CloseHandle", UInt,hPipeWrite )

  AIC := ( SubStr( A_AhkVersion, 1, 3 ) = "1.0" ) ;  A_IsClassic
  VarSetCapacity( Buffer, 4096, 0 ), nSz := 0

  While DllCall( "ReadFile", UInt,hPipeRead, UInt,&Buffer, UInt,4094, UIntP,nSz, Int,0 ) {

   tOutput := ( AIC && NumPut( 0, Buffer, nSz, "Char" ) && VarSetCapacity( Buffer,-1 ) )
              ? Buffer : %StrGet%( &Buffer, nSz, "CP0" ) ; formerly CP850, but I guess CP0 is suitable for different locales

   Isfunc( Callback ) ? %Callback%( tOutput, A_Index ) : sOutput .= tOutput

  }

  DllCall( "GetExitCodeProcess", UInt,hProcess, UIntP,ExitCode )
  DllCall( "CloseHandle",  UInt,hProcess  )
  DllCall( "CloseHandle",  UInt,hThread   )
  DllCall( "CloseHandle",  UInt,hPipeRead )
  DllCall( "SetLastError", UInt,ExitCode  )
  VarSetCapacity(STARTUPINFO, 0)
  VarSetCapacity(PROCESS_INFORMATION, 0)

Return Isfunc( Callback ) ? %Callback%( "", 0 ) : sOutput
} ;</02.01.000004>
;<02.01.000005>
StdoutToVar_CreateProcess(sCmd, sEncoding:="CP0", sDir:="", ByRef nExitCode:=0) {	;-- Runs a command line program and returns its output

		/*    	DESCRIPTION of function StdoutToVar_CreateProcess() 02.01.000005
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Runs a command line program and returns its output
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=791
			Author         	:	Sean (http://goo.gl/o3VCO8), modified by nfl and by Cyruz
			Date             	:	Feb. 20, 2007 - Sean version.
			AHK-Version	:	AHK_L x32/64 Unicode/ANSI
			License         	:	WTFPL - http://www.wtfpl.net/txt/copying/
			Syntax          	:
			Parameter(s)	:	sCmd        	- Commandline to execute.
                                		sEncoding 	- Encoding used by the target process. Look at StrGet() for possible values.
                                		sDir          	- Working directory.
                                		nExitCode 	- Process exit code, receive it as a byref parameter.
			Return value	:	Command output as a string on success, empty string on error
			Changelog   	:	Sep. 21	, 2011	- nfl version.
	                                	Nov. 27, 2013	- Cyruz version (code refactored and exit code).
	                                	Mar. 09, 2014	- Removed input, doesn't seem reliable. Some code improvements.
	                                	Mar. 16, 2014	- Added encoding parameter as pointed out by lexikos.
	                                	Jun. 02	, 2014	- Corrected exit code error.
	                                	Nov. 02, 2016	- Fixed blocking behavior due to ReadFile thanks to PeekNamedPipe.
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	command line, stdout,
        	-------------------------------------------------------------------------------------------------------------------
	*/

    DllCall( "CreatePipe",           PtrP,hStdOutRd, PtrP,hStdOutWr, Ptr,0, UInt,0 )
    DllCall( "SetHandleInformation", Ptr,hStdOutWr, UInt,1, UInt,1                 )

            VarSetCapacity( pi, (A_PtrSize == 4) ? 16 : 24,  0 )
    siSz := VarSetCapacity( si, (A_PtrSize == 4) ? 68 : 104, 0 )
    NumPut( siSz,      si,  0,                          "UInt" )
    NumPut( 0x100,     si,  (A_PtrSize == 4) ? 44 : 60, "UInt" )
    NumPut( hStdOutWr, si,  (A_PtrSize == 4) ? 60 : 88, "Ptr"  )
    NumPut( hStdOutWr, si,  (A_PtrSize == 4) ? 64 : 96, "Ptr"  )

    If ( !DllCall( "CreateProcess", Ptr,0, Ptr,&sCmd, Ptr,0, Ptr,0, Int,True, UInt,0x08000000
                                  , Ptr,0, Ptr,sDir?&sDir:0, Ptr,&si, Ptr,&pi ) )
        Return ""
      , DllCall( "CloseHandle", Ptr,hStdOutWr )
      , DllCall( "CloseHandle", Ptr,hStdOutRd )

    DllCall( "CloseHandle", Ptr,hStdOutWr ) ; The write pipe must be closed before reading the stdout.
    While ( 1 )
    { ; Before reading, we check if the pipe has been written to, so we avoid freezings.
        If ( !DllCall( "PeekNamedPipe", Ptr,hStdOutRd, Ptr,0, UInt,0, Ptr,0, UIntP,nTot, Ptr,0 ) )
            Break
        If ( !nTot )
        { ; If the pipe buffer is empty, sleep and continue checking.
            Sleep, 100
            Continue
        } ; Pipe buffer is not empty, so we can read it.
        VarSetCapacity(sTemp, nTot+1)
        DllCall( "ReadFile", Ptr,hStdOutRd, Ptr,&sTemp, UInt,nTot, PtrP,nSize, Ptr,0 )
        sOutput .= StrGet(&sTemp, nSize, sEncoding)
    }

    ; * SKAN has managed the exit code through SetLastError.
    DllCall( "GetExitCodeProcess", Ptr,NumGet(pi,0), UIntP,nExitCode )
    DllCall( "CloseHandle",        Ptr,NumGet(pi,0)                  )
    DllCall( "CloseHandle",        Ptr,NumGet(pi,A_PtrSize)          )
    DllCall( "CloseHandle",        Ptr,hStdOutRd                     )
    Return sOutput
} ;</02.01.000005>
;<02.01.000006>
RunUTF8(target, workdir:=".") {                                                                                       	;-- if a .exe file really requires its command line to be encoded as UTF-8, the following might work (a lexikos function)

    ; PROCESS_INFORMATION pi;
    VarSetCapacity(pi, 24, 0)
    ; STARTUPINFO si; si.cb = sizeof(si);
    VarSetCapacity(si, si_size := 32+9*A_PtrSize, 0), NumPut(si_size, si)
    ; Encode command line as UTF-8.
    VarSetCapacity(utf8, StrPut(target, "utf-8"))
    StrPut(target, &utf8, "utf-8")
    ; Launch process.
    if !DllCall("CreateProcessA", "ptr", 0, "ptr", &utf8, "ptr", 0
        , "ptr", 0, "int", false, "uint", 0, "ptr", 0, "str", workdir
        , "ptr", &si, "ptr", &pi)
        throw Exception("CreateProcessA failed; error " A_LastError, -1)
    ; Clean up.
    DllCall("CloseHandle", "ptr", NumGet(pi, 0))
    DllCall("CloseHandle", "ptr", NumGet(pi, A_PtrSize))
} ;</02.01.000006>

}
;|   CMDret_RunReturn(01)               	|   ConsoleSend(02)                  	|   StdOutStream(03)                    	|   StdoutToVar_CreateProcess(04)	|
;|   RunUTF8(05)                               	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Date or Time (06) -                                                                                                                                   	baseID: <03>
;<03.01.000001>
PrettyTickCount(timeInMilliSeconds) {                                                                 	;-- takes a time in milliseconds and displays it in a readable fashion
   ElapsedHours := SubStr(0 Floor(timeInMilliSeconds / 3600000), -1)
   ElapsedMinutes := SubStr(0 Floor((timeInMilliSeconds - ElapsedHours * 3600000) / 60000), -1)
   ElapsedSeconds := SubStr(0 Floor((timeInMilliSeconds - ElapsedHours * 3600000 - ElapsedMinutes * 60000) / 1000), -1)
   ElapsedMilliseconds := SubStr(0 timeInMilliSeconds - ElapsedHours * 3600000 - ElapsedMinutes * 60000 - ElapsedSeconds * 1000, -2)
   returned := ElapsedHours "h:" ElapsedMinutes "m:" ElapsedSeconds "s." ElapsedMilliseconds
   return returned
} ;</03.01.000001>
;<03.01.000002>
TimePlus(one, two) {                                                                                            	;--

   returned:=0
   returned+=Mod(one, 100) + Mod(two, 100)
   ;one/=100
   ;two/=100
   returned+=one
   return returned
} ;</03.01.000002>
;<03.01.000003>
FormatSeconds(Secs) {                                                                                        	;-- formats seconds to hours,minutes and seconds -> 12:36:10

	Return SubStr("0" . Secs // 3600, -1) . ":"
        . SubStr("0" . Mod(Secs, 3600) // 60, -1) . ":"
        . SubStr("0" . Mod(Secs, 60), -1)

} ;</03.01.000003>
;<03.01.000004>
TimeCode(MaT) {	                                                                                                	;-- TimCode can be used for protokoll or error logs

	;Month & Time (MaT) = 1 - it's clear!

	If MaT = 1
		TC:= A_DD "." A_MM "." A_YYYY "`, "

	TC.= A_Hour ":" A_Min ":" A_Sec "`." A_MSec

return TC
} ;</03.01.000004>
;<03.01.000005>
Time(to,from="",units="d",params="") {	                                                            	;-- calculate with time, add minutes, hours, days - add or subtract time

	/*                              	DESCRIPTION
				Link: https://autohotkey.com/board/topic/42668-time-count-days-hours-minutes-seconds-between-dates/
	*/
	/*                              	EXAMPLE(s)

			NoEnv
			SetBatchLines,-1
			MsgBox % "Count days from 12 May until 15 May`n"
					. Time("May-15","12.May","d")

			MsgBox % "Working hours from 01.05.2009 00:00:00   to   10.05.09 09:30:00`n"
					. "Count only working hours from 09 to 17 and consider weekends and 01.May bank holiday`n"
					. Time("20090504093000","20090501000000","h","W1.7 H9-17 B0105")

			MsgBox % "Days to work till end of 2009`n" . Time("01.01.2010","","d","W1.7")

			MsgBox % "Hours to work till end of 2009 from 09 - 17`n" . Time("01.01.2010","","h","W1.7 H9-17")

			ExitApp

	*/

	static _:="0000000000",s:=1,m:=60,h:=3600,d:=86400
				,Jan:="01",Feb:="02",Mar:="03",Apr:="04",May:="05",Jun:="06",Jul:="07",Aug:="08",Sep:="09",Okt:=10,Nov:=11,Dec:=12
	r:=0
	units:=units ? %units% : 8640
	If (InStr(to,"/") or InStr(to,"-") or InStr(to,".")){
		Loop,Parse,to,/-.,%A_Space%
			_%A_Index%:=RegExMatch(A_LoopField,"\d+") ? A_LoopField : %A_LoopField%
			,_%A_Index%:=(StrLen(_%A_Index%)=1 ? "0" : "") . _%A_Index%
		to:=SubStr(A_Now,1,8-StrLen(_1 . _2 . _3)) . _3 . (RegExMatch(SubStr(to,1,1),"\d") ? (_2 . _1) : (_1 . _2))
		_1:="",_2:="",_3:=""
	}
	If (from and InStr(from,"/") or InStr(from,"-") or InStr(from,".")){
		Loop,Parse,from,/-.,%A_Space%
			_%A_Index%:=RegExMatch(A_LoopField,"\d+") ? A_LoopField : %A_LoopField%
			,_%A_Index%:=(StrLen(_%A_Index%)=1 ? "0" : "") . _%A_Index%
		from:=SubStr(A_Now,1,8-StrLen(_1 . _2 . _3)) . _3 . (RegExMatch(SubStr(from,1,1),"\d") ? (_2 . _1) : (_1 . _2))
	}
   count:=StrLen(to)<9 ? "days" : StrLen(to)<11 ? "hours" : StrLen(to)<13 ? "minutes" : "seconds"
	to.=SubStr(_,1,14-StrLen(to)),(from ? from.=SubStr(_,1,14-StrLen(from)))
	Loop,Parse,params,%A_Space%
		If (unit:=SubStr(A_LoopField,1,1))
			 %unit%1:=InStr(A_LoopField,"-") ? SubStr(A_LoopField,2,InStr(A_LoopField,"-")-2) : ""
			,%unit%2:=SubStr(A_LoopField,InStr(A_LoopField,"-") ? (InStr(A_LoopField,"-")+1) : 2)
	count:=!params ? count : "seconds"
	add:=!params ? 1 : (S2="" ? (M2="" ? (H2="" ? ((D2="" and B2="" and W="") ? d : h) : m) : s) : s)
	While % (from<to){
		FormatTime,year,%from%,YYYY
		FormatTime,month,%from%,MM
		FormatTime,day,%from%,dd
		FormatTime,hour,%from%,H
		FormatTime,minute,%from%,m
		FormatTime,second,%from%,s
		FormatTime,WDay,%from%,WDay
		EnvAdd,from,%add%,%count%
		If (W1 or W2){
			If (W1=""){
				If (W2=WDay or InStr(W2,"." . WDay) or InStr(W2,WDay . ".")){
					Continue=1
				}
			} else If WDay not Between %W1% and %W2%
				Continue=1
			;else if (Wday=W2)
			;	Continue=1
			If (Continue){
				tempvar:=SubStr(from,1,8)
				EnvAdd,tempvar,1,days
				EnvSub,tempvar,%from%,seconds
				EnvAdd,from,%tempvar% ,seconds
				Continue=
				continue
			}
		}
		If (D1 or D2 or B2){
			If (D1=""){
				If (D2=day or B2=(day . month) or InStr(B2,"." . day . month) or InStr(B2,day . month . ".") or InStr(D2,"." . day) or InStr(D2,day . ".")){
					Continue=1
				}
			} else If day not Between %D1% and %D2%
				Continue=1
			;else if (day=D2)
			;	Continue=1
			If (Continue){
				tempvar:=SubStr(from,1,8)
				EnvAdd,tempvar,1,days
				EnvSub,tempvar,%from%,seconds
				EnvAdd,from,%tempvar% ,seconds
				Continue=
				continue
			}
		}
		If (H1 or H2){
			If (H1=""){
				If (H2=hour or InStr(H2,hour . ".") or InStr(H2,"." hour)){
					Continue=1
				}
			} else If hour not Between %H1% and %H2%
				continue=1
			;else if (hour=H2)
			;	continue=1
			If (continue){
				tempvar:=SubStr(from,1,10)
				EnvAdd,tempvar,1,hours
				EnvSub,tempvar,%from%,seconds
				EnvAdd,from,%tempvar% ,seconds
				continue=
				continue
			}
		}
		If (M1 or M2){
			If (M1=""){
				If (M2=minute or InStr(M2,minute . ".") or InStr(M2,"." minute)){
					Continue=1
				}
			} else If minute not Between %M1% and %M2%
				continue=1
			;else if (minute=M2)
			;	continue=1
			If (continue){
				tempvar:=SubStr(from,1,12)
				EnvAdd,tempvar,1,minutes
				EnvSub,tempvar,%from%,seconds
				EnvAdd,from,%tempvar% ,seconds
				continue=
				continue
			}
		}
		If (S1 or S2){
			If (S1=""){
				If (S2=second or InStr(S2,second . ".") or InStr(S2,"." second)){
					Continue
				}
			} else if (second!=S2)
				If second not Between %S1% and %S2%
					continue
		}
		r+=add
	}
	tempvar:=SubStr(count,1,1)
	tempvar:=%tempvar%
	Return (r*tempvar)/units
} ;</03.01.000005>
;<03.01.000006>
DateDiff(fnTimeUnits,fnStartDate,fnEndDate) {                                                   	;-- returns the difference between two timestamps in the specified units
	; MsgBox fnTimeUnits: %fnTimeUnits%`nfnStartDate: %fnStartDate%`nfnEndDate: %fnEndDate%
	; declare local, global, static variables

		; set default return value
		TimeDifference := 0


		; validate parameters
		If fnTimeUnits not in YY,MM,DD,HH,MI,SS
			Throw, Exception("fnTimeUnits were not valid")

		If fnStartDate is not date
			Throw, Exception("fnStartDate was not a date")

		If fnEndDate is not date
			Throw, Exception("fnEndDate was not a date")


		; initialise variables
		DatePadding := "00000101000000"
		StartDate := fnStartDate . SubStr(DatePadding,StrLen(fnStartDate)+1) ; normalise start date to 14 digits
		EndDate   := fnEndDate   . SubStr(DatePadding,StrLen(fnEndDate  )+1) ; normalise end   date to 14 digits


		; for day or time, use native function
		If fnTimeUnits in DD,HH,MI,SS
		{

			TimeDifference := EndDate
			TimeUnit := fnTimeUnits = "SS" ? "S"
					 :  fnTimeUnits = "MI" ? "M"
					 :  fnTimeUnits = "HH" ? "H"
					 :  fnTimeUnits = "DD" ? "D"
					 :                       ""

			EnvSub, TimeDifference, %StartDate%, %TimeUnit%
		}

		; for year or month
		FormatTime, StartYear , %StartDate%, yyyy
		FormatTime, StartMonth, %StartDate%, MM
		FormatTime, StartDay  , %StartDate%, dd
		FormatTime, StartTime , %StartDate%, HHmmss

		FormatTime, EndYear , %EndDate%, yyyy
		FormatTime, EndMonth, %EndDate%, MM
		FormatTime, EndDay  , %EndDate%, dd
		FormatTime, EndTime , %EndDate%, HHmmss

		If fnTimeUnits in MM
		{

			StartInMonths := (StartYear*12)+StartMonth
			EndInMonths   := (EndYear  *12)+EndMonth

			TimeDifference := EndInMonths-StartInMonths

			If (StartDate < EndDate)
				If (EndDay < StartDay)
					TimeDifference--

			If (StartDate > EndDate)
				If (EndDay > StartDay)
					TimeDifference++
		}

		If fnTimeUnits in YY
		{
			TimeDifference := EndYear-StartYear

			If (StartDate < EndDate)
				If (EndMonth <= StartMonth)
					If (EndDay < StartDay)
						TimeDifference--

			If (StartDate > EndDate)
				If (EndMonth >= StartMonth)
					If (EndDay > StartDay)
						TimeDifference++
		}


	; return
	Return TimeDifference
} ;</03.01.000006>



;functions end
}
;|   PrettyTickCount(01)                	|   TimePlus(02)                            	|   FormatSeconds(03)                  	|   TimeCode(04)                          	|
;|   Time(05)                                  	|   DateDiff(06)                             	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Varius get (22) -- functions for retreaving informations - missing something - see Gui/Window --          	baseID: <04>
;<04.01.000001>
GetProcesses() {                                                                                                	;-- get the name of all running processes

   d = `n  ; string separator
   s := 4096  ; size of buffers and arrays (4 KB)

   Process, Exist  ; sets ErrorLevel to the PID of this running script
   ; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400)
   h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel)
   ; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
   DllCall("Advapi32.dll\OpenProcessToken", "UInt", h, "UInt", 32, "UIntP", t)
   VarSetCapacity(ti, 16, 0)  ; structure of privileges
   NumPut(1, ti, 0)  ; one entry in the privileges array...
   ; Retrieves the locally unique identifier of the debug privilege:
   DllCall("Advapi32.dll\LookupPrivilegeValueA", "UInt", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
   NumPut(luid, ti, 4, "int64")
   NumPut(2, ti, 12)  ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
   ; Update the privileges of this process with the new access token:
   DllCall("Advapi32.dll\AdjustTokenPrivileges", "UInt", t, "Int", false, "UInt", &ti, "UInt", 0, "UInt", 0, "UInt", 0)
   DllCall("CloseHandle", "UInt", h)  ; close this process handle to save memory

   hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ; increase performance by preloading the libaray
   s := VarSetCapacity(a, s)  ; an array that receives the list of process identifiers:
   c := 0  ; counter for process idendifiers
   DllCall("Psapi.dll\EnumProcesses", "UInt", &a, "UInt", s, "UIntP", r)
   Loop, % r // 4  ; parse array for identifiers as DWORDs (32 bits):
   {
      id := NumGet(a, A_Index * 4)
      ; Open process with: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400)
      h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id)
      VarSetCapacity(n, s, 0)  ; a buffer that receives the base name of the module:
      e := DllCall("Psapi.dll\GetModuleBaseNameA", "UInt", h, "UInt", 0, "Str", n, "UInt", s)
      DllCall("CloseHandle", "UInt", h)  ; close process handle to save memory
      if (n && e)  ; if image is not null add to list:
         l .= n . d, c++
   }
   DllCall("FreeLibrary", "UInt", hModule)  ; unload the library to free memory
   Sort, l, C  ; uncomment this line to sort the list alphabetically
   ;MsgBox, 0, %c% Processes, %l%
   return l
} ;</04.01.000001>
;<04.01.000002>
getProcesses(ignoreSelf := True, searchNames := "") {                                 		;-- get running processes with search using comma separated list

	s := 100096  ; 100 KB will surely be HEAPS

	array := []
	PID := DllCall("GetCurrentProcessId")
	; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400)
	h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", PID, "Ptr")
	; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
	DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
	VarSetCapacity(ti, 16, 0)  ; structure of privileges
	NumPut(1, ti, 0, "UInt")  ; one entry in the privileges array...
	; Retrieves the locally unique identifier of the debug privilege:
	DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
	NumPut(luid, ti, 4, "Int64")
	NumPut(2, ti, 12, "UInt")  ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
	; Update the privileges of this process with the new access token:
	r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
	DllCall("CloseHandle", "Ptr", t)  ; close this access token handle to save memory
	DllCall("CloseHandle", "Ptr", h)  ; close this process handle to save memory

	hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ; increase performance by preloading the library
	s := VarSetCapacity(a, s)  ; an array that receives the list of process identifiers:
	DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
	Loop, % r // 4  ; parse array for identifiers as DWORDs (32 bits):
	{
	   currentPID := NumGet(a, A_Index * 4, "UInt")
	   if (ignoreSelf && currentPID = PID)
			continue ; this is own script
	   ; Open process with: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400)
	   h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", currentPID, "Ptr")
	   if !h
	      continue
	   VarSetCapacity(n, s, 0)  ; a buffer that receives the base name of the module:
	   e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
	   if !e    ; fall-back method for 64-bit processes when in 32-bit mode:
	      if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
	         SplitPath n, n
	   DllCall("CloseHandle", "Ptr", h)  ; close process handle to save memory
	  	if searchNames
	  	{
			  if n not in %searchNames%
			  	continue
	  	}
	   if (n && e)  ; if image is not null add to list:
	   		array.insert({"Name": n, "PID": currentPID})
	}
	DllCall("FreeLibrary", "Ptr", hModule)  ; unload the library to free memory
	return array
} ;</04.01.000002>
;<04.01.000003>
GetProcessWorkingDir(PID) {																				;-- like the name explains

	static PROCESS_ALL_ACCESS:=0x1F0FFF,MEM_COMMIT := 0x1000,MEM_RELEASE:=0x8000,PAGE_EXECUTE_READWRITE:=64
		,GetCurrentDirectoryW,init:=MCode(GetCurrentDirectoryW,"8BFF558BECFF75088B450803C050FF15A810807CD1E85DC20800")
	nDirLength := VarSetCapacity(nDir, 512, 0)
	hProcess := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID)
	if !hProcess
	return
	pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", nDirLength + 1, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")

	pThreadRemote := DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", 26, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
	DllCall("WriteProcessMemory", "Ptr", hProcess, "Ptr", pThreadRemote, "Ptr", &GetCurrentDirectoryW, "PTR", 26, "Ptr", 0)

	If hThread := DllCall("CreateRemoteThread", "PTR", hProcess, "UInt", 0, "UInt", 0, "PTR", pThreadRemote, "PTR", pBufferRemote, "UInt", 0, "UInt", 0)
	{
	DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
	DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)
	If lpExitCode {
		DllCall("ReadProcessMemory", "PTR", hProcess, "PTR", pBufferRemote, "Str", nDir, "UInt", lpExitCode*2, "UInt", 0)
		VarSetCapacity(nDir,-1)
	}
	DllCall("CloseHandle", "PTR", hThread)
	}
	DllCall("VirtualFreeEx","PTR",hProcess,"PTR",pBufferRemote,"PTR",nDirLength + 1,"UInt",MEM_RELEASE)
	DllCall("VirtualFreeEx","PTR",hProcess,"PTR",pThreadRemote,"PTR",31,"UInt",MEM_RELEASE)
	DllCall("CloseHandle", "PTR", hProcess)

	return nDir

} ;</04.01.000003>
;<04.01.000004>
GetTextSize(pStr, pSize, pFont, pWeight:= 400, pHeight:= false) {						;-- precalcute the Textsize (Width & Height)

  Gui, 55: Font, s%pSize% w%pWeight%, %pFont%
  Gui, 55: Add, Text, R1, %pStr%
  GuiControlGet T, 55: Pos, Static1
  Gui, 55: Destroy
  Return pHeight ? TW "," TH : TW

} ;</04.01.000004>
;<04.01.000005>
GetTextSize(pStr, pFont="", pHeight=false, pAdd=0) {										;-- different function to the above one

	/*			DESCRIPTION of GetTextSize
	----------------------------------------------------------------------------------------------------------------------------------------
		Function: 						GetTextSize
		Description:					Calculate widht and/or height of text. Font face, style and number of lines is taken into account
		Author: 	 					majkinetor
		Date:							------
		Link: 							https://autohotkey.com/board/topic/16625-function-gettextsize-calculate-text-dimension/
		Parameters:					pStr			- Text to be measured
											pFont		- Font description in AHK syntax, default size is 10, default font is MS Sans Serif
											pHeight	- Set to true to return height also. False is default.
											pAdd		- Number to add on width and height.
		Returns:						Text width if pHeight=false. Otherwise, dimension is returned as "width,height"
		Dependencies:				<ExtractInteger>
		Examples:					width := GetTextSize("string to be measured", "bold s22, Courier New" )
	----------------------------------------------------------------------------------------------------------------------------------------
	*/


	local height, weight, italic, underline, strikeout , nCharSet
	local hdc := DllCall("GetDC", "Uint", 0)
	local hFont, hOldFont
	local resW, resH, SIZE

 ;parse font
	italic		:= InStr(pFont, "italic")	 ?  1	:
	underline	:= InStr(pFont, "underline") ?  1	:  0
	strikeout	:= InStr(pFont, "strikeout") ?  1	:  0
	weight		:= InStr(pFont, "bold")		 ? 700	: 400

	;height
	RegExMatch(pFont, "(?<=[S|s])(\d{1,2})(?=[ ,])", height)
	if (height = "")
		height := 10


	RegRead, LogPixels, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI, LogPixels
	Height := -DllCall("MulDiv", "int", Height, "int", LogPixels, "int", 72)
	;face
	RegExMatch(pFont, "(?<=,).+", fontFace)
	if (fontFace != "")
		 fontFace := RegExReplace( fontFace, "(^\s*)|(\s*$)")		;trim
	else fontFace := "MS Sans Serif"

 ;create font
	hFont	:= DllCall("CreateFont", "int",  height,	"int",  0,		  "int",  0, "int", 0
									,"int",  weight,	"Uint", italic,   "Uint", underline
									,"uint", strikeOut, "Uint", nCharSet, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "str", fontFace)
	hOldFont := DllCall("SelectObject", "Uint", hDC, "Uint", hFont)

	VarSetCapacity(SIZE, 16)
	curW=0
	Loop,  parse, pStr, `n
	{
		DllCall("DrawTextA", "Uint", hDC, "str", A_LoopField, "int", StrLen(pStr), "uint", &SIZE, "uint", 0x400)
		resW := ExtractInteger(SIZE, 8)
		curW := resW > curW ? resW : curW
	}
	DllCall("DrawTextA", "Uint", hDC, "str", pStr, "int", StrLen(pStr), "uint", &SIZE, "uint", 0x400)
 ;clean

	DllCall("SelectObject", "Uint", hDC, "Uint", hOldFont)
	DllCall("DeleteObject", "Uint", hFont)
	DllCall("ReleaseDC", "Uint", 0, "Uint", hDC)

	resW := ExtractInteger(SIZE, 8) + pAdd
  	resH := ExtractInteger(SIZE, 12) + pAdd


	if (pHeight)
		resW = W%resW% H%resH%

	return	%resW%
} ;</04.01.000005>
;<04.01.000006>
MeasureText(hwnd,text,Font,size, layout) {                                                     	;-- alternative to other functions which calculate the text size before display on the screen

	; functionstatus: tested, working
	; http://ahkscript.org/germans/forums/viewtopic.php?t=6726&sid=a0d79e1c0831c7bae622912df2b1df9d

	/*			EXAMPLE
		MsgBox % MeasureText(0,"Hello world","Consolas",14, "italic")
	*/

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

   HDC := GetDC(hwnd)
   G := Gdip_GraphicsFromHDC(hdc)

   If !hFamily := Gdip_FontFamilyCreate(Font)
   {
      MsgBox, 48, Font error!, The font you have specified does not exist on the system
      ExitApp
   }

   hFont := Gdip_FontCreate(hFamily, size, layout)
   hFormat := Gdip_StringFormatCreate(0x4000)

   CreateRectF(RectF, 0, 0, 0, 0)
   RECTF_STR := Gdip_MeasureString(G, text, hFont, hFormat, RectF)
   StringSplit,RCI,RECTF_STR, |
   Width := RCI3

   Gdip_DeleteFont(hFont),Gdip_DeleteStringFormat(hFormat)
   DeleteDC(hdc), Gdip_DeleteGraphics(G)

   Gdip_Shutdown(pToken)
   Return, Width
} ;</04.01.000006>
;<04.01.000007>
monitorInfo() {																										;-- shows infos about your monitors
	sysget,monitorCount,monitorCount
	arr:=[],sorted:=[]
	loop % monitorCount {
		sysget,mon,monitor,% a_index
		arr.insert({l:monLeft,r:monRight,b:monBottom,t:monTop,w:monRight-monLeft+1,h:monBottom-monTop+1})
		k:=a_index
		while strlen(k)<3
			k:="0" k
		sorted[monLeft k]:=a_index
	}
	arr2:=[]
	for k,v in sorted
		arr2.insert(arr[v])
	return arr2
} ;</04.01.000007>
;<04.01.000008>
whichMonitor(x="",y="",byref monitorInfo="") { 												;-- return [current monitor, monitor count]
	CoordMode,mouse,screen
	if (x="" || y="")
		mousegetpos,x,y
	if !IsObject(monitorInfo)
		monitorInfo:=monitorInfo()

	for k,v in monitorInfo
		if (x>=v.l&&x<=v.r&&y>=v.t&&y<=v.b)
			return [k,monitorInfo.maxIndex()]
} ;</04.01.000008>
;<04.01.000009>
IsOfficeFile(FileName, Extensions:= "doc,docx,xls,xlsx,ppt,pptx") { 					;-- checks if a file is an Office file

	;  Last update: 2014-4-23

	static doc  := "57006f007200640044006f00630075006d0065006e0074"                                 ; W.o.r.d.D.o.c.u.m.e.n.t
	,      docx := "00776F72642F"                                                                   ; .word/
	,      xls  := "0057006f0072006b0062006f006f006b00"                                             ; .W.o.r.k.b.o.o.k.
	,      xlsx := "0000786C2F"                                                                     ; ..xl/
	,      ppt  := "0050006f0077006500720050006f0069006e007400200044006f00630075006d0065006e007400" ; .P.o.w.e.r.P.o.i.n.t. .D.o.c.u.m.e.n.t.
	,      pptx := "00007070742F"                                                                   ; ..ppt/

	; =======================================
	; Check first 4 bytes
	; =======================================
	File := FileOpen(FileName, "r")
	File.RawRead(bin, 4)
	MCode_Bin2Hex(&bin, 4, hex)

	; Magic Numbers (http://en.wikipedia.org/wiki/List_of_file_signatures)
	;   doc/xls/ppt: D0CF11E0
	;   zip/jar/odt/ods/odp/docx/xlsx/pptx/apk: 504B0304, 504B0506 (empty archive) or 504B0708 (spanned archive)
	If hex not in D0CF11E0,504B0304,504B0506,504B0708
		Return "", File.Close()

	; =======================================
	; docx/xlsx/pptx --> check last 1024 bytes
	; =======================================
	If hex in 504B0304,504B0506,504B0708
	{
		File.Position := File.Length - 1024
		File.RawRead(bin, 1024)
		File.Close()
		MCode_Bin2Hex(&bin, 1024, hex)

		Loop, Parse, Extensions, CSV, %A_Space%%A_Tab%
			If (  InStr(hex, %A_LoopField%)  )
				Return A_LoopField

		Return
	}

	; =======================================
	; detect doc/xls/ppt
	; Reference: Daniel Rentz. Microsoft Compound Document File Format. 2006-Dec - 21.
	; =======================================
	; SecID of first sector of the directory stream
	File.Position := 48
	File.RawRead(bin, 4)
	MCode_Bin2Hex(&bin, 4, hex)
	SecID1 := "0x" SubStr(hex, 7, 2) SubStr(hex, 5, 2) SubStr(hex, 3, 2) SubStr(hex, 1, 2)
	SecID1 := SecID1 + 0

	; Jump to this offset...
	Offset := 512 * (SecID1 + 1)
	Length := 5 * 128

	File.Position := Offset
	File.RawRead(bin, Length)
	MCode_Bin2Hex(&bin, Length, hex)

	File.Close()

	; detecting...
	Loop, Parse, Extensions, CSV, %A_Space%%A_Tab%
		If (  InStr(hex, %A_LoopField%)  )
			Return A_LoopField
} ;</04.01.000009>
;<04.01.000010>
DeskIcons(coords="") {																						;-- i think its for showing all desktop icons

   Critical
   static MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x04, MEM_RELEASE := 0x8000
   static LVM_GETITEMPOSITION := 0x00001010, LVM_SETITEMPOSITION := 0x0000100F, WM_SETREDRAW := 0x000B

   ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
   if !hwWindow ; #D mode
      ControlGet, hwWindow, HWND,, SysListView321, A
   IfWinExist ahk_id %hwWindow% ; last-found window set
      WinGet, iProcessID, PID
   hProcess := DllCall("OpenProcess"   , "UInt",   0x438 ; PROCESS-OPERATION|READ|WRITE|QUERY_INFORMATION
                              , "Int",   FALSE         ; inherit = false
                              , "UInt",   iProcessID)
   if hwWindow and hProcess
   {
      ControlGet, list, list,Col1
      if !coords
      {
         VarSetCapacity(iCoord, 8)
         pItemCoord := DllCall("VirtualAllocEx", "UInt", hProcess, "UInt", 0, "UInt", 8, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE)
         Loop, Parse, list, `n
         {
            SendMessage, %LVM_GETITEMPOSITION%, % A_Index-1, %pItemCoord%
            DllCall("ReadProcessMemory", "UInt", hProcess, "UInt", pItemCoord, "UInt", &iCoord, "UInt", 8, "UIntP", cbReadWritten)
            ret .= A_LoopField ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 16) "`n"
         }
         DllCall("VirtualFreeEx", "UInt", hProcess, "UInt", pItemCoord, "UInt", 0, "UInt", MEM_RELEASE)
      }
      else
      {
         SendMessage, %WM_SETREDRAW%,0,0
         Loop, Parse, list, `n
            If RegExMatch(coords,"\Q" A_LoopField "\E:\K.*",iCoord_new)
               SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
         SendMessage, %WM_SETREDRAW%,1,0
         ret := true
      }
   }
   DllCall("CloseHandle", "UInt", hProcess)
   return ret
} ;</04.01.000010>
;<04.01.000011>
GetFuncDefs(scriptPath) {                                                                                	;-- get function definitions from a script

	; does not include those with a definition of "()" (no parameters)
	; this is part of  "Insert User Function Definitions -- for Notepad++" from boiler, maybe you need a different output
	;https://autohotkey.com/boards/viewtopic.php?f=60&t=29996
	defs := ""
	FileRead, rawScript, %scriptPath%

	; remove comment blocks:
	cleanScript := "`n" ; start with `n so RegEx can know a func def is preceded by one even if first line
	blockStart := 0
	Loop, Parse, rawScript, `n, `r
	{
		if blockStart
		{
			if (SubStr(LTrim(A_LoopField), 1, 2) = "*/")
				blockStart := 0
		}
		else
		{
			if (SubStr(LTrim(A_LoopField), 1, 2) = "/*")
				blockStart := 1
			else
				cleanScript .= A_LoopField "`n"
		}
	}

	; get function definitions:
	startPos := 1
	Loop
	{
		; original: if (foundPos := RegExMatch(cleanScript, "\n\s*\K[\w#@$]+\([^\n;]+\)(?=\s*(;[^n]*)*\n*{)", match, startPos))
		if (foundPos := RegExMatch(cleanScript, "U)\n\s*\K[ \t]*(?!(if\(|while\(|for\())([\w#!^+&<>*~$])+\d*\([^)]+\)([\s]|(/\*.*?\*)/|((?<=[\s]);[^\r\n]*?$))*?[\s]*\n*(?=\{)", match, startPos))
		{
			defs .= Trim(RegExReplace(match, "\s*\n\s*$")) " {`n"
			startPos := InStr(cleanScript, "`n",, foundPos) ; start at next line
		}
	} until !foundPos

	return defs
} ;</04.01.000011>
;<04.01.000012>
IndexOfIconResource(Filename, ID) {                                                              	;-- function is used to convert an icon resource id (as those used in the registry) to icon index(as used by ahk)

	;By Lexikos http://www.autohotkey.com/community/viewtopic.php?p=168951
    hmod := DllCall("GetModuleHandle", "str", Filename, "PTR")
    ; If the DLL isn't already loaded, load it as a data file.
    loaded := !hmod
        && hmod := DllCall("LoadLibraryEx", "str", Filename, "PTR", 0, "uint", 0x2)

    enumproc := RegisterCallback("IndexOfIconResource_EnumIconResources","F")
    VarSetCapacity(param,12,0)
    NumPut(ID,param,0)
    ; Enumerate the icon group resources. (RT_GROUP_ICON=14)
    DllCall("EnumResourceNames", "uint", hmod, "uint", 14, "uint", enumproc, "PTR", &param)
    DllCall("GlobalFree", "PTR", enumproc)

    ; If we loaded the DLL, free it now.
    if loaded
        DllCall("FreeLibrary", "PTR", hmod)

    return NumGet(param,8) ? NumGet(param,4) : 0
} ;</04.01.000012>
;<04.01.000013>
IndexOfIconResource_EnumIconResources(hModule, lpszType, lpszName, lParam) {  ;-- subfunction of IndexOfIconResource()

	;By Lexikos http://www.autohotkey.com/community/viewtopic.php?p=168951
    NumPut(NumGet(lParam+4)+1, lParam+4)

    if (lpszName = NumGet(lParam+0))
    {
        NumPut(1, lParam+8)
        return false    ; break
    }
    return true
} ;</04.01.000013>
;<04.01.000014>
GetIconforext(ext) {                                                                                         	;-- Gets default registered icon for an extension

	; source: https://github.com/aviaryan/autohotkey-scripts/blob/master/Functions/Miscellaneous-Functions.ahk
	; dependings: none

	/*			DESCRIPTION
		Gets default registered icon for an extension
		Eg - GetIconforext(".ahk")
		Note - The icon path is not returned in pure-form but of the form     <path>, <icon index>
	*/

    RegRead, ThisExtClass, HKEY_CLASSES_ROOT, %ext%
    RegRead, DefaultIcon, HKEY_CLASSES_ROOT, %ThisExtClass%\DefaultIcon
	IfEqual, Defaulticon
	{
		Regread, Application, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\%ext%\UserChoice, Progid
		IfNotEqual, Application
			Regread, DefaultIcon, HKCR, %Application%\DefaultIcon
	}
    Return DefaultIcon
} ;</04.01.000014>
;<04.01.000015>
GetImageType(PID) {																							;-- returns whether a process is 32bit or 64bit

	; PROCESS_QUERY_INFORMATION
    hProc := DllCall("OpenProcess", "UInt", 0x400, "Int", False, "UInt", PID, "Ptr")
    If (!hProc) {
        Return "N/A"
    }

    If (A_Is64bitOS) {
        ; Determines whether the specified process is running under WOW64.
        Try DllCall("IsWow64Process", "Ptr", hProc, "Int*", Is32Bit := True)
    } Else {
        Is32Bit := True
    }

    DllCall("CloseHandle", "Ptr", hProc)

    Return (Is32Bit) ? "32-bit" : "64-bit"
} ;</04.01.000015>
;<04.01.000016>
GetProcessName(hwnd) {																					;-- Gets the process name from a window handle.

	WinGet, ProcessName, processname, ahk_id %hwnd%
	return ProcessName
} ;</04.01.000016>
;<04.01.000017>
GetDisplayOrientation() {																					;-- working function to get the orientation of screen

	DEVMODE_Size := 226
	VarSetCapacity(DEVMODE, DEVMODE_Size, 0)
	NumPut(DEVMODE_Size, DEVMODE, 68, "UShort")
	NumPut(64, DEVMODE, 70, "UShort")

	ret := DllCall("EnumDisplaySettings", "Ptr", 0, "UInt", 0xFFFFFFFF, "Str", DEVMODE)
	dmDisplayOrientation := 0
	;DM_DISPLAYORIENTATION = 0x00000080
	If (ret && NumGet(DEVMODE, 72, "UInt") & 0x00000080)
			dmDisplayOrientation := NumGet(DEVMODE, 84, "UInt")
	VarSetCapacity(DEVMODE, 0)
	Return dmDisplayOrientation
} ;</04.01.000017>
;<04.01.000018>
GetSysErrorText(errNr) { 																						;-- method to get meaningful data out of the error codes

	; http://www.autohotkey.com/forum/post-72230.html#72230 by PhiLho
  bufferSize = 1024 ; Arbitrary, should be large enough for most uses
  VarSetCapacity(buffer, bufferSize)
  DllCall("FormatMessage"
     , "UInt", FORMAT_MESSAGE_FROM_SYSTEM := 0x1000
     , "UInt", 0
     , "UInt", errNr
     , "UInt", 0  ;LANG_USER_DEFAULT := 0x20000 ; LANG_SYSTEM_DEFAULT := 0x10000
     , "Str", buffer
     , "UInt", bufferSize
     , "UInt", 0)
  Return buffer
} ;</04.01.000018>
;<04.01.000019>
getSysLocale() { 																									;-- gets the system language

	; fork of http://stackoverflow.com/a/7759505/883015
	; Source: https://github.com/joedf/AEI.ahk/blob/master/AEI.ahk
	VarSetCapacity(buf_a,9,0), VarSetCapacity(buf_b,9,0)
	f:="GetLocaleInfo" (A_IsUnicode?"W":"A")
	DllCall(f,"Int",LOCALE_SYSTEM_DEFAULT:=0x800
			,"Int",LOCALE_SISO639LANGNAME:=89
			,"Str",buf_a,"Int",9)
	DllCall(f,"Int",LOCALE_SYSTEM_DEFAULT
			,"Int",LOCALE_SISO3166CTRYNAME:=90
			,"Str",buf_b,"Int",9)
	return buf_a "-" buf_b
} ;</04.01.000019>
;<04.01.000020>
GetThreadStartAddr(ProcessID) {                                                                     	;-- returns start adresses from all threads of a process

	/*                              	EXAMPLE(s)

			MsgBox % "StartAddr of first Thread:`t" GetThreadStartAddr(2280)[1].StartAddr
			; Tested with PID of notepad
			; 0x000000003c5aa2

			; ================================================================================

			for k, v in GetThreadStartAddr(2280)
			    MsgBox % "ThreadID:`t`t" v.ThreadID "`nStartAddr:`t`t" v.StartAddr
			; Tested with PID of notepad
			; ThreadID:     8052              |  1460              |  12116             |  8668              |  5376
			; StartAddr:    0x000000003c5aa2  |  0x000000777ac6d0  |  0x0000000032c660  |  0x000000748875f0  |  0x000000777ac6d0

	*/


    hModule := DllCall("LoadLibrary", "str", "ntdll.dll", "uptr")

    if !(hSnapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x4, "uint", ProcessID))
        return "Error in CreateToolhelp32Snapshot"

    NumPut(VarSetCapacity(THREADENTRY32, 28, 0), THREADENTRY32, "uint")
    if !(DllCall("Thread32First", "ptr", hSnapshot, "ptr", &THREADENTRY32))
        return "Error in Thread32First", DllCall("CloseHandle", "ptr", hSnapshot)

    Addr := {}, cnt := 1
    while (DllCall("Thread32Next", "ptr", hSnapshot, "ptr", &THREADENTRY32)) {
        if (NumGet(THREADENTRY32, 12, "uint") = ProcessID) {
            hThread := DllCall("OpenThread", "uint", 0x0040, "int", 0, "uint", NumGet(THREADENTRY32, 8, "uint"), "ptr")
            if (DllCall("ntdll\NtQueryInformationThread", "ptr", hThread, "uint", 9, "ptr*", ThreadStartAddr, "uint", A_PtrSize, "uint*", 0) != 0)
                return "Error in NtQueryInformationThread", DllCall("CloseHandle", "ptr", hThread) && DllCall("FreeLibrary", "ptr", hModule)
            Addr[cnt, "StartAddr"] := Format("{:#016x}", ThreadStartAddr)
            Addr[cnt, "ThreadID"]  := NumGet(THREADENTRY32, 8, "uint")
            DllCall("CloseHandle", "ptr", hThread), cnt++
        }
    }

    return Addr, DllCall("CloseHandle", "ptr", hSnapshot) && DllCall("FreeLibrary", "ptr", hModule)
} ;</04.01.000020>
;<04.01.000021>
ScriptExist(scriptname) {                                                                                     	;-- true oder false if Script is running or not

	dtWin:= A_DetectHiddenWindows
	DetectHiddenWindows, On							;this must be set to On to find scripts without a gui

	WinGet, hwnd, List, ahk_class AutoHotkey

	Loop, %hwnd%
	{
			ID := hwnd%A_Index%
			WinGetTitle, Titel, ahk_id %ID%
			WinGet, PID, PID, ahk_id %ID%
			SplitPath, Titel, runningAHK
			If InStr(runningAHK, tostartAHK)
							return 1
	}

	DetectHiddenWindows, % dtWin

return 0
} ;</04.01.000021>
;<04.01.000022>
GetStartupWindowState() {                                                        	                    	;-- to check, if script exe was launched by windows's shortcut with MAXIMIZE

	/*	DESCRIPTION OF FUNCTION: -- GetStartupWindowState --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	to check, if script exe was launched by windows's shortcut with MAXIMIZE
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=76&t=48090&p=215504&hilit=GetStartupInfo#p215504
	Author         	:	Lexikos
	Date             	:	29.04.2018
	AHK-Version	:	AHK_L
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:	system,process
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	minmax := GetStartupWindowState()
		if InStr(minmax, "Min")
			MsgBox Minimize
		else if (minmax = "Max")
			MsgBox Maximize
		else
			MsgBox minmax=%minmax%
	*/
    static states := {0: "Hide", 1: "Show", 3: "Max", 6: "Min", 7: "MinNA"}  ; https://msdn.com/ms633548
    VarSetCapacity(startupinfo, 9*A_PtrSize+32)
    DllCall("GetStartupInfo", "ptr", &startupinfo)  ; https://msdn.com/ms683230
    if !(NumGet(startupinfo, 4*A_PtrSize+28, "uint") & 1)
        return ""  ; Unspecified (STARTF_USESHOWWINDOW flag is not set).
    wShowWindow := NumGet(startupinfo, 4*A_PtrSize+32, "ushort")
    if state := states[wShowWindow]
        return state
    return wShowWindow
} ;</04.01.000022>
}
;|   GetProcesses(01)                     	|   GetProcessWorkingDir(02)       	|   GetTextSize(03)                        	|   GetTextSize(04)                        	|
;|   MeasureText()                         	|   monitorInfo()                           	|   whichMonitor()                        	|   IsOfficeFile()                             	|
;|   DeskIcons()                              	|   GetFuncDefs()                          	|   IndexOfIconResource()             	|   GetIconforext()                         	|
;|   GetImageType()                       	|   GetProcessName()                   	|   GetDisplayOrientation()           	|   GetSysErrorText()                     	|
;|   getSysLocale()                         	|   GetThreadStartAddr(20)           	|   ScriptExist(21)                          	|   GetStartupWindowState(22)    	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;graphic (64) -                                                                                                                                           	baseID: <05>
;<05.01.000001>
LoadPicture(aFilespec, aWidth:=0, aHeight:=0, ByRef aImageType:="",       	    	;-- Loads a picture and returns an HBITMAP or HICON to the caller
aIconNumber:=0, aUseGDIPlusIfAvailable:=1) {

	; Returns NULL on failure.
	; If aIconNumber > 0, an HICON or HCURSOR is returned (both should be interchangeable), never an HBITMAP.
	; However, aIconNumber==1 is treated as a special icon upon which LoadImage is given preference over ExtractIcon
	; for .ico/.cur/.ani files.
	; Otherwise, .ico/.cur/.ani files are normally loaded as HICON (unless aUseGDIPlusIfAvailable is true or
	; something else unusual happened such as file contents not matching file's extension).  This is done to preserve
	; any properties that HICONs have but HBITMAPs lack, namely the ability to be animated and perhaps other things.
	;
	; Loads a JPG/GIF/BMP/ICO/etc. and returns an HBITMAP or HICON to the caller (which it may call
	; DeleteObject()/DestroyIcon() upon, though upon program termination all such handles are freed
	; automatically).  The image is scaled to the specified width and height.  If zero is specified
	; for either, the image's actual size will be used for that dimension.  If -1 is specified for one,
	; that dimension will be kept proportional to the other dimension's size so that the original aspect
	; ratio is retained.

	static IMAGE_ICON,IMAGE_BITMAP,IMAGE_CURSOR,LR_LOADFROMFILE,LR_CREATEDIBSECTION,GdiplusStartupInput,gdi_input,CLR_DEFAULT,GENERIC_READ,OPEN_EXISTING,GMEM_MOVEABLE,LR_COPYRETURNORG,bitmap,ii,LR_COPYDELETEORG,INVALID_HANDLE_VALUE,IID_IPicture

	if !IMAGE_ICON
    IMAGE_ICON:=1,IMAGE_BITMAP:=0,IMAGE_CURSOR:=2,LR_LOADFROMFILE:=16, LR_CREATEDIBSECTION:=8192
    ,GdiplusStartupInput :="UINT32 GdiplusVersion;PTR DebugEventCallback;BOOL SuppressBackgroundThread;BOOL SuppressExternalCodecs"
    ,gdi_input:=Struct(GdiplusStartupInput),CLR_DEFAULT:=4278190080,GENERIC_READ:=2147483648
    ,OPEN_EXISTING:=3,GMEM_MOVEABLE:=2,LR_COPYRETURNORG:=4
    ,bitmap:=Struct("LONG bmType;LONG bmWidth;LONG bmHeight;LONG bmWidthBytes;WORD bmPlanes;WORD bmBitsPixel;LPVOID bmBits") ;BITMAP
    ,ii:=Struct("BOOL fIcon;DWORD xHotspot;DWORD yHotspot;HBITMAP hbmMask;HBITMAP hbmColor") ; ICONINFO
    ,LR_COPYDELETEORG:=8,INVALID_HANDLE_VALUE:=-1,VarSetCapacity(IID_IPicture,16,0) CLSIDFromString("{7BF80980-BF32-101A-8BBB-00AA00300CAB}", &IID_IPicture)
	hbitmap := 0
	,aImageType := -1 ; The type of image currently inside hbitmap.  Set default value for output parameter as "unknown".

	if (aFilespec="") ; Allow blank filename to yield NULL bitmap (and currently, some callers do call it this way).
		return 0

	; Lexikos: Negative values now indicate an icon's integer resource ID.
	;if (aIconNumber < 0) ; Allowed to be called this way by GUI and others (to avoid need for validation of user input there).
	;	aIconNumber = 0 ; Use the default behavior, which is "load icon or bitmap, whichever is most appropriate".

	file_ext := SubStr(aFilespec, InStr(aFilespec,".",1,-1) + 1)

	; v1.0.43.07: If aIconNumber is zero, caller didn't specify whether it wanted an icon or bitmap.  Thus,
	; there must be some kind of detection for whether ExtractIcon is needed instead of GDIPlus/OleLoadPicture.
	; Although this could be done by attempting ExtractIcon only after GDIPlus/OleLoadPicture fails (or by
	; somehow checking the internal nature of the file), for performance and code size, it seems best to not
	; to incur this extra I/O and instead make only one attempt based on the file's extension.
	; Must use ExtractIcon() if either of the following is true:
	; 1) Caller gave an icon index of the second or higher icon in the file.  Update for v1.0.43.05: There
	;    doesn't seem to be any reason to allow a caller to explicitly specify ExtractIcon as the method of
	;    loading the *first* icon from a .ico file since LoadImage is likely always superior.  This is
	;    because unlike ExtractIcon/Ex, LoadImage: 1) Doesn't distort icons, especially 16x16 icons 2) is
	;    capable of loading icons other than the first by means of width and height parameters.
	; 2) The target file is of type EXE/DLL/ICL/CPL/etc. (LoadImage() is documented not to work on those file types).
	;    ICL files (v1.0.43.05): Apparently ICL files are an unofficial file format. Someone on the newsgroups
	;    said that an ICL is an "ICon Library... a renamed 16-bit Windows .DLL (an NE format executable) which
	;    typically contains nothing but a resource section. The ICL extension seems to be used by convention."
	; L17: Support negative numbers to mean resource IDs. These are supported by the resource extraction method directly, and by ExtractIcon if aIconNumber < -1.
	; Icon library: Unofficial dll container, see notes above. (*.icl)
	; Control panel extension/applet (ExtractIcon is said to work on these). (*.cpl)
	; Screen saver (ExtractIcon should work since these are really EXEs). (*.src)
	If (ExtractIcon_was_used := aIconNumber > 1 || aIconNumber < 0 || file_ext = "exe" || file_ext="dll" || file_ext="icl" || file_ext="cpl" || file_ext="scr"){
		; v1.0.44: Below are now omitted to reduce code size and improve performance. They are still supported
		; indirectly because ExtractIcon is attempted whenever LoadImage() fails further below.
		; !_tcsicmp(file_ext, _T("drv")) ; Driver (ExtractIcon is said to work on these).
		; !_tcsicmp(file_ext, _T("ocx")) ; OLE/ActiveX Control Extension
		; !_tcsicmp(file_ext, _T("vbx")) ; Visual Basic Extension
		; !_tcsicmp(file_ext, _T("acm")) ; Audio Compression Manager Driver
		; !_tcsicmp(file_ext, _T("bpl")) ; Delphi Library (like a DLL?)
		; Not supported due to rarity, code size, performance, and uncertainty of whether ExtractIcon works on them.
		; Update for v1.0.44: The following are now supported indirectly because ExtractIcon is attempted whenever
		; LoadImage() fails further below.
		; !_tcsicmp(file_ext, _T("nil")) ; Norton Icon Library
		; !_tcsicmp(file_ext, _T("wlx")) ; Total/Windows Commander Lister Plug-in
		; !_tcsicmp(file_ext, _T("wfx")) ; Total/Windows Commander File System Plug-in
		; !_tcsicmp(file_ext, _T("wcx")) ; Total/Windows Commander Plug-in
		; !_tcsicmp(file_ext, _T("wdx")) ; Total/Windows Commander Plug-in

		aImageType := IMAGE_ICON

		; L17: Manually extract the most appropriately sized icon resource for the best results.
		,hbitmap := ExtractIconFromExecutable(aFilespec, aIconNumber, aWidth, aHeight)

		if (hbitmap < 2) ; i.e. it's NULL or 1. Return value of 1 means "incorrect file type".
			return 0 ; v1.0.44: Fixed to return NULL vs. hbitmap, since 1 is an invalid handle (perhaps rare since no known bugs caused by it).
		;else continue on below so that the icon can be resized to the caller's specified dimensions.
	}	else if (aIconNumber > 0) ; Caller wanted HICON, never HBITMAP, so set type now to enforce that.
		aImageType := IMAGE_ICON ; Should be suitable for cursors too, since they're interchangeable for the most part.
	else if (file_ext) ; Make an initial guess of the type of image if the above didn't already determine the type.
	{
		if (file_ext = "ico")
			aImageType := IMAGE_ICON
		else if (file_ext="cur" || file_ext="ani")
			aImageType := IMAGE_CURSOR
		else if (file_ext="bmp")
			aImageType := IMAGE_BITMAP
		;else for other extensions, leave set to "unknown" so that the below knows to use IPic or GDI+ to load it.
	}
	;else same comment as above.

	if ((aWidth = -1 || aHeight = -1) && (!aWidth || !aHeight))
		aWidth := aHeight := 0 ; i.e. One dimension is zero and the other is -1, which resolves to the same as "keep original size".
	keep_aspect_ratio := aWidth = -1 || aHeight = -1

	; Caller should ensure that aUseGDIPlusIfAvailable==false when aIconNumber > 0, since it makes no sense otherwise.
	if (aUseGDIPlusIfAvailable && !(hinstGDI := LoadLibrary("gdiplus"))) ; Relies on short-circuit boolean order for performance.
		aUseGDIPlusIfAvailable := false ; Override any original "true" value as a signal for the section below.
	if (!hbitmap && aImageType > -1 && !aUseGDIPlusIfAvailable)
	{
		; Since image hasn't yet be loaded and since the file type appears to be one supported by
		; LoadImage() [icon/cursor/bitmap], attempt that first.  If it fails, fall back to the other
		; methods below in case the file's internal contents differ from what the file extension indicates.
		if (keep_aspect_ratio) ; Load image at its actual size.  It will be rescaled to retain aspect ratio later below.
		{
			desired_width := 0
			,desired_height := 0
		}
		else
		{
			desired_width := aWidth
			,desired_height := aHeight
		}
		; For LoadImage() below:
		; LR_CREATEDIBSECTION applies only when aImageType == IMAGE_BITMAP, but seems appropriate in that case.
		; Also, if width and height are non-zero, that will determine which icon of a multi-icon .ico file gets
		; loaded (though I don't know the exact rules of precedence).
		; KNOWN LIMITATIONS/BUGS:
		; LoadImage() fails when requesting a size of 1x1 for an image whose orig/actual size is small (e.g. 1x2).
		; Unlike CopyImage(), perhaps it detects that division by zero would occur and refuses to do the
		; calculation rather than providing more code to do a correct calculation that doesn't divide by zero.
		; For example:
		; LoadImage() Success:
		;   Gui, Add, Pic, h2 w2, bitmap 1x2.bmp
		;   Gui, Add, Pic, h1 w1, bitmap 4x6.bmp
		; LoadImage() Failure:
		;   Gui, Add, Pic, h1 w1, bitmap 1x2.bmp
		; LoadImage() also fails on:
		;   Gui, Add, Pic, h1, bitmap 1x2.bmp
		; And then it falls back to GDIplus, which in the particular case above appears to traumatize the
		; parent window (or its picture control), because the GUI window hangs (but not the script) after
		; doing a FileSelectFolder.  For example:
		;   Gui, Add, Button,, FileSelectFile
		;   Gui, Add, Pic, h1, bitmap 1x2.bmp   Causes GUI window to hang after FileSelectFolder (due to LoadImage failing then falling back to GDIplus i.e. GDIplus is somehow triggering the problem).
		;   Gui, Show
		;   return
		;   ButtonFileSelectFile:
		;   FileSelectFile, outputvar
		;   return
		if (hbitmap := LoadImage(0, aFilespec, aImageType, desired_width, desired_height, LR_LOADFROMFILE | LR_CREATEDIBSECTION))
		{
			; The above might have loaded an HICON vs. an HBITMAP (it has been confirmed that LoadImage()
			; will return an HICON vs. HBITMAP is aImageType is IMAGE_ICON/CURSOR).  Note that HICON and
			; HCURSOR are identical for most/all Windows API uses.  Also note that LoadImage() will load
			; an icon as a bitmap if the file contains an icon but IMAGE_BITMAP was passed in (at least
			; on Windows XP).
			if (!keep_aspect_ratio) ; No further resizing is needed.
				return hbitmap
			; Otherwise, continue on so that the image can be resized via a second call to LoadImage().
		}
		; v1.0.40.10: Abort if file doesn't exist so that GDIPlus isn't even attempted. This is done because
		; loading GDIPlus apparently disrupts the color palette of certain games, at least old ones that use
		; DirectDraw in 256-color depth.
		else if (GetFileAttributes(aFilespec) = 0xFFFFFFFF) ; For simplicity, we don't check if it's a directory vs. file, since that should be too rare.
			return 0
		; v1.0.43.07: Also abort if caller wanted an HICON (not an HBITMAP), since the other methods below
		; can't yield an HICON.
		else if (aIconNumber > 0)
		{
			; UPDATE for v1.0.44: Attempt ExtractIcon in case its some extension that's
			; was recognized as an icon container (such as AutoHotkeySC.bin) and thus wasn't handled higher above.
			;hbitmap = (HBITMAP)ExtractIcon(g_hInstance, aFilespec, aIconNumber - 1)

			; L17: Manually extract the most appropriately sized icon resource for the best results.
			hbitmap := ExtractIconFromExecutable(aFilespec, aIconNumber, aWidth, aHeight)

			if (hbitmap < 2) ; i.e. it's NULL or 1. Return value of 1 means "incorrect file type".
				return 0
			ExtractIcon_was_used := true
		}
		;else file exists, so continue on so that the other methods are attempted in case file's contents
		; differ from what the file extension indicates, or in case the other methods can be successful
		; even when the above failed.
	}

	; pic := 0 is also used to detect whether IPic method was used to load the image.

	if (!hbitmap) ; Above hasn't loaded the image yet, so use the fall-back methods.
	{
		; At this point, regardless of the image type being loaded (even an icon), it will
		; definitely be converted to a Bitmap below.  So set the type:
		aImageType := IMAGE_BITMAP
		; Find out if this file type is supported by the non-GDI+ method.  This check is not foolproof
		; since all it does is look at the file's extension, not its contents.  However, it doesn't
		; need to be 100% accurate because its only purpose is to detect whether the higher-overhead
		; calls to GdiPlus can be avoided.

		if (aUseGDIPlusIfAvailable || !file_ext || file_ext!="jpg"
			&& file_ext!="jpeg" && file_ext!="gif") ; Non-standard file type (BMP is already handled above).
			if (!hinstGDI) ; We don't yet have a handle from an earlier call to LoadLibary().
				hinstGDI := LoadLibrary("gdiplus")
		; If it is suspected that the file type isn't supported, try to use GdiPlus if available.
		; If it's not available, fall back to the old method in case the filename doesn't properly
		; reflect its true contents (i.e. in case it really is a JPG/GIF/BMP internally).
		; If the below LoadLibrary() succeeds, either the OS is XP+ or the GdiPlus extensions have been
		; installed on an older OS.
		if (hinstGDI)
		{
			; LPVOID and "int" are used to avoid compiler errors caused by... namespace issues?

			gdi_input.Fill()
			if !GdiplusStartup(getvar(token:=0), gdi_input[], 0)
			{
				if !GdipCreateBitmapFromFile(aFilespec, getvar(pgdi_bitmap:=0))
				{
					if GdipCreateHBITMAPFromBitmap(pgdi_bitmap, hbitmap, CLR_DEFAULT)
						hbitmap := 0 ; Set to NULL to be sure.
					GdipDisposeImage(pgdi_bitmap) ; This was tested once to make sure it really returns Gdiplus::Ok.
				}
				; The current thought is that shutting it down every time conserves resources.  If so, it
				; seems justified since it is probably called infrequently by most scripts:
				GdiplusShutdown(token)
			}
			FreeLibrary(hinstGDI)
		}
		else ; Using old picture loading method.
		{
			; Based on code sample at http:;www.codeguru.com/Cpp/G-M/bitmap/article.php/c4935/
			hfile := CreateFile(aFilespec, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)
			if (hfile = INVALID_HANDLE_VALUE)
				return 0
			size := GetFileSize(hfile, 0)
			if !(hglobal := GlobalAlloc(GMEM_MOVEABLE, size)){
				CloseHandle(hfile)
				return 0
			}
			if !(hlocked := GlobalLock(hglobal)){
				CloseHandle(hfile)
				,GlobalFree(hglobal)
				return 0
			}
			; Read the file into memory:
			ReadFile(hfile, hlocked, size, getvar(size), 0)
			,GlobalUnlock(hglobal)
			,CloseHandle(hfile)
			if (0 > CreateStreamOnHGlobal(hglobal, FALSE, getvar(stream:=0)) || !stream )  ; Relies on short-circuit boolean order.
			{
				GlobalFree(hglobal)
				return 0
			}

			; Specify TRUE to have it do the GlobalFree() for us.  But since the call might fail, it seems best
			; to free the mem ourselves to avoid uncertainty over what it does on failure:
			if (0 > OleLoadPicture(stream, size, FALSE, &IID_IPicture,getvar(pic:=0)))
				pic:=0

			DllCall(NumGet(NumGet(stream+0)+8),"PTR",stream) ;->Release()
			,GlobalFree(hglobal)
			if !pic
				return 0
			DllCall(NumGet(NumGet(pic+0)+12),"PTR",pic,"PTR*",hbitmap)
			; Above: MSDN: "The caller is responsible for this handle upon successful return. The variable is set
			; to NULL on failure."
			if (!hbitmap)
			{
				DllCall(NumGet(NumGet(pic+0)+8),"PTR",pic)
				return 0
			}
			; Don't pic->Release() yet because that will also destroy/invalidate hbitmap handle.
		} ; IPicture method was used.
	} ; IPicture or GDIPlus was used to load the image, not a simple LoadImage() or ExtractIcon().

	; Above has ensured that hbitmap is now not NULL.
	; Adjust things if "keep aspect ratio" is in effect:
	if (keep_aspect_ratio)
	{
		ii.Fill()
		if (aImageType = IMAGE_BITMAP)
			hbitmap_to_analyze := hbitmap
		else ; icon or cursor
		{
			if (GetIconInfo(hbitmap, ii[])) ; Works on cursors too.
				hbitmap_to_analyze := ii.hbmMask ; Use Mask because MSDN implies hbmColor can be NULL for monochrome cursors and such.
			else
			{
				DestroyIcon(hbitmap)
				return 0 ; No need to call pic->Release() because since it's an icon, we know IPicture wasn't used (it only loads bitmaps).
			}
		}
		; Above has ensured that hbitmap_to_analyze is now not NULL.  Find bitmap's dimensions.
		bitmap.Fill()
		,GetObject(hbitmap_to_analyze, sizeof(_BITMAP), bitmap[]) ; Realistically shouldn't fail at this stage.
		if (aHeight = -1)
		{
			; Caller wants aHeight calculated based on the specified aWidth (keep aspect ratio).
			if (bitmap.bmWidth) ; Avoid any chance of divide-by-zero.
				aHeight := (bitmap.bmHeight / bitmap.bmWidth) * aWidth + 0.5 ; Round.
		}
		else
		{
			; Caller wants aWidth calculated based on the specified aHeight (keep aspect ratio).
			if (bitmap.bmHeight) ; Avoid any chance of divide-by-zero.
				aWidth := (bitmap.bmWidth / bitmap.bmHeight) * aHeight + 0.5 ; Round.
		}
		if (aImageType != IMAGE_BITMAP)
		{
			; It's our responsibility to delete these two when they're no longer needed:
			DeleteObject(ii.hbmColor)
			,DeleteObject(ii.hbmMask)
			; If LoadImage() vs. ExtractIcon() was used originally, call LoadImage() again because
			; I haven't found any other way to retain an animated cursor's animation (and perhaps
			; other icon/cursor attributes) when resizing the icon/cursor (CopyImage() doesn't
			; retain animation):
			if (!ExtractIcon_was_used)
			{
				DestroyIcon(hbitmap) ; Destroy the original HICON.
				; Load a new one, but at the size newly calculated above.
				; Due to an apparent bug in Windows 9x (at least Win98se), the below call will probably
				; crash the program with a "divide error" if the specified aWidth and/or aHeight are
				; greater than 90.  Since I don't know whether this affects all versions of Windows 9x, and
				; all animated cursors, it seems best just to document it here and in the help file rather
				; than limiting the dimensions of .ani (and maybe .cur) files for certain operating systems.
				return LoadImage(0, aFilespec, aImageType, aWidth, aHeight, LR_LOADFROMFILE)
			}
		}
	}


	if (pic) ; IPicture method was used.
	{
		; The below statement is confirmed by having tested that DeleteObject(hbitmap) fails
		; if called after pic->Release():
		; "Copy the image. Necessary, because upon pic's release the handle is destroyed."
		; MSDN: CopyImage(): "[If either width or height] is zero, then the returned image will have the
		; same width/height as the original."
		; Note also that CopyImage() seems to provide better scaling quality than using MoveWindow()
		; (followed by redrawing the parent window) on the static control that contains it:
		hbitmap_new := CopyImage(hbitmap, IMAGE_BITMAP, aWidth, aHeight ; We know it's IMAGE_BITMAP in this case.
														, (aWidth || aHeight) ? 0 : LR_COPYRETURNORG) ; Produce original size if no scaling is needed.
		,DllCall(NumGet(NumGet(pic+0)+8),"PTR",pic)
		; No need to call DeleteObject(hbitmap), see above.
	}
	else ; GDIPlus or a simple method such as LoadImage or ExtractIcon was used.
	{
		if (!aWidth && !aHeight) ; No resizing needed.
			return hbitmap
		; The following will also handle HICON/HCURSOR correctly if aImageType == IMAGE_ICON/CURSOR.
		; Also, LR_COPYRETURNORG|LR_COPYDELETEORG is used because it might allow the animation of
		; a cursor to be retained if the specified size happens to match the actual size of the
		; cursor.  This is because normally, it seems that CopyImage() omits cursor animation
		; from the new object.  MSDN: "LR_COPYRETURNORG returns the original hImage if it satisfies
		; the criteria for the copy�that is, correct dimensions and color depth�in which case the
		; LR_COPYDELETEORG flag is ignored. If this flag is not specified, a new object is always created."
		; KNOWN BUG: Calling CopyImage() when the source image is tiny and the destination width/height
		; is also small (e.g. 1) causes a divide-by-zero exception.
		; For example:
		;   Gui, Add, Pic, h1 w-1, bitmap 1x2.bmp   Crash (divide by zero)
		;   Gui, Add, Pic, h1 w-1, bitmap 2x3.bmp   Crash (divide by zero)
		; However, such sizes seem too rare to document or put in an exception handler for.
		hbitmap_new := CopyImage(hbitmap, aImageType, aWidth, aHeight, LR_COPYRETURNORG | LR_COPYDELETEORG)
		; Above's LR_COPYDELETEORG deletes the original to avoid cascading resource usage.  MSDN's
		; LoadImage() docs say:
		; "When you are finished using a bitmap, cursor, or icon you loaded without specifying the
		; LR_SHARED flag, you can release its associated memory by calling one of [the three functions]."
		; Therefore, it seems best to call the right function even though DeleteObject might work on
		; all of them on some or all current OSes.  UPDATE: Evidence indicates that DestroyIcon()
		; will also destroy cursors, probably because icons and cursors are literally identical in
		; every functional way.  One piece of evidence:
		;> No stack trace, but I know the exact source file and line where the call
		;> was made. But still, it is annoying when you see 'DestroyCursor' even though
		;> there is 'DestroyIcon'.
		; "Can't be helped. Icons and cursors are the same thing" (Tim Robinson (MVP, Windows SDK)).
		;
		; Finally, the reason this is important is that it eliminates one handle type
		; that we would otherwise have to track.  For example, if a gui window is destroyed and
		; and recreated multiple times, its bitmap and icon handles should all be destroyed each time.
		; Otherwise, resource usage would cascade upward until the script finally terminated, at
		; which time all such handles are freed automatically.
	}
	return hbitmap_new
} ;</05.01.000001>
;<05.01.000002>
GetImageDimensionProperty(ImgPath, Byref width, Byref height, 						;-- this retrieves the dimensions from a dummy Gui
PropertyName="dimensions") {

    Static DimensionIndex
    SplitPath, ImgPath , FileName, DirPath,
    objShell := ComObjCreate("Shell.Application")
    objFolder := objShell.NameSpace(DirPath)
    objFolderItem := objFolder.ParseName(FileName)

    if !DimensionIndex {
        Loop
            DimensionIndex := A_Index
        Until (objFolder.GetDetailsOf(objFolder.Items, A_Index) = PropertyName) || (A_Index > 300)
    }

    if (DimensionIndex = 301)
        Return

    dimensions := objFolder.GetDetailsOf(objFolderItem, DimensionIndex)
    width := height := ""
    pos := len := 0
    loop 2
    {
        pos := RegExMatch(dimensions, "O)\d+", oM, pos+len+1)
        if (A_Index = 1)
            width := oM.Value(0), len := oM.len(0)
        else
            height := oM.Value(0)
    }

} ;</05.01.000002>
;<05.01.000003>
GetImageDimensions(ImgPath, Byref width, Byref height) {									;-- Retrieves image width and height of a specified image file

	/*											Description

		Link              	:	https://sites.google.com/site/ahkref/custom-functions/getimagedimensions
		Description  	:	Retrieves image width and height of a specified image file.
		Requirements	: 	AutoHotkey 1.1.05.00 or later. Tested on: Windows 7 64bit, AutoHotkey 32bit Unicode 1.1.05.05.
		License	        	:	Public Domain.
		Format         	:	GetImageDimensionProperty(ImgPath, Byref width, Byref height, PropertyName="dimensions")
		Parameters   	:	ImgPath	: the path of the file to look up the dimensions.
		                        	width   	: pass a variable to store the retrieved width.
		                        	height   	: pass a variable to store the retrieved height.
		PropertyName	:	the property name which stores the information of image dimensions. In English OS, it is dimensions.
		Return Value	:	None
		Remarks       	:	This function retrieves the information of detail properties and the PropertyName parameter must match the property name in the property details

	*/

	/*											Example(s)

		ImageFile := A_ScriptDir "\logo.gif"
		if !FileExist(ImageFile)
			UrlDownloadToFile, http://www.autohotkey.com/docs/images/AutoHotkey_logo.gif, % ImageFile

		GetImageDimensions(ImageFile, w, h)
		msgbox % "Width:`t" w "`nHeight:`t" h

	*/


    DHW := A_DetectHiddenWIndows
    DetectHiddenWindows, ON
    Gui, AnimatedGifControl_GetImageDimensions: Add, Picture, hwndhWndImage, % ImgPath
    GuiControlGet, Image, AnimatedGifControl_GetImageDimensions:Pos, % hWndImage
    Gui, AnimatedGifControl_GetImageDimensions: Destroy
    DetectHiddenWindows, % DHW
    width := ImageW,     height := ImageH

} ;</05.01.000003>
;<05.01.000004>
Gdip_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r) {								;--

	Region := Gdip_GetClipRegion(pGraphics)
	Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
	E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r)-1, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r)-1, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r)-1, y+h-(2*r)-1, 2*r, 2*r)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)
	Return E

} ;</05.01.000004>
;<05.01.000005>
Redraw(hwnd=0) {																									;-- redraws the overlay window(s) using the position, text and scrolling settings

    ;This function redraws the overlay window(s) using the position, text and scrolling settings
    global MainOverlay, PreviewOverlay, PreviewWindow, MainWindow
	outputdebug redraw
	;Called without parameters, recursive calls for both overlays
	if (hwnd=0)
	{
		if (MainOverlay && PreviewOverlay)
		{
			Redraw(MainWindow)
			Redraw(PreviewWindow)
			return
		}
		Else
		{
			msgbox Redraw() called with invalid window handle
			Exit
		}
	}
	;Get Position of overlay area and text position
	GetOverlayArea(x,y,w,h,hwnd)
	GetAbsolutePosition(CenterX,CenterY,hwnd)
	GetDrawingSettings(text,font,FontColor,style,BackColor,hwnd)

	; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything
	hbm := CreateDIBSection(w, h)

	; Get a device context compatible with the screen
	hdc := CreateCompatibleDC()

	; Select the bitmap into the device context
	obm := SelectObject(hdc, hbm)

	; Get a pointer to the graphics of the bitmap, for use with drawing functions
	G := Gdip_GraphicsFromHDC(hdc)

	; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
	Gdip_SetSmoothingMode(G, 4)
	Gdip_SetTextRenderingHint(G, 1)
	; Create a partially transparent, black brush (ARGB = Transparency, red, green, blue) to draw a rounded rectangle with
	pBrush := Gdip_BrushCreateSolid(backcolor)
	hFont := Font("", style "," font )
	size := Font_DrawText(text, hdc, hFont, "CALCRECT")		;measure the text, use already created font
	StringSplit, size, size, .
	FontWidth := size1,	FontHeight := size2
	DrawX:=CenterX-Round(FontWidth/2)
	DrawY:=CenterY-Round(FontHeight/2)

	corners:=min(Round(min(FontWidth,FontHeight)/5),20)
	Gdip_FillRoundedRectangle(G, pBrush, DrawX, DrawY, FontWidth, FontHeight, corners)
	; Delete the brush as it is no longer needed and wastes memory
	Gdip_DeleteBrush(pBrush)

	Options = x%DrawX% y%DrawY% cff%FontColor% %style% r4
	Gdip_TextToGraphics(G, text, Options, Font)


	; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
	; With some simple maths we can place the gui in the centre of our primary monitor horizontally and vertically at the specified heigth and width
	if (hwnd=PreviewWindow)
		UpdateLayeredWindow(PreviewOverlay, hdc, x, y, w, h)
	else if (hwnd=MainWindow)
		UpdateLayeredWindow(MainOverlay, hdc, x, y, w, h)

	; Select the object back into the hdc
	SelectObject(hdc, obm)

	; Now the bitmap may be deleted
	DeleteObject(hbm)

	; Also the device context related to the bitmap may be deleted
	DeleteDC(hdc)

	; The graphics may now be deleted
	Gdip_DeleteGraphics(G)
} ;</05.01.000005>
;<05.01.000006>
CreateSurface(monitor := 0, window := 0) {															;-- creates a drawing GDI surface

	global DrawSurface_Hwnd

	if (monitor = 0) {
		if (window) {
			WinGetPos, sX, sY, sW, sH, ahk_id %window%
		} else {
			WinGetPos, sX, sY, sW, sH, Program Manager
		}
	} else {
		Sysget, MonitorInfo, Monitor, %monitor%
		sX := MonitorInfoLeft, sY := MonitorInfoTop
		sW := MonitorInfoRight - MonitorInfoLeft
		sH := MonitorInfoBottom - MonitorInfoTop
	}

	Gui DrawSurface:Color, 0xFFFFFF
	Gui DrawSurface: +E0x20 -Caption +LastFound +ToolWindow +AlwaysOnTop
	WinGet, DrawSurface_Hwnd, ID,
	WinSet, TransColor, 0xFFFFFF

	Gui DrawSurface:Show, x%sX% y%sY% w%sW% h%sH%
	Sleep, 100
	Gui DrawSurface:Submit

	return DrawSurface_Hwnd
} ;</05.01.000006>
;<05.01.000007>
ShowSurface() {                                                                                                   	;-- subfunction for CreateSurface
	WinGet, active_win, ID, A
	Gui DrawSurface:Show
	WinActivate, ahk_id %active_win%
} ;</05.01.000007>
;<05.01.000008>
HideSurface() {                                                                                                     	;-- subfunction for CreateSurface
	Gui DrawSurface:Submit
} ;</05.01.000008>
;<05.01.000009>
WipeSurface(hwnd) {                                                                                              	;-- subfunction for CreateSurface
	DllCall("InvalidateRect", UInt, hwnd, UInt, 0, Int, 1)
    DllCall("UpdateWindow", UInt, hwnd)
} ;</05.01.000009>
;<05.01.000010>
StartDraw(wipe := true) {                                                                                        	;-- subfunction for CreateSurface

	global DrawSurface_Hwnd

	if (wipe)
		WipeSurface(DrawSurface_Hwnd)

    HDC := DllCall("GetDC", Int, DrawSurface_Hwnd)

    return HDC
} ;</05.01.000010>
;<05.01.000011>
EndDraw(hdc) {                                                                                                    	;-- subfunction for CreateSurface
	global DrawSurface_Hwnd
	DllCall("ReleaseDC", Int, DrawSurface_Hwnd, Int, hdc)
} ;</05.01.000011>
;<05.01.000012>
SetPen(color, thickness, hdc) {                                                                               	;-- subfunction for CreateSurface

	global DrawSurface_Hwnd

	static pen := 0

	if (pen) {
		DllCall("DeleteObject", Int, pen)
		pen := 0
	}

	pen := DllCall("CreatePen", UInt, 0, UInt, thickness, UInt, color)
    DllCall("SelectObject", Int, hdc, Int, pen)

} ;</05.01.000012>
;<05.01.000013>
DrawLine(hdc, rX1, rY1, rX2, rY2) {																			;-- used DLLCall to draw a line

	DllCall("MoveToEx", Int, hdc, Int, rX1, Int, rY1, UInt, 0)
	DllCall("LineTo", Int, hdc, Int, rX2, Int, rY2)

} ;</05.01.000013>
;<05.01.000014>
DrawRectangle(hdc, left, top, right, bottom) {                                                    	;-- used DLLCall to draw a rectangle

	DllCall("MoveToEx", Int, hdc, Int, left, Int, top, UInt, 0)
    DllCall("LineTo", Int, hdc, Int, right, Int, top)
    DllCall("LineTo", Int, hdc, Int, right, Int, bottom)
    DllCall("LineTo", Int, hdc, Int, left, Int, bottom)
    DllCall("LineTo", Int, hdc, Int, left, Int, top-1)

} ;</05.01.000014>
;<05.01.000015>
DrawRectangle(startNewRectangle := false) {                                                     	;-- this is for screenshots

	static lastX, lastY
	static xorigin, yorigin

	if (startNewRectangle) {
	  MouseGetPos, xorigin, yorigin
	}

	CoordMode, Mouse, Screen
	MouseGetPos, currentX, currentY

	; Has the mouse moved?
	if (lastX lastY) = (currentX currentY)
	return

	lastX := currentX
	lastY := currentY

	x := Min(currentX, xorigin)
	w := Abs(currentX - xorigin)
	y := Min(currentY, yorigin)
	h := Abs(currentY - yorigin)

	Gui, ScreenshotSelection:Show, % "NA X" x " Y" y " W" w " H" h
	Gui, ScreenshotSelection:+LastFound

} ;</05.01.000015>
;<05.01.000016>
DrawFrameAroundControl(ControlID, WindowUniqueID, frame_t) {                  	;-- paints a rectangle around a specified control

    global h_brushC, h_brushW, ChkDrawRectCtrl, ChkDrawRectWin

    ;get coordinates of Window and control again
    ;(could have been past into the function but it seemed too much parameters)
    WinGetPos, WindowX, WindowY, WindowWidth, WindowHeight, ahk_id %WindowUniqueID%
    ControlGetPos, ControlX, ControlY, ControlWidth, ControlHeight, %ControlID%, ahk_id %WindowUniqueID%

    ;find upper left corner relative to screen
    StartX := WindowX + ControlX
    StartY := WindowY + ControlY

    ;show ID in upper left corner
    CoordMode, ToolTip, Screen

    ;show frame gui above AOT apps
    Gui, 2: +AlwaysOnTop

    If ChkDrawRectWin {
        ;if windows upper left corner is outside the screen
        ; it is assumed that the window is maximized and the frame is made smaller
        If ( WindowX < 0 AND WindowY < 0 ){
            WindowX += 4
            WindowY += 4
            WindowWidth -= 8
            WindowHeight -= 8
          }

        ;remove old rectangle from screen and save/buffer screen below new rectangle
        BufferAndRestoreRegion( WindowX, WindowY, WindowWidth, WindowHeight )

        ;draw rectangle frame around window
        DrawFrame( WindowX, WindowY, WindowWidth, WindowHeight, frame_t, h_brushW )

        ;show tooltip above window frame when enough space
        If ( WindowY > 22)
            WindowY -= 22

        ;Show tooltip with windows unique ID
        ToolTip, %WindowUniqueID%, WindowX, WindowY, 3
      }
    Else
        ;remove old rectangle from screen and save/buffer screen below new rectangle
        BufferAndRestoreRegion( StartX, StartY, ControlWidth, ControlHeight )

    If ChkDrawRectCtrl {
        ;draw rectangle frame around control
        DrawFrame( StartX, StartY, ControlWidth, ControlHeight, frame_t, h_brushC )

        ;show tooltip above control frame when enough space, or below
        If ( StartY > 22)
            StartY -= 22
        Else
            StartY += ControlHeight

        ;show control tooltip left of window tooltip if position identical (e.g. Windows Start Button on Taskbar)
        If (StartY = WindowY
            AND StartX < WindowX + 50)
            StartX += 50

        ;Show tooltip with controls unique ID
        ToolTip, %ControlID%, StartX, StartY, 2
      }
    ;set back ToolTip position to default
    CoordMode, ToolTip, Relative

} ;</05.01.000016>
;<05.01.000017>
Highlight(reg, delay=1500) {                                                                                	;-- Show a red rectangle outline to highlight specified region, it's useful to debug

	/*	DESCRIPTION OF FUNCTION: -- Highlight --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Show a red rectangle outline to highlight specified region, it's useful to debug
	Link              	:	-
	Author         	:	-
	Date             	:	-
	AHK-Version	:	AHK_L
	License         	:	-
	Syntax          	:	Highlight(region [, delay = 1500])
	Parameter(s)	:	reg    	- The region for highlight
	                        	delay	- Show time (milliseconds)
	Return value	:	Real string without variable(s) - "this string has real variable"
	Remark(s)    	:	SendSpiCall, SendWapiCall
	Dependencies	:	Gdip.ahk
	KeyWords    	:	Gdip, Rectangle, Gui
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Highlight("100,200,300,400")
    Highlight("100,200,300,400", 1000)
	*/

    global @reg_global
; Start gdi+
	If !pToken := Gdip_Startup()
	{
		MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
		ExitApp
	}

	StringSplit, g_coors, @reg_global, `,
	; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
	Width := g_coors3
	Height := g_coors4
    ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
	Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop

	; Show the window
	Gui, 1: Show, NA

	; Get a handle to this window we have created in order to update it later
	hwnd1 := WinExist()

	; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything
	hbm := CreateDIBSection(Width, Height)

	; Get a device context compatible with the screen
	hdc := CreateCompatibleDC()

	; Select the bitmap into the device context
	obm := SelectObject(hdc, hbm)

	; Get a pointer to the graphics of the bitmap, for use with drawing functions
	G := Gdip_GraphicsFromHDC(hdc)

	; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
	Gdip_SetSmoothingMode(G, 4)


	; Create a slightly transparent (66) blue pen (ARGB = Transparency, red, green, blue) to draw a rectangle
	; This pen is wider than the last one, with a thickness of 10
	pPen := Gdip_CreatePen(0xffff0000, 2)

	; Draw a rectangle onto the graphics of the bitmap using the pen just created
	; Draws the rectangle from coordinates (250,80) a rectangle of 300x200 and outline width of 10 (specified when creating the pen)

	StringSplit, reg_coors, reg, `,
	x := reg_coors1
	y := reg_coors2
	w := reg_coors3 - reg_coors1
	h := reg_coors4 - reg_coors2

	Gdip_DrawRectangle(G, pPen, x, y, w, h)

	; Delete the brush as it is no longer needed and wastes memory
	Gdip_DeletePen(pPen)

	; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
	; So this will position our gui at (0,0) with the Width and Height specified earlier
	UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)

	; Select the object back into the hdc
	SelectObject(hdc, obm)

	; Now the bitmap may be deleted
	DeleteObject(hbm)

	; Also the device context related to the bitmap may be deleted
	DeleteDC(hdc)

	; The graphics may now be deleted
	Gdip_DeleteGraphics(G)
	Sleep, %delay%
	Gui, 1: Show, Hide
	Gdip_Shutdown(pToken)

} ;</05.01.000017>
;<05.01.000018>
SetAlpha(hwnd, alpha) {                                                                                       	;-- set alpha to a layered window

    DllCall("UpdateLayeredWindow","uint",hwnd,"uint",0,"uint",0
        ,"uint",0,"uint",0,"uint",0,"uint",0,"uint*",alpha<<16|1<<24,"uint",2)

} ;</05.01.000018>
;<05.01.000019>
CircularText(Angle, Str, Width, Height, Font, Options){                                       	;-- given a string it will generate a bitmap of the characters drawn with a given angle between each char

	;-- Given a string it will generate a bitmap of the characters drawn with a given angle between each char, if the angle is 0 it will try to make the string fill the entire circle.
	;--https://autohotkey.com/boards/viewtopic.php?t=32179
	;--by Capn Odin 23 Mai 2017

	pBitmap := Gdip_CreateBitmap(Width, Height)

	G := Gdip_GraphicsFromImage(pBitmap)

	Gdip_SetSmoothingMode(G, 4)

	if (!Angle) {
		Angle := 360 / StrLen(Str)
	}

	for i, chr in StrSplit(Str) {
		RotateAroundCenter(G, Angle, Width, Height)
		Gdip_TextToGraphics(G, chr, Options, Font, Width, Height)
	}

	Gdip_DeleteGraphics(G)

	Return pBitmap
} ;</05.01.000019>
;<05.01.000020>
RotateAroundCenter(G, Angle, Width, Height) {                                                 	;-- GDIP rotate around center

	Gdip_TranslateWorldTransform(G, Width / 2, Height / 2)
	Gdip_RotateWorldTransform(G, Angle)
	Gdip_TranslateWorldTransform(G, - Width / 2, - Height / 2)

} ;</05.01.000020>
;<05.01.000021>
Screenshot(outfile, screen) {                                                                                 	;-- screenshot function 1

    pToken := Gdip_Startup()
    raster := 0x40000000 + 0x00CC0020 ; get layered windows

    pBitmap := Gdip_BitmapFromScreen(screen, raster)

    Gdip_SetBitmapToClipboard(pBitmap)
    Gdip_SaveBitmapToFile(pBitmap, outfile)
    Gdip_DisposeImage(pBitmap)
    Gdip_Shutdown(pToken)

    PlaceTooltip("Screenshot copied and saved.")
} ;</05.01.000021>
;<05.01.000022>
TakeScreenshot(dir) {                                                                                            	;-- screenshot function 2

    CoordMode, Mouse, Screen
    MouseGetPos, begin_x, begin_y
    DrawRectangle(true)
    SetTimer, rectangle, 10
    KeyWait, RButton

    SetTimer, rectangle, Off
    Gui, ScreenshotSelection:Cancel
    MouseGetPos, end_x, end_y

    Capture_x := Min(end_x, begin_x)
    Capture_y := Min(end_y, begin_y)
    Capture_width := Abs(end_x - begin_x)
    Capture_height := Abs(end_y - begin_y)

    area := Capture_x . "|" . Capture_y . "|" . Capture_width . "|" Capture_height ; X|Y|W|H

    FormatTime, CurrentDateTime,, yyyy-MM-ddTHH-mm-ss

    filename := dir CurrentDateTime ".png"

    Screenshot(filename,area)

return
} ;</05.01.000022>
;<05.01.000023>
CaptureWindow(hwndOwner, hwnd) {                                                                	;-- screenshot function 3

    VarSetCapacity(RECT, 16, 0)
    DllCall("GetWindowRect", "Ptr", hwnd, "Ptr", &RECT)
    width  := NumGet(RECT, 8, "Int")  - NumGet(RECT, 0, "Int")
    height := NumGet(RECT, 12, "Int") - NumGet(RECT, 4, "Int")

    hdc    := DllCall("GetDC", "Ptr", 0, "Ptr")
    hdcMem := DllCall("CreateCompatibleDC", "Ptr", hdc, "UPtr")
    hBmp   := DllCall("CreateCompatibleBitmap", "Ptr", hdc, "Int", width, "Int", height, "UPtr")
    hdcOld := DllCall("SelectObject", "Ptr", hdcMem, "Ptr", hBmp)

    DllCall("BitBlt", "Ptr", hdcMem
        , "Int", 0, "Int", 0, "Int", width, "Int", height
        , "Ptr", hdc, "Int", Numget(RECT, 0, "Int"), "Int", Numget(RECT, 4, "Int")
        , "UInt", 0x00CC0020) ; SRCCOPY

    DllCall("SelectObject", "Ptr", hdcMem, "Ptr", hdcOld)

    DllCall("OpenClipboard", "Ptr", hwndOwner) ; Clipboard owner
    DllCall("EmptyClipboard")
    DllCall("SetClipboardData", "uint", 0x2, "Ptr", hBmp) ; CF_BITMAP
    DllCall("CloseClipboard")

    DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdc)

    Return True

} ;</05.01.000023>
;<05.01.000024>
CaptureScreen(aRect = 0,  sFile = "", bCursor = false, nQuality = "") {                	;-- screenshot function 4 - orginally from CaptureScreen.ahk

	/*			DESCRIPTIONS OF FUNCTION CaptureScreen()

	CaptureScreen(aRect, sFileTo, bCursor, nQuality)

	Author             	:	RaptorX
	Link                  	:	https://github.com/RaptorX/AHK-ToolKit/blob/master/lib/sc.ahk
	Parameter        	:	1) If the optional parameter bCursor is True, captures the cursor too.
                     	        	2) If the optional parameter sFileTo is 0, set the image to Clipboard.
										 If it is omitted or "", saves to screen.bmp in the script folder,
										 otherwise to sFileTo which can be BMP/JPG/PNG/GIF/TIF.
                     	        	3) The optional parameter nQuality is applicable only when sFileTo is JPG.
										 Set it to the desired quality level of the resulting JPG, an integer between 0 - 100.
                     	        	4) If aRect is 0/1/2/3, captures the entire desktop/active window/active client area/active monitor.
                     	        	5) aRect can be comma delimited sequence of coordinates, e.g., "Left, Top,
										Right, Bottom" or "Left, Top, Right, Bottom, Width_Zoomed, Height_Zoomed".
										In this case, only that portion of the rectangle will be captured. Additionally,
										in the latter case, zoomed to the new width/height, Width_Zoomed/Height_Zoomed.
	related functions	:	can be found in the following libraries
									Unicode4Ansi          	-		CoHelper.ahk
									Ansi4Unicode          	-		CoHelper.ahk
									Zoomer                    	-		this library or ScreenCapture.ahk
	                                CreateDIBSection    	-		Gdip_all.ahk
                                    SaveHBITMAPToFile	-		this library or ScreenCapture.ahk
	                                SetClipboardData    	-		Gdip_all.ahk
									Convert                    	-		this library
	*/

	/*			EXAMPLE(s)

		CaptureScreen(0)
		CaptureScreen(1)
		CaptureScreen(2)
		CaptureScreen(3)
		CaptureScreen("100, 100, 200, 200")
		CaptureScreen("100, 100, 200, 200, 400, 400")   ; Zoomed

	*/

	If (!aRect) {
		SysGet, nL, 76
		SysGet, nT, 77
		SysGet, nW, 78
		SysGet, nH, 79
	}
	Else If (aRect = 1)
		WinGetPos, nL, nT, nW, nH, A
	Else If (aRect = 2) 	{
		WinGet, hWnd, ID, A
		VarSetCapacity(rt, 16, 0)
		DllCall("GetClientRect" , "Uint", hWnd, "Uint", &rt)
		DllCall("ClientToScreen", "Uint", hWnd, "Uint", &rt)
		nL := NumGet(rt, 0, "int")
		nT := NumGet(rt, 4, "int")
		nW := NumGet(rt, 8)
		nH := NumGet(rt,12)
	} Else If (aRect = 3) 	{
		VarSetCapacity(mi, 40, 0)
		DllCall("GetCursorPos", "int64P", pt)
		DllCall("GetMonitorInfo", "Uint", DllCall("MonitorFromPoint", "int64", pt, "Uint", 2), "Uint", NumPut(40,mi)-4)
		nL := NumGet(mi, 4, "int")
		nT := NumGet(mi, 8, "int")
		nW := NumGet(mi,12, "int") - nL
		nH := NumGet(mi,16, "int") - nT
	} Else If (isObject(aRect)) {
		nL := aRect.Left, nT := aRect.Top, nW := aRect.Right - aRect.Left, nH := aRect.Bottom - aRect.Top
		znW := aRect.ZoomW, znH := aRect.ZoomH
	} Else {
		StringSplit, rt, aRect, `,, %A_Space%%A_Tab%
		nL := rt1, nT := rt2, nW := rt3 - rt1, nH := rt4 - rt2
		znW := rt5, znH := rt6
	}

	mDC := DllCall("CreateCompatibleDC", "Uint", 0)
	hBM := CreateDIBSection(mDC, nW, nH)
	oBM := DllCall("SelectObject", "Uint", mDC, "Uint", hBM)
	hDC := DllCall("GetDC", "Uint", 0)
	DllCall("BitBlt", "Uint", mDC, "int", 0, "int", 0, "int", nW, "int", nH, "Uint", hDC, "int", nL, "int", nT, "Uint", 0x40000000 | 0x00CC0020)
	DllCall("ReleaseDC", "Uint", 0, "Uint", hDC)
	If	bCursor
		CaptureCursor(mDC, nL, nT)
	DllCall("SelectObject", "Uint", mDC, "Uint", oBM)
	DllCall("DeleteDC", "Uint", mDC)
	If	znW && znH
		hBM := Zoomer(hBM, nW, nH, znW, znH)
	If	sFile = 0
		SetClipboardData(hBM)
	Else Convert(hBM, sFile, nQuality), DllCall("DeleteObject", "Uint", hBM)

} ;</05.01.000024>
;<05.01.000025>
CaptureCursor(hDC, nL, nT) {																					;-- subfunction for CaptureScreen() - this captures the cursor

	VarSetCapacity(mi, 20, 0)
	mi := Chr(20)
	DllCall("GetCursorInfo", "Uint", &mi)
	bShow   := NumGet(mi, 4)
	hCursor := NumGet(mi, 8)
	xCursor := NumGet(mi,12)
	yCursor := NumGet(mi,16)

	VarSetCapacity(ni, 20, 0)
	DllCall("GetIconInfo", "Uint", hCursor, "Uint", &ni)
	xHotspot := NumGet(ni, 4)
	yHotspot := NumGet(ni, 8)
	hBMMask  := NumGet(ni,12)
	hBMColor := NumGet(ni,16)

	If	bShow
		DllCall("DrawIcon", "Uint", hDC, "int", xCursor - xHotspot - nL, "int", yCursor - yHotspot - nT, "Uint", hCursor)
	If	hBMMask
		DllCall("DeleteObject", "Uint", hBMMask)
	If	hBMColor
		DllCall("DeleteObject", "Uint", hBMColor)

} ;</05.01.000025>
;<05.01.000026>
Zoomer(hBM, nW, nH, znW, znH) {																			;-- subfunction for CaptureScreen() - zooms a HBitmap, depending function of CaptureScreen()

	mDC1 := DllCall("CreateCompatibleDC", "Uint", 0)
	mDC2 := DllCall("CreateCompatibleDC", "Uint", 0)
	zhBM := CreateDIBSection(mDC2, znW, znH)
	oBM1 := DllCall("SelectObject", "Uint", mDC1, "Uint",  hBM)
	oBM2 := DllCall("SelectObject", "Uint", mDC2, "Uint", zhBM)
	DllCall("SetStretchBltMode", "Uint", mDC2, "int", 4)
	DllCall("StretchBlt", "Uint", mDC2, "int", 0, "int", 0, "int", znW, "int", znH, "Uint", mDC1, "int", 0, "int", 0, "int", nW, "int", nH, "Uint", 0x00CC0020)
	DllCall("SelectObject", "Uint", mDC1, "Uint", oBM1)
	DllCall("SelectObject", "Uint", mDC2, "Uint", oBM2)
	DllCall("DeleteDC", "Uint", mDC1)
	DllCall("DeleteDC", "Uint", mDC2)
	DllCall("DeleteObject", "Uint", hBM)
	Return	zhBM

} ;</05.01.000026>
;<05.01.000027>
Convert(sFileFr = "", sFileTo = "", nQuality = "") {													;-- subfunction for CaptureScreen() - converts from one picture format to another one, depending on Gdip restriction only .bmp, .jpg, .png is possible

	/*			DESCRIPTION AND DEPENDING FUNCTIONS

			Convert(sFileFr, sFileTo, nQuality)
			Convert("C:\image.bmp", "C:\image.jpg")
			Convert("C:\image.bmp", "C:\image.jpg", 95)
			Convert(0, "C:\clip.png")   ; Save the bitmap in the clipboard to sFileTo if sFileFr is "" or 0.

			depending functions:			can be found in library
			   Unicode4Ansi	-			CoHelper.ahk
	 		   Ansi4Unicode	-			CoHelper.ahk
	  SaveHBITMAPToFile	-			this library or ScreenCapture.ahk

	*/

	If	sFileTo  =
		sFileTo := A_ScriptDir . "\screen.bmp"
	SplitPath, sFileTo, , sDirTo, sExtTo, sNameTo

	If Not	hGdiPlus := DllCall("LoadLibrary", "str", "gdiplus.dll")
		Return	sFileFr+0 ? SaveHBITMAPToFile(sFileFr, sDirTo . "\" . sNameTo . ".bmp") : ""
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "UintP", pToken, "Uint", &si, "Uint", 0)

	If	!sFileFr
	{
		DllCall("OpenClipboard", "Uint", 0)
		If	 DllCall("IsClipboardFormatAvailable", "Uint", 2) && (hBM:=DllCall("GetClipboardData", "Uint", 2))
		DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Uint", hBM, "Uint", 0, "UintP", pImage)
		DllCall("CloseClipboard")
	}
	Else If	sFileFr Is Integer
		DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Uint", sFileFr, "Uint", 0, "UintP", pImage)
	Else	DllCall("gdiplus\GdipLoadImageFromFile", a_isunicode ? "Str" : "Uint", a_isunicode ? sFileFr : Unicode4Ansi(wFileFr,sFileFr), "UintP", pImage)

	DllCall("gdiplus\GdipGetImageEncodersSize", "UintP", nCount, "UintP", nSize)
	VarSetCapacity(ci,nSize,0)
	DllCall("gdiplus\GdipGetImageEncoders", "Uint", nCount, "Uint", nSize, "Uint", &ci)
	Loop, %	nCount
		If	InStr(a_isunicode ? StrGet(NumGet(ci,76*(A_Index-1)+44), "UTF-16") : Ansi4Unicode(NumGet(ci,76*(A_Index-1)+44)), "." . sExtTo)
		{
			pCodec := &ci+76*(A_Index-1)
			Break
		}
	If	InStr(".JPG.JPEG.JPE.JFIF", "." . sExtTo) && nQuality<>"" && pImage && pCodec
	{
	DllCall("gdiplus\GdipGetEncoderParameterListSize", "Uint", pImage, "Uint", pCodec, "UintP", nSize)
	VarSetCapacity(pi,nSize,0)
	DllCall("gdiplus\GdipGetEncoderParameterList", "Uint", pImage, "Uint", pCodec, "Uint", nSize, "Uint", &pi)
	Loop, %	NumGet(pi)
		If	NumGet(pi,28*(A_Index-1)+20)=1 && NumGet(pi,28*(A_Index-1)+24)=6
		{
			pParam := &pi+28*(A_Index-1)
			NumPut(nQuality,NumGet(NumPut(4,NumPut(1,pParam+0)+20)))
			Break
		}
	}

	If	pImage
		pCodec	? DllCall("gdiplus\GdipSaveImageToFile", "Uint", pImage, a_isunicode ? "Str" : "Uint", a_isunicode ? sFileTo : Unicode4Ansi(wFileTo,sFileTo), "Uint", pCodec, "Uint", pParam) : DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Uint", pImage, "UintP", hBitmap, "Uint", 0) . SetClipboardData(hBitmap), DllCall("gdiplus\GdipDisposeImage", "Uint", pImage)

	DllCall("gdiplus\GdiplusShutdown" , "Uint", pToken)
	DllCall("FreeLibrary", "Uint", hGdiPlus)
} ;</05.01.000027>
;<05.01.000028>
SaveHBITMAPToFile(hBitmap, sFile) {																		;-- subfunction for CaptureScreen() - saves a HBitmap to a file

	DllCall("GetObject", "Uint", hBitmap, "int", VarSetCapacity(oi,84,0), "Uint", &oi)
	hFile:=	DllCall("CreateFile", "Uint", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 0x4D42|14+40+NumGet(oi,44)<<16, "Uint", 6, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", &oi+24, "Uint", 40, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", NumGet(oi,20), "Uint", NumGet(oi,44), "UintP", 0, "Uint", 0)
	DllCall("CloseHandle", "Uint", hFile)

} ;</05.01.000028>
;<05.01.000029>
RGBRange(x, y=0, c=0, delim=",") {                                                                     	;-- returns an array for a color transition from x to y

	; RGBRange by [VxE]

	oif := A_FormatInteger
	SetFormat, Integer, H

	dr:=(y>>16&255)-(r:=x>>16&255)
	dg:=(y>>8&255)-(g:=x>>8&255)
	db:=(y&255)-(b:=x&255)
	d := sqrt(dr**2 + dg**2 + db**2)
	v := Floor(d/c)

	IfLessOrEqual, c, 0, SetEnv, c, % d/( v := c<-3 ? -1-Ceil(c) : 2 )
			s := c/d

	cr:=sqrt(d**2-dg**2-db**2)*s*((dr>0)*2-1)
	cg:=sqrt(d**2-dr**2-db**2)*s*((dg>0)*2-1)
	cb:=sqrt(d**2-dg**2-dr**2)*s*((db>0)*2-1)

	Loop %v% {
		u := SubStr("000000" SubStr( "" . ((Round(r+cr*A_Index)&255)<<16) | ((Round(g+cg*A_Index)&255)<<8) | (Round(b+cb*A_Index)&255), 3) ,-5)
		StringUpper, u, u
		x .= delim "0x" u
	}

	SetFormat, Integer, %oif%
	return x
} ;</05.01.000029>
;<05.01.000030>
getSelectionCoords(ByRef x_start, ByRef x_end, ByRef y_start, ByRef y_end) {    	;-- creates a click-and-drag selection box to specify an area

	/*			EXAMPLE

				;hotkey to activate OCR
				!q:: ;press ALT Q
				getSelectionCoords(x_start, x_end, y_start, y_end)
				MsgBox, In area :: x_start: %x_start%, y_start: %y_start% --> x_end: %x_end%, y_end: %y_end%
				return

			Esc:: ExitApp

	*/

	;Mask Screen
	Gui, Color, FFFFFF
	Gui +LastFound
	WinSet, Transparent, 50
	Gui, -Caption
	Gui, +AlwaysOnTop
	Gui, Show, x0 y0 h%A_ScreenHeight% w%A_ScreenWidth%,"AutoHotkeySnapshotApp"

	;Drag Mouse
	CoordMode, Mouse, Screen
	CoordMode, Tooltip, Screen
	WinGet, hw_frame_m,ID,"AutoHotkeySnapshotApp"
	hdc_frame_m := DllCall( "GetDC", "uint", hw_frame_m)
	KeyWait, LButton, D
	MouseGetPos, scan_x_start, scan_y_start
	Loop
	{
		Sleep, 10
		KeyIsDown := GetKeyState("LButton")
		if (KeyIsDown = 1)
		{
			MouseGetPos, scan_x, scan_y
			DllCall( "gdi32.dll\Rectangle", "uint", hdc_frame_m, "int", 0,"int",0,"int", A_ScreenWidth,"int",A_ScreenWidth)
			DllCall( "gdi32.dll\Rectangle", "uint", hdc_frame_m, "int", scan_x_start,"int",scan_y_start,"int", scan_x,"int",scan_y)
		} else {
			break
		}
	}

	;KeyWait, LButton, U
	MouseGetPos, scan_x_end, scan_y_end
	Gui Destroy

	if (scan_x_start < scan_x_end)
	{
		x_start := scan_x_start
		x_end := scan_x_end
	} else {
		x_start := scan_x_end
		x_end := scan_x_start
	}

	if (scan_y_start < scan_y_end)
	{
		y_start := scan_y_start
		y_end := scan_y_end
	} else {
		y_start := scan_y_end
		y_end := scan_y_start
	}

} ;</05.01.000030>
;<05.01.000031>
GetRange(ByRef x="",ByRef y="",ByRef w="",ByRef h="") {                                  	;-- another good screen area selection function

	 ;Last edited by feiyue on 07 Jun 2018, 16:51, edited

	 SetBatchLines, -1

	  ; Save the initial state and set the current state
	  cmm:=A_CoordModeMouse
	  CoordMode, Mouse, Screen

	  ; Create canvas GUI
	  nW:=A_ScreenWidth, nH:=A_ScreenHeight
	  Gui, Canvas:New, +AlWaysOnTop +ToolWindow -Caption
	  Gui, Canvas:Add, Picture, x0 y0 w%nW% h%nH% +0xE HwndPicID

	  ; Create selection range GUI
	  Gui, Range:New, +LastFound +AlWaysOnTop -Caption +Border
		+OwnerCanvas +HwndRangeID
	  WinSet, Transparent, 50
	  Gui, Range:Color, Yellow

	  ; Screenshots to the memory image and sent to
	  ; the picture control of the canvas window.
	  Ptr:=A_PtrSize ? "UPtr":"UInt", int:="int"
	  hDC:=DllCall("GetDC", Ptr,0, Ptr)
	  mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
	  hBM:=DllCall("CreateCompatibleBitmap", Ptr,hDC, int,nW, int,nH, Ptr)
	  oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
	  DllCall("BitBlt", Ptr,mDC, int,0, int,0, int,nW, int,nH
		, Ptr,hDC, int,0, int,0, int,0x00CC0020|0x40000000)
	  DllCall("ReleaseDC", Ptr,0, Ptr,hDC)
	  ;---------------------
	  SendMessage, 0x172, 0, hBM,, ahk_id %PicID%
	  if ( E:=ErrorLevel )
		DllCall("DeleteObject", Ptr,E)
	  ;---------------------
	  DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
	  DllCall("DeleteDC", Ptr,mDC)

	  ; Display the canvas window and start to wait for the selection range
	  Gui, Canvas:Show, NA x0 y0 w%nW% h%nH%

	  ; Prompt to hold down the LButton key
	  ListLines, Off

	  oldx:=oldy:=""
	  Loop {
		Sleep, 10
		MouseGetPos, x, y
		if (oldx=x and oldy=y)
		  Continue
		oldx:=x, oldy:=y
		;--------------------
		ToolTip, Please hold down LButton key to select a range
	  }
	  Until GetkeyState("LButton","P")

	  ; Prompt to release the LButton key
	  x1:=x, y1:=y, oldx:=oldy:=""
	  Loop {
		Sleep, 10
		MouseGetPos, x, y
		if (oldx=x and oldy=y)
		  Continue
		oldx:=x, oldy:=y
		;--------------------
		w:=Abs(x1-x), h:=Abs(y1-y)
		x:=(x1+x-w)//2, y:=(y1+y-h)//2
		Gui, Range:Show, NA x%x% y%y% w%w% h%h%
		ToolTip, Please drag the mouse and release the LButton key
	  }
	  Until !GetkeyState("LButton","P")

	  ; Prompt to click the RButton key to determine the range
	  oldx:=oldy:=""
	  Loop {
		Sleep, 10
		MouseGetPos, x, y, id
		if (id=RangeID) and GetkeyState("LButton","P")
		{
		  WinGetPos, x1, y1,,, ahk_id %RangeID%
		  Loop {
			Sleep, 100
			MouseGetPos, x2, y2
			Gui, Range:Show, % "NA x" x1+x2-x " y" y1+y2-y
		  }
		  Until !GetkeyState("LButton","P")
		}
		if (oldx=x and oldy=y)
		  Continue
		oldx:=x, oldy:=y
		;--------------------
		ToolTip, Please click the RButton key to determine the scope`,`n
		and use the LButton key can adjust the scope
	  }
	  Until GetkeyState("RButton","P")
	  KeyWait, RButton
	  ToolTip
	  ListLines, On

	  ; Clean the canvas and selection range GUI
	  WinGetPos, x, y, w, h, ahk_id %RangeID%
	  Gui, Range:Destroy
	  Gui, Canvas:Destroy

	  ; Clean the memory image and restore the initial state
	  DllCall("DeleteObject", Ptr,hBM)
	  CoordMode, Mouse, %cmm%

} ;</05.01.000031>
;<05.01.000032>
FloodFill(x, y, target, replacement, mode=1, key="") {                                        	;-- filling an area using color banks

	;function is from https://rosettacode.org/wiki/Bitmap/Flood_fill#AutoHotkey

	/*				Example

		SetBatchLines, -1
		CoordMode, Mouse
		CoordMode, Pixel
		CapsLock::
		KeyWait, CapsLock
		MouseGetPos, X, Y
		PixelGetColor, color, X, Y
		FloodFill(x, y, color, 0x000000, 1, "CapsLock")
		MsgBox Done!
		Return

	*/

   If GetKeyState(key, "P")
      Return
   PixelGetColor, color, x, y
   If (color <> target || color = replacement || target = replacement)
      Return
   VarSetCapacity(Rect, 16, 0)
   NumPut(x, Rect, 0)
   NumPut(y, Rect, 4)
   NumPut(x+1, Rect, 8)
   NumPut(y+1, Rect, 12)
   hDC := DllCall("GetDC", UInt, 0)
   hBrush := DllCall("CreateSolidBrush", UInt, replacement);
   DllCall("FillRect", UInt, hDC, Str, Rect, UInt, hBrush)
   DllCall("ReleaseDC", UInt, 0, UInt, hDC)
   DllCall("DeleteObject", UInt, hBrush)
   FloodFill(x+1, y, target, replacement, mode, key)
   FloodFill(x-1, y, target, replacement, mode, key)
   FloodFill(x, y+1, target, replacement, mode, key)
   FloodFill(x, y-1, target, replacement, mode, key)
   If (mode = 2 || mode = 4)
      FloodFill(x, y, target, replacement, mode, key)
   If (Mode = 3 || mode = 4)
   {
      FloodFill(x+1, y+1, target, replacement, key)
      FloodFill(x-1, y+1, target, replacement, key)
      FloodFill(x+1, y-1, target, replacement, key)
      FloodFill(x-1, y-1, target, replacement, key)
   }

} ;</05.01.000032>
;<05.01.000033>
CreateBMPGradient(File, RGB1, RGB2, Vertical=1) {                                            	;-- Horizontal/Vertical gradient

	; SKAN: http://www.autohotkey.com/forum/viewtopic.php?p=61081#61081

	; Left/Bottom -> Right/Top color, File is overwritten
	   If Vertical
		 H:="424d3e000000000000003600000028000000010000000200000001001800000000000800000000000000000000000000000000000000"
		   . BGR(RGB1) "00" BGR(RGB2) "00"
	   Else
		 H:="424d3e000000000000003600000028000000020000000100000001001800000000000800000000000000000000000000000000000000"
		   . BGR(RGB1) BGR(RGB2) "0000"

	   Handle:= DllCall("CreateFile",Str,file,Uint,0x40000000,Uint,0,UInt,0,UInt,4,Uint,0,UInt,0)

	   Loop 62 {
		 Hex := "0x" SubStr(H,2*A_Index-1,2)
		 DllCall("WriteFile", UInt,Handle, UCharP,Hex, UInt,1, UInt,0, UInt,0)
		}

	   DllCall("CloseHandle", "Uint", Handle)

} ;</05.01.000033>
;<05.01.000034>
BGR(RGB) {																									        	;-- BGR() subfunction from CreateBMPGradient()

	RGB = 00000%RGB%
		Return SubStr(RGB,-1) . SubStr(RGB,-3,2) . SubStr(RGB,-5,2)

} ;</05.01.000034>
;<05.01.000035>
CreatePatternBrushFrom(hbm, x, y, w, h) {                                                          	;-- as it says

	;found on https://autohotkey.com/board/topic/20588-adding-pictures-to-controls-eg-as-background/page-3

    hbm1 := DllCall("CopyImage","uint",hbm,"uint",0,"int",0,"int",0,"uint",0x2000)

    VarSetCapacity(dib,84,0)
    DllCall("GetObject","uint",hbm1,"int",84,"uint",&dib)
    NumPut(h,NumPut(w,dib,28))
    hbm2 := DllCall("CreateDIBSection","uint",0,"uint",&dib+24,"uint",0,"uint*",0,"uint",0,"uint",0)

    Loop, 2 {
        hdc%A_Index% := DllCall("CreateCompatibleDC","uint",0)
        obm%A_Index% := DllCall("SelectObject","uint",hdc%A_index%,"uint",hbm%A_Index%)
    }

    DllCall("BitBlt"
        ,"uint",hdc2,"int",0,"int",0,"int",w,"int",h    ; destination
        ,"uint",hdc1,"int",x,"int",y                    ; source
        ,"uint",0xCC0020)                               ; operation = SRCCOPY

    Loop, 2 {
        DllCall("SelectObject","uint",hdc%A_Index%,"uint",obm%A_Index%)
        DllCall("DeleteDC","uint",hdc%A_Index%)
    }

    hbr := DllCall("CreatePatternBrush","uint",hbm2)
    DllCall("DeleteObject","uint",hbm2)
    DllCall("DeleteObject","uint",hbm1)
    return hbr
} ;</05.01.000035>
;<05.01.000036>
ResConImg(OriginalFile, NewWidth:="", NewHeight:="", NewName:="",          	;-- Resize and convert images. png, bmp, jpg, tiff, or gif
NewExt:="", NewDir:="", PreserveAspectRatio:=true, BitDepth:=24) {

    /*  ResConImg
         *    By kon
         *    Updated November 2, 2015
         *    http://ahkscript.org/boards/viewtopic.php?f=6&t=2505
         *
         *  Resize and convert images. png, bmp, jpg, tiff, or gif.
         *
         *  Requires Gdip.ahk in your Lib folder or #Included. Gdip.ahk is available at:
         *      http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/
         *
         *  ResConImg( OriginalFile             ;- Path of the file to convert
         *           , NewWidth                 ;- Pixels (Blank = Original Width)
         *           , NewHeight                ;- Pixels (Blank = Original Height)
         *           , NewName                  ;- New file name (Blank = "Resized_" . OriginalFileName)
         *           , NewExt                   ;- New file extension can be png, bmp, jpg, tiff, or gif (Blank = Original extension)
         *           , NewDir                   ;- New directory (Blank = Original directory)
         *           , PreserveAspectRatio      ;- True/false (Blank = true)
         *           , BitDepth)                ;- 24/32 only applicable to bmp file extension (Blank = 24)
     */
    SplitPath, OriginalFile, SplitFileName, SplitDir, SplitExtension, SplitNameNoExt, SplitDrive
    pBitmapFile := Gdip_CreateBitmapFromFile(OriginalFile)                  ; Get the bitmap of the original file
    Width := Gdip_GetImageWidth(pBitmapFile)                                ; Original width
    Height := Gdip_GetImageHeight(pBitmapFile)                              ; Original height
    NewWidth := NewWidth ? NewWidth : Width
    NewHeight := NewHeight ? NewHeight : Height
    NewExt := NewExt ? NewExt : SplitExtension
    if SubStr(NewExt, 1, 1) != "."                                          ; Add the "." to the extension if required
        NewExt := "." NewExt
    NewPath := ((NewDir != "") ? NewDir : SplitDir)                         ; NewPath := Directory
            . "\" ((NewName != "") ? NewName : "Resized_" SplitNameNoExt)       ; \File name
            . NewExt                                                            ; .Extension
    if (PreserveAspectRatio) {                                              ; Recalcultate NewWidth/NewHeight if required
        if ((r1 := Width / NewWidth) > (r2 := Height / NewHeight))          ; NewWidth/NewHeight will be treated as max width/height
            NewHeight := Height / r1
        else
            NewWidth := Width / r2
    }
    pBitmap := Gdip_CreateBitmap(NewWidth, NewHeight                        ; Create a new bitmap
    , (SubStr(NewExt, -2) = "bmp" && BitDepth = 24) ? 0x21808 : 0x26200A)   ; .bmp files use a bit depth of 24 by default
    G := Gdip_GraphicsFromImage(pBitmap)                                    ; Get a pointer to the graphics of the bitmap
    Gdip_SetSmoothingMode(G, 4)                                             ; Quality settings
    Gdip_SetInterpolationMode(G, 7)
    Gdip_DrawImage(G, pBitmapFile, 0, 0, NewWidth, NewHeight)               ; Draw the original image onto the new bitmap
    Gdip_DisposeImage(pBitmapFile)                                          ; Delete the bitmap of the original image
    Gdip_SaveBitmapToFile(pBitmap, NewPath)                                 ; Save the new bitmap to file
    Gdip_DisposeImage(pBitmap)                                              ; Delete the new bitmap
    Gdip_DeleteGraphics(G)                                                  ; The graphics may now be deleted
} ;</05.01.000036>
;<05.01.000037>
CreateCircleProgress(diameter:=50,thickness:=5,color:=0x99009933,               	;-- very nice to see functions for a circle progress
xPos:="center",yPos:="center",guiId:=1) {

	; from Learning one
	; https://autohotkey.com/boards/viewtopic.php?t=6947

	/* Example scripts

		############## Example1

		#Include, Gdip.ahk ; http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/
		;#Include progressCircle.ahk

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

		circleObj := CreateCircleProgress(50,5)
		Loop, 100 {
			UpdateCircleProgress(circleObj,A_Index)
			Sleep, 10
		}
		DestroyCircleProgress(circleObj)

		Gdip_Shutdown(pToken)
		ExitApp

		############## Example2

		#Include, Gdip.ahk ; http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/
	;#Include progressCircle.ahk

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

	DownloadFile("http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe", "firefox_setup.exe")

	Gdip_Shutdown(pToken)
	ExitApp

	DownloadFile(UrlToFile, SaveFileAs, Overwrite := True, UseProgressBar := True) {
		;Check if the file already exists and if we must not overwrite it
		  If (!Overwrite && FileExist(SaveFileAs))
			  Return
		;Check if the user wants a progressbar
		  If (UseProgressBar) {
			  ;Initialize the WinHttpRequest Object
				WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
			  ;Download the headers
				WebRequest.Open("HEAD", UrlToFile)
				WebRequest.Send()
			  ;Store the header which holds the file size in a variable:
				FinalSize := WebRequest.GetResponseHeader("Content-Length")
			  ;Create the progressbar and the timer
				Progress, H80, , Downloading..., %UrlToFile%
				circleObj := CreateCircleProgress(450,60)
				SetTimer, __UpdateProgressBar, 100
		  }
		;Download the file
		  UrlDownloadToFile, %UrlToFile%, %SaveFileAs%
		;Remove the timer and the progressbar because the download has finished
		  If (UseProgressBar) {
			  Progress, Off
			  SetTimer, __UpdateProgressBar, Off
			  DestroyCircleProgress(circleObj)
		  }
		Return

		;The label that updates the progressbar
		  __UpdateProgressBar:
			  ;Get the current filesize and tick
				CurrentSize := FileOpen(SaveFileAs, "r").Length ;FileGetSize wouldn't return reliable results
				CurrentSizeTick := A_TickCount
			  ;Calculate the downloadspeed
				Speed := Round((CurrentSize/1024-LastSize/1024)/((CurrentSizeTick-LastSizeTick)/1000)) . " Kb/s"
			  ;Save the current filesize and tick for the next time
				LastSizeTick := CurrentSizeTick
				LastSize := FileOpen(SaveFileAs, "r").Length
			  ;Calculate percent done
				PercentDone := Round(CurrentSize/FinalSize*100)
			  ;Update the ProgressBar
				Progress, %PercentDone%, %PercentDone%`% Done, Downloading...  (%Speed%), Downloading %SaveFileAs% (%PercentDone%`%)
				UpdateCircleProgress(circleObj,percentDone)
		  Return
		}

	*/

    width := height := diameter+thickness*2
    xPos := (xPos=="center" ? A_ScreenWidth/2-diameter/2-thickness : xPos)
    yPos := (yPos=="center" ? A_ScreenHeight/2-diameter/2-thickness : yPos)
    Gui, %guiId%: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
    Gui, %guiId%: Show, NA

    hwnd := WinExist()
    hbm := CreateDIBSection(width, height)
    hdc := CreateCompatibleDC()
    obm := SelectObject(hdc, hbm)
    G := Gdip_GraphicsFromHDC(hdc)
    Gdip_SetSmoothingMode(G, 4)

    pen:=Gdip_CreatePen(color, thickness)
    Gdip_SetCompositingMode(G, 1)
    Return {hwnd:hwnd, hdc:hdc, obm:obm, hbm:hbm, pen:pen, G:G, diameter: diameter, thickness:thickness, xPos:xPos, yPos:yPos, width:width, height:height}
} ;</05.01.000037>
;<05.01.000038>
UpdateCircleProgress(circleObj,percent) {                                                          	;-- subfunction for CreateCircleProgress
    Gdip_Drawarc(circleObj.G, circleObj.pen, circleObj.thickness, circleObj.thickness, circleObj.diameter, circleObj.diameter, 270, 360/100*percent)
    UpdateLayeredWindow(circleObj.hwnd, circleObj.hdc, circleObj.xPos, circleObj.yPos, circleObj.width, circleObj.height)
} ;</05.01.000038>
;<05.01.000039>
DestroyCircleProgress(circleObj) {                                                                       	;-- subfunction for CreateCircleProgress
    Gui % circleObj.hwnd ":Destroy"
    SelectObject(circleObj.hdc, circleObj.obm)
    DeleteObject(circleObj.hbm)
    DeleteDC(circleObj.hdc)
    Gdip_DeleteGraphics(circleObj.G)
} ;</05.01.000039>
;<05.01.000040>
RGBrightnessToHex(r := 0, g := 0, b := 0, brightness := 1) {                               	;-- transform rbg (with brightness) values to hex
	;https://autohotkey.com/boards/viewtopic.php?f=6&p=191294
	return (b * brightness << 16) + (g * brightness << 8) + (r * brightness)
} ;</05.01.000040>
;<05.01.000041>
GetHueColorFromFraction(hue, brightness := 1) {                                              	;-- get hue color from fraction. example: h(0) is red, h(1/3) is green and h(2/3) is blue

	;https://autohotkey.com/boards/viewtopic.php?f=6&p=191294
	if (hue<0,hue:=abs(mod(hue, 1)))
		hue:=1-hue
	Loop 3
		col+=max(min(-8*abs(mod(hue+A_Index/3-0.5,1)-0.5)+2.5,1),0)*255*brightness<<16-(A_Index-1)*8
	return col
} ;</05.01.000041>
;<05.01.000042>
SaveHBITMAPToFile(hBitmap, sFile) {                                                                  	;-- saves the hBitmap to a file
	DllCall("GetObject", "Uint", hBitmap, "int", VarSetCapacity(oi,84,0), "Uint", &oi)
	hFile:=	DllCall("CreateFile", "Uint", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 0x4D42|14+40+NumGet(oi,44)<<16, "Uint", 6, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", &oi+24, "Uint", 40, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", NumGet(oi,20), "Uint", NumGet(oi,44), "UintP", 0, "Uint", 0)
	DllCall("CloseHandle", "Uint", hFile)
} ;</05.01.000042>
;<05.01.000043>
DrawRotatePictureOnGraphics(G,pBitmap,x,y,size,angle) {                                 	;-- rotate a pBitmap
	;X and Y describe the new center of the model  - https://autohotkey.com/board/topic/95329-tower-defense-game-in-ahk/
dist:=(((size/2)**2)*2)**0.5
VarSetCapacity(Points,24,0)
numput(round(sin((45+angle)*0.01745329252)*dist+x),Points,0,"float")
numput(round(cos((45+angle)*0.01745329252)*dist+y),Points,4,"float")
numput(round(sin((135+angle)*0.01745329252)*dist+x),Points,8,"float")
numput(round(cos((135+angle)*0.01745329252)*dist+y),Points,12,"float")
numput(round(sin((315+angle)*0.01745329252)*dist+x),Points,16,"float")
numput(round(cos((315+angle)*0.01745329252)*dist+y),Points,20,"float")
;Msgbox %  "x1:" numget(Points,0,"float") "y1:" numget(Points,4,"float") "x2:" numget(Points,8,"float")"y2:" numget(Points,12,"float") "x3:" numget(Points,16,"float") "y3:" numget(Points,20,"float")
DllCall("gdiplus\GdipDrawImagePointsRect", "uint", G, "uint", pBitmap
	, "ptr", &Points, "int", 3, "float", 0, "float", 0
	, "float", size, "float", size
	, "int", 2, "uint", 0, "uint", 0, "uint", 0)
} ;</05.01.000043>
;<05.01.000044>
CopyBitmapOnGraphic(pGraphics,pBitmap,w,h) {                                               	;-- copy a pBitmap of a specific width and height to the Gdip graphics container (pGraphics)
return DllCall("gdiplus\GdipDrawImageRectRect", "uint", pGraphics, "uint", pBitmap
	, "float", 0, "float", 0, "float", w, "float", h
	, "float", 0, "float", 0, "float", w, "float", h
	, "int", 2, "uint", 0, "uint", 0, "uint", 0)
} ;</05.01.000044>
;<05.01.000045>
GDI_GrayscaleBitmap( hBM ) {                                                                            	;-- Converts GDI bitmap to 256 color GreyScale

	; www.autohotkey.com/community/viewtopic.php?t=88996    By SKAN,  Created : 19-Jul-2012

	Static RGBQUAD256

	If ! VarSetCapacity( RGBQUAD256 ) {
		VarSetCapacity( RGBQUAD256, 256*4, 0 ),  Color := 0
		Loop 255
			Numput( Color := Color + 0x010101, RGBQUAD256, A_Index*4, "UInt" )
	}

	VarSetCapacity( BM,24,0 ),  DllCall( "GetObject", UInt,hBM, UInt,24, UInt,&BM )
	W := NumGet( BM,4 ), H := NumGet( BM,8 )

	hdcSrc := DllCall( "CreateCompatibleDC", UInt,0 )
	hbmPrS := DllCall( "SelectObject", UInt,hdcSrc, UInt,hBM )

	dBM := DllCall( "CopyImage", UInt
				, DllCall( "CreateBitmap", Int,2, Int,2, UInt,1, UInt,8, UInt,0 )
				, UInt,0, Int,W, Int,H, UInt,0x2008, UInt )

	hdcDst  := DllCall( "CreateCompatibleDC", UInt,0 )
	hbmPrD  := DllCall( "SelectObject", UInt,hdcDst, UInt,dBM )
	DllCall( "SetDIBColorTable", UInt,hdcDst, UInt,0, UInt,256, UInt,&RGBQUAD256 )

	DllCall( "BitBlt", UInt,hdcDst, Int,0, Int,0, Int,W, Int,H
                  , UInt,hdcSrc, Int,0, Int,0, UInt,0x00CC0020 )

	DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrS )
	DllCall( "DeleteDC",     UInt,hdcSrc )
	DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrD )
	DllCall( "DeleteDC",     UInt,hdcDst )

Return dBM
} ;</05.01.000045>
;<05.01.000046>
Convert_BlackWhite(InputImage, OutputImage) {                                              	;--Convert exist imagefile to black&white , it uses machine code

	/*
			; Best speed
			MCode(blackwhite, "518B4424188B4C24149983E20303C2C1F80285C90F8E820000008B542"
			. "40C535503C05603C0578B7C24208944241089542428894C242485FF7E"
			. "4C8B7424182B74241C8B04168BD8C1FB108BE8C1FD0881E3FF0000008"
			. "1E5FF0000008BC803DD25FF00000003D881E1000000FF81FB7E0100007"
			. "C0681C1FFFFFF00890A83C2044F75C08B7C24208B54242803542410FF4C"
			. "242489542428759E5F5E5D5B33C059C3")

			; Smallest size
			MCode(blackwhite, "558BEC8B45188B4D149983E20383EC0C03C285C97E7753568B75"
			. "0C83E0FC578945F4897514894DFCBAFF0000008B4D1085C97E488"
			. "B45082B450C894D188945F8EB038B45F88B04308BF8C1FF108BD8C"
			. "1FB0823FA23DA8BC803FB23C203F881E1000000FF81FF7E0100007C0"
			. "681C1FFFFFF00890E83C604FF4D1875C68B75140375F4FF4DFC89751"
			. "475A35F5E5B33C0C9C3")
	*/

    global blackwhite
    SetBatchLines, -1
    If !pToken := Gdip_Startup()
        {
 	   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
 	   ExitApp
        }
    InputFile = %InputImage%
    OutputFile = %OutputImage%
    pBitmap := Gdip_CreateBitmapFromFile(InputFile)

    MCode(blackwhite, "518B4424188B4C24149983E20303C2C1F80285C90F8E820000008B54240C535503C05603C0578B7C24208944241089542428894C242"
    . "485FF7E4C8B7424182B74241C8B04168BD8C1FB108BE8C1FD0881E3FF00000081E5FF0000008BC803DD25FF00000003D881E1000000FF81FB7E010000"
    . "7C0681C1FFFFFF00890A83C2044F75C08B7C24208B54242803542410FF4C242489542428759E5F5E5D5B33C059C3")
    ;Get the width and height of the picture, this never changes
    Width := Gdip_GetImageWidth(pBitmap)*2, Height := Gdip_GetImageHeight(pBitmap)
    ;Create a blank bitmap to store the new image in
    pBitmapOut := Gdip_CreateBitmap(Width//2, Height)
    ;Some more good stuff
    hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
    G := Gdip_GraphicsFromHDC(hdc)
    Gdip_DrawImage(G, pBitmap, 0, 0, Width, Height, 0, 0, Width, Height)
    BlackWhite(pBitmap, pBitmapOut, Width//2, Height)
    Gdip_DrawImage(G, pBitmapOut, Width//2, 0, Width, Height, 0, 0, Width, Height)
    Gdip_SaveBitmapToFile(pBitmapOut, OutputFile)
    Gdip_DisposeImage(pBitmapOut), Gdip_DisposeImage(pBitmap)
    SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
    Gdip_DeleteGraphics(G)
    Gdip_Shutdown(pToken)


    return
} ;</05.01.000046>
;<05.01.000047>
 BlackWhite(pBitmap, ByRef pBitmapOut, Width, Height)       {                           	;-- sub from Convert_BlackWhite
           global blackwhite
           E1 := Gdip_LockBits(pBitmap, 0, 0, Width, Height, Stride1, Scan01, BitmapData1)
           E2 := Gdip_LockBits(pBitmapOut, 0, 0, Width, Height, Stride2, Scan02, BitmapData2)
           R := DllCall(&blackwhite, "uint", Scan01, "uint", Scan02, "int", Width, "int", Height, "int", Stride1)
           Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapOut, BitmapData2)
           return (R)
        } ;</05.01.000047>
;<05.01.000048>
getHBMinfo( hBM ) {                                                                                           	;--
Local SzBITMAP := ( A_PtrSize = 8 ? 32 : 24 ),  BITMAP := VarSetCapacity( BITMAP, SzBITMAP )
  If DllCall( "GetObject", "Ptr",hBM, "Int",SzBITMAP, "Ptr",&BITMAP )
    Return {  Width:      Numget( BITMAP, 4, "UInt"  ),  Height:     Numget( BITMAP, 8, "UInt"  )
           ,  WidthBytes: Numget( BITMAP,12, "UInt"  ),  Planes:     Numget( BITMAP,16, "UShort")
           ,  BitsPixel:  Numget( BITMAP,18, "UShort"),  bmBits:     Numget( BITMAP,20, "UInt"  ) }
} ;</05.01.000048>
;<05.01.000049>
CreateDIB( PixelData, W, H, ResizeW := 0, ResizeH := 0, Gradient := 1  ) {          	;-- a wonderfull function by SKAN to draw tiled backgrounds (like chess pattern) to a gui, it can also draw gradients
		/*    	DESCRIPTION of function CreateDIB
			 ==================================================================================================================================
			 Function:					draw tiled backgrounds (like chess pattern) to a gui, it can also draw gradients
			 Author:                	SKAN, CD: 01-Apr-2014 MD: 05-May-2014
			 Parameters:			AddrOrName  -  host/domain name or IPv4 address (xxx.xxx.xxx.xxx).
				                        	ResultArray -  optional array to retrieve multiple answers.
				                        	CNAME       -  optional variable to retrieve the 'canonical name' (CNAME) returned from DNS for host/domain name queries.
			 Return values:        	On success: First returned address or name.
				                        	On failure: an empty string, ErrorLevel is set to the DNS error code.
			 Link:    					http://ahkscript.org/boards/viewtopic.php?t=3203

			 ==================================================================================================================================
	*/

	/*    	EXAMPLE(s)

			#SingleInstance, Force

			PixelData=
			( LTrim Join|
			  FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000
			  000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF
			  FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000
			  000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF
			  FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000
			  000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF
			  FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000
			  000000|FFFFFF|000000|FFFFFF|000000|FFFFFF|000000|FFFFFF
			)
			hBM := CreateDIB( PixelData, 8, 8 )

			Gui, Margin, 0, 0
			Gui, Add, Picture, w640 h640 0x4E hwndcHwnd ; SS_REALSIZECONTROL = 0x40 | SS_BITMAP = 0xE
			DllCall( "SendMessage", "Ptr",cHwnd, "UInt",0x172, "Ptr",0, "Ptr",hBM ) ; STM_SETIMAGE = 0x172
			Gui, Show,, CreateDIB() Demo

	*/

		Static LR_Flag1 := 0x2008 ; LR_CREATEDIBSECTION := 0x2000 | LR_COPYDELETEORG := 8
			,  LR_Flag2 := 0x200C ; LR_CREATEDIBSECTION := 0x2000 | LR_COPYDELETEORG := 8 | LR_COPYRETURNORG := 4
			,  LR_Flag3 := 0x0008 ; LR_COPYDELETEORG := 8
		WB := Ceil( ( W * 3 ) / 2 ) * 2,  VarSetCapacity( BMBITS, WB * H + 1, 0 ),  P := &BMBITS
		Loop, Parse, PixelData, |
		P := Numput( "0x" A_LoopField, P+0, 0, "UInt" ) - ( W & 1 and Mod( A_Index * 3, W * 3 ) = 0 ? 0 : 1 )
		hBM := DllCall( "CreateBitmap", "Int",W, "Int",H, "UInt",1, "UInt",24, "Ptr",0, "Ptr" )
		hBM := DllCall( "CopyImage", "Ptr",hBM, "UInt",0, "Int",0, "Int",0, "UInt",LR_Flag1, "Ptr" )
		DllCall( "SetBitmapBits", "Ptr",hBM, "UInt",WB * H, "Ptr",&BMBITS )
		If not ( Gradient + 0 )
			hBM := DllCall( "CopyImage", "Ptr",hBM, "UInt",0, "Int",0, "Int",0, "UInt",LR_Flag3, "Ptr" )
		Return DllCall( "CopyImage", "Ptr",hBM, "Int",0, "Int",ResizeW, "Int",ResizeH, "Int",LR_Flag2, "UPtr" )
	} ;</05.01.000049>
;<05.01.000050	>
GuiControlLoadImage(HCTRL, PicPath, Rotate = "") {                                         	;-- scale down a picture to fit the given width and height of a picture control

	/*    	DESCRIPTION of function GuiControlLoadImage()

			Link				:	https://autohotkey.com/board/topic/86978-rotate-gui-picture/
			Author			:	just me
			Date				:	Nov 14 2012
			Description	:	scale down a picture to fit the given width and height of a picture control
			Parameter	:	HCTRL     -  HWND or VarName of the picture control
									PicPath   -  	Path of the image
									Rotate    -  	Rotate the image:
														1 :   90 degrees right
														2 :   Flip vertically
														3 :   90 degrees left
														4 :   Flip horizontally
														Default: "" : no rotation
			Remark		:	You have to set the maximum width and height in the global variables PicW and PicH before calling it.
									Also you have to call Gdip_Startup() prior in your script. The control must have the style SS_BITMAP := 0x000E set

	*/


   Global PicW, PicH
   Static STM_GETIMAGE := 0x0173
   Static STM_SETIMAGE := 0x0172
   Static Rotate90FlipNone  := 1
   Static RotateNoneFlipY   := 2
   Static Rotate270FlipNone := 3
   Static RotateNoneFlipX   := 4
   If !(HCTRL + 0)
      GuiControlGet, HCTRL, HWND, %HCTRL%
   If !(HCTRL)
      Return
   DllCall("Gdiplus.dll\GdipCreateBitmapFromFile", "WStr", PicPath, "PtrP", GDIPBitmap)
   If Rotate Between 1 And 4
      DllCall("Gdiplus.dll\GdipImageRotateFlip", "Ptr", GDIPBitmap, "Int", Rotate)
   DllCall("Gdiplus.dll\GdipGetImageWidth", "Ptr", GDIPBitmap, "UIntP", PW)
   DllCall("Gdiplus.dll\GdipGetImageHeight", "Ptr", GDIPBitmap, "UIntP", PH)
   DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", GDIPBitmap, "PtrP", HBITMAP, "UInt", 0xFFFFFFFF)
   DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", GDIPBitmap)
   W := PW
   H := PH
   If (H > PicH) {
      W := Round(PW * PicH / H)
      H := PicH
   }
   If (W > PicW) {
      H := Round(H * PicW / W)
      W := PicW
   }
   HBITMAP := DllCall("User32.dll\CopyImage", "Ptr", HBITMAP, "UInt", 0, "Int", W, "Int", H, "UInt", 0x08, "UPtr")
   SendMessage, STM_SETIMAGE, 0, HBITMAP, , ahk_id %HCTRL%
   If (ErrorLevel + 0)
      DllCall("Gdi32.dll\DeleteObject", "Ptr", ErrorLevel)
   SendMessage, STM_GETIMAGE, 0, 0, , ahk_id %HCTRL%
   If (ErrorLevel <> HBITMAP)
      DllCall("Gdi32.dll\DeleteObject", "Ptr", HBITMAP)
   Return PW . "|" . PH
} ;</05.01.000050>
;<05.01.000051>
Gdip_ResizeBitmap(pBitmap, PercentOrWH, Dispose=1) {                                 	;-- returns resized bitmap

	/*    	DESCRIPTION of function ()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	returns resized bitmap
			Link1            	:	https://autohotkey.com/board/topic/86978-rotate-gui-picture/
			Link2            	:	http://www.autohotkey.com/community/viewtopic.php?p=477333#p477333
			Author         	:	Learning one
			Date	            	:	Nov 14 2012
			AHK-Version	:	AHK_L
			License        	:	unknown
			Parameter(s)	:	see examples
			Remark(s)    	:	none
			Dependencies	:	GDIP.ahk
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			pResizedBitmap := Gdip_ResizeBitmap(pBitmap, 120) ; resizes to 120%. Disposes of pBitmap.
			pResizedBitmap := Gdip_ResizeBitmap(pBitmap, 50, 0) ; resizes to 50%. Does not dispose pBitmap.
			pResizedBitmap := Gdip_ResizeBitmap(pBitmap, "w180 h80") ; resizes to width: 180 height: 80 (does not maintain aspect ratio). Disposes of pBitmap.
			pResizedBitmap := Gdip_ResizeBitmap(pBitmap, "w200") ; resizes to width: 200, automatically adjusts height (maintains aspect ratio). Disposes of pBitmap.
			pResizedBitmap := Gdip_ResizeBitmap(pBitmap, "h50") ; resizes to height: 50, automatically adjusts width (maintains aspect ratio). Disposes of pBitmap.

	*/

		Gdip_GetImageDimensions(pBitmap, origW, origH)
		if PercentOrWH contains w,h
		{
		RegExMatch(PercentOrWH, "i)w(\d*)", w), RegExMatch(PercentOrWH, "i)h(\d*)", h)
		NewWidth := w1, NewHeight := h1
		NewWidth := (NewWidth = "") ? origW/(origH/NewHeight) : NewWidth
		NewHeight := (NewHeight = "") ? origH/(origW/NewWidth) : NewHeight
		}
		else
		NewWidth := origW*PercentOrWH/100, NewHeight := origH*PercentOrWH/100
		pBitmap2 := Gdip_CreateBitmap(NewWidth, NewHeight)
		G2 := Gdip_GraphicsFromImage(pBitmap2), Gdip_SetSmoothingMode(G2, 4), Gdip_SetInterpolationMode(G2, 7)
		Gdip_DrawImage(G2, pBitmap, 0, 0, NewWidth, NewHeight)
		Gdip_DeleteGraphics(G2)
		if Dispose
		Gdip_DisposeImage(pBitmap)
		return pBitmap2
} ;</05.01.000051>
;<05.01.000052>
Gdip_CropBitmap(pBitmap, left, right, up, down, Dispose=1) {                          	;-- returns cropped bitmap. Specify how many pixels you want to crop (omit) from each side of bitmap rectangle

	/*    	DESCRIPTION of function Gdip_CropBitmap()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	returns cropped bitmap. Specify how many pixels you want to crop (omit) from each side of bitmap rectangle
			Link              	:	http://www.autohotkey.com/community/viewtopic.php?p=477333#p477333
			Author         	:	Learning one
			Date	            	:	Nov 14 2012
			AHK-Version	:	AHK_L
			License        	:	unknown
			Parameter(s)	:	see examples
			Remark(s)    	:	none
			Dependencies	:	GDIP.ahk
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			pCroppedBitmap := Gdip_CropBitmap(pBitmap, 10, 10, 10, 10) ; crops 10 pixels from each side of bitmap rectangle. Disposes of pBitmap.
			pCroppedBitmap := Gdip_CropBitmap(pBitmap, 50, 50, 0, 0) ; crops 50 pixels from left and right side of bitmap rectangle. Disposes of pBitmap.
			pCroppedBitmap := Gdip_CropBitmap(pBitmap, 0, 0, 77, 77, 0) ; crops 77 pixels from upper and lower side of bitmap rectangle. Does not dispose of pBitmap.

	*/


		Gdip_GetImageDimensions(pBitmap, origW, origH)
		NewWidth := origW-left-right, NewHeight := origH-up-down
		pBitmap2 := Gdip_CreateBitmap(NewWidth, NewHeight)
		G2 := Gdip_GraphicsFromImage(pBitmap2), Gdip_SetSmoothingMode(G2, 4), Gdip_SetInterpolationMode(G2, 7)
		Gdip_DrawImage(G2, pBitmap, 0, 0, NewWidth, NewHeight, left, up, NewWidth, NewHeight)
		Gdip_DeleteGraphics(G2)
		if Dispose
				Gdip_DisposeImage(pBitmap)

return pBitmap2
} ;</05.01.000052>
;<05.01.000053>
GetBitmapSize(h_bitmap, ByRef width, ByRef height, ByRef bpp="") {                	;-- Lexikos function to get the size of bitmap

	/*    	DESCRIPTION of function GetBitmapSize() ID: 05.01.00053
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Lexikos function to get the size of bitmap
			Link              	:	https://autohotkey.com/board/topic/20338-transparent-background-problem-with-images/#entry133445
			Author         	:	Lexikos
			Date             	:	15.07.2007
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:	hIcon - handle
			Remark(s)    	:	function is copied from my (Lexikos') Menu Icons script
			Dependencies	:
			KeyWords    	:	icon, hIcon, load resources, extract
        	-------------------------------------------------------------------------------------------------------------------
	*/

    VarSetCapacity(bm, 24, 0) ; BITMAP
    if (!DllCall("GetObject", "UInt", h_bitmap, "Int", 24, "UInt", &bm))
        return false
    width  := NumGet(bm, 4, "int")
    height := NumGet(bm, 8, "int")
    bpp    := NumGet(bm,18, "ushort")
    return true
} ;</05.01.000053>
;<05.01.000054>
Gdip_BitmapReplaceColor(pBitmap, ByRef pBitmapOut, Color                           	;-- using Mcode to replace a color with a specific variation
, ReplaceColor, Variation) {

	/*    	DESCRIPTION of function Gdip_BitmapReplaceColor() ID: 05.01.00054
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	using Mcode to replace a color with a specific variation
			Link              	:	https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/page-60
			Author         	:	????
			Date	            	:	????
			AHK-Version	:	AHK V1
			License         	:	????
			KeyWords    	:	gdi, image, mcode, processing, color
        	-------------------------------------------------------------------------------------------------------------------
	*/

   static BitmapReplaceColor
   if !BitmapReplaceColor
   {
      MCode_BitmapReplaceColor := "83EC248B4424388B4C243C995683E2038BF103C28B542438C1FE10C1F90881E6FF00000081E1FF000000C1F8028"
      . "9742408894C244085D20F8E0A010000538B5C2430558B6C245033C903C0578B7C243C03C0894C241C89442430897C241889542420837C2440000F8"
      . "EB90000008D43018BD32BD083C202895424282BF5894C244403C88BD32BD08B442440897424248954242C89442410EB0B8DA424000000008B74242"
      . "48B5424280FB6140A0FB6013BD67E0A8B74241403F53BD67C268B74244C2BF53BC67E248B5C244C03DD3BC38B5C24387C0E3BC67E128B74244C03F"
      . "53BC67D088B4424508907EB228B7424440FB6741E03C1E6080BF28B54242CC1E6080BF00FB6040AC1E6080BF08937834424440483C10483C704FF4"
      . "C241075828B4C241C8B7424148B7C2418037C2430034C2448FF4C2420897C2418894C241C0F851EFFFFFF5F5D5BB8010000005E83C424C3"

      VarSetCapacity(BitmapReplaceColor, StrLen(MCode_BitmapReplaceColor)//2)
      Loop % StrLen(MCode_BitmapReplaceColor)//2      ;%
         NumPut("0x" SubStr(MCode_BitmapReplaceColor, (2*A_Index)-1, 2), BitmapReplaceColor, A_Index-1, "char")
   }

   Width := Gdip_GetImageWidth(pBitmap), Height := Gdip_GetImageHeight(pBitmap)
   if (Width != Gdip_GetImageWidth(pBitmapOut) || Height != Gdip_GetImageHeight(pBitmapOut))
      return -1

   if (Variation > 255 || Variation < 0)
      return -2

   E1 := Gdip_LockBits(pBitmap, 0, 0, Width, Height, Stride1, Scan01, BitmapData1)
   E2 := Gdip_LockBits(pBitmapOut, 0, 0, Width, Height, Stride2, Scan02, BitmapData2)
   if (E1 || E2)
      return -3

   E := DllCall(&BitmapReplaceColor, "uint", Scan01, "uint", Scan02, "int", Width, "int", Height, "int", Stride1, "int", Color, "int", ReplaceColor, "int", Variation)
   Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapOut, BitmapData2)
   return 0
} ;</05.01.000054>
;<05.01.000055>
Gdi_ExtFloodFill(hDC, XStart, YStart, Color, FillType=0) {                                    	;-- fills an area with the current brush

	/*    	DESCRIPTION of function ExtFloodFill()  ID: 05.01.00055
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Fills an area with the current brush
			Link              	:	https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/page-62
			Author         	:	nimda
			Date	            	:	????
			AHK-Version	:	AHK V1
			License         	:	????
			Parameter(s)	:	Filltypes: 	FloodFillBorder  = 0, FloodFillSurface = 1
			Remark(s)    	:	Per MSDN [ http://msdn.microsoft.com/en-us/library/dd162709 ]:
                                    	If the fuFillType parameter is FLOODFILLBORDER, the system assumes that
                                    	the area to be filled is completely bounded by the color specified by
                                    	the crColor parameter. The function begins filling at the point specified
                                    	by the nXStart and nYStart parameters and continues in all directions
                                    	until it reaches the boundary.

                                    	If fuFillType is FLOODFILLSURFACE, the system assumes that the area to
                                    	be filled is a single color. The function begins to fill the area at the
                                    	point specified by nXStart and nYStart and continues in all directions,
                                    	filling all adjacent regions containing the color specified by crColor.
			Dependencies	:	none
			KeyWords    	:	gdi, image, processing
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*		EXAMPLE(s)

        	CoordMode, Mouse
        	CoordMode, Pixel
        	KeyWait, LButton, D
        	MouseGetPos, X, Y
        	PixelGetColor, color, X, Y
        	Color |= 0xFF000000

        	up := (A_PtrSize ? "UPtr" : "UInt")

        	hDC := DllCall("GetDC", up, 0, up)
        	hBrushRed := DllCall("CreateSolidBrush", UInt, 0xFFFF0000, up)
        	DllCall("SelectObject", up, hDC, up, hBrushRed, up)
        	r := ExtFloodFill(hDC, X, Y, Color, 0)
        	DllCall("DeleteObject", up, hBrushRed, "int")
        	DllCall("ReleaseDC", up, 0, up, hDC, "int")

        	MsgBox % r

	*/

	return DllCall( "GDI32\ExtFloodFill", (A_PtrSize ? "UPtr" : "UInt"), hDC
		 , int, XStart, int, YStart, UInt, Color ; color is in ARGB form
		 , UInt, FillType, "int" )
} ;</05.01.000055>
;<05.01.000056>
Gdip_AlphaMask32v1(pBitmap, pBitmapMask, x, y) {                                         	;-- 32bit Gdip-AlphaMask with MCode - one of two builds

	/*    	DESCRIPTION of function Gdip_AlphaMask32v1() ID: 05.01.00056
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	gdi cutting and aliasing
			Link              	:	https://autohotkey.com/board/topic/103475-gdi-cutting-anti-aliasing/
										https://autohotkey.com/boards/viewtopic.php?t=39077
			Author         	:	Tic
			Date	            	:
			AHK-Version	:	AHK_L, AHK V1
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	library Gdip_All.ahk
			KeyWords    	:	GDI, Cut, Crop, MCOde
        	-------------------------------------------------------------------------------------------------------------------
	*/

	static _AlphaMask
	if !_AlphaMask
	{
		MCode_AlphaMask := "8B4424209983E2038D0C028B4424249983E20303C28B54241CC1F902C1F80285D27E7303C003C08944241C8D048D000000000FA"
		. "F4C242C034C2428538B5C240C55568B742424894424308B442418578D3C888954243085F67E2A8B5424142B54241C8BCF8BC38B2C0A332883C00481E"
		. "5FFFFFF003368FC83C1044E8969FC75E68B742428037C2434035C242CFF4C243075C45F5E5D5B33C0C3"

		VarSetCapacity(_AlphaMask, StrLen(MCode_AlphaMask)//2)
		Loop % StrLen(MCode_AlphaMask)//2      ;%
			NumPut("0x" SubStr(MCode_AlphaMask, (2*A_Index)-1, 2), _AlphaMask, A_Index-1, "char")
	}
	Gdip_GetDimensions(pBitmap, w1, h1), Gdip_GetDimensions(pBitmapMask, w2, h2)
	pBitmapNew := Gdip_CreateBitmap(w1, h1)
	if !pBitmapNew
		return -1

	E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
	E2 := Gdip_LockBits(pBitmapMask, 0, 0, w2, h2, Stride2, Scan02, BitmapData2)
	E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
	if (E1 || E2 || E3)
		return -2

	E := DllCall(&_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w1, "int", h1, "int", w2, "int", h2, "int", Stride1, "int", Stride2, "int", x, "int", y)

	Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)
	return (E = "") ? -3 : pBitmapNew
} ;</05.01.000056>
;<05.01.000057>
Gdip_AlphaMask32v2(pBitmap, pBitmapMask, x, y) {                                         	;-- 32bit Gdip-AlphaMask with MCode  - second of two builds

	/*    	DESCRIPTION of function Gdip_AlphaMask32v2() ID: 05.01.00057
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	gdi cutting and aliasing
			Link              	:	https://autohotkey.com/board/topic/103475-gdi-cutting-anti-aliasing/
										https://autohotkey.com/boards/viewtopic.php?t=39077
			Author         	:	Tic
			Date	            	:
			AHK-Version	:	AHK V2
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	library Gdip_All.ahk
			KeyWords    	:	GDI, Cut, Crop, MCOde
        	-------------------------------------------------------------------------------------------------------------------
	*/

	static _AlphaMask
	if !_AlphaMask
    {
        MCode_AlphaMask := "518B4424249983E20303C28BC88B442428995383E20303C28B5424245556C1F902C1F802837C24400057757E85D20F8E0E01000"
        . "08B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B4424208D3C888954244485F67E2C8B5424182B5424208"
        . "BCF8BC38B2C0A332883C00481E5FFFFFF003368FC83C10483EE018969FC75E48B74242C037C2434035C2438836C24440175C15F5E5D33C05B59C385D"
        . "20F8E900000008B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B442420895C24448D3C888954241085F67"
        . "E428B5424182B5424208BC78BCBEB098DA424000000008BFF8B1981E3000000FFBD000000FF2BEB8B1C1081E3FFFFFF000BEB892883C10483C00483E"
        . "E0175D98B74242C8B5C2444035C2438037C2434836C241001895C244475A35F5E5D33C05B59C3"

        VarSetCapacity(_AlphaMask, StrLen(MCode_AlphaMask)//2)
        Loop % StrLen(MCode_AlphaMask)//2      ;%
            NumPut("0x" SubStr(MCode_AlphaMask, (2*A_Index)-1, 2), _AlphaMask, A_Index-1, "char")
    }
	Gdip_GetDimensions(pBitmap, w1, h1), Gdip_GetDimensions(pBitmapMask, w2, h2)
	pBitmapNew := Gdip_CreateBitmap(w1, h1)
	if !pBitmapNew
		return -1

	E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
	E2 := Gdip_LockBits(pBitmapMask, 0, 0, w2, h2, Stride2, Scan02, BitmapData2)
	E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
	if (E1 || E2 || E3)
		return -2

	E := DllCall(&_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w1, "int", h1, "int", w2, "int", h2, "int", Stride1, "int", Stride2, "int", x, "int", y)

	Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)
	return (E = "") ? -3 : pBitmapNew
} ;</05.01.000057>
;<05.01.000058>
Gdip_AlphaMask64(pBitmap, pBitmapMask, x, y, invert=0) {                             	;-- 64bit Gdip-AlphaMask with MCode

	/*    	DESCRIPTION of function Gdip_AlphaMask64() ID: 05.01.00058
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:
			Link              	:	http://www.autohotkey.com/board/topic/103475-gdi-cutting-anti-aliasing/#entry638772
										https://autohotkey.com/boards/viewtopic.php?t=39077
			Author         	:	Tic / Learning one
			Date	            	:
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	library Gdip_All.ahk
			KeyWords    	:	GDI, Cut, Crop, MCOde
        	-------------------------------------------------------------------------------------------------------------------
	*/

    static _AlphaMask := MCode("
	(LTrim Join
1,x86:518b4424249983e2035355568d0c028b4424349983e203c1f902578d3402c1fe02837c2444000f85980000008b4424
308944243885c00f8e340100008d1c8d000000000faf4c24408d14b500000000895c24348b7424208b5c241c89542444034c
243c8d2c8e8b4c242c8b742434669085c97e3b8b7c24188bd52b7c24208bc38bf18b0c178d40043348fc8d520481e1ffffff
003348fc894afc83ee0175e38b4424388b4c242c8b5424448b74243403ee03da83e8018944243875b45f5e5d33c05b59c38b
5424308954241085d20f8e9c0000008b7c24208d04b5000000008b6c241c894424348d048d000000000faf4c24408b5c2434
894424388bf0034c243c8d048f8b4c242c894424440f1f400085c97e4b8b5c24188bd02bdf8bf58bf98b068d760425000000
ff8d5204b9000000ff2bc88b441afc25ffffff000bc8894afc83ef0175d98b4424448b5424108b4c242c8b5c24348b742438
8b7c242003c603eb83ea01894424448954241075a05f5e5d33c05b59c3,x64:48895c24084c8944241848895424105556574
1544155415641574883ec108b8424900000004c8bc248637424789983e2034c8be903c2c1f8024c63d08b842488000000998
3e20303c2c1f80283bc24a8000000004863c848890c240f85a60000008b8c248000000085c90f8e3a0100004c63bc24a0000
0004e8d3495000000004c63a424980000004533c9458bd9498bea498bd88bf94885f67e584c8b5424604b8d1439480faf142
4488bc3492bd34903d448c1e202492bd04c03d24e8d042a488bd60f1f4000660f1f840000000000418b0c003308488d40048
1e1ffffff003348fc41894c02fc4883ea0175e24c8b4424584c03dd4903de49ffc14883ef017594e9a30000008b842480000
00085c00f8e940000004c63b424a00000004533c94c63bc2498000000418bd94c8b642458498bea8bf84885f67e634c8b542
4604b8d1431480fafd14c8bdb4c2bda4d2bdf49c1e3024a8d043a4d2bdd4c8d0485000000004d03dc4d03c5488bd64d2bd54
38b04184d8d400425000000ffb9000000ff2bc8418b40fc25ffffff000bc843894c02fc4883ea0175d6488b0c244803dd49f
fc14883ef01758c33c0488b5c24504883c410415f415e415d415c5f5e5dc3
)")

    Gdip_GetDimensions(pBitmap, w1, h1), Gdip_GetDimensions(pBitmapMask, w2, h2)
    pBitmapNew := Gdip_CreateBitmap(w1, h1)
    if !pBitmapNew
        return -1

    E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
    E2 := Gdip_LockBits(pBitmapMask, 0, 0, w2, h2, Stride2, Scan02, BitmapData2)
    E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
    if (E1 || E2 || E3)
        return -2

    E := DllCall(_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w1, "int", h1, "int", w2, "int", h2, "int", Stride1, "int", Stride2, "int", x, "int", y, "int", invert, "cdecl int")
    Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)

    return (E = "") ? -3 : pBitmapNew
} ;</05.01.000058>
;<05.01.000059>
CircleCrop(pBitmap, x, y, w, h) {                                                                           	;-- gdi circlecrop with MCode

	/*    	DESCRIPTION of function CircleCrop() ID: 05.01.00059
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	gdi cutting and aliasing
			Link              	:	https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/page-73#entry535199
			Author         	:	Tic
			Date	            	:
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	GDI, Cut, Crop, MCOde
        	-------------------------------------------------------------------------------------------------------------------
	*/

	static _CircleCrop
	if !_CircleCrop
	{
		MCode_CircleCrop := "8B44241C9983E20303C28BC88B4424209983E20303C28B542418C1F902C1F80285D27E6803C003C0894424208D048D000000000"
		. "FAF4C2428034C2424535556894424288B442410578B7C24188BDA8B5424248D348885D27E228BC78BCE8D49008B29332883C10481E5FFFFFF00312883"
		. "C00483EA0175E98B5424240374242C037C243083EB0175CD5F5E5D5B33C0C3"

		VarSetCapacity(_CircleCrop, StrLen(MCode_CircleCrop)//2)
		Loop % StrLen(MCode_CircleCrop)//2      ;%
			NumPut("0x" SubStr(MCode_CircleCrop, (2*A_Index)-1, 2), _CircleCrop, A_Index-1, "char")
	}
	Gdip_GetDimensions(pBitmap, w1, h1)
	pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
	Gdip_SetSmoothingMode(G2, 4)

	pBrush := Gdip_BrushCreateSolid(0xff00ff00)
	Gdip_FillEllipse(G2, pBrush, 0, 0, w, h)
	Gdip_DeleteBrush(pBrush)

	E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
	E2 := Gdip_LockBits(pBitmap2, 0, 0, w, h, Stride2, Scan02, BitmapData2)

	E := DllCall(&_CircleCrop, "ptr", Scan01, "ptr", Scan02, "int", w1, "int", h1, "int", w, "int", h, "int", Stride1, "int", Stride2, "int", x, "int", y)

	Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmap2, BitmapData2)
	Gdip_DeleteGraphics(G2)
	return pBitmap2
} ;</05.01.000059>
;<05.01.000060>
get_png_image_info(filename) {                                                                          	;-- Getting PNG image info

	/*    	DESCRIPTION of function get_png_image_info()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Getting PNG image info, like its width, height, bits per pixel, etc. It's accomplished by simply reading the first 33 bytes of the file.
			                          	The other methods I saw required using DLLs (GDIp), or creating a hidden GUI picture control, or shelling out to run IrfanView.
										All of them a bit overly complicated in my opinion
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=10035
			Author         	:	duppy
			Date	            	:	30-Oct-2015
			AHK-Version	:	AHK_v1??
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	It's obviously limited to PNG files, but that's all I need currently (maybe I'll add JPG, BMP, GIF later).
			Dependencies	:
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)

		Loop, Files, d:\pics\*.png
		{
			imageInfo := get_png_image_info(A_LoopFileFullPath)
			if imageInfo
			{
				print_line("""" imageInfo.filename """`n`t"
						 . "width: " imageInfo.width
						 . ", height: " imageInfo.height
						 . ", bpp: " imageInfo.bpp
						 . ", color type: " imageInfo.colortype
						 . ", compression: " imageInfo.compression
						 . ", filter: " imageInfo.filter
						 . ", interlace: " imageInfo.interlace)
			}
		}

*/


	file := FileOpen(filename, "r")
	if !IsObject(file)
	{
		print_line("Error: Can't open '" filename "' for reading.")
		return
	}

	; note: PNG is stored in big-endian format
	signature := file.ReadInt64()
	if signature != 0xa1a0a0d474e5089
	{
		print_line("Error: Not a PNG file")
		return
	}

	file.ReadUInt() ; skip 4 bytes (IHDR's length)

	IHDR_tag := file.ReadInt()
	if IHDR_tag != 0x52444849
	{
		print_line("Error: IHDR expected as first chunk.")
		return
	}

	width := byte_swap_32(file.ReadUInt())
	height := byte_swap_32(file.ReadUInt())
	bpp := file.ReadUChar()         ; valid values are 1, 2, 4, 8, and 16
	colortype := file.ReadUChar()   ; valid values are 0, 2, 3, 4, and 6.
	compression := file.ReadUChar() ; usually 0 for deflate/inflate
	filter := file.ReadUChar()      ; usually 0
	interlace := file.ReadUChar()   ; 0 = none, 1 = Adam7

	return { width: width
		   , height: height
		   , bpp: bpp
		   , colortype: colortype
		   , compression: compression
		   , filter: filter
		   , interlace: interlace
		   , filename: filename }
}
byte_swap_32(x) {                                                                                                	;-- subfunction of get_png_image_info(), change endian-ness for 32-bit integer
	return ((x >> 24) & 0xff)
		 | ((x <<  8) & 0xff0000)
		 | ((x >>  8) & 0xff00)
		 | ((x << 24) & 0xff000000)
}
print_line(str) {                                                                                                       	;-- subfunction of get_png_image_info(),  output line to STDOUT for debugging in my text editor (sublime)
	FileAppend, %str%`n, *
} ;</05.01.000060>
;<05.01.000061>
GetBitmapFromAnything(Anything) {                                                                 	;-- Supports paths, icon handles and hBitmaps

	if(FileExist(Anything))
	{
		pBitmap := Gdip_CreateBitmapFromFile(Anything)
		;hBitmap := Gdip_CreateHBitmapFromBitmap(pBitmap)
		;Gdip_DisposeImage(pBitmap)
	}
	else if(DllCall("GetObjectType", "PTR", hBitmap) = (OBJ_BITMAP := 7)) ;Tread as icon
	{
		hBitmap := Anything
		pBitmap := Gdip_CreateBitmapFromHBitmap(hBitmap)
		DeleteObject(hBitmap)
	}
	else if(Anything != "")
	{
		pBitmap := Gdip_CreateBitmapFromHICON(Anything)
		;hBitmap := Gdip_CreateHBitmapFromBitmap(pBitmap)
		;Gdip_DisposeImage(pBitmap)
	}
	else
		return 0
	return pBitmap
} ;</05.01.000061>
;<05.01.000062>
Image_TextBox(Text:="", FilePath:="", SavePath:="", Options*) {                        	;-- Function to use Gdip to add text to image

	/*	DESCRIPTION OF FUNCTION: -- Image_Textbox --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Function to use Gdip to add text to image
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=59981
	Author         	:	Fanatic Guru
	Date             	:	2018 11 11
	AHK-Version	:
	License         	:
	Syntax          	:
	Parameter(s)	:	Text					text to add to image
								FilePath			path to source file, blank to use image on Clipboard
								SavePath			path to save modified image, blank to save modified image to Clipboard
								Options*			variadic parameter for pseudo named paramater options
								For each named parameter use the format "Name=value"
								FontSize			text font size (default "FontSize=24")
								Font					text font name (default "Font=Arial")
								Style					text font style Regular|Bold|Italic|BoldItalic|Underline|Strikeout (default "Style=Regular")
								Align				alignment of text Near|Left|Centre|Center|Far|Right and Top|Up|Bottom|Down|vCentre|vCenter (default "Align=Center vCenter")
								Margin				clear space between border and text boundary (default "Margin=0")
								TextColor			color of text with alpha transparant, hex aarrggbb (default "TextColor=ffffffff" solid white)
								BoxColor			color of box fill with alpha transparent, hex aarrggbb (default "BoxColor=ff000000" solid black)
								BorderColor		color of border with alpha transparent, hex aarrggbb (default "BorderColor=ffff0000" solid red)
								Weight				weight or thickness of border, 0 weight is no border (default "Weight=2")
								Render				rendering hint (default "Render=0")
															0: SystemDefault, 1: SingleBitPerPixelGridFit, 2: SingleBitPerPixel, 3: AntiAliasGridFit, 4: AntiAlias, 5: ClearTypeGridFit
								Pos					position of box Left|Right|Top|Botton|vCenter or XY in format "x,y" or percentage in format ".x,.y"
															negative amounts goes from right or bottom (default "Pos=Bottom Left")
															examples "Pos=vCenter" vertical center or "Pos=100,200" 100 x 200 y or
															"Pos=.1,.2" 10% x 20% y or "Pos=-20,-.10" 20 x from right, 10% y from bottom
								Quality				quality for images with compression format (default "Quality=75")
								BoxSize			size of box in format "x,y" or "" to autofit (default "BoxSize=Auto")
	Return value	:
	Remark(s)    	:	text will word wrap within box and `n can be used for new line
	Dependencies	:	Gdip
	KeyWords    	:	gdip,text,image
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Example1:
			Image_TextBox("Example Text","Image_Test.PNG",, "FontSize=48", "Weight=6", "Margin=10", "Style=Bold",  "Align=Right vCenter", "BoxSize=200,100", "Pos=-20,-.20", "BoxColor=55000000", "Render=5")

	Example2:
				; Default Options
			FontSize:=24, Font:="Arial",  Style:="Regular", Align:="Center vCenter", Margin:=0, TextColor:="ffffffff", BoxColor:="ff000000", BorderColor:="ffff0000", Weight:="2", Render:=0, Pos:="Bottom Left", Quality:=75, BoxSize:="Auto"
			; Options as Named Parameters
			for key, Option in Options
			{
				Opt := StrSplit(Option, "=")
				var := Opt.1, val := Opt.2
				%var% := val
			}
			; Startup Gdip
			if !pToken
			{
				If !pToken := Gdip_Startup()
				{
				   MsgBox, 48, Gdip+ Error!, Gdip+ failed to start. Please ensure you have Gdip+ on your system.
				   ExitApp
				}
				else
				{
					OnExit, Exit_Image_TextBox
					If !Gdip_FontFamilyCreate(Font)
					{
					   MsgBox, 48, Font Error!, The font you have specified does not exist on the system.
					   ExitApp
					}
				}
			}
			; Get Bitmap, Graphics, Pen, and Brush
			if FilePath
				pBitmapFile := Gdip_CreateBitmapFromFile(FilePath)
			else
				pBitmapFile := Gdip_CreateBitmapFromClipboard()
			pG := Gdip_GraphicsFromImage(pBitmapFile)
			Gdip_SetSmoothingMode(pG, 4)
			pPen := Gdip_CreatePen("0x" BorderColor, Weight)
			pBrush := Gdip_BrushCreateSolid("0x" BoxColor)
			; Get Width and Height of components
			Width := Gdip_GetImageWidth(pBitmapFile)
			Height := Gdip_GetImageHeight(pBitmapFile)
			if (!BoxSize or BoxSize="Auto")
			{
				Options :=  "c" TextColor " s" FontSize " r" Render " " Style " " Align
				Measure := StrSplit(Gdip_TextToGraphics(pG, Text, Options, Font,,,true), "|")
				Box_Width := Measure.3 + (Weight * 2) + (Margin * 2)
				Box_Height := Measure.4 + (Weight * 2) + (Margin * 2)
			}
			else
			{
				XY := StrSplit(BoxSize, ",")
				Box_Width := XY.1, Box_Height := XY.2
			}
			; Process Number Box Position Options
			if InStr(Pos, ",")
			{
				XY := StrSplit(Pos, ",")
				if (0 < XY.1 and XY.1 < 1)
					Box_X := Width * XY.1
				else if (-1 < XY.1 and XY.1 < 0)
					Box_X := Width + (Width * XY.1) - Box_Width - 1
				else if (XY.1 < 0)
					Box_X := Width + XY.1 - Box_Width  - 1
				else
					Box_X := XY.1
				if (0 < XY.2 and XY.2 < 1)
					Box_Y := Height * XY.2
				else if (-1 < XY.2 and XY.2 < 0)
					Box_Y := Height + (Height * XY.2) - Box_Height - 1
				else if (XY.2 < 0)
					Box_Y := Height + XY.2 - Box_Height - 1
				else
					Box_Y := XY.2
				Pos := XY.3
			}
			; Process Word Box Position Options
			if InStr(Pos, "Left")
				Box_X := 0
			else if InStr(Pos, "Right")
				Box_X := Width - Box_Width - 1
			else if (Pos ~= "(?<!v)Center")
				Box_X := (Width - Box_Width) / 2 - 1
			if InStr(Pos, "Bottom")
				Box_Y := Height - Box_Height - 1
			else if InStr(Pos, "Top")
				Box_Y := 0
			else if InStr(Pos, "vCenter")
				Box_Y := (Height - Box_Height) / 2 - 1
			Border_X := Box_X + Weight / 2, Border_Y := Box_Y + Weight / 2
			Border_Width := Box_Width - Weight, Border_Height := Box_Height - Weight
			; Text X, Y, Width, Height
			Padding := Margin + Weight
			Text_X := Box_X + Padding - 1, Text_Y := Box_Y + Padding - 1
			Text_Width := Box_Width - (Padding * 2), Text_Height := Box_Height - (Padding * 2)
			; Draw Box, Border, and Text
			Gdip_FillRectangle(pG, pBrush, Box_X, Box_Y, Box_Width, Box_Height)
			if Weight
				Gdip_DrawRectangle(pG, pPen, Border_X, Border_Y, Border_Width, Border_Height)
			Options := "c" TextColor " s" FontSize " r" Render " " Style " " Align " x" Text_X " y" Text_Y
			Gdip_TextToGraphics(pG, Text, Options, Font, Text_Width, Text_Height)
			; Process Result
			if  SavePath
				Gdip_SaveBitmapToFile(pBitmapFile, SavePath, Quality)
			else
				Gdip_SetBitmapToClipboard(pBitmapFile)
			; Destroy Pen, Brush, Bitmap, and Graphic
			Gdip_DeletePen(pPen)
			Gdip_DeleteBrush(pBrush)
			Gdip_DisposeImage(pBitmapFile)
			Gdip_DeleteGraphics(pG)
			return
			; On Exit, make sure all Pointers Destroyed and Gdip Shutdown
			Exit_Image_TextBox:
				Gdip_DeletePen(pPen)
				Gdip_DeleteBrush(pBrush)
				Gdip_DisposeImage(pBitmapFile)
				Gdip_DeleteGraphics(pG)
				Gdip_Shutdown(pToken)
				ExitApp
			return
		}
		{ ;#Include [Function] Image_TextBox.ahk

		F1::
			send !{PrintScreen} ; get an image of current window on the clipboard for testing
			Sleep 500
			Comment = Default Bottom Left`nSize to Fit`nCenter Text
			Image_TextBox(Comment)
			DisplayClipboardInGui()
		return

		F2::
			send !{PrintScreen} ; get an image of current window on the clipboard for testing
			Sleep 500
			Comment = Bigger Font with Style`nPostion 30 from Left`n150 from Bottom
			Image_TextBox(Comment,,, "FontSize=36", "Weight=6", "Margin=10", "Style=Bold",  "Pos=30,-150")
			DisplayClipboardInGui()
		return

		F3::
			send !{PrintScreen} ; get an image of current window on the clipboard for testing
			Sleep 500
			Comment = Bigger Font with Style`nText Aligned Right with Vertical Center Text Wrap`nSpecific Box Size`nPostion 15`% from Right`n10`% from Top`nColor Fill with Transparent
			Image_TextBox(Comment,,, "FontSize=36", "Weight=6", "Margin=10", "Style=Bold",  "Align=Right vCenter", "BoxSize=515,400", "Pos=-.15,.10", "BoxColor=55ff0000", "Render=5")
			DisplayClipboardInGui()
		return

		; display modified image on clipboard in GUI
		DisplayClipboardInGui() {

			static
			Gui, Destroy
			if DllCall("OpenClipboard", "uint", 0) {
				if DllCall("IsClipboardFormatAvailable", "uint", 8) {
					hBitmap := DllCall("GetClipboardData", "uint", 2)
				}
				DllCall("CloseClipboard")
			}
			Gui, Add, Pic, vPic, % "HBITMAP:*" hBitmap
			Gui, Show
		}

		Esc::ExitApp

	*/
} ;</05.01.000062>
;<05.01.000063>
ColorAdjL(Lum:=235, RGB:="") {                                                                         	;-- Adjust Luminance for a given RGB color

	/*	DESCRIPTION OF FUNCTION: -- ColorAdj() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Adjust Luminance for a given RGB color. In other words, this function can derive a lighter / darker shade for a given RGB color
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-8
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	Luminance	- Value between 1 - 239 ( 0 is black and 240 is White )
                            	RGB         	- The RGB color to be adjusted. If ignored, a random color will be generated and used
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	gdi,graphic,color
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	;To derive a dark / light shade of red
		darkRed	:= ColorAdjL(  70, 0xFF0000 )
		liteRed 	:= ColorAdjL( 235, 0xFF0000 )

	;To derive a random ( but matching ) dark / light shade
		darkRandom	:= ColorAdjL(  70 )
		liteRandom  	:= ColorAdjL( 235, "0x" darkRandom )

	;example with gui
		Gui +ToolWindow +AlwaysOnTop
		Dark  := ColorAdjL(  70, 0xFF0000 )
		Light := ColorAdjL( 235, 0xFF0000 )
		Gui, Color, %Light%
		Gui, Font, s50
		Gui, Add, Text, x5 y5 w200 h75 c%Dark% Center vText, Hello
		Gui, Font
		Gui, Add, Edit, x36 y100 w30 h20 Limit3 Center vLum, 230
		Gui, Add, Button, x+5 h20 w100 gChangeGuiColor, Random Color
		Gui, Show, w210 h130, % " GuiColor : " Light
		Return

		ChangeGuiColor:
		 GuiControlGet, Lum
		 Light := ColorAdjL( Lum )
		 Gui, Color, %Light%
		 Gui, Show,, % " GuiColor : " Light
		Return

		GuiClose:
		 ExitApp
	*/

	 IfEqual, RGB,, Random, RGB, 1, 16777215
	 DllCall( "shlwapi\ColorRGBToHLS", UInt,RGB, UIntP,H, UIntP,L, UIntP,S )
	 CC := DllCall( "shlwapi\ColorHLSToRGB", UInt,H, UInt,Lum, UInt,S )
	 VarSetCapacity(RGB,6,0), DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,CC )
Return RGB
} ;</05.01.000063>
;<05.01.000064>
PixelCheckSum(X:=0, Y:=0, W:=3, H:=3, Title:="" ) {                                           	;-- Generates a CheckSum for a region of pixels in Screen/Window

	/*	DESCRIPTION OF FUNCTION: -- PixelCheckSum --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Generates a CheckSum for a region of pixels in Screen/Window
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-8
								http://ahkscript.org/boards/viewtopic.php?&t=4431
	Author         	:	SKAN
	Date             	:	31.08.2014
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	Credit: Thanks to Sean. Screen Capture with Transparent Windows and Mouse Cursor
								http://www.autohotkey.com/forum/viewtopic.php?t=18146&start=0&postdays=0&postorder=asc&highlight=screencapture
	Dependencies	:	none
	KeyWords    	:	gdi,graphics,checksum
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	; Example - Wait for a Screen Region to change
	ChkSum := PixelChecksum( 0,0,32,32 )

	While % ( ChkSum = PixelChecksum( 0,0,32,32 ) )
	   Sleep, 100
	MsgBox, Screen Region Change Detected!
	*/

	 Static DIBSECTION, SRCCOPY := 0x00CC0020, CAPTUREBLT := 0x40000000, BPP := 32
	  Local hWnd, hDC, mDC, hBM, oBM, nSize, pBITMAPINFOHEADER, ppvBits := 0

	  If not VarSetCapacity( DIBSECTION )
			 VarSetCapacity( DIBSECTION, 104, 0 )

	  pBITMAPINFOHEADER := &DIBSECTION + ( A_PtrSize = 4 ? 24 : 32 )

	  NumPut(  40, pBITMAPINFOHEADER +  0, "UInt"   )
	  NumPut(   W, pBITMAPINFOHEADER +  4, "UInt"   )
	  NumPut(   H, pBITMAPINFOHEADER +  8, "UInt"   )
	  NumPut(   1, pBITMAPINFOHEADER + 12, "UShort" )
	  NumPut( BPP, pBITMAPINFOHEADER + 14, "UShort" )

	  hWnd  := WinExist( Title )
	  hDC   := DllCall( "GetDC", "Ptr",hWnd, "UPtr" )
	  mDC   := DllCall( "CreateCompatibleDC", UInt,hDC, "UPtr" )

	  hBM   := DllCall( "CreateDIBSection", "Ptr", mDC, "Ptr", pBITMAPINFOHEADER, "Int",0, "PtrP",ppvBits, "Ptr",0, "Int",0, "UPtr" )

	  oBM   := DllCall( "SelectObject", "Ptr",mDC, "Ptr",hBM, "UPtr" )

	  DllCall( "BitBlt", "Ptr",mDC, "Int",0, "Int",0, "Int",W, "Int",H, "Ptr",hDC, "Int",X, "Int",Y, "UInt",SRCCOPY | CAPTUREBLT )

	  DllCall( "SelectObject", "Ptr",mDC, "Ptr",oBM )
	  DllCall( "DeleteDC",  "Ptr",mDC )
	  DllCall( "ReleaseDC", "Ptr",hWnd, "Ptr",hDC )

	  DllCall( "GetObject", "Ptr",hBM, "Int",( A_PtrSize = 4 ? 84 : 104 ), "Ptr",&DIBSECTION )
	  nSize := NumGet( pBITMAPINFOHEADER + 20, "UInt" )

Return DllCall( "NTDLL\RtlComputeCrc32", "UInt",0, "Ptr",ppvBits, "UInt",nSize, "UInt" ), DllCall( "DeleteObject", "Ptr",hBM )
} ;</05.01.000064>
}
;|   LoadPicture(01)                       	|   GetImageDimensionProperty(02)	|   GetImageDimensions(03)         	|   Gdip_FillRoundedRectangle(04)	|
;|   Redraw(05)                              	|   CreateSurface(06)                    	|   ShowSurface(07)                      	|   HideSurface(08)                       	|
;|   WipeSurface()                          	|   StartDraw()                              	|   EndDraw()                                	|   SetPen()                                   	|
;|   DrawLine()                              	|   SDrawRectangle()                    	|   SetAlpha()                                	|   DrawRectangle()                      	|
;|   Highlight()                               	|   Screenshot()                             	|   TakeScreenshot()                      	|   CaptureWindow()                     	|
;|   CaptureScreen()                      	|   CaptureCursor()                       	|   Zoomer()                                  	|   Convert()                                 		|
;|   SaveHBITMAPToFile()              	|   DrawFrameAroundControl       	|   CircularText()                           	|   RotateAroundCenter()              	|
;|   RGBRange()                             	|   getSelectionCoords()                	|   GetRange()                               	|   FloodFill()                                 	|
;|   CreateBMPGradient()              	|   CreatePatternBushFrom()        	|   ResConImg()                            	|   CreateCircleProgress()              	|
;|   RGBrightnessToHex()               	|   GetHueColorFromFraction()     	|   SaveHBITMAPToFile()               	|   DrawRotatePictureOnGraphics	|
;|   CopyBitmapOnGraphic()          	|   GDI_GrayscaleBitmap()            	|   Convert_BlackWhite()               	|   getHBMinfo()                           	|
;|   CreateDIB(49)                         	|   GuiControlLoadImage(50)        	|   Gdip_ResizeBitmap(51)            	|   Gdip_CropBitmap(52)              	|
;|   GetBitmapSize(53)                  	|   Gdip_BitmapReplaceColor(54)  	|   Gdi_ExtFloodFill(55)                  	|   Gdip_AlphaMask32v1(56)         	|
;|   Gdip_AlphaMask32v2(57)         	|   Gdip_AlphaMask64(58)             	|   CircleCrop(59)                          	|   get_png_image_info(60)           	|
;|   GetBitmapFromAnything(61)   	|   Image_TextBox(62)                   	|   ColorAdjL(63)                           	|   PixelCheckSum(64)                   	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;gui - customize (22) -- full gui functions, custom gui elements --                                                             	baseID: <06.01>
;<06.01.000001>
HtmlBox(Html, Title="", Timeout=0, Permanent=False,                            				;-- Gui with ActiveX - Internet Explorer - Control
GUIOptions="Resize MaximizeBox Minsize420x320", ControlOptions="W400 H300", Margin=10, Hotkey=True) {

	/*	DESCRIPTION OF FUNCTION: -- HtmlBox() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Gui with ActiveX - Internet Explorer - Control
	Link              	:	-
	Author         	:	-
	Date             	:	-
	AHK-Version	:	AutoHotkey_L 1.1.04+
	License         	:	-
	Syntax          	:	-
	Parameter(s)	:	Timeout : The seconds to make the HTML window disappear.
								Permanent : if this is True, closing the GUI window does not destroy it but it is hidden.
	Return value	:	the handle of the created window(Hwnd)
	Remark(s)    	:	-
	Dependencies	:	none
	KeyWords    	:	gui, activeX, html
	-------------------------------------------------------------------------------------------------------------------
	*/

    static HtmlBoxInfo := [], WindowHideStack := [] , WB , ExecCmd := { a : "selectall", c : "copy",  p : "print", v : "paste" }
    Gui, New, LabelHtmlBox HWNDHwndHtml %GUIOptions%, % Title     ;v1.1.04+
    Gui, Margin, %Margin%, %Margin%
    Gui, Add, ActiveX, vWB HwndHwndHtmlControl %ControlOptions%, Shell.Explorer    ;v1.1.03+
    WB.silent := true
    WB.Navigate("about:blank")
    Loop
       Sleep 10
    Until   (WB.readyState=4 && WB.document.readyState="complete" && !WB.busy)
    WB.document.write(html)
    Gui, Show
    If Timeout {
        ExecuteTime := A_TickCount + Timeout * 1000
        loop % (WindowHideStack.MaxIndex() ? WindowHideStack.MaxIndex() + 1 : 1) {
            if (!(WindowHideStack[A_Index].ExecuteTime) && (A_Index = 1)) || (WindowHideStack[A_Index].ExecuteTime > ExecuteTime) {
                Inserted := True, WindowHideStack.Insert(A_Index, { ExecuteTime: ExecuteTime, Hwnd : HwndHtml })    ;increment the rest
                if (A_Index = 1)
                    SetTimer, HtmlBoxClose, % Timeout * -1 * 1000
            }
        } Until (Inserted)
        if !Inserted
            WindowHideStack.Insert({ ExecuteTime: ExecuteTime, Hwnd : HwndHtml })    ;insert it at the very end
    }
    HtmlBoxInfo[HwndHtml] := { HwndWindow : HwndHtml, Margin : Margin, HwndHtmlControl : HwndHtmlControl, Permanent: Permanent, doc : WB.document }
    If Hotkey {
        Hotkey, IfWinActive, ahk_id %HwndHtml%
        For key in ExecCmd
            Hotkey, ^%key%, HtmlBoxExecCommand
        Hotkey, IfWinActive
    }
Return HwndHtml
    HtmlBoxSize:
        If (A_EventInfo = 1)  ; The window has been minimized.  No action needed.
            Return
        GuiControl, Move, % HtmlBoxInfo[Trim(A_GUI)].HwndHtmlControl
                  , % "H" (A_GuiHeight - HtmlBoxInfo[A_GUI].margin * 2) " W" ( A_GuiWidth - HtmlBoxInfo[A_GUI].margin * 2)
    Return
    HtmlBoxEscape:
    HtmlBoxClose:
        if (_HwndHtml := WindowHideStack[WindowHideStack.MinIndex()].Hwnd)  {     ;this means it's called from the timer, so the least index is removed
            WindowHideStack.Remove(WindowHideStack.MinIndex())
            if (NextTimer := WindowHideStack[WindowHideStack.MinIndex()].ExecuteTime)        ;this means a next timer exists
                SetTimer,, % A_TickCount - NextTimer < 0 ? A_TickCount - NextTimer : -1        ;v1.1.01+
        } else
            _HwndHtml := HtmlBoxInfo[A_GUI].HwndWindow
        DHW := A_DetectHiddenWindows
        DetectHiddenWindows, ON
        if WinExist("ahk_id " _HwndHtml) {        ;in case timeout is set and the user closes before the timeout
            if !HtmlBoxInfo[_HwndHtml].Permanent {
                Gui, %_HwndHtml%:Destroy
                WB := ""
                HtmlBoxInfo.Remove(_HwndHtml, "")
            } else
                Gui, %_HwndHtml%:Hide
        }
        DetectHiddenWindows, % DHW
    Return
    HtmlBoxExecCommand:        ;this is called when the user presses one of the hotkeys
        HtmlBoxInfo[WinExist("A")].doc.ExecCommand(ExecCmd[SubStr(A_ThisHotkey, 2)])
    Return
} ;</06.01.000001>
;<06.01.000002>
EditBox(Text, Title="", Timeout=0, Permanent=False,                             				;-- Displays an edit box with the given text, tile, and options
GUIOptions="Resize MaximizeBox Minsize420x320", ControlOptions="VScroll W400 H300", Margin=10) {

	/*	DESCRIPTION OF FUNCTION: -- HtmlBox() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Displays an edit box with the given text, tile, and options.
	Link              	:	-
	Author         	:	?A_Samurai?
	Date             	:	?2011?
	AHK-Version	:	AutoHotkey_L 1.1.04 or later.  Tested on: Windows 7 64bit, AutoHotkey 32bit Unicode 1.1.05.01.
	License         	:	Public Domain
	Syntax          	:	EditBox(Text, Title="", Timeout=0, Permanent=False, GUIOptions="Resize MaximizeBox Minsize420x320", ControlOptions="VScroll W400 H300", Margin=10)
	Parameter(s)	:	Text : 					the text strings to display in the edit box.
	                        	Title : 					the title for the GUI window.
	                        	Timeout : 			if specified, the edit box will disappear in the given seconds.
	                        	Permanent : 		if this is TRUE, closing the window does not destroy the window but hide it.
								                         	So it can be displayed again with the window handle.
	                        	GUIOptions : 		the options for the Edit box GUI window.
	                        	ControlOptions : 	the options for the Edit control.
	                        	Margin : 				the margin in pixels between the window borders and the control.
	Return value	:	The window handle (hwnd) of the created GUI window
	Remark(s)    	:	No global variables are used. However, it uses these label names: EditBoxClose, EditBoxEscape,
	                        	EditBoxResize. So the script should avoid using the label names.
	Dependencies	:	none
	KeyWords    	:	gui, activeX, html
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Text =
	(
		Copyright 2011 A_Samurai. All rights reserved.

		Redistribution and use in source and binary forms, with or without modification, are
		permitted provided that the following conditions are met:

		   1. Redistributions of source code must retain the above copyright notice, this list of
			  conditions and the following disclaimer.

		   2. Redistributions in binary form must reproduce the above copyright notice, this list
			  of conditions and the following disclaimer in the documentation and/or other materials
			  provided with the distribution.

		THIS SOFTWARE IS PROVIDED BY A_Samurai ''AS IS'' AND ANY EXPRESS OR IMPLIED
		WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
		FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL A_Samurai OR
		CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
		CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
		SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
		ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
		NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
		ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

		The views and conclusions contained in the software and documentation are those of the
		authors and should not be interpreted as representing official policies, either expressed
		or implied, of A_Samurai.
	)

	EditBox(Text, "Free BSD Licence")

	*/

    Static EditBoxInfo := [], WindowHideStack := []
    Gui, New, LabelEditBox HWNDHwndEdit %GUIOptions%, % Title     ;v1.1.04+
    Gui, Margin, %Margin%, %Margin%
    Gui, Add, Edit, HwndHwndEditControl %ControlOptions%, % Text
    ControlFocus,, ahk_id %HwndEditControl%
    Gui, Show
    If Timeout {
        WindowHideStack[A_TickCount + Timeout * 1000] := HwndEdit
        SetTimer, EditBoxClose, % Timeout * -1 * 1000
    }
    EditBoxInfo[HwndEdit] := { HwndWindow : HwndEdit, Margin : Margin, HwndEditControl : HwndEditControl }
Return HwndEdit

    EditBoxSize:
        If (A_EventInfo = 1)  ; The window has been minimized.  No action needed.
            Return
        GuiControl, Move, % EditBoxInfo[Trim(A_GUI)].HwndEditControl
                  , % "H" (A_GuiHeight - EditBoxInfo[A_GUI].margin * 2) " W" ( A_GuiWidth - EditBoxInfo[A_GUI].margin * 2)
    Return
    EditBoxEscape:
    EditBoxClose:
        if (HwndEdit := WindowHideStack.Remove(WindowHideStack.MinIndex(), "")) { ;this means it's called from the timer, so the least index is removed
            if (NextTimer := WindowHideStack.MinIndex())        ;this means a next timer exists
                SetTimer,, % A_TickCount - NextTimer < 0 ? A_TickCount - NextTimer : -1        ;v1.1.01+
        } else
            HwndEdit := EditBoxInfo[A_GUI].HwndWindow
        if !Permanent {
            Gui, %HwndEdit%:Destroy
            EditBoxInfo.Remove(HwndEdit, "")
        } else
            Gui, %HwndEdit%:Hide
    Return
} ;</06.01.000002>
;<06.01.000003>
Popup(title, action, close=true, image="", w=197, h=46) {                            	    	;-- Splashtext Gui

    SysGet, Screen, MonitorWorkArea
    ScreenRight-=w+3
    ScreenBottom-=h+4
    SplashImage,%image%,CWe0dfe3 b1 x%ScreenRight% y%ScreenBottom% w%w% h%h% C00 FM8 FS8, %action%,%title%,Popup
    WinSet, Transparent, 216, Popup
    if close
        SetTimer, ClosePopup, -2000
    return

	ClosePopup:
    WinGet,WinID,ID,Popup
    MouseGetPos,,,MouseWinID
    ifEqual,WinID,%MouseWinID%
    {
        SetTimer, ClosePopup, -2000
    }else{
        SplashImage, Off
    }
    return

} ;</06.01.000003>
;<06.01.000004>
PIC_GDI_GUI(GuiName, byref File, GDIx, GDIy , GDIw, GDIh) {                            	;-- a GDI-gui to show a picture

				global GGhdc
			If !pToken := Gdip_Startup() {
			   MsgBox, 0x40048, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
			   ExitApp
			}
			; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
			Gui, %GuiName%:-Caption +E0x80000 +LastFound +AlwaysOnTop
			Gui, %GuiName%:+Owner
			Gui, %GuiName%: Show, Center ; x%GDIx% y%GDIy%

			hwnd1 := WinExist()

			pBitmap1 := Gdip_CreateBitmapFromFile(file)
			; Check to ensure we actually got a bitmap from the file, in case the file was corrupt or some other error occured
			If (!pBitmap1) {
				MsgBox, 0x40048, File loading error!, Could not load '%file%'
				ExitApp
			}
			;Load picture to pBitmap
			IWidth := Gdip_GetImageWidth(pBitmap1), IHeight := Gdip_GetImageHeight(pBitmap1)
			hbm := CreateDIBSection(GDIw, GDIh)
			GGhdc := CreateCompatibleDC()
			obm := SelectObject(GGhdc, hbm)
			G1 := Gdip_GraphicsFromHDC(GGhdc)
			Gdip_SetInterpolationMode(G, 7)
			Gdip_DrawImage(G1, pBitmap1, 0, 0, GDIw, GDIh, 0, 0, GDIw, GDIh)
			UpdateLayeredWindow(hwnd1, GGhdc, GDIx, GDIy, GDIw, GDIh)

			SelectObject(hdc, obm)
			DeleteObject(hbm)
			DeleteDC(hdc)
			Gdip_DeleteGraphics(G1)

return [hwnd1, GGhdc]
} ;</06.01.000004>
;<06.01.000005>
SplitButton(hButton, GlyphSize=16, Menu="", hDontUse="") {                          	;--	drop down button

	/*	DESCRIPTION OF FUNCTION: -- SplitButton() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	proof-of-concept stdlib function for creating split buttons (drop down buttons).
	                        	Needs more options built in (changing the glyph, styles, etc) but its a start... Enjoy
	Link              	:	https://autohotkey.com/boards/viewtopic.php?t=22830
	Author         	:	gwarble
	Date             	:	09 September, 2016
	AHK-Version	:	AHK_L
	License         	:	-
	Syntax          	:	SplitButton ( hButton [, GlyphSize, MenuName, hDontUse ] )
	Parameter(s)	:	- hButton     	= hWnd of button to turn into SplitButton
		                     	- GlyphSize  	= size of down arrow glyph (default: 16)
		                     	- MenuName	= name of menu to call when clicked (default: SplitButton_Menu)
								parameters need to be expanded to cover these options:
	                        	BUTTON_SPLITINFO struct     	;INFO mask flags        				;STYLE flags
								UINT       mask;        			  	;BCSIF_GLYPH 	:= 0x0001  		;BCSS_NOSPLIT	:= 0x0001
								HIMAGELIST himlGlyph;      	;BCSIF_IMAGE 	:= 0x0002  		;BCSS_STRETCH  	:= 0x0002
								UINT       uSplitStyle; 		       	;BCSIF_STYLE 	:= 0x0004  		;BCSS_ALIGNLEFT:= 0x0004
								SIZE       size;        			       	;BCSIF_SIZE  	:= 0x0008  		;BCSS_IMAGE   	:= 0x0008
	Return value	:
	Remark(s)    	:	- statically saved hwnd of button from first call needs turned into array...
								 for now only one button can be a SplitButton
	                         	- will conflict with other code using WM_Notify OnMessage()
	                         	- missing features from API for glyph size, imagelist, styles, etc...
	                         	- Requires Vista+, unsupported on XP
	Dependencies	:
	KeyWords    	:	Gui, Control
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Menu, SplitButton_Menu, Add, First Item, DoNothing
	Menu, SplitButton_Menu, Add, Second Item, DoNothing
	Gui, Add, Button, w160 h80 hwndhButton, Button
	SplitButton(hButton)
	Gui, Show
	DoNothing:
	Return

	*/

	Static       	 _  	:= OnMessage(0x4E, "SplitButton") ;WM_NOTIFY
	Static Menu_	:= "SplitButton_Menu"
	Static hButton_


	If (Menu=0x4E) {

			hCtrl := NumGet(GlyphSize+0, 0, "Ptr") ;-> lParam -> NMHDR -> hCtrl

			If (hCtrl = hButton_) { ;BCN_DROPDOWN for SplitButton

				id := NumGet(GlyphSize+0, A_PtrSize * 2, "uInt")
				If (id = 0xFFFFFB20) {
					ControlGetPos, cX, cY, cW, cH,, ahk_id %hButton_%
					Menu, %Menu_%, Show, % cX+1, % cY + cH
					}
			}
	 } Else {

			If (Menu <> "")
				Menu_ := Menu

			hButton_ := hButton
			Winset,   Style, +0x0C, ahk_id %hButton%          ;BS_SPLITBUTTON
			VarSetCapacity(   pBUTTON_SPLITINFO,  40, 0)
			NumPut(8,         pBUTTON_SPLITINFO,   0, "Int")  ;set glyph size
			NumPut(GlyphSize, pBUTTON_SPLITINFO,  4 + A_PtrSize * 2, "Int")
			SendMessage, BCM_SETSPLITINFO := 0x1607, 0, &pBUTTON_SPLITINFO, , ahk_id %hButton%
			Return

	}

} ;</06.01.000005>
;<06.01.000006>
BetterBox(Title := "", Prompt := "", Default := "", Pos := -1) {                              	;--	custom input box allows to choose the position of the text insertion point

	;-------------------------------------------------------------------------------
    ; custom input box allows to choose the position of the text insertion point
    ; return the entered text
    ;
    ; Title is the title for the GUI
    ; Prompt is the text to display
    ; Default is the text initially shown in the edit control
    ; Pos is the position of the text insertion point
    ;   Pos =  0  => at the start of the string
    ;   Pos =  1  => after the first character of the string
    ;   Pos = -1  => at the end of the string
    ;---------------------------------------------------------------------------

    static Result ; used as a GUI control variable

    ; create GUI
    Gui, BetterBox: New, +LastFound, %Title%
    Gui, -MinimizeBox
    Gui, Margin, 30, 18
    Gui, Add, Text,, %Prompt%
    Gui, Add, Edit, w290 vResult, %Default%
    Gui, Add, Button, x80 w80 Default, &OK
    Gui, Add, Button, x+m wp, &Cancel

    ; main loop
    Gui, Show
    SendMessage, 0xB1, %Pos%, %Pos%, Edit1, A ; EM_SETSEL
    WinWaitClose
    Return, Result

    ;-----------------------------------
    ; event handlers
    ;-----------------------------------
    BetterBoxButtonOK: ; "OK" button
        Gui, Submit ; get Result from GUI
        Gui, Destroy
    Return

    BetterBoxButtonCancel: ; "Cancel" button
    BetterBoxGuiClose:     ; {Alt+F4} pressed, [X] clicked
    BetterBoxGuiEscape:    ; {Esc} pressed
        Result := "BetterBoxCancel"
        Gui, Destroy
    Return
} ;</06.01.000006>
;<06.01.000007>
BtnBox(Title := "", Prompt := "", List := "", Seconds := "") {                                 	;--	show a custom MsgBox with arbitrarily named buttons
;-------------------------------------------------------------------------------
    ; show a custom MsgBox with arbitrarily named buttons
    ; return the text of the button pressed
    ;
    ; Title is the title for the GUI
    ; Prompt is the text to display
    ; List is a pipe delimited list of captions for the buttons
    ; Seconds is the time in seconds to wait before timing out
    ;---------------------------------------------------------------------------

    ; create GUI
    Gui, BtnBox: New, +LastFound, %Title%
    Gui, -MinimizeBox
    Gui, Margin, 30, 18
    Gui, Add, Text,, %Prompt%
    Loop, Parse, List, |
        Gui, Add, Button, % (A_Index = 1 ? "" : "x+10") " gBtn", %A_LoopField%

    ; main loop
    Gui, Show
    WinWaitClose,,, %Seconds%
    If (ErrorLevel = 1) {
        Result := "TimeOut"
        Gui, Destroy
    }
    Return, Result


    ;-----------------------------------
    ; event handlers
    ;-----------------------------------
    Btn: ; all the buttons come here
        Result := A_GuiControl
        Gui, Destroy
    Return

    BtnBoxGuiClose: ; {Alt+F4} pressed, [X] clicked
        Result := "WinClose"
        Gui, Destroy
    Return

    BtnBoxGuiEscape: ; {Esc} pressed
        Result := "EscapeKey"
        Gui, Destroy
    Return
} ;</06.01.000007>
;<06.01.000008>
LoginBox(Title := "") {                                                                                          	;-- show a custom input box for credentials, return an object with Username and Password
	;-------------------------------------------------------------------------------
    ; show a custom input box for credentials
    ; return an object with Username and Password
    ;
    ; Title is the title for the GUI
    ;---------------------------------------------------------------------------

    static Name, Pass ; used as a GUI control variables

    ; create GUI
    Gui, LoginBox: New, +LastFound, %Title%
    Gui, -MinimizeBox
    Gui, Margin, 30, 18
    Gui, Add, Text, ym+4 w55, Username:
    Gui, Add, Edit, x+10 yp-4 w100 vName
    Gui, Add, Text, xm y+10 w55, Password:
    Gui, Add, Edit, x+10 yp-4 w100 vPass Password
    Gui, Add, Button, w80 Default, &OK

    ; main loop
    Gui, Show
    WinWaitClose
    Return, Result


    ;-----------------------------------
    ; event handlers
    ;-----------------------------------
    LoginBoxButtonOK:  ; "OK" button, {Enter} pressed
        Gui, Submit
        Result := {Username: Name, Password: Pass}
        Gui, Destroy
    Return

    LoginBoxGuiClose:  ; {Alt+F4} pressed, [X] clicked
        Result := "WinClose"
        Gui, Destroy
    Return

    LoginBoxGuiEscape: ; {Esc} pressed
        Result := "EscapeKey"
        Gui, Destroy
    Return
} ;</06.01.000008>
;<06.01.000009>
MultiBox(Title := "", Prompt := "", Default := "") {                                               	;-- show a multi-line input box, return the entered text

;-------------------------------------------------------------------------------
    ; show a multi-line input box
    ; return the entered text
    ;
    ; Title is the title for the GUI
    ; Prompt is the text to display
    ; Default is shown in the edit control
    ;---------------------------------------------------------------------------

    static Result ; used as a GUI control variable

    ; create GUI
    Gui, MultiBox: New, +LastFound, %Title%
    Gui, -MinimizeBox
    Gui, Margin, 30, 18
    Gui, Add, Text,, %Prompt%
    Gui, Add, Edit, w640 r10 vResult, %Default%
    Gui, Add, Button, w80 Default, &OK
    Gui, Add, Button, x+m wp, &Cancel

    ; main loop
    Gui, Show
    SendMessage, 0xB1, -1,, Edit1, A ; EM_SETSEL
    WinWaitClose
    Return, Result


    ;-----------------------------------
    ; event handlers
    ;-----------------------------------
    MultiBoxButtonOK: ; "OK" button, {Enter} pressed
        Gui, Submit ; get Result from GUI
        Gui, Destroy
    Return

    MultiBoxButtonCancel: ; "Cancel" button
    MultiBoxGuiClose:     ; {Alt+F4} pressed, [X] clicked
    MultiBoxGuiEscape:    ; {Esc} pressed
        Result := "MultiBoxCancel"
        Gui, Destroy
    Return
} ;</06.01.000009>
;<06.01.000010>
PassBox(Title := "", Prompt := "") {                                                                      	;-- show a custom input box for a password

	;-------------------------------------------------------------------------------
    ; show a custom input box for a password
    ; return the entered password
    ;
    ; Title is the title for the GUI
    ; Prompt is the text to display
    ;---------------------------------------------------------------------------

    static Result ; used as a GUI control variables

    ; create GUI
    Gui, PassBox: New, +LastFound, %Title%
    Gui, -MinimizeBox
    Gui, Margin, 30, 18
    Gui, Add, Text,, %Prompt%
    Gui, Add, Edit, w100 vResult Password
    Gui, Add, Button, w80 Default, &OK

    ; main loop
    Gui, Show
    WinWaitClose
    Return, Result


    ;-----------------------------------
    ; event handlers
    ;-----------------------------------
    PassBoxButtonOK: ; "OK" button, {Enter} pressed
        Gui, Submit ; get Result from GUI
        Gui, Destroy
    Return

    PassBoxGuiClose: ; {Alt+F4} pressed, [X] clicked
        Result := "WinClose"
        Gui, Destroy
    Return

    PassBoxGuiEscape: ; {Esc} pressed
        Result := "EscapeKey"
        Gui, Destroy
    Return
} ;</06.01.000010>
;<06.01.000011>
CreateHotkeyWindow(key) {      	                                                                         	;-- Hotkey Window

	/*                            				Example

		#7::
		CreateWindow(Win + 7)
		return

	*/

	GetTextSize(key,35,Verdana,height,width)
	bgTopPadding = 40
	bgWidthPadding = 100
	bgHeight = % height + bgTopPadding
	bgWidth = % width + bgWidthPadding
	padding = 20
	yPlacement = % A_ScreenHeight ֠bgHeight ֠padding
	xPlacement = % A_ScreenWidth ֠bgWidth ֠padding

	Gui, Color, 46bfec
	Gui, Margin, 0, 0
	Gui, Add, Picture, x0 y0 w%bgWidth% h%bgHeight%, C:\Users\IrisDaniela\Pictures\bg.png
	Gui, +LastFound +AlwaysOnTop -Border -SysMenu +Owner -Caption +ToolWindow
	Gui, Font, s35 cWhite, Verdana
	Gui, Add, Text, xm y20 x25 ,%key%
	Gui, Show, x%xPlacement% y%yPlacement%
	SetTimer, RemoveGui, 5000

	return

	RemoveGui:
		Gui, Destroy
	return

} ;</06.01.000011>
;<06.01.000012>
GetUserInput(Default="",Text="",Options="",Control="") {                                	;-- allows you to create custom dialogs that can store different values (each value has a different set of controls)

	; http://ahkscript.org/germans/forums/viewtopic.php?t=7505 by Banane 2015
	/*	DESCRIPTION OF FUNCTION: --  --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	This function allows you to create custom dialogs that can store different values (each
	                        	value has a different set of controls).	Either the dialog can be used to type plain text or
								a number, or to let the user select a file, all in one dialog, whose texts and Gui options
								are freely configurable.

	                        	Both option parameters share the same syntax: "Option=Value", separated by commas,
								some options can also be specified without a value, if this is intended by the function,
								and the options do not have to be written out, since only the first letter of the name
								is important.

	                        	Optionally you can also specify a "Control Definitions List", this is a command chain
								separated by "`n", which serves to add new controls to the dialog, using an AHK-like
								syntax: "Command, Parameter1, Parameter2,...", you can also leave	parameters empty
								and to write a comma, `, must be used.
	Link              	:
	Author         	:
	Date             	:
	AHK-Version	:
	License         	:
	Syntax          	:
	Parameter(s)	:	========================================================
                              	Text - Options Parameter
                            	========================================================
                            	Window        	= Window Title
                            	Description    	= Description
                            	Ok                	= Text button
                            	Select           	= File selection dialog
                            	InvalidText     	= Error / Info Message
                            	========================================================
                            	Options - Options Parameter
                            	========================================================
                            	Gui                 	= Gui Options
                            	Value             	= Value Type
                            	                        	Num: Edit + UpDown Control
                            	                        	Str: Edit
                            	                        	File: Edit + Button
                            	Size                 	= Window Size
                            	Transparency	= Transparency of the Gui
                            	Region = Changes the Gui form
                            	NoEmptyStr = Blank text is invalid
                            	FileExist = Only existing file is valid
                            	InputRange = Lowest-Highest Number
                            	DisableEdit = Disables the input field
                            	=========================================================
                            	Control - Can create a Control Definitions list to display the dialog New Controls to add
                            	            	Available Controls: :
                            	                	Button, text, position, options, label
                            	                	GroupBox, Text, Position, Options
                            	                	Picture, File, Position, Options, Label
                            	                	Text, Text, Position, Options, Label
                            	=========================================================
	Return value	:
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	;Example 1 - Numerical value
	;Code:
	MsgBox % GetUserInput(0,"Window=Numerical Value,Description=Enter a numerical value,Ok=Ok","Value=Num,Size=xCenter yCenter w250 h80")


	;Example 2 - File Selection
	;Code:
	MsgBox % GetUserInput("Hello World.txt","Window=File-Selection,Select=Select a file:,Ok=Ok","Gui=+ToolWindow,Value=File")


	;Example 3 - List of Control Definitions
	;Code:
	Definition =
	(
	GroupBox,, x5 y45 w330 h75, +BackgroundTrans
	Button, Help, x10 y55 w100 h20, -Theme, Dialog_Handler
	)

	MsgBox % GetUserInput("","","Gui=-Theme,Size=xCenter yCenter w340 h150,NoEmptyStr",Definition)

	Dialog_Handler:
	  MsgBox User pressed "Dialog Button-%A_GuiControl%"
	  Return

	*/
	/*			Description:



	*/

  ;--- Default Options
  TXT_W := "Input",TXT_D := "Enter a value:",TXT_O := "Apply",TXT_S := "Select a file",TXT_I := "Invalid Input."
  OPT_G := "+Toolwindow -SysMenu +AlwaysOnTop",OPT_V := "Str",OPT_S := "xCenter yCenter w340 h80"
  OPT_T := 255,OPT_R := "",OPT_N := "",OPT_F := "",OPT_I := "0-100",OPT_D := ""

  ;--- Parse value lists
  Loop, Parse, Text, `,, % A_Space
    If (InStr("W,D,O,S,I",SubStr(A_LoopField,1,1)))
      NM := SubStr(A_LoopField,1,1),TXT_%NM% := SubStr(A_LoopField,InStr(A_LoopField,"=") + 1,StrLen(A_LoopField))
  Loop, Parse, Options, `,, % A_Space
    If (InStr("G,V,S,T,R,N,F,I,D",SubStr(A_LoopField,1,1)))
      NM := SubStr(A_LoopField,1,1),OPT_%NM% := SubStr(A_LoopField,InStr(A_LoopField,"=") + 1,StrLen(A_LoopField))
  ;--- And retrieved positions keyvalue list
  Loop, Parse, OPT_S, % A_Space, % A_Space
    NM := SubStr(A_LoopField,1,1),VL := SubStr(A_LoopField,2,StrLen(A_LoopField)),POS_%NM% := VL
  ;--- Interpret the control definition
  Loop, Parse, Control, `n, % A_Space
    ;--- Only proceed on valid controls
    If (InStr("Pict,Butt,Text,Grou",SubStr(A_LoopField,1,4))) {
      ;--- Reset arguments variables
      ARG_1 := "",ARG_2 := "",ARG_3 := "",ARG_4 := "",ARG_5 := ""
      ;--- Replace `, temporary (as we parse it with comma)
      Values := RegExReplace(A_LoopField,"\``,","[TEXC]")
      ;--- Parse each param
      Loop, Parse, Values, `,, % A_Space
        ;--- Save argument and restore comma
        ARG_%A_Index% := RegExReplace(A_LoopField,"\[TEXC]",",")
      ;--- Add control to gui
      Gui, 99:Add, % ARG_1, %ARG_3% %ARG_4% g%ARG_5%, % ARG_2
    }

  ;--- Create the dialog
  Gui, 99:%OPT_G% -Resize -MinimizeBox -MaximizeBox +LastFound +LabelGetUserInput_
    Gui, 99:Add, Text, x5 y5 w%POS_W% h15 +BackgroundTrans, % TXT_D
    ;--- Add select button and shorten the edit field
    If (OPT_V = "File") {
      W := POS_W - 35
      Gui, 99:Add, Button, x%W% y25 w30 h20 gGetUserInput_SelectFile, ...
      W := W - 10
    } Else W := POS_W - 10
    ;--- Add the edit field with calculated dimensions
    Gui, 99:Add, Edit, x5 y25 w%W% h20, % Default
    ;--- Disable edit if wanted
    If (SubStr(OPT_D,1,1) = "D" && OPT_V = "File")
      GuiControl, 99:+Disabled, Edit1
    ;--- Create UpDown control for numbers and check edit content
    If (OPT_V = "Num") {
      Gui, 99:Add, UpDown, +Range%OPT_I%, % Value
      GuiControl, 99:+gGetUserInput_CheckEdit, Edit1
    }
    ;--- Calculate button position
    X := (POS_W - 100) / 2,Y := POS_H - 25
    Gui, 99:Add, Button, x%X% y%Y% w100 h20 +Default gGetUserInput_Apply, % TXT_O
  ;--- Show the dialog
  Gui, 99:Show, x%POS_X% y%POS_Y% w%POS_W% h%POS_H%, % TXT_W
  ;--- Apply transparency
  WinSet, Transparent, % OPT_T
  ;--- Apply region
  WinSet, Region, % OPT_R
  ;--- Wait until the dialog is closed
  WinWaitClose
  ;--- And return the input
  Return Edit1

  GetUserInput_CheckEdit:
    ;--- Retrieve the edit's value
    GuiControlGet, Edit1
    ;--- Check if edit's content isn't a numerical value
    If Edit1 is not Number
      ;--- If Type isn't the same as specified "Value" option, apply default
      GuiControl, 99:, Edit1, % Default
    Return

  GetUserInput_Apply:
    ;--- Retrieve the edit's value
    GuiControlGet, Edit1
    GoSub, GetUserInput_Do
    Return

  GetUserInput_SelectFile:
    ;--- Let the user select a file
    FileSelectFile, Value,,, % TXT_S
    ;--- Only apply if a file was selected
    If (Value <> "")
      GuiControl, 99:, Edit1, % Value
    Return

  GetUserInput_Close:
  GetUserInput_Do:
    ;--- Check which value to use
    If (A_GuiControl = TXT_O) {
      GuiControlGet, Edit1
      ;--- Stop if value doesn't complies the requirements
      If (SubStr(OPT_N,1,1) = "N" && Edit1 = "") || (SubStr(OPT_F,1,1) = "F" && FileExist(Edit1) = "") {
        MsgBox, 48, % TXT_W, % TXT_I
        Return
      }
    } Else Edit1 := Default
    ;--- Destroy the window to finish function
    Gui, 99:Destroy
    Return
} ;</06.01.000012>
;<06.01.000013>
guiMsgBox(title, text, owner="", isEditable=0, wait=0, w="", h="") {                 	;-- GUI Message Box to allow selection

	;dependings: function - getControlInfo()

	static thebox
	wf := getControlInfo("edit", text, "w", "s9", "Lucida Console")
	hf := getControlInfo("edit", text, "h", "s9", "Lucida Console")
	w := !w ? (wf > A_ScreenWidth/1.5 ? A_ScreenWidth/1.5 : wf+200) : w 	;+10 for scl bar
	h := !h ? (hf > A_ScreenHeight ? A_ScreenHeight : hf+65) : h 		;+10 for margin, +more for the button

	Gui, guiMsgBox:New
	Gui, guiMsgBox:+Owner%owner%
	Gui, -MaximizeBox +AlwaysOnTop
	Gui, Font, s9, Lucida Console
	Gui, Add, Edit, % "x5 y5 w" w-10 " h" h-35 (isEditable ? " -" : " +") "Readonly vthebox +multi -Border", % text
	Gui, Add, button, % "x" w/2-20 " w40 y+5", OK
	GuiControl, Focus, button1
	Gui, guiMsgBox:Show, % "w" w " h" h, % title
	if wait
		while GuiEnds
			sleep 100
	return thebox

guiMsgBoxButtonOK:
guiMsgBoxGuiClose:
guiMsgBoxGuiEscape:
	Gui, guiMsgBox:Submit, nohide
	Gui, guiMsgBox:Destroy
	GuiEnds := 1
	return
} ;</06.01.000013>
;<06.01.000014>
URLPrefGui(p_w, p_l, p_m, p_hw)   {                                                                    	;-- shimanov's workaround for displaying URLs in a gui
	/*                              	DESCRIPTION

			     Thanks to shimanov for this function

			     Link         	:  	http://www.autohotkey.com/forum/viewtopic.php?p=37805 <-- link is dead
										a bit different but uses the same function: https://autohotkey.com/board/topic/5896-gui-hyperlink/
			     Parameter	:  	p_w            	: WPARAM value
										p_l             	: LPARAM value
										p_m          	: message number
										p_hw          	: window handle HWND

			     Remark(s)	:	Further details can be found in the documentation for 'OnMessage()'

	*/
	/*                              	EXAMPLE(s)

			Gui, Margin, 5, 5
			  Gui, Add, Text, xm ym, Multiple URLs in one GUI
			  Gui, Add, Text, xp( yp"5 cBlue gLink1 v[color=red]URL[/color]_Link1, www.autohotkey.com
			  Gui, Add, Text, xp   yp"0 cBlue gLink2 v[color=red]URL[/color]_Link2, de.autohotkey.com
			  Gui, Add, Text, xp   yp"0 cBlue gLink3 v[color=red]URL[/color]_Link3, www.google.com
			  Gui, Add, Text, xp   yp"0 cBlue gLink4 v[color=red]URL[/color]_Link4, www.msdn.com
			  Gui, Font, norm
			  Gui, Show,, URL

			  ; Retrieve scripts PID
			  Process, Exist
			  pid_this := ErrorLevel

			  ; Retrieve unique ID number (HWND/handle)
			  WinGet, hw_gui, ID, ahk_class AutoHotkeyGUI ahk_pid %pid_this%

			  ; Call "HandleMessage" when script receives WM_SETCURSOR message
			  WM_SETCURSOR = 0x20
			  OnMessage(WM_SETCURSOR, "URLPrefGui")

			  ; Call "HandleMessage" when script receives WM_MOUSEMOVE message
			  WM_MOUSEMOVE = 0x200
			  OnMessage(WM_MOUSEMOVE, "URLPrefGui")
			Return

			GuiClose:
			  ExitApp
			;End of GUI


			;GUI glabels
			Link1:
			  Run, http://www.autohotkey.com/forum
			Return

			Link2:
			  Run, http://de.autohotkey.com
			Return

			Link3:
			  Run, http://www.google.com
			Return

			Link4:
			  Run, http://www.msdn.com
			Return
			;End Of GUI glabels

	*/


    global   WM_SETCURSOR, WM_MOUSEMOVE
    static   URL_hover, h_cursor_hand, h_old_cursor

    If (p_m = WM_SETCURSOR)
      {
        If URL_hover
          Return, true
      }
    Else If (p_m = WM_MOUSEMOVE)
      {
        ; Mouse cursor hovers URL Text control
        If (A_GuiControl = "URL_DocLink")
          {
            If URL_hover=
              {
                Gui, Font, cBlue underline
                GuiControl, Font, URL_DocLink

                h_cursor_hand := DllCall("LoadCursor", "uint", 0, "uint", 32649)

                URL_hover := true
              }
              h_old_cursor := DllCall("SetCursor", "uint", h_cursor_hand)
          }
        ; Mouse cursor doesn't hover URL Text control
        Else
          {
            If URL_hover
              {
                Gui, Font, norm cBlue
                GuiControl, Font, URL_DocLink

                DllCall("SetCursor", "uint", h_old_cursor)

                URL_hover=
              }
          }
      }
}  ;</06.01.000014>
;<06.01.000015>
TaskDialog(Instruction, Content := "", Title := "", Buttons := 1,                          	;-- a Task Dialog is a new kind of dialogbox that has been added in Windows Vista and later. They are similar to message boxes, but with much more power.
IconID := 0, IconRes := "", Owner := 0x10010) {
    Local hModule, LoadLib, Ret

    If (IconRes != "") {
        hModule := DllCall("GetModuleHandle", "Str", IconRes, "Ptr")
        LoadLib := !hModule
            && hModule := DllCall("LoadLibraryEx", "Str", IconRes, "UInt", 0, "UInt", 0x2, "Ptr")
    } Else {
        hModule := 0
        LoadLib := False
    }

    DllCall("TaskDialog"
        , "Ptr" , Owner        ; hWndParent
        , "Ptr" , hModule      ; hInstance
        , "Ptr" , &Title       ; pszWindowTitle
        , "Ptr" , &Instruction ; pszMainInstruction
        , "Ptr" , &Content     ; pszContent
        , "Int" , Buttons      ; dwCommonButtons
        , "Ptr" , IconID       ; pszIcon
        , "Int*", Ret := 0)    ; *pnButton

    If (LoadLib) {
        DllCall("FreeLibrary", "Ptr", hModule)
    }

    Return {1: "OK", 2: "Cancel", 4: "Retry", 6: "Yes", 7: "No", 8: "Close"}[Ret]
} ;</06.01.000015>
;<06.01.000016>
TaskDialogDirect(Instruction, Content := "", Title := "", CustomButtons := "",   		;-- part of TaskDialog ?
CommonButtons := 0, MainIcon := 0, Flags := 0, Owner := 0x10010, VerificationText := "", ExpandedText := "", FooterText := "", FooterIcon := 0, Width := 0) {
    Static x64 := A_PtrSize == 8, Button := 0, Checked := 0

    If (CustomButtons != "") {
        Buttons := StrSplit(CustomButtons, "|")
        cButtons := Buttons.Length()
        VarSetCapacity(pButtons, 4 * cButtons + A_PtrSize * cButtons, 0)
        Loop %cButtons% {
            iButtonText := &(b%A_Index% := Buttons[A_Index])
            NumPut(100 + A_Index, pButtons, (4 + A_PtrSize) * (A_Index - 1), "Int")
            NumPut(iButtonText, pButtons, (4 + A_PtrSize) * A_Index - A_PtrSize, "Ptr")
        }
    } Else {
        cButtons := 0
        pButtons := 0
    }

    NumPut(VarSetCapacity(TDC, (x64) ? 160 : 96, 0), TDC, 0, "UInt") ; cbSize
    NumPut(Owner, TDC, 4, "Ptr") ; hwndParent
    NumPut(Flags, TDC, (x64) ? 20 : 12, "Int") ; dwFlags
    NumPut(CommonButtons, TDC, (x64) ? 24 : 16, "Int") ; dwCommonButtons
    NumPut(&Title, TDC, (x64) ? 28 : 20, "Ptr") ; pszWindowTitle
    NumPut(MainIcon, TDC, (x64) ? 36 : 24, "Ptr") ; pszMainIcon
    NumPut(&Instruction, TDC, (x64) ? 44 : 28, "Ptr") ; pszMainInstruction
    NumPut(&Content, TDC, (x64) ? 52 : 32, "Ptr") ; pszContent
    NumPut(cButtons, TDC, (x64) ? 60 : 36, "UInt") ; cButtons
    NumPut(&pButtons, TDC, (x64) ? 64 : 40, "Ptr") ; pButtons
    NumPut(&VerificationText, TDC, (x64) ? 92 : 60, "Ptr") ; pszVerificationText
    NumPut(&ExpandedText, TDC, (x64) ? 100 : 64, "Ptr") ; pszExpandedInformation
    NumPut(FooterIcon, TDC, (x64) ? 124 : 76, "Ptr") ; pszFooterIcon
    NumPut(&FooterText, TDC, (x64) ? 132 : 80, "Ptr") ; pszFooter
    NumPut(Width, TDC, (x64) ? 156 : 92, "UInt") ; cxWidth

    If (DllCall("Comctl32.dll\TaskDialogIndirect", "Ptr", &TDC, "Int*", Button, "Int", 0, "Int*", Checked) == 0) {
        Return (VerificationText == "") ? Button : [Button, Checked]
    } Else {
        Return "ERROR"
    }
} ;</06.01.000016>
;<06.01.000017>
TaskDialogMsgBox(Main, Extra, Title := "", Buttons := 0, Icon := 0,                    	;-- part of TaskDialog ?
Parent := 0, TimeOut := 0) {

	Static MBICON := {1: 0x30, 2: 0x10, 3: 0x40, WARN: 0x30, ERROR: 0x10, INFO: 0x40, QUESTION: 0x20}
		, TDBTNS := {OK: 1, YES: 2, NO: 4, CANCEL: 8, RETRY: 16}
	BTNS := 0
	if Buttons Is Integer
		BTNS := Buttons & 0x1F
	else
		For Each, Btn In StrSplit(Buttons, ["|", " ", ",", "`n"])
	BTNS |= (B := TDBTNS[Btn]) ? B : 0
	Options := 0
	Options |= (I := MBICON[Icon]) ? I : 0
	Options |= Parent = -1 ? 262144 : Parent > 0 ? 8192 : 0
	if ((BTNS & 14) = 14)
		Options |= 0x03 ; Yes/No/Cancel
	else if ((BTNS & 6) = 6)
		Options |= 0x04 ; Yes/No
	else if ((BTNS & 24) = 24)
		Options |= 0x05 ; Retry/Cancel
	else if ((BTNS & 9) = 9)
		Options |= 0x01 ; OK/Cancel
	Main .= Extra <> "" ? "`n`n" . Extra : ""
	MsgBox, % Options, %Title%, %Main%, %TimeOut%
	IfMsgBox, OK
		return 1
	IfMsgBox, Cancel
		return 2
	IfMsgBox, Retry
		return 4
	IfMsgBox, Yes
		return 6
	IfMsgBox, No
		return 7
	IfMsgBox, TimeOut
		return -1
	return 0

} ;</06.01.000017>
;<06.01.000018>
TaskDialogToUnicode(String, ByRef Var) {                            						     		;-- part of TaskDialog ?

	VarSetCapacity(Var, StrPut(String, "UTF-16") * 2, 0)
	StrPut(String, &Var, "UTF-16")
	return &Var

} ;</06.01.000018>
;<06.01.000019>
TaskDialogCallback(H, N, W, L, D) {                                                        	     			;-- part of TaskDialog ?

	Static TDM_Click_BUTTON := 0x0466
		, TDN_CREATED := 0
		, TDN_TIMER   := 4
	TD := Object(D)
	if (N = TDN_TIMER) && (W > TD.Timeout) {
		TD.TimedOut := True
		PostMessage, %TDM_Click_BUTTON%, 2, 0, , ahk_id %H% ; IDCANCEL = 2
	}
	else if (N = TDN_CREATED) && TD.AOT {
		DHW := A_DetectHiddenWindows
		DetectHiddenWindows, On
		WinSet, AlwaysOnTop, On, ahk_id %H%
		DetectHiddenWindows, %DHW%
	}
	return 0

} ;</06.01.000019>
;<06.01.000020>
TT_Console(msg, keys, x="", y="", fontops=""                                                    	;-- Use Tooltip as a User Interface it returns the key which has been pressed
, fontname="", whichtooltip=1, followMouse=0) {

	; Source: https://github.com/aviaryan/Clipjump/blob/master/lib/TT_Console.ahk
	; dependings: ToolTipEx()

	/*			DESCRIPTION
			TT_Console() v0.03
				Use Tooltip as a User Interface
			By:				Avi Aryan
			Info:				keys - stores space separated values of keys that are prompted for a user input
			            		font_options - Font options as in Gui ( eg -> s8 bold underline )
			            		font_face - Font face names. Separate them by a | to set prority
			Returns:   	The key which has been pressed
	*/

	/*			EXAMPLE
			;a := TT_Console( "Hi`nPress Y to see another message.`nPress N to exit script", "y n", empty_var, empty_var, 1, "s12", "Arial|Consolas")
			;if a = y
			;...
			;return
	*/

	hFont := getHFONT(fontops, fontname)
	TooltipEx(msg, x, y, whichtooltip, hFont)

	;create hotkeys
	loop, parse, keys, %A_space%, %a_space%
		hkZ(A_LoopField, "TT_Console_Check", 1)

	is_TTkey_pressed := 0
	while !is_TTkey_pressed
	{
		if followMouse
		{
			TooltipEx(msg,,, whichtooltip)
			sleep 100
		} else {
			sleep 20
		}
	}

	TooltipEx(,,, whichtooltip)

	loop, parse, keys, %A_space%, %a_space%
		hkZ(A_LoopField, "TT_Console_Check", 0)

	return what_pressed


TT_Console_Check:
	what_pressed := A_ThisHotkey
	is_TTkey_pressed := 1
	return
} ;</06.01.000020>
;<06.01.000021>
ToolTipEx(Text:="", X:="", Y:="", WhichToolTip:=1                                             	;-- Display ToolTips with custom fonts and colors
, HFONT:="", BgColor:="", TxColor:="", HICON:="", CoordMode:="W") {

	;source: https://github.com/aviaryan/Clipjump/blob/master/lib/TooltipEx.ahk
	;dependings: no

	/*		DESCRIPTION
		======================================================================================================================
		 ToolTipEx()     Display ToolTips with custom fonts and colors.
		                 Code based on the original AHK ToolTip implementation in Script2.cpp.
		 Tested with:    AHK 1.1.15.04 (A32/U32/U64)
		 Tested on:      Win 8.1 Pro (x64)
		 Change history:
		     1.1.01.00/2014-08-30/just me     -  fixed  bug preventing multiline tooltips.
		     1.1.00.00/2014-08-25/just me     -  added icon support, added named function parameters.
		     1.0.00.00/2014-08-16/just me     -  initial release.
		 Parameters:
		     Text           -  the text to display in the ToolTip.
		                       If omitted or empty, the ToolTip will be destroyed.
		     X              -  the X position of the ToolTip.
		                       Default: "" (mouse cursor)
		     Y              -  the Y position of the ToolTip.
		                       Default: "" (mouse cursor)
		     WhichToolTip   -  the number of the ToolTip.
		                       Values:  1 - 20
		                       Default: 1
		     HFONT          -  a HFONT handle of the font to be used.
		                       Default: 0 (default font)
		     BgColor        -  the background color of the ToolTip.
		                       Values:  RGB integer value or HTML color name.
		                       Default: "" (default color)
		     TxColor        -  the text color of the TooöTip.
		                       Values:  RGB integer value or HTML color name.
		                       Default: "" (default color)
		     HICON          -  the icon to display in the upper-left corner of the TooöTip.
		                       This can be the number of a predefined icon (1 = info, 2 = warning, 3 = error - add 3 to
		                       display large icons on Vista+) or a HICON handle. Specify 0 to remove an icon from the ToolTip.
		                       Default: "" (no icon)
		     CoordMode      -  the coordinate mode for the X and Y parameters, if specified.
		                       Values:  "C" (Client), "S" (Screen), "W" (Window)
		                       Default: "W" (CoordMode, ToolTip, Window)
		 Return values:
		     On success: The HWND of the ToolTip window.
		     On failure: False (ErrorLevel contains additional informations)
		 ======================================================================================================================
*/

	; ToolTip messages
	Static ADDTOOL  := A_IsUnicode ? 0x0432 : 0x0404 ; TTM_ADDTOOLW : TTM_ADDTOOLA
	Static BKGCOLOR := 0x0413 ; TTM_SETTIPBKCOLOR
	Static MAXTIPW  := 0x0418 ; TTM_SETMAXTIPWIDTH
	Static SETMARGN := 0x041A ; TTM_SETMARGIN
	Static SETTHEME := 0x200B ; TTM_SETWINDOWTHEME
	Static SETTITLE := A_IsUnicode ? 0x0421 : 0x0420 ; TTM_SETTITLEW : TTM_SETTITLEA
	Static TRACKACT := 0x0411 ; TTM_TRACKACTIVATE
	Static TRACKPOS := 0x0412 ; TTM_TRACKPOSITION
	Static TXTCOLOR := 0x0414 ; TTM_SETTIPTEXTCOLOR
	Static UPDTIPTX := A_IsUnicode ? 0x0439 : 0x040C ; TTM_UPDATETIPTEXTW : TTM_UPDATETIPTEXTA
	; Other constants
	Static MAX_TOOLTIPS := 20 ; maximum number of ToolTips to appear simultaneously
	Static SizeTI   := (4 * 6) + (A_PtrSize * 6) ; size of the TOOLINFO structure
	Static OffTxt   := (4 * 6) + (A_PtrSize * 3) ; offset of the lpszText field
	Static TT := [] ; ToolTip array
	; HTML Colors (BGR)
	Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080, GREEN: 0x008000
					  , LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080, PURPLE: 0x800080, RED: 0x0000FF
					  , SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF, YELLOW: 0x00FFFF}
	; -------------------------------------------------------------------------------------------------------------------
	; Init TT on first call
	If (TT.MaxIndex() = "")
		Loop, 20
			TT[A_Index] := {HW: 0, IC: 0, TX: ""}
	; -------------------------------------------------------------------------------------------------------------------
	; Check params
	TTTX := Text
	TTXP := X
	TTYP := Y
	TTIX := WhichToolTip = "" ? 1 : WhichToolTip
	TTHF := HFONT = "" ? 0 : HFONT
	TTBC := BgColor
	TTTC := TxColor
	TTIC := HICON
	TTCM := CoordMode = "" ? "W" : SubStr(CoordMode, 1, 1)
	If TTXP Is Not Digit
		Return False, ErrorLevel := "Invalid parameter X-position!", False
	If TTYP Is Not Digit
		Return  False, ErrorLevel := "Invalid parameter Y-Position!", False
	If (TTIX < 1) || (TTIX > MAX_TOOLTIPS)
		Return False, ErrorLevel := "Max ToolTip number is " . MAX_TOOLTIPS . ".", False
	If (TTHF) && !(DllCall("Gdi32.dll\GetObjectType", "Ptr", TTHF, "UInt") = 6) ; OBJ_FONT
		Return False, ErrorLevel := "Invalid font handle!", False
	If TTBC Is Integer
		TTBC := ((TTBC >> 16) & 0xFF) | (TTBC & 0x00FF00) | ((TTBC & 0xFF) << 16)
	Else
		TTBC := HTML.HasKey(TTBC) ? HTML[TTBC] : ""
	If TTTC Is Integer
		TTTC := ((TTTC >> 16) & 0xFF) | (TTTC & 0x00FF00) | ((TTTC & 0xFF) << 16)
	Else
		TTTC := HTML.HasKey(TTTC) ? HTML[TTTC] : ""
	If !InStr("CSW", TTCM)
		Return False, ErrorLevel := "Invalid parameter CoordMode!", False
	; -------------------------------------------------------------------------------------------------------------------
	; Destroy the ToolTip window, if Text is empty
	TTHW := TT[TTIX].HW
	If (TTTX = "") && (TTHW) {
		If DllCall("User32.dll\IsWindow", "Ptr", TTHW, "UInt")
			DllCall("User32.dll\DestroyWindow", "Ptr", TTHW)
		TT[TTIX] := {HW: 0, TX: ""}
		Return True
	}
	; -------------------------------------------------------------------------------------------------------------------
	; Get the virtual desktop rectangle
	SysGet, X, 76
	SysGet, Y, 77
	SysGet, W, 78
	SysGet, H, 79
	DTW := {L: X, T: Y, R: X + W, B: Y + H}
	; -------------------------------------------------------------------------------------------------------------------
	; Initialise the ToolTip coordinates. If either X or Y is empty, use the cursor position for the present.
	PT := {X: 0, Y: 0}
	If (TTXP = "") || (TTYP = "") {
		VarSetCapacity(Cursor, 8, 0)
		DllCall("User32.dll\GetCursorPos", "Ptr", &Cursor)
		Cursor := {X: NumGet(Cursor, 0, "Int"), Y: NumGet(Cursor, 4, "Int")}
		PT := {X: Cursor.X + 16, Y: Cursor.Y + 16}
	}
	; -------------------------------------------------------------------------------------------------------------------
	; If either X or Y  is specified, get the position of the active window considering CoordMode.
	Origin := {X: 0, Y: 0}
	If ((TTXP <> "") || (TTYP <> "")) && ((TTCM = "W") || (TTCM = "C")) { ; if (*aX || *aY) // Need the offsets.
		HWND := DllCall("User32.dll\GetForegroundWindow", "UPtr")
		If (TTCM = "W") {
			WinGetPos, X, Y, , , ahk_id %HWND%
			Origin := {X: X, Y: Y}
		}
		Else {
			VarSetCapacity(OriginPT, 8, 0)
			DllCall("User32.dll\ClientToScreen", "Ptr", HWND, "Ptr", &OriginPT)
			Origin := {X: NumGet(OriginPT, 0, "Int"), Y: NumGet(OriginPT, 0, "Int")}
		}
	}
	; -------------------------------------------------------------------------------------------------------------------
	; If either X or Y is specified, use the window related position for this parameter.
	If (TTXP <> "")
		PT.X := TTXP + Origin.X
	If (TTYP <> "")
		PT.Y := TTYP + Origin.Y
	; -------------------------------------------------------------------------------------------------------------------
	; Create and fill a TOOLINFO structure.
	TT[TTIX].TX := "T" . TTTX ; prefix with T to ensure it will be stored as a string in either case
	VarSetCapacity(TI, SizeTI, 0) ; TOOLINFO structure
	NumPut(SizeTI, TI, 0, "UInt")
	NumPut(0x0020, TI, 4, "UInt") ; TTF_TRACK
	NumPut(TT[TTIX].GetAddress("TX") + (1 << !!A_IsUnicode), TI, OffTxt, "Ptr")
	; -------------------------------------------------------------------------------------------------------------------
	; If the ToolTip window doesn't exist, create it.
	If !(TTHW) || !DllCall("User32.dll\IsWindow", "Ptr", TTHW, "UInt") {
		; ExStyle = WS_TOPMOST, Style = TTS_NOPREFIX | TTS_ALWAYSTIP
		TTHW := DllCall("User32.dll\CreateWindowEx", "UInt", 8, "Str", "tooltips_class32", "Ptr", 0, "UInt", 3
								, "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", A_ScriptHwnd, "Ptr", 0, "Ptr", 0, "Ptr", 0)
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", ADDTOOL, "Ptr", 0, "Ptr", &TI)
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", MAXTIPW, "Ptr", 0, "Ptr", A_ScreenWidth)
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", TRACKPOS, "Ptr", 0, "Ptr", PT.X | (PT.Y << 16))
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", TRACKACT, "Ptr", 1, "Ptr", &TI)
	}
	; -------------------------------------------------------------------------------------------------------------------
	; Update the text and the font and colors, if specified.
	If (TTBC <> "") || (TTTC <> "") { ; colors
		DllCall("UxTheme.dll\SetWindowTheme", "Ptr", TTHW, "Ptr", 0, "Str", "")
		VarSetCapacity(RC, 16, 0)
		NumPut(4, RC, 0, "Int"), NumPut(4, RC, 4, "Int"), NumPut(4, RC, 8, "Int"), NumPut(1, RC, 12, "Int")
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", SETMARGN, "Ptr", 0, "Ptr", &RC)
		If (TTBC <> "")
			DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", BKGCOLOR, "Ptr", TTBC, "Ptr", 0)
		If (TTTC <> "")
			DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", TXTCOLOR, "Ptr", TTTC, "Ptr", 0)
	}
	If (TTIC <> "")
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", SETTITLE, "Ptr", TTIC, "Str", " ")
	If (TTHF) ; font
		DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", 0x0030, "Ptr", TTHF, "Ptr", 1) ; WM_SETFONT
	DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", UPDTIPTX, "Ptr", 0, "Ptr", &TI)
	; -------------------------------------------------------------------------------------------------------------------
	; Get the ToolTip window dimensions.
	VarSetCapacity(RC, 16, 0)
	DllCall("User32.dll\GetWindowRect", "Ptr", TTHW, "Ptr", &RC)
	TTRC := {L: NumGet(RC, 0, "Int"), T: NumGet(RC, 4, "Int"), R: NumGet(RC, 8, "Int"), B: NumGet(RC, 12, "Int")}
	TTW := TTRC.R - TTRC.L
	TTH := TTRC.B - TTRC.T
	; -------------------------------------------------------------------------------------------------------------------
	; Check if the Tooltip will be partially outside the virtual desktop and adjust the position, if necessary.
	If (PT.X + TTW >= DTW.R)
		PT.X := DTW.R - TTW - 1
	If (PT.Y + TTH >= DTW.B)
		PT.Y := DTW.B - TTH - 1
	; -------------------------------------------------------------------------------------------------------------------
	; Check if the cursor is inside the ToolTip window and adjust the position, if necessary.
	If (TTXP = "") || (TTYP = "") {
		TTRC.L := PT.X, TTRC.T := PT.Y, TTRC.R := TTRC.L + TTW, TTRC.B := TTRC.T + TTH
		If (Cursor.X >= TTRC.L) && (Cursor.X <= TTRC.R) && (Cursor.Y >= TTRC.T) && (Cursor.Y <= TTRC.B)
			PT.X := Cursor.X - TTW - 3, PT.Y := Cursor.Y - TTH - 3
	}
	; -------------------------------------------------------------------------------------------------------------------
	; Show the Tooltip using the final coordinates.
	DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", TRACKPOS, "Ptr", 0, "Ptr", PT.X | (PT.Y << 16))
	DllCall("User32.dll\SendMessage", "Ptr", TTHW, "UInt", TRACKACT, "Ptr", 1, "Ptr", &TI)
	TT[TTIX].HW := TTHW
	Return TTHW
} ;</06.01.000021>
;<06.01.000022>
SafeInput(Title, Prompt, Default = "") {     ;-- makes sure the same window stays active after showing the InputBox. Otherwise you might get the text pasted into another window unexpectedly.

   ActiveWin := WinExist("A")
   InputBox OutPut, %Title%, %Prompt%,,, 120,,,,, %Default%
   WinActivate ahk_id %ActiveWin%
   Return OutPut
} ;</06.01.000022>
;functions end
}
;|   HtmlBox(01)                            	|   EditBox(02)                              	|   Popup(03)                                	|   PIC_GDI_GUI(04)                      	|
;|   SplitButton(05)                        	|   BetterBox(06)                           	|   BtnBox(07)                               	|   LoginBox(08)                            	|
;|   MultiBox(09)                            	|   PassBox(10)                             	|   CreateHotkeyWindow(11)        	|   GetUserInput(12)                     	|
;|   guiMsgBox(13)                        	|   URLPrefGui(14)                        	|   TaskDialog(15)                         	|   ITaskDialogDirect(16)              	|
;|   TaskDialogMsgBox(17)            	|   TaskDialogToUnicode(18)        	|   TaskDialogCallback(19)           	|   TT_Console(20)                        	|
;|   ToolTipEx(21)                          	|   SafeInput(22)                           	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;gui - to change (23) -- change position, fading, remove --                                                                       	baseID: <06.02>
;<06.02.000001>
FadeGui(guihwnd, fading_time, inout) {                                                                    	;-- used DllCall to Animate (Fade in/out) a window

	AW_BLEND := 0x00080000
	AW_HIDE  := 0x00010000

	if inout	= "out"
		DllCall("user32\AnimateWindow", "ptr", guihwnd, "uint", fading_time, "uint", AW_BLEND|AW_HIDE)    ; Fade Out
	if inout = "in"
		DllCall("user32\AnimateWindow", "ptr", guihwnd, "uint", fading_time, "uint", AW_BLEND)    ; Fade In

return
} ;</06.02.000001>
;<06.02.000002>
WinFadeToggle(WinTitle, Duration := 1, Hide := false) {	                                        	;-- smooth fading in out a window

	;attention: you need library print.ahk

	/**
	*  WinFadeTo( WinTitle, [, Duration] )
	*   WinTitle
	*      A window title identifying the name of the target window.
	*   Duration (default 1 second)
	*      A number (in seconds) defining how long the animation will take to complete.
	*      NOTE: The duration cannot be set to lower than 1 second.
	*   Hide (disabled by default)
	*      Set the visible state of the target window after fade out.
	*      NOTE: Enabled by default if "DetectHiddenWindows" is set to on, otherwise disabled.
	*/

	DetectHiddenWindows, On     ; Determines whether invisible windows are "seen" by the script.
	; Declarations
	LoopCount := 64 * Duration                      ; Calculated number of iterations for loop
	WinGet, WinOpacity, Transparent, %WinTitle%     ; Get transparency level of target window

	; Return error if target window does not exist or is not active
	If !WinExist(WinTitle) && !WinActive(WinTitle) {
		ErrorMessage := "Target window is not active or does not exist."
	}

	; Check "DetectHiddenWindows" state
	if ( A_DetectHiddenWindows = "On" ) {
		Hide := true
	}

	; Check target window for transparency level
	If ( WinOpacity = "" ) {
		WinSet, Transparent, 255, %WinTitle% ; Set transparency of target window
	}

	; Set the direction of the fade (in/out)
	if (WinOpacity = 255 || WinOpacity = "") {
		start := -255
		} else {
			start := 0
			WinShow, %WinTitle%
			WinActivate, %WinTitle%     ; Activate target window on fade in
		}

		; Iterate through each change in opacity level
		timer_start := A_TickCount ; Log time of fade start
		Loop, % LoopCount {
			opacity := Abs(255/LoopCount * A_Index + start) ; opacity value for the current iteration
			WinSet, Transparent, %opacity%, %WinTitle%      ; Set opacity level for target window
			Sleep, % duration                               ; Pause between each iteration
		}
		timer_stop := A_TickCount ; Log time of fade completion

		; Hide target window after fade-out completes
		if (start != 0 && Hide = true) {
			WinHide, %WinTitle%
		}

		Return ErrorMessage
} ;</06.02.000002>
;<06.02.000003>
winfade(w:="",t:=128,i:=1,d:=10) {                                                                           	;-- another winfade function

	; https://github.com/joedf/AEI.ahk/blob/master/AEI.ahk
	w:=(w="")?("ahk_id " WinActive("A")):w
	t:=(t>255)?255:(t<0)?0:t
	WinGet,s,Transparent,%w%
	s:=(s="")?255:s ;prevent trans unset bug
	WinSet,Transparent,%s%,%w%
	i:=(s<t)?abs(i):-1*abs(i)
	while(k:=(i<0)?(s>t):(s<t)&&WinExist(w)) {
		WinGet,s,Transparent,%w%
		s+=i
		WinSet,Transparent,%s%,%w%
		sleep %d%
	}
} ;</06.02.000003>
;<06.02.000004>
ShadowBorder(handle) {                                                                                          	;-- used DllCall to draw a shadow around a gui

    DllCall("user32.dll\SetClassLongPtr", "ptr", handle, "int", -26, "ptr", DllCall("user32.dll\GetClassLongPtr", "ptr", handle, "int", -26, "uptr") | 0x20000)

} ;</06.02.000004>
;<06.02.000005>
FrameShadow(handle) {																				            	;-- FrameShadow1
    DllCall("dwmapi.dll\DwmIsCompositionEnabled", "int*", DwmEnabled)
    if !(DwmEnabled)
        DllCall("user32.dll\SetClassLongPtr", "ptr", handle, "int", -26, "ptr", DllCall("user32.dll\GetClassLongPtr", "ptr", handle, "int", -26) | 0x20000)
    else {
        VarSetCapacity(MARGINS, 16, 0) && NumPut(1, NumPut(1, NumPut(1, NumPut(1, MARGINS, "int"), "int"), "int"), "int")
        DllCall("dwmapi.dll\DwmSetWindowAttribute", "ptr", handle, "uint", 2, "ptr*", 2, "uint", 4)
        DllCall("dwmapi.dll\DwmExtendFrameIntoClientArea", "ptr", handle, "ptr", &MARGINS)
    }
} ;</06.02.000005>
;<06.02.000006>
FrameShadow(HGui) {																					            	;-- FrameShadow(): Drop Shadow On Borderless Window, (DWM STYLE)

	;--https://autohotkey.com/boards/viewtopic.php?t=29117

	/*
	Gui, +HwndHGui -Caption - Example
	FrameShadow(HGui)
	Gui, Add, Button, x10 y130 w100 h30, Minimize
	Gui, Add, Button, x365 y130 w100 h30, Exit
	Gui, Add, GroupBox, x10 y10 w455 h110, GroupBox
	Gui, Add, Edit, x20 y30 w435 h80 +Multi, Edit
	Gui, Show, Center w475 h166, Frame Shadow Test
	*/

	DllCall("dwmapi\DwmIsCompositionEnabled","IntP",_ISENABLED) ; Get if DWM Manager is Enabled
	if !_ISENABLED ; if DWM is not enabled, Make Basic Shadow
		DllCall("SetClassLong","UInt",HGui,"Int",-26,"Int",DllCall("GetClassLong","UInt",HGui,"Int",-26)|0x20000)
	else {
		VarSetCapacity(_MARGINS,16)
		NumPut(1,&_MARGINS,0,"UInt")
		NumPut(1,&_MARGINS,4,"UInt")
		NumPut(1,&_MARGINS,8,"UInt")
		NumPut(1,&_MARGINS,12,"UInt")
		DllCall("dwmapi\DwmSetWindowAttribute", "Ptr", HGui, "UInt", 2, "Int*", 2, "UInt", 4)
		DllCall("dwmapi\DwmExtendFrameIntoClientArea", "Ptr", HGui, "Ptr", &_MARGINS)
	}
} ;</06.02.000006>
;<06.02.000007>
RemoveWindowFromTaskbar(WinTitle) {															    	;-- remove the active window from the taskbar by using COM

/*
      Example: Temporarily remove the active window from the taskbar by using COM.
      Methods in ITaskbarList's VTable:
        IUnknown:
          0 QueryInterface  -- use ComObjQuery instead
          1 AddRef          -- use ObjAddRef instead
          2 Release         -- use ObjRelease instead
        ITaskbarList:
          3 HrInit
          4 AddTab
          5 DeleteTab
          6 ActivateTab
          7 SetActiveAlt
    */
    IID_ITaskbarList  := "{56FDF342-FD6D-11d0-958A-006097C9A090}"
    CLSID_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}"

    ; Create the TaskbarList object and store its address in tbl.
    tbl := ComObjCreate(CLSID_TaskbarList, IID_ITaskbarList)

    activeHwnd := WinExist(WinTitle)

    DllCall(vtable(tbl,3), "ptr", tbl)                     ; tbl.HrInit()
    DllCall(vtable(tbl,5), "ptr", tbl, "ptr", activeHwnd)  ; tbl.DeleteTab(activeHwnd)
    Sleep 3000
    DllCall(vtable(tbl,4), "ptr", tbl, "ptr", activeHwnd)  ; tbl.AddTab(activeHwnd)

    ; Non-dispatch objects must always be manually freed.
    ObjRelease(tbl)
    return

}
vtable(ptr, n) {																												;-- subfunction of RemoveWindowFromTaskbar(), ; NumGet(ptr+0) returns the address of the object's virtual function
    ; NumGet(ptr+0) returns the address of the object's virtual function
    ; table (vtable for short). The remainder of the expression retrieves
    ; the address of the nth function's address from the vtable.
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
} ;</06.02.000007>
;<06.02.000008>
ToggleTitleMenuBar(ahkid:=0, bHideTitle:=1, bHideMenuBar:=0) {				         	;-- show or hide Titlemenubar

    if ( ahkid = 0 ) ; must with () wrap
        WinGet, ahkid, ID, A
    ; ToolTip, % "AHKID is: " ahkid, 300, 300,
    if ( bHideTitle = 1 ) {
        WinSet, Style, ^0xC00000, ahk_id %ahkid%     ; titlebar toggle
    }
    if ( bHideMenuBar = 1 ) {
        WinSet, Style, ^0x40000, ahk_id %ahkid%      ; menubar toggle
    }

} ;</06.02.000008>
;<06.02.000009>
ToggleFakeFullscreen() {																				            	;-- sets styles to a window to look like a fullscreen

    CoordMode Screen, Window
    static WINDOW_STYLE_UNDECORATED := -0xC40000
    static savedInfo := Object() ;; Associative array!
    WinGet, id, ID, A

    if (savedInfo[id]) {
        inf := savedInfo[id]
        WinSet, Style, % inf["style"], ahk_id %id%
        WinMove, ahk_id %id%,, % inf["x"], % inf["y"], % inf["width"], % inf["height"]
        savedInfo[id] := ""
    } else {
        savedInfo[id] := inf := Object()
        WinGet, ltmp, Style, A
        inf["style"] := ltmp
        WinGetPos, ltmpX, ltmpY, ltmpWidth, ltmpHeight, ahk_id %id%
        inf["x"] := ltmpX
        inf["y"] := ltmpY
        inf["width"] := ltmpWidth
        inf["height"] := ltmpHeight
        WinSet, Style, %WINDOW_STYLE_UNDECORATED%, ahk_id %id%
        mon := GetMonitorActiveWindow()
        SysGet, mon, Monitor, %mon%
        WinMove, A,, %monLeft%, %monTop%, % monRight-monLeft, % monBottom-monTop
    }
    WinSet Redraw

} ;</06.02.000009>
;<06.02.000010>
FullScreenToggleUnderMouse(WT) {                                                                      	;-- toggles a window under the mouse to look like fullscreen

		DetectHiddenWindows, On
		MouseGetPos,,,WinUnderMouse
		WinGetTitle, WTm, %WinUnderMouse%
		WinSet, Style, ^0xC00000, ahk_id %WinUnderMouse%
		WinSet, AlwaysOnTop, Toggle, ahk_id %WinUnderMouse%
		PostMessage, 0x112, 0xF030,,, ahk_id %WinUnderMouse% ;WinMaximize
		;PostMessage, 0x112, 0xF120,,, Fenstertitel, Fenstertext 	;WinRestore
		WinGet, Style, Style, ahk_class Shell_TrayWnd
			If (Style & 0x10000000) {
				  WinShow ahk_class Shell_TrayWnd
				  WinShow Start ahk_class Button

			} Else {
				WinHide ahk_class Shell_TrayWnd
				  WinHide Start ahk_class Button
			}

} ;</06.02.000010>
;<06.02.000011>
SetTaskbarProgress(pct, state="", hwnd="") { 													    	;-- accesses Windows 7's ability to display a progress bar behind a taskbar button.

	; https://autohotkey.com/board/topic/46860-windows-7-settaskbarprogress/ - from Lexikos
	; edited version of Lexikos' SetTaskbarProgress() function to work with Unicode 64bit, Unicode 32bit, Ansi 32bit, and Basic/Classic (1.0.48.5)
	; SetTaskbarProgress  -  Requires Windows 7.
	;
	; pct    -  A number between 0 and 100 or a state value (see below).
	; state  -  "N" (normal), "P" (paused), "E" (error) or "I" (indeterminate).
	;           If omitted (and pct is a number), the state is not changed.
	; hwnd   -  The ID of the window which owns the taskbar button.
	;           If omitted, the Last Found Window is used.

	/*		EXAMPLE

		Gui, Font, s15
		Gui, Add, Text,, % "This GUI should show a progress bar on its taskbar button.`n"
						 . "It will demonstrate the four different progress states:`n"
						 . "(N)ormal, (P)aused, (E)rror and (I)ndeterminate."
		Gui, Show        ; Show the window and taskbar button.
		Gui, +LastFound  ; SetTaskbarProgress will use this window.
		Loop
		{
			progress_states=NPE
			Loop, Parse, progress_states
			{
				SetTaskbarProgress(0, A_LoopField)
				Loop 50 {
					SetTaskbarProgress(A_Index*2)
					Sleep 50
				}
				Sleep 1000
				Loop 50 {
					SetTaskbarProgress(100-A_Index*2)
					Sleep 50
				}
				SetTaskbarProgress(0)
				Sleep 1000
			}
			SetTaskbarProgress("I")
			Sleep 4000
		}
		GuiClose:
		GuiEscape:
		ExitApp
	*/

    static tbl, s0:=0, sI:=1, sN:=2, sE:=4, sP:=8
	 if !tbl
	  Try tbl := ComObjCreate("{56FDF344-FD6D-11d0-958A-006097C9A090}"
							, "{ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}")
	  Catch
	   Return 0
	 If hwnd =
	  hwnd := WinExist()
	 If pct is not number
	  state := pct, pct := ""
	 Else If (pct = 0 && state="")
	  state := 0, pct := ""
	 If state in 0,I,N,E,P
	  DllCall(NumGet(NumGet(tbl+0)+10*A_PtrSize), "uint", tbl, "uint", hwnd, "uint", s%state%)
	 If pct !=
	  DllCall(NumGet(NumGet(tbl+0)+9*A_PtrSize), "uint", tbl, "uint", hwnd, "int64", pct*10, "int64", 1000)
	Return 1

} ;</06.02.000011>
;<06.02.000012>
SetTaskbarProgress(State, hWnd := "") { 														        	;-- modified function

	/*		DESCRIPTION

			Link: 					http://ahkscript.org/boards/viewtopic.php?p=48299#p48299
			Author:				Flipeador
			Date:
			Parameter: 			SetTaskbarProgress( [0~100 | Normal, Paused, Indeterminate, Error], [Win ID] )

	*/

	/*		EXAMPLE

		Gui, Font, s15
		Gui, Add, Text,, % "------------------------------------------------------"
		Gui, Show
		Gui, +LastFound +HWND_G

		SetTaskbarProgress( 0, _G )
		Sleep 100
		Loop, 50 {
			SetTaskbarProgress( A_Index, _G )
			Sleep 50
		}
		Sleep 100
		SetTaskbarProgress( "Paused", _G )
		Sleep, 1000
		SetTaskbarProgress( "Normal", _G )
		Sleep, 1000
		Loop, 49 {
			SetTaskbarProgress( A_Index * 2, _G )
			Sleep 100
		}
		Sleep 100
		SetTaskbarProgress( "Error", _G )
		Sleep 1000
		SetTaskbarProgress( "Indeterminate", _G )
		Sleep 1000
		ExitApp
		Esc::ExitApp

	*/

	static ppv
	if !ppv
		DllCall("ole32.dll\OleInitialize", "PtrP", 0)
		, VarSetCapacity(CLSID, 16), VarSetCapacity(riid, 16)
		, DllCall("ole32.dll\CLSIDFromString", "Str", "{56FDF344-FD6D-11d0-958A-006097C9A090}", "Ptr", &CLSID)
		, DllCall("ole32.dll\CLSIDFromString", "Str", "{ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}", "Ptr", &riid)
		, DllCall("ole32.dll\CoCreateInstance", "Ptr", &CLSID, "Ptr", 0, "UInt", 21, "Ptr", &riid, "PtrP", ppv)
	hWnd := hWnd ? hWnd : IsWindow()
	s0 := 0, sI := sIndeterminate := 1, sN := sNormal := 2, sE := sError := 4, sP := sPaused := 8
	if InVar( State, "0,N,P,E,I,Normal,Paused,Error,Indeterminate" )
		return DllCall(NumGet(NumGet(ppv+0)+10*A_PtrSize), "Ptr", ppv, "Ptr", hWnd, "UInt", s%State%)
	return DllCall(NumGet(NumGet(ppv+0)+9*A_PtrSize), "Ptr", ppv, "Ptr", hWnd, "Int64", State * 10, "Int64", 1000)
} ;</06.02.000012>
;<06.02.000014>
InVar(Haystack, Needle, Delimiter := ",", OmitChars := "") {										;-- sub of SetTaskbarProgress, parsing list search
	Loop, Parse, % Needle, %Delimiter%, %OmitChars%
		if (A_LoopField = Haystack)
			return 1
	return 0
} ;</06.02.000014>
;<06.02.000015>
IsWindow(hWnd*) {																										;-- sub of SetTaskbarProgress, different approach to IsWindow in gui + window - get/find section
	if !hWnd.MaxIndex()
		return DllCall("User32.dll\GetForegroundWindow")
	return i := DllCall("User32.dll\IsWindow", "Ptr", hWnd[1] )
		, ErrorLevel := !i
} ;</06.02.000015>
;<06.02.000016>
WinSetPlacement(hwnd, x="",y="",w="",h="",state="") {											;-- Sets window position using workspace coordinates (-> no taskbar)

	WinGetPlacement(hwnd, x1, y1, w1, h1, state1)
	if (x = "")
		x := x1
	if (y = "")
		y := y1
	if (w = "")
		w := w1
	if (h = "")
		h := h1
	if (state = "")
		state := state1
	VarSetCapacity(wp, 44), NumPut(44, wp)
	if (state = 6)
		NumPut(7, wp, 8) ;SW_SHOWMINNOACTIVE
	else if (state = 1)
		NumPut(4, wp, 8) ;SW_SHOWNOACTIVATE
	else if (state = 3)
		NumPut(3, wp, 8) ;SW_SHOWMAXIMIZED and/or SW_MAXIMIZE
	else
		NumPut(state, wp, 8)
	NumPut(x, wp, 28, "Int")
    NumPut(y, wp, 32, "Int")
    NumPut(x+w, wp, 36, "Int")
    NumPut(y+h, wp, 40, "Int")
	DllCall("SetWindowPlacement", "Ptr", hwnd, "Ptr", &wp)
} ;</06.02.000016>
;<06.02.000017>
AttachToolWindow(hParent, GUINumber, AutoClose) {												;-- Attaches a window as a tool window to another window from a different process.
	global ToolWindows
	outputdebug AttachToolWindow %GUINumber% to %hParent%
	if (!IsObject(ToolWindows))
		ToolWindows := Object()
	if (!WinExist("ahk_id " hParent))
		return false
	Gui %GUINumber%: +LastFoundExist
	if (!(hGui := WinExist()))
		return false
	;SetWindowLongPtr is defined as SetWindowLong in x86
	if (A_PtrSize = 4)
		DllCall("SetWindowLong", "Ptr", hGui, "int", -8, "PTR", hParent) ;This line actually sets the owner behavior
	else
		DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", hParent) ;This line actually sets the owner behavior
	ToolWindows.Insert(Object("hParent", hParent, "hGui", hGui,"AutoClose", AutoClose))
	Gui %GUINumber%: Show, NoActivate
	return true
} ;</06.02.000017>
;<06.02.000018>
DeAttachToolWindow(GUINumber) {																			;-- removes the attached ToolWindow

	global ToolWindows
	Gui %GUINumber%: +LastFoundExist
	if (!(hGui := WinExist()))
		return false
	Loop % ToolWindows.MaxIndex()
	{
		if (ToolWindows[A_Index].hGui = hGui)
		{
			;SetWindowLongPtr is defined as SetWindowLong in x86
			if (A_PtrSize = 4)
				DllCall("SetWindowLong", "Ptr", hGui, "int", -8, "PTR", 0) ;Remove tool window behavior
			else
				DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", 0) ;Remove tool window behavior
			DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", 0)
			ToolWindows.Remove(A_Index)
			break
		}
	}
} ;</06.02.000018>
;<06.02.000019>
Control_SetTextAndResize(controlHwnd, newText) {                                              	;-- set a new text to a control and resize depending on textwidth and -height

    dc := DllCall("GetDC", "Ptr", controlHwnd)

    ; 0x31 = WM_GETFONT
    SendMessage 0x31,,,, ahk_id %controlHwnd%
    hFont := ErrorLevel
    oldFont := 0
    if (hFont != "FAIL")
        oldFont := DllCall("SelectObject", "Ptr", dc, "Ptr", hFont)

    VarSetCapacity(rect, 16, 0)
    ; 0x440 = DT_CALCRECT | DT_EXPANDTABS
    h := DllCall("DrawText", "Ptr", dc, "Ptr", &newText, "Int", -1, "Ptr", &rect, "UInt", 0x440)
    ; width = rect.right - rect.left
    w := NumGet(rect, 8, "Int") - NumGet(rect, 0, "Int")

    if oldFont
        DllCall("SelectObject", "Ptr", dc, "Ptr", oldFont)
    DllCall("ReleaseDC", "Ptr", controlHwnd, "Ptr", dc)

    GuiControl,, %controlHwnd%, %newText%
    GuiControl Move, %controlHwnd%, % "h" h " w" w
} ;</06.02.000019>
;<06.02.000020>
DropShadow(HGUI:="", Style:="", GetGuiClassStyle:="", SetGuiClassStyle:="") {   	;-- Drop Shadow On Borderless Window, (DWM STYLE)

	/*	DESCRIPTION OF FUNCTION: -- DropShadow --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	draws a shadow on borderless windows
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&p=264108#p264108
	Author         	:	DRocks and justme
	Date             	:	18.02.2019
	AHK-Version	:	v1 and ?v2?
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:	tested on Windows 7
	Dependencies	:	GetGuiClassStyle(), SetGuiClassStyle(HGUI, Style)
	KeyWords    	:	gui, style, shadow
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	if (GetGuiClassStyle) {
		ClassStyle:=GetGuiClassStyle()
		return ClassStyle
	}

	if (SetGuiClassStyle) {
		SetGuiClassStyle(HGUI, Style)
	}

} ;</06.02.000020>
;<06.02.000021>
GetGuiClassStyle() {                                                                                                 	;-- returns the class style of a Autohotkey-Gui
	Gui, GetGuiClassStyleGUI:Add, Text
	Module := DllCall("GetModuleHandle", "Ptr", 0, "UPtr")
	VarSetCapacity(WNDCLASS, A_PtrSize * 10, 0)
	ClassStyle := DllCall("GetClassInfo", "Ptr", Module, "Str", "AutoHotkeyGUI", "Ptr", &WNDCLASS, "UInt")
                 ? NumGet(WNDCLASS, "Int")
                 : ""
	Gui, GetGuiClassStyleGUI:Destroy
	Return ClassStyle
} ;</06.02.000021>
;<06.02.000022>
SetGuiClassStyle(HGUI, Style) {                                                                               	;-- sets the class style of a Autohotkey-Gui
	Return DllCall("SetClassLong" . (A_PtrSize = 8 ? "Ptr" : ""), "Ptr", HGUI, "Int", -26, "Ptr", Style, "UInt")
} ;</06.02.000022>
;<06.02.000023>
HideFocusBorder(wParam, lParam := "", uMsg := "", hWnd := "") {                         	;-- Hide the dotted focus border

	/*	DESCRIPTION OF FUNCTION: -- HideFocusBorder() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Hides the focus border for the given GUI control or GUI and all of its children
                            	Call the function passing only the HWND of the control / GUI in wParam as only parameter.
								WM_UPDATEUISTATE  -> msdn.microsoft.com/en-us/library/ms646361(v=vs.85).aspx
								The Old New Thing -> blogs.msdn.com/b/oldnewthing/archive/2013/05/16/10419105.aspx
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=9919
	Author         	:	just me
	Date             	:	23 Oct 2015
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:	none
	KeyWords    	:	gui, focus, border
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

   ; WM_UPDATEUISTATE = 0x0128
	Static Affected := [] ; affected controls / GUIs
        , HideFocus := 0x00010001 ; UIS_SET << 16 | UISF_HIDEFOCUS
	     , OnMsg := OnMessage(0x0128, Func("HideFocusBorder"))
	If (uMsg = 0x0128) { ; called by OnMessage()
      If (wParam = HideFocus)
         Affected[hWnd] := True
      Else If Affected[hWnd]
         PostMessage, 0x0128, %HideFocus%, 0, , ahk_id %hWnd%
   }
   Else If DllCall("IsWindow", "Ptr", wParam, "UInt")
	  PostMessage, 0x0128, %HideFocus%, 0, , ahk_id %wParam%

} ;</06.02.000023>
}
;|   FadeGui()                                	|   WinFadeToggle()                      	|   ShadowBorder()                       	|   FrameShadow() - 2 versions     	|
;|   RemoveWindowFromTaskbar()	|   ToggleTitleMenuBar()               	|   ToggleFakeFullscreen()             	|   ListView_HeaderFontSet()         	|
;|   CreateFont()                            	|   FullScreenToggleUnderMouse()	|   SetTaskbarProgress() x 2          	|   WinSetPlacement()                  	|
;|   AttachToolWindow()               	|   DeAttachToolWindow()            	|   ControlSetTextAndResize()       	|   DropShadow(20)                      	|
;   GetGuiClassStyle(21)                	|   SetGuiClassStyle(22)                	|   HideFocusBorder(23)                 	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;gui - control type (61) -- specialized functions for controls --                                                                   	baseID: <06.03>

{ ;<06.03.01>: ComboBox 		(1)

;<06.03.01.000001>
GetComboBoxChoice(TheList, TheCurrent) {																	;-- Combobox function
	; https://github.com/altbdoor/ahk-hs-chara/blob/master/utility.ahk
	TheValue := -1

	Loop % TheList.Length() {
		If (TheCurrent == TheList[A_Index]) {
			TheValue := A_Index
			Break
		}
	}
	TheList := JoinArray(TheList, "|")

	Return {"Index": TheValue, "Choices": TheList}
} ;</06.03.01.000001>

}

{ ;<06.03.02>: Edit and HEdit 	(7)

;<06.03.02.000001>
Edit_Standard_Params(ByRef Control, ByRef WinTitle) {  								;-- these are helper functions to use with edit controls
	if (Control = "A" && WinTitle="") { ; Control is "A", use focused control.
		ControlGetFocus, Control, A
		WinTitle = A
	} else if (Control+0!="" && WinTitle="") {  ; Control is numeric, assume its a ahk_id.
		WinTitle := "ahk_id " . Control
		Control := ""
	}
} ;</06.03.02.000001>
;<06.03.02.000002>
Edit_TextIsSelected(Control="", WinTitle="") {												;-- returns bool if text is selected in an edit control
	; Returns true if text is selected, otherwise false.
;
	Edit_Standard_Params(Control, WinTitle)
	return Edit_GetSelection(start, end, Control, WinTitle) and (start!=end)
} ;</06.03.02.000002>
;<06.03.02.000003>
Edit_GetSelection(ByRef start, ByRef end, Control="", WinTitle="") {				;-- get selected text in an edit control
	; Gets the start and end offset of the current selection.
;
	Edit_Standard_Params(Control, WinTitle)
	VarSetCapacity(start, 4), VarSetCapacity(end, 4)
	SendMessage, 0xB0, &start, &end, %Control%, %WinTitle%  ; EM_GETSEL
	if (ErrorLevel="FAIL")
		return false
	start := NumGet(start), end := NumGet(end)
	return true
} ;</06.03.02.000003>
;<06.03.02.000004>
Edit_Select(start=0, end=-1, Control="", WinTitle="") {									;-- selects text inside in an edit control
	; Selects text in a text box, given absolute character positions (starting at 0.)
	;
	; start:    Starting character offset, or -1 to deselect.
	; end:      Ending character offset, or -1 for "end of text."
	;

	Edit_Standard_Params(Control, WinTitle)
	SendMessage, 0xB1, start, end, %Control%, %WinTitle%  ; EM_SETSEL
	return (ErrorLevel != "FAIL")
} ;</06.03.02.000004>
;<06.03.02.000005>
Edit_SelectLine(line=0, include_newline=false, Control="", WinTitle="") {		;-- selects one line in an edit control
		; Selects a line of text.
	;
	; line:             One-based line number, or 0 to select the current line.
	; include_newline:  Whether to also select the line terminator (`r`n).
	;

	Edit_Standard_Params(Control, WinTitle)

	ControlGet, hwnd, Hwnd,, %Control%, %WinTitle%
	if (!WinExist("ahk_id " hwnd))
		return false

	if (line<1)
		ControlGet, line, CurrentLine

	SendMessage, 0xBB, line-1, 0  ; EM_LINEINDEX
	offset := ErrorLevel

	SendMessage, 0xC1, offset, 0  ; EM_LINELENGTH
	lineLen := ErrorLevel

	if (include_newline) {
		WinGetClass, class
		lineLen += (class="Edit") ? 2 : 1 ; `r`n : `n
	}

	; Select the line.
	SendMessage, 0xB1, offset, offset+lineLen  ; EM_SETSEL
	return (ErrorLevel != "FAIL")
} ;</06.03.02.000005>
;<06.03.02.000006>
Edit_DeleteLine(line=0, Control="", WinTitle="") {											;-- delete one line in an edit control
	; Deletes a line of text.
	;
	; line:     One-based line number, or 0 to delete current line.
	;

	Edit_Standard_Params(Control, WinTitle)
	; Select the line.
	if (Edit_SelectLine(line, true, Control, WinTitle))
	{   ; Delete it.
		ControlSend, %Control%, {Delete}, %WinTitle%
		return true
	}
	return false
} ;</06.03.02.000006>
;<06.03.02.000007>
Edit_VCenter(HEDIT) {																						;-- Vertically Align Text for edit controls

	; by just me, http://ahkscript.org/boards/viewtopic.php?f=5&t=4673#p44099
	; the Edit control must have the ES_MULTILINE style (0x0004 \ +Multi)!
	; EM_GETRECT := 0x00B2 <- msdn.microsoft.com/en-us/library/bb761596(v=vs.85).aspx
	; EM_SETRECT := 0x00B3 <- msdn.microsoft.com/en-us/library/bb761657(v=vs.85).aspx

	VarSetCapacity(RC, 16, 0)
	DllCall("User32.dll\GetClientRect", "Ptr", HEDIT, "Ptr", &RC)
	CLHeight := NumGet(RC, 12, "Int")
	SendMessage, 0x0031, 0, 0, , ahk_id %HEDIT% ; WM_GETFONT
	HFONT := ErrorLevel
	HDC := DllCall("GetDC", "Ptr", HEDIT, "UPtr")
	DllCall("SelectObject", "Ptr", HDC, "Ptr", HFONT)
	VarSetCapacity(RC, 16, 0)
	DTH := DllCall("DrawText", "Ptr", HDC, "Str", "W", "Int", 1, "Ptr", &RC, "UInt", 0x2400)
	DllCall("ReleaseDC", "Ptr", HEDIT, "Ptr", HDC)
	SendMessage, 0x00BA, 0, 0, , ahk_id %HEDIT% ; EM_GETLINECOUNT
	TXHeight := DTH * ErrorLevel
	If (TXHeight > CLHeight)
			Return False
	VarSetCapacity(RC, 16, 0)
	SendMessage, 0x00B2, 0, &RC, , ahk_id %HEDIT%
	DY := (CLHeight - TXHeight) // 2
	NumPut(DY, RC, 4, "Int")
	NumPut(TXHeight + DY, RC, 12, "Int")
	SendMessage, 0x00B3, 0, &RC, , ahk_id %HEDIT%

} ;</06.03.02.000007>

}

{ ;<06.03.03>: ImageList 			(2)

		;<06.03.03.000001>
		IL_LoadIcon(FullFilePath, IconNumber := 1, LargeIcon := 1) {										;-- no description
			HIL := IL_Create(1, 1, !!LargeIcon)
			IL_Add(HIL, FullFilePath, IconNumber)
			HICON := DllCall("Comctl32.dll\ImageList_GetIcon", "Ptr", HIL, "Int", 0, "UInt", 0, "UPtr")
			IL_Destroy(HIL)
			return HICON
		} ;</06.03.03.000001>
		;<06.03.03.000002>
		IL_GuiButtonIcon(Handle, File, Index := 1, Options := "") {											;-- no description
			RegExMatch(Options, "i)w\K\d+", W), (W="") ? W := 16 :
			RegExMatch(Options, "i)h\K\d+", H), (H="") ? H := 16 :
			RegExMatch(Options, "i)s\K\d+", S), S ? W := H := S :
			RegExMatch(Options, "i)l\K\d+", L), (L="") ? L := 0 :
			RegExMatch(Options, "i)t\K\d+", T), (T="") ? T := 0 :
			RegExMatch(Options, "i)r\K\d+", R), (R="") ? R := 0 :
			RegExMatch(Options, "i)b\K\d+", B), (B="") ? B := 0 :
			RegExMatch(Options, "i)a\K\d+", A), (A="") ? A := 4 :
			Psz := A_PtrSize = "" ? 4 : A_PtrSize, DW := "UInt", Ptr := A_PtrSize = "" ? DW : "Ptr"
			VarSetCapacity( button_il, 20 + Psz, 0 )
			NumPut( normal_il := DllCall( "ImageList_Create", DW, W, DW, H, DW, 0x21, DW, 1, DW, 1 ), button_il, 0, Ptr )   ; Width & Height
			NumPut( L, button_il, 0 + Psz, DW )     ; Left Margin
			NumPut( T, button_il, 4 + Psz, DW )     ; Top Margin
			NumPut( R, button_il, 8 + Psz, DW )     ; Right Margin
			NumPut( B, button_il, 12 + Psz, DW )    ; Bottom Margin
			NumPut( A, button_il, 16 + Psz, DW )    ; Alignment
			SendMessage, BCM_SETIMAGELIST := 5634, 0, &button_il,, AHK_ID %Handle%
			return IL_Add( normal_il, File, Index )
		} ;</06.03.03.000002>

}

{ ;<06.03.04>: Listbox 				(3)

		;<06.03.04.000001>
		LB_AdjustItemHeight(HListBox, Adjust) {																	;-- Listbox function
			; https://autohotkey.com/board/topic/89793-set-height-of-listbox-rows/
			; https://github.com/altbdoor/ahk-hs-chara/blob/master/utility.ahk
			Return LB_SetItemHeight(HListBox, LB_GetItemHeight(HListBox) + Adjust)
		} ;</06.03.04.000001>
		;<06.03.04.000002>
		LB_GetItemHeight(HListBox) {																						;-- Listbox function
			; https://github.com/altbdoor/ahk-hs-chara/blob/master/utility.ahk
			Static LB_GETITEMHEIGHT := 0x01A1
			SendMessage, %LB_GETITEMHEIGHT%, 0, 0, , ahk_id %HListBox%
			Return ErrorLevel
		} ;</06.03.04.000002>
		;<06.03.04.000003>
		LB_SetItemHeight(HListBox, NewHeight) {																	;-- Listbox function
			; https://github.com/altbdoor/ahk-hs-chara/blob/master/utility.ahk
			Static LB_SETITEMHEIGHT := 0x01A0
			SendMessage, %LB_SETITEMHEIGHT%, 0, %NewHeight%, , ahk_id %HListBox%
			WinSet, Redraw, , ahk_id %HListBox%
			Return ErrorLevel
		} ;</06.03.04.000003>

}

{ ;<06.03.05>: Listview 			(41)

;<06.03.05.000001>
LV_GetCount(hLV) {																											;-- get current count of notes in from any listview

	;https://autohotkey.com/boards/viewtopic.php?t=26317
	;hLV - Listview handle
	c := DllCall("SendMessage", "uint", hLV, "uint", 0x18B) ; LB_GETCOUNT
return c
} ;</06.03.05.000001>
;<06.03.05.000002>
LV_SetSelColors(HLV, BkgClr := "", TxtClr := "", Dummy := "") {										;-- sets the colors for selected rows in a listView.

	; ==================================================================================================================================
	; Sets the colors for selected rows in a ListView.
	; Parameters:
	;     HLV      -  handle (HWND) of the ListView control.
	;     BkgClr   -  background color as RGB integer value (0xRRGGBB).
	;                 If omitted or empty the ListViews's background color will be used.
	;     TxtClr   -  text color as RGB integer value (0xRRGGBB).
	;                 If omitted or empty the ListView's text color will be used.
	;                 If both BkgColor and TxtColor are omitted or empty the control will be reset to use the default colors.
	;     Dummy    -  must be omitted or empty!!!
	; Return value:
	;     No return value.
	; Remarks:
	;     The function adds a handler for WM_NOTIFY messages to the chain of existing handlers.
	; ==================================================================================================================================

	Static OffCode := A_PtrSize * 2              ; offset of code        (NMHDR)
	, OffStage := A_PtrSize * 3             ; offset of dwDrawStage (NMCUSTOMDRAW)
	, OffItem := (A_PtrSize * 5) + 16       ; offset of dwItemSpec  (NMCUSTOMDRAW)
	, OffItemState := OffItem + A_PtrSize   ; offset of uItemState  (NMCUSTOMDRAW)
	, OffClrText := (A_PtrSize * 8) + 16    ; offset of clrText     (NMLVCUSTOMDRAW)
	, OffClrTextBk := OffClrText + 4        ; offset of clrTextBk   (NMLVCUSTOMDRAW)
	, Controls := {}
	, MsgFunc := Func("LV_SetSelColors")
	, IsActive := False
	Local Item, H, LV, Stage
	If (Dummy = "") { ; user call ------------------------------------------------------------------------------------------------------
	If (BkgClr = "") && (TxtClr = "")
	Controls.Delete(HLV)
	Else {
	If (BkgClr <> "")
	Controls[HLV, "B"] := ((BkgClr & 0xFF0000) >> 16) | (BkgClr & 0x00FF00) | ((BkgClr & 0x0000FF) << 16) ; RGB -> BGR
	If (TxtClr <> "")
	Controls[HLV, "T"] := ((TxtClr & 0xFF0000) >> 16) | (TxtClr & 0x00FF00) | ((TxtClr & 0x0000FF) << 16) ; RGB -> BGR
	}

	If (Controls.MaxIndex() = "") {
	If (IsActive) {
	OnMessage(0x004E, MsgFunc, 0)
	IsActive := False
	}  } Else If !(IsActive) {
	OnMessage(0x004E, MsgFunc)
	IsActive := True
	}  }
	Else { ; system call ------------------------------------------------------------------------------------------------------------
	; HLV : wParam, BkgClr : lParam, TxtClr : uMsg, Dummy : hWnd
	H := NumGet(BkgClr + 0, "UPtr")
	If (LV := Controls[H]) && (NumGet(BkgClr + OffCode, "Int") = -12) { ; NM_CUSTOMDRAW
	Stage := NumGet(BkgClr + OffStage, "UInt")
	If (Stage = 0x00010001) { ; CDDS_ITEMPREPAINT
	Item := NumGet(BkgClr + OffItem, "UPtr")
	If DllCall("SendMessage", "Ptr", H, "UInt", 0x102C, "Ptr", Item, "Ptr", 0x0002, "UInt") { ; LVM_GETITEMSTATE, LVIS_SELECTED
	; The trick: remove the CDIS_SELECTED (0x0001) and CDIS_FOCUS (0x0010) states from uItemState and set the colors.
	NumPut(NumGet(BkgClr + OffItemState, "UInt") & ~0x0011, BkgClr + OffItemState, "UInt")
	If (LV.B <> "")
	  NumPut(LV.B, BkgClr + OffClrTextBk, "UInt")
	If (LV.T <> "")
	  NumPut(LV.T, BkgClr + OffClrText, "UInt")
	Return 0x02 ; CDRF_NEWFONT
	}  }
	Else If (Stage = 0x00000001) ; CDDS_PREPAINT
	Return 0x20 ; CDRF_NOTIFYITEMDRAW
	Return 0x00 ; CDRF_DODEFAULT
	}  }
} ;</06.03.05.000002>
;<06.03.05.000003>
LV_Select(r:=1, Control:="", WinTitle:="") {																		;-- select/deselect 1 to all rows of a listview

	; Modified from http://www.autohotkey.com/board/topic/54752-listview-select-alldeselect-all/?p=343662
	; Examples: LVSel(1 , "SysListView321", "Win Title")   ; Select row 1. (or use +1)
	;           LVSel(-1, "SysListView321", "Win Title")   ; Deselect row 1
	;           LVSel(+0, "SysListView321", "Win Title")   ; Select all
	;           LVSel(-0, "SysListView321", "Win Title")   ; Deselect all
	;           LVSel(+0,                 , "ahk_id " HLV) ; Use listview's hwnd

	VarSetCapacity(LVITEM, 4*15, 0) ;Do *13 if you're not on Vista or Win 7 (see MSDN)

	state := InStr(r, "-") ? 0x00000000 : 0x00000002
	NumPut(0x00000008, LVITEM, 4*0) ;mask = LVIF_STATE
	NumPut(state,      LVITEM, 4*3) ;state = <second LSB must be 1>
	NumPut(0x0002,     LVITEM, 4*4) ;stateMask = LVIS_SELECTED

	;LVM_SETITEMSTATE = LVM_FIRST + 43
	r := RegExReplace(r, "\D") - 1
	SendMessage, 0x1000 + 43, r, &LVITEM, %Control%, %WinTitle%

} ;</06.03.05.000003>
;<06.03.05.000004>
LV_GetItemText(item_index, sub_index, ctrl_id, win_id) {												;-- read the text from an item in a ListView

; https://autohotkey.com/board/topic/18299-reading-listview-of-another-app/
; code from Tigerite

/* 			Example

F4::
pList = ahk_class TPlayerListForm
WinGet, active_id, ID, %pList%
;WinGet, active_id, ID, ahk_class TPlayerListForm
;MsgBox, The active window's ID is "%a_id%".

p0 := LV_GetItemText((0, 2, "TListView1", active_id)
p1 := LV_GetItemText((1, 2, "TListView1", active_id)
p2 := LV_GetItemText((2, 2, "TListView1", active_id)
p3 := LV_GetItemText((3, 2, "TListView1", active_id)
p4 := LV_GetItemText((4, 2, "TListView1", active_id)
p5 := LV_GetItemText((5, 2, "TListView1", active_id)
MsgBox %p0%`n %p1%`n %p2%`n %p3%`n %p4%`n %p5%
Return

*/

;const
MAX_TEXT = 260

VarSetCapacity(szText, MAX_TEXT, 0)
VarSetCapacity(szClass, MAX_TEXT, 0)
ControlGet, hListView, Hwnd, , %ctrl_id%, ahk_id %win_id%
DllCall("GetClassName", UInt,hListView, Str,szClass, Int,MAX_TEXT)
if (DllCall("lstrcmpi", Str,szClass, Str,"SysListView32") == 0 || DllCall("lstrcmpi", Str,szClass, Str,"TListView") == 0)
{
LVGet_Text(hListView, item_index, sub_index, szText, MAX_TEXT)
}

return %szText%
} ;</06.03.05.000004>
;<06.03.05.000005>
LV_GetText(hListView,iItem,iSubItem,ByRef lpString,nMaxCount) {									;-- get text by item and subitem from a Listview
;const
NULL := 0
PROCESS_ALL_ACCESS := 0x001F0FFF
INVALID_HANDLE_VALUE := 0xFFFFFFFF
PAGE_READWRITE := 4
FILE_MAP_WRITE := 2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
LV_ITEM_mask := 0
LV_ITEM_iItem := 4
LV_ITEM_iSubItem := 8
LV_ITEM_state := 12
LV_ITEM_stateMask := 16
LV_ITEM_pszText := 20
LV_ITEM_cchTextMax := 24
LVIF_TEXT := 1
LVM_GETITEM = 0x1005
SIZEOF_LV_ITEM = 0x28
SIZEOF_TEXT_BUF = 0x104
SIZEOF_BUF = 0x120
SIZEOF_INT = 4
SIZEOF_POINTER = 4

;var
result := 0
hProcess := NULL
dwProcessId := 0

if lpString <> NULL && nMaxCount > 0
{
DllCall("lstrcpy", Str,lpString, Str,"")
DllCall("GetWindowThreadProcessId", UInt,hListView, UIntP,dwProcessId)
hProcess := DllCall("OpenProcess", UInt,PROCESS_ALL_ACCESS, Int,false, UInt,dwProcessId)
if hProcess <> NULL
{
;var
lpProcessBuf := NULL
hMap := NULL
hKernel := DllCall("GetModuleHandle", Str,"kernel32.dll", UInt)
pVirtualAllocEx := DllCall("GetProcAddress", UInt,hKernel, Str,"VirtualAllocEx", UInt)

if pVirtualAllocEx == NULL
{
	hMap := DllCall("CreateFileMapping", UInt,INVALID_HANDLE_VALUE, Int,NULL, UInt,PAGE_READWRITE, UInt,0, UInt,SIZEOF_BUF, UInt)
	if hMap <> NULL
		lpProcessBuf := DllCall("MapViewOfFile", UInt,hMap, UInt,FILE_MAP_WRITE, UInt,0, UInt,0, UInt,0, UInt)
}
else
{
	lpProcessBuf := DllCall("VirtualAllocEx", UInt,hProcess, UInt,NULL, UInt,SIZEOF_BUF, UInt,MEM_COMMIT, UInt,PAGE_READWRITE)
}

if lpProcessBuf <> NULL
{
	;var
	VarSetCapacity(buf, SIZEOF_BUF, 0)

	InsertInteger(LVIF_TEXT, buf, LV_ITEM_mask, SIZEOF_INT)
	InsertInteger(iItem, buf, LV_ITEM_iItem, SIZEOF_INT)
	InsertInteger(iSubItem, buf, LV_ITEM_iSubItem, SIZEOF_INT)
	InsertInteger(lpProcessBuf + SIZEOF_LV_ITEM, buf, LV_ITEM_pszText, SIZEOF_POINTER)
	InsertInteger(SIZEOF_TEXT_BUF, buf, LV_ITEM_cchTextMax, SIZEOF_INT)

	if DllCall("WriteProcessMemory", UInt,hProcess, UInt,lpProcessBuf, UInt,&buf, UInt,SIZEOF_BUF, UInt,NULL) <> 0
		if DllCall("SendMessage", UInt,hListView, UInt,LVM_GETITEM, Int,0, Int,lpProcessBuf) <> 0
			if DllCall("ReadProcessMemory", UInt,hProcess, UInt,lpProcessBuf, UInt,&buf, UInt,SIZEOF_BUF, UInt,NULL) <> 0
			{
				DllCall("lstrcpyn", Str,lpString, UInt,&buf + SIZEOF_LV_ITEM, Int,nMaxCount)
				result := DllCall("lstrlen", Str,lpString)
			}
}

if lpProcessBuf <> NULL
	if pVirtualAllocEx <> NULL
		DllCall("VirtualFreeEx", UInt,hProcess, UInt,lpProcessBuf, UInt,0, UInt,MEM_RELEASE)
	else
		DllCall("UnmapViewOfFile", UInt,lpProcessBuf)

if hMap <> NULL
	DllCall("CloseHandle", UInt,hMap)

DllCall("CloseHandle", UInt,hProcess)
}
}
return result
}
{ ;Sub of LV_GetItemText and LV_GetText
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4) {					;-- Sub of LV_GetItemText and LV_GetText

; Original versions of ExtractInteger and InsertInteger provided by Chris
; - from the AutoHotkey help file - Version 1.0.37.04

; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).

SourceAddress := &pSource + pOffset  ; Get address and apply the caller's offset.
result := 0  ; Init prior to accumulation in the loop.
Loop %pSize%  ; For each byte in the integer:
{
result := result | (*SourceAddress << 8 * (A_Index - 1))  ; Build the integer from its bytes.
SourceAddress += 1  ; Move on to the next byte.
}
if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
return result  ; Signed vs. unsigned doesn't matter in these cases.
; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
return -(0xFFFFFFFF - result + 1)
}
InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4) {										;-- Sub of LV_GetItemText and LV_GetText
; To preserve any existing contents in pDest, only pSize number of bytes starting at pOffset
; are altered in it. The caller must ensure that pDest has sufficient capacity.

mask := 0xFF  ; This serves to isolate each byte, one by one.
Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
{
DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index - 1, UInt, 1  ; Write one byte.
, UChar, (pInteger & mask) >> 8 * (A_Index - 1))  ; This line is auto-merged with above at load-time.
mask := mask << 8  ; Set it up for isolation of the next byte.
}
}
} ;</06.03.05.000005>
;<06.03.05.000006>
LV_SetBackgroundURL(URL, ControlID) {																		;-- set a ListView's background image - please pay attention to the description

/*											Function: LV_SetBackgroundURL

Origin 	: https://autohotkey.com/board/topic/20588-adding-pictures-to-controls-eg-as-background/#entry135365
Author	: Lexikos

The function below tiles the background, since the only alternative is to attach it to the top-left of the very first item (in which
case it scrolls with the ListView's contents.)

Since LVM_SETBKIMAGE (internally) uses COM, CoInitialize() must be called when the script starts:

DllCall("ole32\CoInitialize", "uint", 0)

..and CoUninitialize() when the script exits:

DllCall("ole32\CoUninitialize")Important: The ListView/GUI should be destroyed before calling CoUninitialize(),
otherwise the script will crash on exit for some versions of Windows.

LVM_SETBKIMAGE can be made to accept a bitmap handle, so it would be possible to manually stretch an image to fit the
ListView rather than tiling it. (Search MSDN for LVM_SETBKIMAGE.)

*/

/*											Example

LV_SetBackgroundURL("http://www.autohotkey.com/docs/images/AutoHotkey_logo.gif", "SysListView321")

If the ListView has an associated variable, its name can be used in place of SysListView321.
Don't forget CoInitialize() and CoUninitialize().

Edit: Added line to set text background to transparent. Also added note about destroying GUI before CoUninitialize().

*/

; URL:          URL or file path (absolute, not relative)
; ControlID:    ClassNN or associated variable of a ListView on the default GUI.

GuiControlGet, hwnd, Hwnd, %ControlID%
VarSetCapacity(bki, 24, 0)
NumPut(0x2|0x10, bki, 0)  ; LVBKIF_SOURCE_URL | LVBKIF_STYLE_TILE
NumPut(&URL, bki, 8)
SendMessage, 0x1044, 0, &bki,, ahk_id %hwnd%  ; LVM_SETBKIMAGE
SendMessage, 0x1026, 0, -1,, ahk_id %ControlID%  ; LVM_SETTEXTBKCOLOR,, CLR_NONE
} ;</06.03.05.000006>
;<06.03.05.000007>
LV_MoveRow(up=true) {																									;-- moves a listview row up or down

if (up && LV_GetNext() == 1)
|| (!up && LV_GetNext() == LV_GetCount())
|| (LV_GetNext() == 0)
return

pos := LV_GetNext()
, xpos := up ? pos-1 : pos+1

Loop,% LV_GetCount("Col") {
LV_GetText(a, pos, A_Index)
LV_GetText(b, xpos, A_Index)
LV_Modify(pos, "Col" A_Index, b)
LV_Modify(xpos, "Col" A_Index, a)
}
LV_Modify(pos, "-Select -Focus")
, LV_Modify(xpos, "Select Focus")
} ;</06.03.05.000007>
;<06.03.05.000008>
LV_MoveRow(moveup = true) {																						;-- the same like above, but slightly different. With integrated script example.

/*			Example with Gui and key support

Gui, Add, Listview, w260 h200 vmylistview, test|test2|test3|test4
LV_Modifycol(1, 60)
LV_Modifycol(2, 60)
LV_Modifycol(3, 60)
LV_Modifycol(4, 60)

Loop, 10
LV_Add("", A_Index, "-" A_Index, (10 - A_Index), "x" A_Index)

Gui, Show, Center AutoSize, TestGUI
Return

GuiClose:
GuiEscape:
ExitApp

PgUp::LV_MoveRow()
PgDn::LV_MoveRow(false)
*/

; Original by diebagger (Guest) from:
; http://de.autohotkey.com/forum/viewtopic.php?p=58526#58526
; Slightly Modifyed by Obi-Wahn
; http://ahkscript.org/germans/forums/viewtopic.php?t=7285
If moveup not in 1,0
Return   ; If direction not up or down (true or false)
while x := LV_GetNext(x)   ; Get selected lines
i := A_Index, i%i% := x
If (!i) || ((i1 < 2) && moveup) || ((i%i% = LV_GetCount()) && !moveup)
Return   ; Break Function if: nothing selected, (first selected < 2 AND moveup = true) [header bug]
; OR (last selected = LV_GetCount() AND moveup = false) [delete bug]
cc := LV_GetCount("Col"), fr := LV_GetNext(0, "Focused"), d := moveup ? -1 : 1
; Count Columns, Query Line Number of next selected, set direction math.
Loop, %i% {   ; Loop selected lines
r := moveup ? A_Index : i - A_Index + 1, ro := i%r%, rn := ro + d
; Calculate row up or down, ro (current row), rn (target row)
Loop, %cc% {   ; Loop through header count
LV_GetText(to, ro, A_Index), LV_GetText(tn, rn, A_Index)
; Query Text from Current and Targetrow
LV_Modify(rn, "Col" A_Index, to), LV_Modify(ro, "Col" A_Index, tn)
; Modify Rows (switch text)
}
LV_Modify(ro, "-select -focus"), LV_Modify(rn, "select vis")
If (ro = fr)
LV_Modify(rn, "Focus")
}
} ;</06.03.05.000008>
;<06.03.05.000009>
LV_Find( lvhwnd, str, start = 0 ) { 	        																		;-- I think it's usefull to find an item position a listview
	;Copyright © 2013 VxE. All rights reserved.
	Static LVFI_STRING := 2, LVFI_SUBSTRING := 4
	LVM_FINDITEM := A_IsUnicode = 1 ? 0x1053 : 0x100D
	oel := ErrorLevel
	start |= 0
	If ( partial := ( SubStr( str, 0 ) = "*" ? LVFI_SUBSTRING : 0 ) )
	StringTrimRight str, str, 1
	VarSetCapacity( LVFINDINFO, 12 + 3 * ( A_PtrSize = 8 ? 8 : 4 ), 0 )
	NumPut( LVFI_STRING | partial, LVFINDINFO, 0, "UInt" )
	NumPut( &str, LVFINDINFO, 4 )
	SendMessage, LVM_FINDITEM, % start < 0 ? -1 : start - 1, &LVFINDINFO,, Ahk_ID %lvhwnd%
	Return ( ErrorLevel & 0xFFFFFFFF ) + 1, ErrorLevel := oel
} ;</06.03.05.000009>
;<06.03.05.000010>
LV_GetSelectedText(FromColumns="",ColumnsDelimiter="`t",RowsDelimiter= "`n") { ;-- Returns text from selected rows in ListView (in a user friendly way IMO.)

; by Learning one,	https://autohotkey.com/board/topic/61750-lv-getselectedtext/
/*                                         	EXAMPLE
Gui 1: Add, ListView, x5 y5 w250 h300, First name|Last name|Occupation
LV_Add("","Jim","Tucker","Driver")
LV_Add("","Jill","Lochte","Artist")
LV_Add("","Jessica","Hickman","Student")
LV_Add("","Mary","Jones","Teacher")
LV_Add("","Tony","Jackman","Surfer")
Gui 1: Show, w260 h310
return

F1::MsgBox % LV_GetSelectedText() ; get text from selected rows
F2::MsgBox % LV_GetSelectedText("1|3") ; get text from selected rows, but only from 1. and 3. column
F3::MsgBox % LV_GetSelectedText("1|3","|","#") ; same as above but use custom delimiters in returning string
*/

if FromColumns = ; than get text from all columns
{
Loop, % LV_GetCount("Column") ; total number of columns in LV
FromColumns .= A_Index "|"
}
if (SubStr(FromColumns,0) = "|")
StringTrimRight, FromColumns, FromColumns, 1
Loop
{
RowNumber := LV_GetNext(RowNumber)
if !RowNumber
		break

Loop, parse, FromColumns, |
{
		LV_GetText(FieldText, RowNumber, A_LoopField)
		Selected .= FieldText ColumnsDelimiter
}

if (SubStr(Selected,0) = ColumnsDelimiter)
		StringTrimRight, Selected, Selected, 1

Selected .= RowsDelimiter
}

if (SubStr(Selected,0) = RowsDelimiter)
StringTrimRight, Selected, Selected, 1

return Selected
} ;</06.03.05.000010>
;<06.03.05.000011>
LV_Notification(WParam, LParam, msg, hwnd) {                                                         	;-- easy function for showing notifications by hovering over a listview

	;http://ahkscript.org/germans/forums/viewtopic.php?t=8225&sid=35ddff584bfe8d4e4c44a0789b388655
	; this line for autoexec: OnMessage(WM_NOTIFY, "Notification")

	Global lvx, toggle, HLV1, HLV2
	Static LVN_ITEMCHANGING := -100
	Static LVIS_STATEIMAGEMASK := 0xF000 ; checked

	;---THX an "ich" für diese Routine, um check/-uncheck zu verhindern
	If (toggle = 0) ;0, dann keinen check/-Uncheck zulassen
	If (NumGet(LParam+0) = HLV1) OR (NumGet(LParam+0) = HLV2) ; NMHDR -> hwndFrom
	If (NumGet(LParam+0, 8, "Int") = LVN_ITEMCHANGING) ; NMHDR -> code
	If (NumGet(LParam+0, 24) & LVIS_STATEIMAGEMASK) ; NMLISTVIEW -> uChanged
		Return True ; True verhindert die Änderung

	;---from Titan für Color-Rows
	If (NumGet(LParam + 0) == NumGet(lvx))
		Return, LVX_Notify(WParam, LParam, msg)

	;---verhindert das Ändern der Spaltenbreite
	If (Code:=(~NumGet(LParam+0,8))+1)
		Return,Code=306||Code=326 ? True:""
}  ;</06.03.05.000011>
;<06.03.05.000012>
LV_IsChecked( lvhwnd, nRow ) {                                                                                  	;-- alternate method to find out if a particular row number is checked
;https://autohotkey.com/docs/commands/ListView.htm#ColN
SendMessage, 4140, nRow - 1, 0xF000, ahk_id %lvhwnd%  	; 4140 is LVM_GETITEMSTATE. 0xF000 is LVIS_STATEIMAGEMASK.
IsChecked := (ErrorLevel >> 12) - 1                                 	; This sets IsChecked to true if RowNumber is checked or false otherwise.
return IsChecked
} ;</06.03.05.000012>
;<06.03.05.000013>
LV_HeaderFontSet(p_hwndlv="", p_fontstyle="", p_fontname="") {				         		;-- sets a different font to a Listview header (it's need CreateFont() function)

	;//******************* Functions *******************
	;//Sun, Jul 13, 2008 --- 7/13/08, 7:19:19pm
	;//Function: ListView_HeaderFontSet
	;//Params...
	;//		p_hwndlv    = ListView hwnd
	;//		p_fontstyle = [b[old]] [i[talic]] [u[nderline]] [s[trike]]
	;//		p_fontname  = <any single valid font name = Arial, Tahoma, Trebuchet MS>
	; dependings: no (changed 24.06.2018)

	static hFont1stBkp
	method:="CreateFont"
	;//method="CreateFontIndirect"
	WM_SETFONT:=0x0030
	WM_GETFONT:=0x0031

	LVM_FIRST:=0x1000
	LVM_GETHEADER:=LVM_FIRST+31

	;// /* Font Weights */
	FW_DONTCARE:=0
	FW_THIN:=100
	FW_EXTRALIGHT:=200
	FW_LIGHT:=300
	FW_NORMAL:=400
	FW_MEDIUM:=500
	FW_SEMIBOLD:=600
	FW_BOLD:=700
	FW_EXTRABOLD:=800
	FW_HEAVY:=900

	FW_ULTRALIGHT:=FW_EXTRALIGHT
	FW_REGULAR:=FW_NORMAL
	FW_DEMIBOLD:=FW_SEMIBOLD
	FW_ULTRABOLD:=FW_EXTRABOLD
	FW_BLACK:=FW_HEAVY
	/*
	parse p_fontstyle for...
	cBlue	color	*** Note *** OMG can't set ListView/SysHeader32 font/text color??? ***
	s19		size
	b		bold
	w500	weight?
	*/
	;//*** Note *** yes I will allow mixed types later!...this was quick n dirty...
	;//*** Note *** ...it now supports bold italic underline & strike-thru...all at once
	style:=p_fontstyle
	;//*** Note *** change RegExReplace to RegExMatch
	style:=RegExReplace(style, "i)\s*\b(?:I|U|S)*B(?:old)?(?:I|U|S)*\b\s*", "", style_bold)
	style:=RegExReplace(style, "i)\s*\b(?:B|U|S)*I(?:talic)?(?:B|U|S)*\b\s*", "", style_italic)
	style:=RegExReplace(style, "i)\s*\b(?:B|I|S)*U(?:nderline)?(?:B|I|S)*\b\s*", "", style_underline)
	style:=RegExReplace(style, "i)\s*\b(?:B|I|U)*S(?:trike)?(?:B|I|U)*\b\s*", "", style_strike)
	;//style:=RegExReplace(style, "i)\s*\bW(?:eight)(\d+)\b\s*", "", style_weight)
	if (style_bold)
		fnWeight:=FW_BOLD
	if (style_italic)
		fdwItalic:=1
	if (style_underline)
		fdwUnderline:=1
	if (style_strike)
		fdwStrikeOut:=1
	;//if (mweight)
	;//	fnWeight:=mweight
	lpszFace:=p_fontname

	ret:=hHeader:= DllCall("SendMessage", "UInt", p_hwndlv, "UInt", LVM_GETHEADER, "UInt", 0, "UInt", 0)
	el:=Errorlevel
	le:=A_LastError
	;//msgbox, 64, , SendMessage LVM_GETHEADER: ret(%ret%) el(%el%) le(%le%)

	ret:= hFontCurr:= DllCall("SendMessage", "UInt", hHeader, "UInt", WM_GETFont, "UInt", 0, "UInt", 0)
	el:=Errorlevel
	le:=A_LastError
	;//msgbox, 64, , SendMessage WM_GETFONT: ret(%ret%) el(%el%) le(%le%)
	if !hFont1stBkp)
		hFont1stBkp:=hFontCurr

	if (method="CreateFont") {
		if (p_fontstyle!="" || p_fontname!="") {
			ret:=hFontHeader:=CreateFont(nHeight, nWidth, nEscapement, nOrientation
							, fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut
							, fdwCharSet, fdwOutputPrecision, fdwClipPrecision
							, fdwQuality, fdwPitchAndFamily, lpszFace)
			el:=Errorlevel
			le:=A_LastError
	} else hFontHeader:=hFont1stBkp
	ret:= DllCall("SendMessage", "UInt", hHeader, "UInt", WM_SETFONT, "UInt", hFontHeader, "UInt", 1)
	el	:=Errorlevel
	le	:=A_LastError

	}
} ;</06.03.05.000013>
;<06.03.05.000014>
LV_SetCheckState(hLV,p_Item,p_Checked) {                                                                	;-- check (add check mark to) or uncheck (remove the check mark from) an item in the ListView control
/*                              	DESCRIPTION

Function: 								LVM_SetCheckState

Description:						   Check (add check mark to) or uncheck (remove the check mark from) an item in
											the ListView control.

Parameters:						   p_Item - Zero-based index of the item.  Set to -1 to change all items.
											p_Checked - Set to TRUE to check item FALSE to uncheck.

Returns:								   TRUE if successful, otherwise FALSE.

Calls To Other Functions:		 * <LVM_SetItemState>

Remarks:									 * This function should only be used on a ListView control with the
											LVS_EX_CHECKBOXES style.
											* This function emulates the ListView_SetCheckState macro.

From:										jballi

Link:											https://autohotkey.com/board/topic/86149-checkuncheck-checkbox-in-listview-using-sendmessage/
*/

Static LVIS_UNCHECKED     :=0x1000
,LVIS_CHECKED       :=0x2000
,LVIS_STATEIMAGEMASK:=0xF000

Return LVM_SetItemState(hLV,p_Item,p_Checked ? LVIS_CHECKED:LVIS_UNCHECKED,LVIS_STATEIMAGEMASK)
} ;</06.03.05.000014>
;<06.03.05.000015>
LV_SetItemState(hLV,p_Item,p_State,p_StateMask) {                                                   	;-- with this function you can set all avaible states to a listview item

	/*                              	DESCRIPTION

	Function: LVM_SetItemState

	Description:			   	Changes the state of an item in a ListView control.

	Parameters:			   	p_Item - Zero-based index of the item. If set to -1, the state change is
									applied to all items.

									p_State, p_StateMask - p_stateMask specifies which state bits to change and
									p_State contains the new values for those bits.  The other state membersare ignored.

	Returns:					   TRUE if successful, otherwise FALSE.

	From:							jballi

	Link:								https://autohotkey.com/board/topic/86149-checkuncheck-checkbox-in-listview-using-sendmessage/
	*/
	Static Dummy7168

	;-- State flags
	,LVIF_STATE         :=0x8
	,LVIS_FOCUSED       :=0x1
	,LVIS_SELECTED      :=0x2
	,LVIS_CUT           :=0x4
	,LVIS_DROPHILITED   :=0x8
	,LVIS_OVERLAYMASK   :=0xF00
	,LVIS_UNCHECKED     :=0x1000
	,LVIS_CHECKED       :=0x2000
	,LVIS_STATEIMAGEMASK:=0xF000

	;-- Message
	,LVM_SETITEMSTATE   :=0x102B                  ;-- LVM_FIRST + 43

	;-- Define/Populate LVITEM Structure
	VarSetCapacity(LVITEM,20,0)
	NumPut(LVIF_STATE, LVITEM,0,"UInt")                 ;-- mask
	NumPut(p_Item,     LVITEM,4,"Int")                 	 ;-- iItem
	NumPut(p_State,    LVITEM,12,"UInt")                	;-- state
	NumPut(p_StateMask,LVITEM,16,"UInt")            ;-- stateMask

	;-- Set state
	SendMessage LVM_SETITEMSTATE,p_Item,&LVITEM,,ahk_id %hLV%

Return ErrorLevel
} ;</06.03.05.000015>
;<06.03.05.000016>
LV_SubitemHitTest(HLV) {																								;-- get's clicked column in listview

	/*                              	EXAMPLE(s)

	NoEnv
	Gui, Margin, 20, 20
	Gui, Add, ListView, w400 r9 Grid HwndHLV1 gSubLV AltSubmit, Column 1|Column 2|Column 3
	Loop, 9
	LV_Add("", A_Index, A_Index, A_Index)
	Loop, 3
	LV_ModifyCol(A_Index, "AutoHdr")
	Gui, Show, , ListView
	Return
	; ----------------------------------------------------------------------------------------------------------------------
	GuiCLose:
	ExitApp
	; ----------------------------------------------------------------------------------------------------------------------
	SubLV:
	If (A_GuiEvent = "Normal")
	  Row := A_EventInfo
	  Column := LV_SubItemHitTest(HLV1)
					  SetTimer, KillToolTip, -1500

	Return
	; ----------------------------------------------------------------------------------------------------------------------
	KillToolTip:
	ToolTip
	Return

	*/

	; To run this with AHK_Basic change all DllCall types "Ptr" to "UInt", please.
	; HLV - ListView's HWND
	Static LVM_SUBITEMHITTEST := 0x1039
	VarSetCapacity(POINT, 8, 0)
	; Get the current cursor position in screen coordinates
	DllCall("User32.dll\GetCursorPos", "Ptr", &POINT)
	; Convert them to client coordinates related to the ListView
	DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &POINT)
	; Create a LVHITTESTINFO structure (see below)
	VarSetCapacity(LVHITTESTINFO, 24, 0)
	; Store the relative mouse coordinates
	NumPut(NumGet(POINT, 0, "Int"), LVHITTESTINFO, 0, "Int")
	NumPut(NumGet(POINT, 4, "Int"), LVHITTESTINFO, 4, "Int")
	; Send a LVM_SUBITEMHITTEST to the ListView
	SendMessage, LVM_SUBITEMHITTEST, 0, &LVHITTESTINFO, , ahk_id %HLV%
	; If no item was found on this position, the return value is -1
	If (ErrorLevel = -1)
	Return 0
	; Get the corresponding subitem (column)
	Subitem := NumGet(LVHITTESTINFO, 16, "Int") + 1
Return Subitem
} ;</06.03.05.000016>
;<06.03.05.000017>
LV_EX_FindString(HLV, Str, Start := 0, Partial := False) {													;-- find an item in any listview , function works with ANSI and UNICODE (tested)
	; LVM_FINDITEM -> http://msdn.microsoft.com/en-us/library/bb774903(v=vs.85).aspx
	Static LVM_FINDITEM := A_IsUnicode ? 0x1053 : 0x100D ; LVM_FINDITEMW : LVM_FINDITEMA
	Static LVFISize := 40
	VarSetCapacity(LVFI, LVFISize, 0) ; LVFINDINFO
	Flags := 0x0002 ; LVFI_STRING
	If (Partial)
	Flags |= 0x0008 ; LVFI_PARTIAL
	NumPut(Flags, LVFI, 0, "UInt")
	NumPut(&Str,  LVFI, A_PtrSize, "Ptr")
	SendMessage, % LVM_FINDITEM, % (Start - 1), % &LVFI, , % "ahk_id " . HLV
Return (ErrorLevel > 0x7FFFFFFF ? 0 : ErrorLevel + 1)
} ;</06.03.05.000017>
;<06.03.05.000018>
LV_RemoveSelBorder(HLV, a*) {																						;-- remove the listview's selection border

;https://autohotkey.com/boards/viewtopic.php?p=49507#p49507
;https://stackoverflow.com/questions/2691726/how-can-i-remove-the-selection-border-on-a-listviewitem
Static WM_CHANGEUISTATE := 0x127
, WM_UPDATEUISTATE := 0x128
, UIS_SET := 1
, UISF_HIDEFOCUS := 0x1
, wParam := (UIS_SET << 16) | (UISF_HIDEFOCUS & 0xffff) ; MakeLong
, _ := OnMessage(WM_UPDATEUISTATE, "LV_RemoveSelBorder")
If (a.2 = WM_UPDATEUISTATE)
Return 0 ; Prevent alt key from restoring the selection border
PostMessage, WM_CHANGEUISTATE, wParam, 0,, % "ahk_id " . HLV
} ;</06.03.05.000018>
;<06.03.05.000019>
LV_SetExplorerTheme(HCTL) { 																						;-- set 'Explorer' theme for ListViews & TreeViews on Vista+
; HCTL : handle of a ListView or TreeView control
If (DllCall("GetVersion", "UChar") > 5) {
VarSetCapacity(ClassName, 1024, 0)
If DllCall("GetClassName", "Ptr", HCTL, "Str", ClassName, "Int", 512, "Int")
If (ClassName = "SysListView32") || (ClassName = "SysTreeView32")
Return !DllCall("UxTheme.dll\SetWindowTheme", "Ptr", HCTL, "WStr", "Explorer", "Ptr", 0)
}
Return False
} ;</06.03.05.000019>
;<06.03.05.000020>
LV_Update(hWnd, Item) {																								;-- update one listview item
return SendMessage(hWnd, 0x1000+42, "Int", Item-1)
} ;</06.03.05.000020>
;<06.03.05.000021>
LV_RedrawItem(hWnd, ItemFirst := 0, ItemLast := "") {													;-- this one redraws on listview item
If (ItemFirst > 0)
ItemLast := ItemLast=""?ItemFirst:ItemLast
else ItemLast := (ItemFirst:=SendMessage(hWnd, 0x1027))+SendMessage(hWnd, 0x1028)
return SendMessage(hWnd, 0x1000+21, "Int", ItemFirst-1, "Int", ItemLast-1), DllCall("User32.dll\UpdateWindow", "Ptr", hWnd)
} ;</06.03.05.000021>
;<06.03.05.000022>
LV_SetExStyle(hWnd, ExStyle) {																						;-- set / remove / alternate extended styles to the listview control
/*                              	DESCRIPTION

; set / remove / alternate extended styles to the window.
; Syntax: LV_SetExStyle ([hWnd], [ - Styles])
; STYLES: https://msdn.microsoft.com/en-us/library/windows/desktop/bb774732(v=vs.85).aspx
; 0x010000 = drawing via double buffer, which reduces flicker
; 0x00000004 = activate the checkboxes for the elements (checkbox)
; 0x00000001 = shows grid lines around the elements and sub-elements (grid)

*/

Key := SubStr(ExStyle:=Trim(ExStyle), 1, 1), ExStyle := (Key="+"||Key="-"||Key="^")?SubStr(ExStyle, 2):ExStyle
if (Key="-")
return SendMessage(hWnd, 0x1036, "UInt", ExStyle)
if (Key="^")
return LV_SetExStyle(hWnd, ((LV_GetExStyle(hWnd)&ExStyle)?"-":"") ExStyle)
return SendMessage(hWnd, 0x1036, "UInt", ExStyle, "UInt", ExStyle)
}  ;</06.03.05.000022> ;https://msdn.microsoft.com/en-us/library/windows/desktop/bb761165%28v=vs.85%29.aspx
;<06.03.05.000023>
LV_GetExStyle(hWnd) {																									;-- get / remove / alternate extended styles to the listview control
return SendMessage(hWnd, 0x1037,,,,, "UInt")
} ;</06.03.05.000023>
;<06.03.05.000024>
LV_IsItemVisible(hWnd, Item) {																						;-- determines if a listview item is visible
return SendMessage(hWnd, 0x10B6, "Int", Item-1)
} ;</06.03.05.000024>
;<06.03.05.000025>
LV_SetIconSpacing(hWnd, cx, cy) {																					;-- Sets the space between icons in the icon view

	/*                              	DESCRIPTION

	; Sets the space between icons in the icon view.
	; Syntax: LV_SetIconSpacing ([ID], [x-axis, distance in pixels], [y-axis, distance in pixels])

	*/

	cx := ((cx<4)&&(cx!=-1))?4:cx, cy := ((cy<4)&&(cy!=-1))?4:cy

return SendMessage(hWnd, 0x1035,,,, LOWORD(cx)+HIWORD(cy, false))
} ;</06.03.05.000025>
;<06.03.05.000026>
LV_GetIconSpacing(hWnd, ByRef cx := "", ByRef cy := "") {												;-- Get the space between icons in the icon view
/*                              	DESCRIPTION

Get the space between icons in the icon view.
; Syntax: LV_GetIconSpacing ([ID], [x-axis, distance in pixels (output)], [y-axis, distance in pixels (output)])

*/

IcSp := SendMessage(hWnd, 0x1033)
return [cx:=(IcSp & 0xFFFF), cy:=(IcSp >> 16)]
} ;</06.03.05.000026>
;<06.03.05.000027>
LV_GetItemPos(hWnd, Item, ByRef x := "", ByRef y := "") {												;-- obtains the position of an item
/*                              	DESCRIPTION

; get position of an item
; Syntax: LV_GetItemPos ([ID], [item], [x (output)], [y (output)])
; Note: returns an Array with the position xy.

*/

VarSetCapacity(POINT, A_PtrSize*2, 0), SendMessage(hWnd, 0x1010,, Item-1,, &POINT)
return [x:=NumGet(POINT, 0, "Int"), y:=NumGet(POINT, 4, "Int")]
} LV_GetItemPosEx(hWnd, Item, ByRef x := "", ByRef y := "", ByRef ProcessId := "") {
ProcessId := ProcessId?ProcessId:WinGetPid(hWnd), hProcess := OpenProcess(ProcessId, 0x0008|0x0010|0x0020)
, pAddress := VirtualAlloc(hProcess,, 0x00001000), SendMessage(hWnd, 0x1000+16, "Int", Item-1,, pAddress)
, VarSetCapacity(RECT, 16, 0), ReadProcessMemory(hProcess, pAddress, &RECT, 16)
return [x:=NumGet(RECT, 0, "Int"), y:=NumGet(RECT, 4, "Int")], VirtualFree(hProcess, pAddress), CloseHandle(hProcess)
}  ;</06.03.05.000027> ;http://www.autohotkey.com/board/topic/9760-lvm-geticonposition/
;<06.03.05.000028>
LV_SetItemPos(hWnd, Item, x := "", y := "") {																	;-- set the position of an item
/*                              	DESCRIPTION

set the position of an item
Syntax: LV_SetItemPos ([ID], [item], [x], [y])

*/

	if (x="") || (y="")
	LV_GetItemPos(hWnd, Item, _x, _y)
	return SendMessage(hWnd, 0x100F,, Item-1,, LOWORD(x=""?_x:x)+HIWORD(y=""?_y:y, false))
	} LV_SetItemPosEx(hWnd, Item, x := "", y := "", ProcessId := "") {
	if (x="") || (y="")
	LV_GetItemPosEx(hWnd, Item, _x, _y, ProcessId)

return SendMessage(hWnd, 0x100F,, Item-1,, LOWORD(x=""?_x:x)+HIWORD(y=""?_y:y, false))
} ;</06.03.05.000028>
;<06.03.05.000029>
LV_MouseGetCellPos(ByRef LV_CurrRow, ByRef LV_CurrCol, LV_LView) {						;-- returns the number (row, col) of a cell in a listview at present mouseposition

LVIR_LABEL = 0x0002					;LVM_GETSUBITEMRECT constant - get label info
LVM_GETITEMCOUNT = 4100			;gets total number of rows
LVM_SCROLL = 4116						;scrolls the listview
LVM_GETTOPINDEX = 4135			;gets the first displayed row
LVM_GETCOUNTPERPAGE = 4136	;gets number of displayed rows
LVM_GETSUBITEMRECT = 4152		;gets cell width,height,x,y
ControlGetPos, LV_lx, LV_ly, LV_lw, LV_lh, , ahk_id %LV_LView%	;get info on listview

SendMessage, LVM_GETITEMCOUNT, 0, 0, , ahk_id %LV_LView%
LV_TotalNumOfRows := ErrorLevel	;get total number of rows
SendMessage, LVM_GETCOUNTPERPAGE, 0, 0, , ahk_id %LV_LView%
LV_NumOfRows := ErrorLevel	;get number of displayed rows
SendMessage, LVM_GETTOPINDEX, 0, 0, , ahk_id %LV_LView%
LV_topIndex := ErrorLevel	;get first displayed row

CoordMode, MOUSE, RELATIVE
MouseGetPos, LV_mx, LV_my
LV_mx -= LV_lx, LV_my -= LV_ly

VarSetCapacity(LV_XYstruct, 16, 0)	;create struct
Loop,% LV_NumOfRows + 1	;gets the current row and cell Y,H
{	LV_which := LV_topIndex + A_Index - 1	;loop through each displayed row
NumPut(LVIR_LABEL, LV_XYstruct, 0)	;get label info constant
NumPut(A_Index - 1, LV_XYstruct, 4)	;subitem index
SendMessage, LVM_GETSUBITEMRECT, %LV_which%, &LV_XYstruct, , ahk_id %LV_LView%	;get cell coords
LV_RowY := NumGet(LV_XYstruct,4)	;row upperleft y
LV_RowY2 := NumGet(LV_XYstruct,12)	;row bottomright y2
LV_currColHeight := LV_RowY2 - LV_RowY ;get cell height
if (LV_my <= LV_RowY + LV_currColHeight)	;if mouse Y pos less than row pos + height
{	LV_currRow  := LV_which + 1	;1-based current row
LV_currRow0 := LV_which		;0-based current row, if needed
;LV_currCol is not needed here, so I didn't do it! It will always be 0. See my ListviewInCellEditing function for details on finding LV_currCol if needed.
LV_currCol=0
Break
}
}
} ;</06.03.05.000029>
;<06.03.05.000030>
LV_GetColOrderLocal(hCtl, vSep:="") {																			;-- returns the order of listview columns for a local listview

	/*                              	DESCRIPTION

	warning: such functions can potentially crash programs, save any work before testing

	[need functions from here:]
	GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
	https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
	https://autohotkey.com/boards/viewtopic.php?t=52945

	pass listview hWnd (not listview header hWnd)
	for local controls only

	*/

	hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
	vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
	vData := ""
	VarSetCapacity(vData, vCountCol*4, 0)
	SendMessage(0x103B, vCountCol, &vData,, "ahk_id " hCtl) ;LVM_GETCOLUMNORDERARRAY := 0x103B
	if (vSep = "")
	{
	oOutput := []
	Loop, % vCountCol
	oOutput.Push(NumGet(&vData, A_Index*4-4, "Int")+1)
	return oOutput
	}
	else
	{
	vOutput := ""
	Loop, % vCountCol
	vOutput .= NumGet(&vData, A_Index*4-4, "Int")+1 vSep
	return SubStr(vOutput, 1, -StrLen(vSep))
	}

} ;</06.03.05.000030>
;<06.03.05.000031>
LV_GetColOrder(hCtl, vSep:="") {																					;-- returns the order of listview columns for a listview

	;pass listview hWnd (not listview header hWnd)
	vErr := A_PtrSize=8 && JEE_WinIs64Bit(hCtl) ? -1 : 0xFFFFFFFF
	vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
	vPID := WinGetPID("ahk_id " hCtl)
	if (vPID = vScriptPID)
	vIsLocal := 1, vPIs64 := (A_PtrSize=8)

	if !hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
	return
	if !vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
	return
	if (vCountCol = vErr) ;-1
	return

	if !vIsLocal
	{
		if !hProc := JEE_DCOpenProcess(0x438, 0, vPID)
			return
		if A_Is64bitOS && !DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
			return
		vPIs64 := !vIsWow64Process
	}

	vPtrType := vPIs64?"Int64":"Int"
	vSize := vCountCol*4
	VarSetCapacity(vData, vSize, 0)

	if !vIsLocal
		if !pBuf := JEE_DCVirtualAllocEx(hProc, 0, vSize, 0x3000, 0x4)
			return
	else
		pBuf := &vData

	SendMessage(0x103B, vCountCol, pBuf,, "ahk_id " hCtl) ;LVM_GETCOLUMNORDERARRAY := 0x103B
	if !vIsLocal
	{
		JEE_DCReadProcessMemory(hProc, pBuf, &vData, vSize, 0)
		JEE_DCVirtualFreeEx(hProc, pBuf, 0, 0x8000)
		JEE_DCCloseHandle(hProc)
	}
	if (vSep = "")
	{
		oOutput := []
		Loop, % vCountCol
		oOutput.Push(NumGet(&vData, A_Index*4-4, "Int")+1)
		return oOutput
	}
	else
	{
		vOutput := ""
		Loop, % vCountCol
		vOutput .= NumGet(&vData, A_Index*4-4, "Int")+1 vSep
		return SubStr(vOutput, 1, -StrLen(vSep))
	}

} ;</06.03.05.000031>
;<06.03.05.000032>
LV_SetColOrderLocal(hCtl, oList, vSep:="") {																	;-- pass listview hWnd (not listview header hWnd)

	;for local controls only
	if !IsObject(oList)
	oList := StrSplit(oList, vSep)
	if !(vCountCol := oList.Length())
	return
	VarSetCapacity(vData, vCountCol*4)
	for _, vValue in oList
	NumPut(vValue-1, &vData, A_Index*4-4, "Int")
	SendMessage(0x103A, vCountCol, &vArray,, "ahk_id " hCtl) ;LVM_SETCOLUMNORDERARRAY := 0x103A

} ;</06.03.05.000032>
;<06.03.05.000033>
LV_SetColOrder(hCtl, oList, vSep:="") {																			;-- pass listview hWnd (not listview header hWnd)
	if !IsObject(oList)
	oList := StrSplit(oList, vSep)
	if !(vCountCol := oList.Length())
	return

	vErr := A_PtrSize=8 && JEE_WinIs64Bit(hCtl) ? -1 : 0xFFFFFFFF
	vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
	vPID := WinGetPID("ahk_id " hCtl)
	if (vPID = vScriptPID)
	vIsLocal := 1, vPIs64 := (A_PtrSize=8)

	if !hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
	return
	if !vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
	return
	if (vCountCol = vErr) ;-1
	return

	if !vIsLocal
	{
	if !hProc := JEE_DCOpenProcess(0x438, 0, vPID)
	return
	if A_Is64bitOS && !DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
	return
	vPIs64 := !vIsWow64Process
	}

	vPtrType := vPIs64?"Int64":"Int"
	vSize := vCountCol*4
	VarSetCapacity(vData, vCountCol*4)
	for _, vValue in oList
	NumPut(vValue-1, &vData, A_Index*4-4, "Int")

	if !vIsLocal
	{
	if !pBuf := JEE_DCVirtualAllocEx(hProc, 0, vSize, 0x3000, 0x4)
	return
	JEE_DCWriteProcessMemory(hProc, pBuf, &vData, vSize, 0)
	}
	else
	pBuf := &vData

	SendMessage(0x103A, vCountCol, pBuf,, "ahk_id " hCtl) ;LVM_SETCOLUMNORDERARRAY := 0x103A

	if !vIsLocal
	{
	JEE_DCVirtualFreeEx(hProc, pBuf, 0, 0x8000)
	JEE_DCCloseHandle(hProc)
	}

} ;</06.03.05.000033>
;<06.03.05.000034>
LV_GetCheckedItems(cN,wN) {																						;-- Returns a list of checked items from a standard ListView Control
;https://gist.github.com/TLMcode/4757894
ControlGet, LVItems, List,, % cN, % wN
Item:=Object()
While Pos
Pos:=RegExMatch(LVItems,"`am)(^.*?$)",_,!Pos?(Pos:=1):Pos+StrLen(_)),mCnt:=A_Index-1,Item[mCnt]:=_1
Loop % mCnt {
SendMessage, 0x102c, A_Index-1, 0x2000, % cN, % wN
ChkItems.=(ErrorLevel ? Item[A_Index-1] "`n" : "")
}
Return ChkItems
} ;</06.03.05.000034>
;<06.03.05.000035>
LV_ClickRow(HLV, Row) { 																								;-- simulates a left mousebutton click on a specific row in a listview

; just me -> http://www.autohotkey.com/board/topic/86490-click-listview-row/#entry550767
; HLV : ListView's HWND, Row : 1-based row number

VarSetCapacity(RECT, 16, 0)
SendMessage, 0x100E, Row - 1, &RECT, , ahk_id %HLV% ; LVM_GETITEMRECT
POINT := NumGet(RECT, 0, "Short") | (NumGet(RECT, 4, "Short") << 16)
PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONUP

} ;</06.03.05.000035>
;<06.03.05.000036>
LV_HeaderFontSet(p_hwndlv="", p_fontstyle="", p_fontname="") {                              	;-- sets font for listview headers

/******************* Functions *******************
;//Sun, Jul 13, 2008 --- 7/13/08, 7:19:19pm
;//Function: ListView_HeaderFontSet
;//Params...
;//		p_hwndlv    = ListView hwnd
;//		p_fontstyle = [b[old]] [i[talic]] [u[nderline]] [s[trike]]
;//		p_fontname  = <any single valid font name = Arial, Tahoma, Trebuchet MS>
*/

static hFont1stBkp
method:="CreateFont"
;//method="CreateFontIndirect"
WM_SETFONT			:=0x0030
WM_GETFONT			:=0x0031
LVM_FIRST				:=0x1000
LVM_GETHEADER	:=LVM_FIRST+31
;// /* Font Weights */
FW_DONTCARE		:=0
FW_THIN					:=100
FW_EXTRALIGHT		:=200
FW_LIGHT				:=300
FW_NORMAL			:=400
FW_MEDIUM			:=500
FW_SEMIBOLD		:=600
FW_BOLD				:=700
FW_EXTRABOLD		:=800
FW_HEAVY				:=900
FW_ULTRALIGHT		:=FW_EXTRALIGHT
FW_REGULAR			:=FW_NORMAL
FW_DEMIBOLD		:=FW_SEMIBOLD
FW_ULTRABOLD		:=FW_EXTRABOLD
FW_BLACK				:=FW_HEAVY
/*
parse p_fontstyle for...
	cBlue	color	*** Note *** OMG can't set ListView/SysHeader32 font/text color??? ***
	s19		size
	b		bold
	w500	weight?
*/
;//*** Note *** yes I will allow mixed types later!...this was quick n dirty...
;//*** Note *** ...it now supports bold italic underline & strike-thru...all at once
style:=p_fontstyle
;//*** Note *** change RegExReplace to RegExMatch
style:=RegExReplace(style, "i)\s*\b(?:I|U|S)*B(?:old)?(?:I|U|S)*\b\s*", "", style_bold)
style:=RegExReplace(style, "i)\s*\b(?:B|U|S)*I(?:talic)?(?:B|U|S)*\b\s*", "", style_italic)
style:=RegExReplace(style, "i)\s*\b(?:B|I|S)*U(?:nderline)?(?:B|I|S)*\b\s*", "", style_underline)
style:=RegExReplace(style, "i)\s*\b(?:B|I|U)*S(?:trike)?(?:B|I|U)*\b\s*", "", style_strike)
;//style:=RegExReplace(style, "i)\s*\bW(?:eight)(\d+)\b\s*", "", style_weight)
if (style_bold)
	fnWeight:=FW_BOLD
if (style_italic)
	fdwItalic:=1
if (style_underline)
	fdwUnderline:=1
if (style_strike)
	fdwStrikeOut:=1
;//if (mweight)
;//	fnWeight:=mweight
lpszFace:=p_fontname

ret:=hHeader:=SendMessage(p_hwndlv, LVM_GETHEADER, 0, 0)
el:=Errorlevel
le:=A_LastError
;//msgbox, 64, , SendMessage LVM_GETHEADER: ret(%ret%) el(%el%) le(%le%)

ret:=hFontCurr:=SendMessage(hHeader, WM_GETFONT, 0, 0)
el:=Errorlevel
le:=A_LastError
;//msgbox, 64, , SendMessage WM_GETFONT: ret(%ret%) el(%el%) le(%le%)
if (!hFont1stBkp) {
	hFont1stBkp:=hFontCurr
}

if (method="CreateFont") {
	if (p_fontstyle!="" || p_fontname!="") {
		ret:=hFontHeader:=CreateFont(nHeight, nWidth, nEscapement, nOrientation
									, fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut
									, fdwCharSet, fdwOutputPrecision, fdwClipPrecision
									, fdwQuality, fdwPitchAndFamily, lpszFace)
		el:=Errorlevel
		le:=A_LastError
		;//msgbox, 64, , CreateFont: ret(%ret%) el(%el%) le(%le%)
	} else hFontHeader:=hFont1stBkp
	ret:=SendMessage(hHeader, WM_SETFONT, hFontHeader, 1)
	;//ret:=SendMessage(hHeader, WM_SETFONT, hFontHeader, 0)
	;//ret:=SendMessage(hHeader, WM_SETFONT, &0, 1)
	el:=Errorlevel
	le:=A_LastError
	;//msgbox, 64, , SendMessage WM_SETFONT: ret(%ret%) el(%el%) le(%le%)
}
} ;</06.03.05.000036>
;<06.03.05.000037>
LV_SetSI(hList, iItem, iSubItem, iImage) {                                                                       	;-- set icon for row "subItem" within Listview

	/*	DESCRIPTION OF FUNCTION: -- LV_SetSI() --
		-------------------------------------------------------------------------------------------------------------------
		Description  	:	set icon for row "subItem" within Listview
		Link              	:	https://gist.github.com/hoppfrosch/11242617
		Author         	:	Tseug (http://www.autohotkey.com/board/topic/72072-listview-icons-in-more-than-first-column-example/)
		Date             	:
		AHK-Version	:	ANSI AHK_L
		License         	:
		Syntax          	:
		Parameter(s)	:
		Return value	:
		Remark(s)    	:
		Dependencies	:
		KeyWords    	:	Listview, gui, icon
		-------------------------------------------------------------------------------------------------------------------
		|	EXAMPLE(s)
		-------------------------------------------------------------------------------------------------------------------
		; example for adding icons to listview columns > the first
		; after Drugwash: http://www.autohotkey.com/forum/post-234198.html#234198

		Gui, add, ListView,	w600 h400		+LV0x2 HwndHLV, Name|Size|Ext
		ImageListID := IL_Create(10)
		LV_SetImageList(ImageListID)
		Loop 10
			IL_Add(ImageListID, "shell32.dll", A_Index)

		Loop, %A_WinDir%\*.*				; fill Listview
		{	if a_Index > 100
				break
			i := Mod(a_index,10)+1			; since I only added 10 icons
			LV_Add("icon" i, A_LoopFileName, A_LoopFileSize, A_LoopFileExt)
			LV_SetSI(hLV, A_Index, 3, i)	; now add icons (i) to the rows of the third column
					; can also call function later for individual cells
		}
		LV_ModifyCol()

		Gui, Show,	, Icons in more than 1 Listview column
		return

		GuiClose:
		ExitApp
	*/

	VarSetCapacity(LVITEM, 60, 0)
	LVM_SETITEM := 0x1006 , mask := 2   ; LVIF_IMAGE := 0x2
	iItem-- , iSubItem-- , iImage--		; Note first column (iSubItem) is #ZERO, hence adjustment
	NumPut(mask, LVITEM, 0, "UInt")
	NumPut(iItem, LVITEM, 4, "Int")
	NumPut(iSubItem, LVITEM, 8, "Int")
	NumPut(iImage, LVITEM, 28, "Int")
	result := DllCall("SendMessageA", UInt, hList, UInt, LVM_SETITEM, UInt, 0, UInt, &LVITEM)
	return result
} ;</06.03.05.000037>
;<06.03.05.000038>
LVM_CalculateSize(hLV,p_NumberOfRows:=-1,ByRef r_Width:="",ByRef r_Height:="") { ;-- calculate the width and height required to display a given number of rows of a ListView control

	/*	DESCRIPTION OF FUNCTION: -- LVM_CalculateSize() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	calculate the width and height required to display a given number of rows of a ListView control
								*    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *
                            	This function uses the LVM_APPROXIMATEVIEWRECT message to calculate the
                            	approximate width and height required to display a given number of rows in a
                            	ListView control.  The AutoHotkey method (extracted from the AutoHotkey
                            	source) makes minor changes to the data that is passed to the message and to
                            	the results that are returned from the message.

                            	The AutoHotkey method is the following.

                            	_Input_: The actual or requested number of row is used minus 1.  For
                            	example, if 10 rows is requested, 9 is passed to the LVM_APPROXIMATEVIEWRECT
                            	message instead.

                            	_Output_: 4 is added to both the width and height return values.  For example, if the
                            	message returned a size of 300x200, the size is adjusted to 304x204.

                            	The final result (in most cases) is a ListView control that is the exact size needed
								to show all of the specified rows and columns without showing the horizontal
                            	or vertical scroll bars.  Exception: If the requested number of rows is less than the
                            	actual number of rows, the horizontal and/or vertical scroll bars may show as a result.
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=74&t=42570
	Author         	:	jballi
	Date             	:	January 09, 2018
	AHK-Version	:	AHK_L
	Parameter(s)	:	p_NumberOfRows - The number of rows to be displayed in the control.  Set to -1 (the default) to use
								the current number of rows in the ListView control
                              	r_Width, r_Height - [Output, Optional] - The calculated width and height of ListView control
	Return value	:	An integer that holds the calculated width (in the LOWORD) and height (in the HIWORD)
                            	needed to display the rows, in pixels.
                            	If the output variables are defined (r_Width and r_Height), the calculated values are also
                            	returned in these variables.
	Remark(s)    	:	This function should only be used on a ListView control in the Report view.
	Dependencies	:	none
	KeyWords    	:	Gui, Listview, Control
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	;This example shows that the size of the ListView control can change as needed.
		#NoEnv
		#SingleInstance Force
		ListLines Off

		;-- GUI options
		gui -DPIScale +hWndhGUI -MinimizeBox

		;-- GUI objects
		gui Add,Text,xm,Current ListView size
		gui Add,Text,xm+20,W:%A_Space%
		gui Add,Text,x+0 vLVPosW Section,99999

		gui Add,Text,xm+20 y+0,H:
		gui Add,Text,xs yp vLVPosH,99999

		gui Add,CheckBox,xm Checked gToggleColumnHeader,Show Column Header

		gui Add,Button,xm w150 gAdd5,Add 5 rows
		gui Add,Button,xm y+0 wp gAdjust1,Adjust using defaults

		gui Font,Bold
		gui Add,Button,xm y+0 wp gAdjust2,Adjust
		gui Font

		gui Add,Button,xm y+0 wp gHelp,Help
		gui Add,Button,xm y+0 wp gReload,Rebuild example...

		;-- Add ListView control
		Random FontSize,8,14
		gui Font,s%FontSize%
		gui Add
		   ,ListView
		   ,% ""
				. "ym "
				. "Report "
				. "hWndhLV "
				. "vMyListView "
		   ,Column 1|Column 2|Column 3|Column 4|Column 5

		gui Font
		gosub UpdateDisplay

		;-- Show
		SplitPath A_ScriptName,,,,$ScriptTitle
		gui Show,x0 y0,%$ScriptTitle%
	return

	GUIClose:
	GUIEscape:
		ExitApp

	Add5:
		Loop 5
			{
			Random RandomNumber,100000,999999
			LV_Add("",RandomNumber,"Dummy data " . A_TickCount,"c3","c4","c5")
			}
	return

	Adjust1:
		LVM_ApproximateViewRect(hLV,-1,AVRWidth,AVRHeight)
		ControlMove,,,,%AVRWidth%,%AVRHeight%,ahk_id %hLV%
		gosub UpdateDisplay
		gui Show,AutoSize
	return


	;-- The methodology (extracted from the AutoHotkey source) is simple.  For the
	;   "number of items" parameter of the LVM_APPROXIMATEVIEWRECT message, the
	;   actual or projected number of items is used minus 1.  After the call, 4 is
	;   added to both the Width and Height return values.  The final result is a
	;   ListView control that is just large enough to not show the horizontal and
	;   vertical scroll bars.  This method seems to work for most fonts.
	Adjust2:
		LVM_ApproximateViewRect(hLV,LV_GetCount()-1,AVRWidth,AVRHeight)

	;-- Add 4 to the Width and Height
		AVRWidth+=4
		AVRHeight+=4

	;-- Adjust
		ControlMove,,,,%AVRWidth%,%AVRHeight%,ahk_id %hLV%
		gosub UpdateDisplay
		gui Show,AutoSize
	return

	Help:
		gui +OwnDialogs
		MsgBox
			,0x40
			,Help,
			   (ltrim join`s
				Instructions:

				`n`n1) Press the "Add 5..." button as needed to add 5 additional dummy
				rows to the ListView control.

				`n`n2) Change the width of any column as needed.

				`n`n3) Press any of the "Adjust..." buttons at any time to calculate and
				show the new size of the ListView control.
			   )

	return

	Reload:
		Reload
	return


	ToggleColumnHeader:
		LVS_NOCOLUMNHEADER :=0x4000
		Control Style,^%LVS_NOCOLUMNHEADER%,,ahk_id %hLV%
	return


	UpdateDisplay:
		ControlGetPos,,,W,H,,ahk_id %hLV%
		GUIControl,,LVPosW,%W%
		GUIControl,,LVPosH,%H%
	return

	*/

    Static Dummy67950827

	  ;-- Messages
	  ,LVM_GETITEMCOUNT              	:=0x1004              ;-- LVM_FIRST + 4
	  ,LVM_APPROXIMATEVIEWRECT	:=0x1040              ;-- LVM_FIRST + 64

    ;-- Collect and/or adjust the number of rows
    if (p_NumberOfRows<0)
   {
        SendMessage LVM_GETITEMCOUNT,0,0,,ahk_id %hLV%
        p_NumberOfRows:=ErrorLevel
        }

    if p_NumberOfRows  ;-- Not zero
        p_NumberOfRows-=1

    ;-- Calculate size
    SendMessage LVM_APPROXIMATEVIEWRECT,p_NumberOfRows,-1,,ahk_id %hLV%

    ;-- Extract, adjust, and return values
    r_Width :=(ErrorLevel&0xFFFF)+4 ;-- LOWORD
    r_Height:=(ErrorLevel>>16)+4    ;-- HIWORD
    Return r_Height<<16|r_Width
} ;</06.03.05.000038>
;<06.03.05.000039>
LV_RemoveSelBorder(HLV, a*) {                                                                                     	;-- to remove the listview's selection border

	/*	DESCRIPTION OF FUNCTION: -- to remove the listview's selection border --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	remove the listview's selection border
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?p=49507#p49507
	                         	http://stackoverflow.com/questions/2691 ... stviewitem
	Author         	:	tmplinshi
	Date             	:	July 17, 2015
	AHK-Version	:	AHK_L
	License         	:	-
	Syntax          	:	-
	Parameter(s)	:	HLV: Listview handle
	Return value	:	none
	Remark(s)    	:	-
	Dependencies	:	non
	KeyWords    	:	gui, Listview
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	Static WM_CHANGEUISTATE	:= 0x127
	        , WM_UPDATEUISTATE	:= 0x128
	        , UIS_SET                      	:= 1
			, UISF_HIDEFOCUS       	:= 0x1
			, wParam := (UIS_SET << 16) | (UISF_HIDEFOCUS & 0xffff) ; MakeLong
			, _ := OnMessage(WM_UPDATEUISTATE, "LV_RemoveSelBorder")
	If (a.2 = WM_UPDATEUISTATE)
		Return 0 ; Prevent alt key from restoring the selection border
	PostMessage, WM_CHANGEUISTATE, wParam, 0,, % "ahk_id " . HLV
} ;</06.03.05.000039>
;<06.03.05.000040>
LVM_GetItemText(hLV,p_Item,p_Column:=0,p_MaxTCHARs:=32768) {                      	;-- gets the text of a ListView item or subitem.

	/*	DESCRIPTION OF FUNCTION: -- LVM_GetItemText --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Gets the text of a ListView item or subitem.
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=58207&start=20
	Author         	:	jballi
	Date             	:	23.10.2018
	AHK-Version	:	all versions of AutoHotkey v1.1+ including the 64-bit version
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	p_Item - Zero-based item index
                            	p_Item - Zero-based item index
	Return value	:	Text from the specified item/column
	Remark(s)    	:	ErrorLevel is set to the number of characters returned
	Dependencies	:	LVM_GetSizeOfLVITEM()
	KeyWords    	:	gui, listview
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

    Static Dummy53843366
          ,sizeofLVITEM:=LVM_GetSizeOfLVITEM()

          ;-- LVITEM flags
          ,LVIF_TEXT:=0x1

          ;-- Messages
          ,LVM_GETITEMTEXTA:=0x102D                     ;-- LVM_FIRST + 45
          ,LVM_GETITEMTEXTW:=0x1073                     ;-- LVM_FIRST + 115

    ;-- Create and populate LVITEM structure
    VarSetCapacity(l_Text,A_IsUnicode ? p_MaxTCHARs*2:p_MaxTCHARs,0)
    VarSetCapacity(LVITEM,sizeofLVITEM,0)
    NumPut(LVIF_TEXT,  LVITEM,0,"UInt")                 ;-- mask
    NumPut(p_Item,     LVITEM,4,"Int")                  ;-- iItem
    NumPut(p_Column,   LVITEM,8,"Int")                  ;-- iSubItem
    NumPut(&l_Text,    LVITEM,(A_PtrSize=8) ? 24:20,"Ptr")
        ;-- pszText
    NumPut(p_MaxTCHARs,LVITEM,(A_PtrSize=8) ? 32:24,"Int")
        ;-- cchTextMax.  Note: This contains the number of TCHARs in the buffer
        ;   pointed to by pszText.

    ;-- Collect text
    SendMessage
        ,% A_IsUnicode ? LVM_GETITEMTEXTW:LVM_GETITEMTEXTA
        ,p_Item
        ,&LVITEM
        ,,ahk_id %hLV%

    VarSetCapacity(l_Text,-1)
Return l_Text
}
LVM_GetSizeOfLVITEM() {	;-- sub of LV_GetItemText (06.03.05.000040)
    sizeofLVITEM:=(A_PtrSize=8) ? 64:52
    if (((GV:=DllCall("GetVersion"))&0xFF . "." . GV>>8&0xFF)>=6.0)  ;-- Vista+
        sizeofLVITEM:=(A_PtrSize=8) ? 72:60
Return sizeofLVITEM
} ;</06.03.05.000040>
;<06.03.05.000041>
LV_EX_SetTileViewLines(HLV, Lines, tileX := "", tileY := "") {                                        	;-- sets the maximum number of additional text lines in each tile, not counting the title

	/*	DESCRIPTION OF FUNCTION: -- LV_EX_SetTileViewLines() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	sets the maximum number of additional text lines in each tile, not counting the title
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=28792
	Author         	:	kczx3
	Date             	:	03 Mar 2017
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	Lines - 	Maximum number of text lines in each item label, not counting the title
	                                    	One line is added internally because the item might be wrapped to two lines!;<04.01.000001>
	Return value	:
	Remark(s)    	:
	Dependencies	:	none
	KeyWords    	:	gui, listview
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	; LVM_GETTILEVIEWINFO = 0x10A3 -> http://msdn.microsoft.com/en-us/library/bb761083(v=vs.85).aspx
	; LVM_SETTILEVIEWINFO = 0x10A2 -> http://msdn.microsoft.com/en-us/library/bb761212(v=vs.85).aspx

	Static SizeLVTVI := 40
	Static offSize := 12
	Static OffLines := 20
	Static LVTVIM_TILESIZE := 0x1
	Static LVTVIM_COLUMNS := 0x2
	Static LVTVIF_AUTOSIZE := 0x0, LVTVIF_FIXEDWIDTH := 0x1, LVTVIF_FIXEDHEIGHT := 0x2, LVTVIF_FIXEDSIZE := 0x3
	Mask := LVTVIM_COLUMNS | (tileX || tileY ? LVTVIM_TILESIZE : 0)
	If (tileX && tileY)
		flag := LVTVIF_FIXEDSIZE
	Else If (tileX && !tileY)
		flag := LVTVIF_FIXEDWIDTH
	Else If (!tileX && tileY)
		flag := LVTVIF_FIXEDHEIGHT
	Else
		flag := LVTVIF_AUTOSIZE
	; If (Lines > 0)
	; Lines++
	VarSetCapacity(LVTVI, SizeLVTVI, 0)     ; LVTILEVIEWINFO
	NumPut(SizeLVTVI, LVTVI, 0, "UInt")     ; cbSize
	NumPut(Mask, LVTVI, 4, "UInt")    ; dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS
	NumPut(flag, LVTVI, 8, "UInt")       ; dwMask
	if (tileX)
		NumPut(tileX, LVTVI, 12, "Int")       ; sizeTile.cx
	if (tileY)
		NumPut(tileY, LVTVI, 16, "Int")       ; sizeTile.cx
	NumPut(Lines, LVTVI, OffLines, "Int") ; c_lines: max lines below first line
	SendMessage, 0x10A2, 0, % &LVTVI, , % "ahk_id " . HLV ; LVM_SETTILEVIEWINFO
	Return ErrorLevel
} ;</04.01.000001>

}

{ ;<06.03.06>: TabControl		(2)
 ;<06.03.06.000001>
TabCtrl_GetCurSel(HWND) { 																						;-- Indexnumber of active tab in a gui
; a function by: "just me" found on https://autohotkey.com/board/topic/79783-how-to-get-the-current-tab-name/
; Returns the 1-based index of the currently selected tab
Static TCM_GETCURSEL := 0x130B
SendMessage, TCM_GETCURSEL, 0, 0, , ahk_id %HWND%
Return (ErrorLevel + 1)
} ;</06.03.06.000001>
;<06.03.06.000002>
TabCtrl_GetItemText(HWND, Index = 0) {																	;-- returns text of a tab
; a function by: "just me" found on https://autohotkey.com/board/topic/79783-how-to-get-the-current-tab-name/

Static TCM_GETITEM  := A_IsUnicode ? 0x133C : 0x1305 ; TCM_GETITEMW : TCM_GETITEMA
Static TCIF_TEXT := 0x0001
Static TCTXTP := (3 * 4) + (A_PtrSize - 4)
Static TCTXLP := TCTXTP + A_PtrSize
ErrorLevel := 0
If (Index = 0)
Index := TabCtrl_GetCurSel(HWND)
If (Index = 0)
Return SetError(1, "")
VarSetCapacity(TCTEXT, 256 * SizeT, 0)
; typedef struct {
;   UINT   mask;           4
;   DWORD  dwState;        4
;   DWORD  dwStateMask;    4 + 4 bytes padding on 64-bit systems
;   LPTSTR pszText;        4 / 8 (32-bit / 64-bit)
;   int    cchTextMax;     4
;   int    iImage;         4
;   LPARAM lParam;         4 / 8
; } TCITEM, *LPTCITEM;
VarSetCapacity(TCITEM, (5 * 4) + (2 * A_PtrSize) + (A_PtrSize - 4), 0)
NumPut(TCIF_TEXT, TCITEM, 0, "UInt")
NumPut(&TCTEXT, TCITEM, TCTXTP, "Ptr")
NumPut(256, TCITEM, TCTXLP, "Int")
SendMessage, TCM_GETITEM, --Index, &TCITEM, , ahk_id %HWND%
If !(ErrorLevel)
Return SetError(1, "")
Else
Return SetError(0, StrGet(NumGet(TCITEM, TCTXTP, "UPtr")))
}
SetError(ErrorValue, ReturnValue) {																				;-- sub of TabCtrl functions

;; a function by: "just me" found on https://autohotkey.com/board/topic/79783-how-to-get-the-current-tab-name/
ErrorLevel := ErrorValue
Return ReturnValue
} ;</06.03.06.000002>
}

{ ;<06.03.07>: Treeview 			(3)
;<06.03.07.000001>
TV_Find(VarText) {																										;-- returns the ID of an item based on the text of the item

Loop {
ItemID := TV_GetNext(ItemID, "Full")
if not ItemID
	break
TV_GetText(ItemText, ItemID)
If (ItemText=VarText)
	Return ItemID
}

Return
} ;</06.03.07.000001>
;<06.03.07.000002>
TV_Load(src, p:=0, recurse:=false) {											     								;-- loads TreeView items from an XML string

/*	Description

a function by Coco found at https://autohotkey.com/boards/viewtopic.php?t=91

This function loads TreeView items from an XML string. By using XPath expressions, the user can instruct the function on how to process/parse
the XML source and on how the items are to be added.

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

A. The XML structure

This function is versatile enough to accept any user-defined XML string. Parsing instructions are defined as XPath expressions assigned as values
to the root element's attribute(s). The following attribute names should be used(strictly applies to the root element only):

name - 		specify an XPath expression, query must resolve to either of the following nodeTypes: element, attribute, text, cdatasection, comment.
			The selection is applied to the element node that is defined as a TreeView item. If not defined, the element node's tagName property
			is used as the TreeView's item's name.

options - 	same as above

global - 	An XPath expression. This attribute defines global TreeView item options to be applied to all TreeView items that are to be added.
			Selection is applied to the root node.

exclude - An XPath expression. Specifies which nodes(element) are not to be added as TreeView items. Selection is applied to the root node.

match - An XPath expression. Specifies which element nodes are to be added as TreeView items. By default all element nodes(except the root
		node) are added as items to the TreeView. Selection is applied to the root node.

Note: Only element nodes are added as TreeView items.

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

B. Function parameters

src - an XML string
p - parentItem's ID. Defaults to '0' - top item of the TreeView

*/

/* Example

#Include TV_Load.ahk ;or Copy-Paste fucntion in script

tv1 := "
(Join
<TREEVIEW name='@n' options='@o' match='//i' global='bold'>
 <i n='AutoHotkey' o='expand'>
  <i n='Hello World'/>
 </i>
 <i n='TreeView Item'/>
 <i n='Another Item' o='-bold expand'>
  <excluded>
   <i n='The quick brown fox'/>
  </excluded>
  <i n='Child Item'>
   <i n='Descendant'/>
  </i>
  <i n='Sibling Item' o='-bold'/>
 </i>
</TREEVIEW>
)"

tv2 := "
(Join
<TREEVIEW name='name/text()' options='options/text()' match='//i' global='expand'>
 <i>
  <name><![CDATA[AutoHotkey]]></name>
  <options>bold</options>
  <i>
   <name><![CDATA[Child Item]]></name>
   <options/>
  </i>
 </i>
 <i>
  <name><![CDATA[<XML STRING/>]]></name>
  <options/>
 </i>
 <i>
  <name><![CDATA[Sibling Item]]></name>
  <options>check</options>
  <i>
   <name><![CDATA[Hello World]]></name>
   <options/>
   <i>
	<name><![CDATA[Descendant]]></name>
	<options>check</options>
   </i>
  </i>
 </i>
 <i>
  <name><![CDATA[Items automatcially expanded]]></name>
  <options/>
 </i>
</TREEVIEW>
)"

Gui, Margin, 0, 0
Gui, Font, s9, Consolas
Gui, Add, TreeView, w250 r15
TV_Load(tv1)
Gui, Add, TreeView, x+5 yp w250 r15 Checked
TV_Load(tv2)
Gui, Show
return
GuiClose:
ExitApp

*/

;recurse is an internal parameter
static xpr , root
static TVL_NAME , TVL_OPTIONS , TVL_GLOBAL , TVL_EXCLUDE , TVL_MATCH

if !xpr
xpr := {TVL_NAME:"@*[translate(name(), 'NAME', 'name')='name']"
	,   TVL_OPTIONS:"@*[translate(name(), 'OPTIONS', 'options')='options']"
	,   TVL_GLOBAL:"@*[translate(name(), 'GLOBAL', 'global')='global']"
	,   TVL_EXCLUDE:"@*[translate(name(), 'EXCLUDE', 'exclude')='exclude']"
	,   TVL_MATCH:"@*[translate(name(), 'MATCH', 'match')='match']"}

if !IsObject(src)
x := ComObjCreate("MSXML2.DOMDocument.6.0")
, x.setProperty("SelectionLanguage", "XPath") ;redundant
, x.async := false , x.loadXML(src)
, src := x.documentElement

if !recurse {
root := src.selectSingleNode("/*") ;src.ownerDocument.documentElement

for var, xp in xpr
	if (var ~= "^TVL_(NAME|OPTIONS|GLOBAL)$")
		%var% := (_:=root.selectSingleNode(xp))
			  ? _.value
			  : (var="TVL_NAME" ? "." : "")

	else if (var ~= "^TVL_(EXCLUDE|MATCH)$")
		%var% := (_:=root.selectSingleNode(xp))
			  ? (_.value<>"" ? root.selectNodes(_.value) : "")
			  : ""
}

for e in src.childNodes {
if (e.nodeTypeString <> "element")
	continue
if (TVL_EXCLUDE && TVL_EXCLUDE.matches(e))
	continue
if (TVL_MATCH && !TVL_MATCH.matches(e))
	continue

for k, v in {name:TVL_NAME, options:TVL_OPTIONS}
	%k% := (n:=e.selectSingleNode(v))[(n.nodeType>1 ? "nodeValue" : "nodeName")]

if (TVL_GLOBAL <> "") {
	go := TVL_GLOBAL
	Loop, Parse, options, % " `t", % " `t"
	{
		if ((alf:=A_LoopField) == "")
			continue
		if InStr(go, m:=RegExReplace(alf, "i)[^a-z]+", ""))
			go := RegExReplace(go, "i)\S*" m "\S*", alf)
		else (go .=  " " . alf)
	}

} else go := options

id := TV_Add(name, p, go)
if e.hasChildNodes()
	TV_Load(e, id, true)
}
;Empty/reset static vars
if !recurse
root := ""
, TVL_NAME := ""
, TVL_OPTIONS := ""
, TVL_GLOBAL := ""
, TVL_EXCLUDE := ""
, TVL_MATCH := ""

} ;</06.03.07.000002>
;<06.03.07.000003>
TV_GetItemText(pItem) {                                                                                            	;-- retrieves the text/name of the specified treeview node +

/*    	DESCRIPTION

	Link: 			https://autohotkey.com/boards/viewtopic.php?t=4998
	Author: 		just me
	Method: 		GetText
						Retrieves the text/name of the specified node
	Parameters: pItem         - Handle to the item
	Returns: 		The text/name of the specified Item. If the text is longer than 127, only the first 127 characters are retrieved.

*/

TVM_GETITEM := A_IsUnicode ? TVM_GETITEMW : TVM_GETITEMA

WinGet ProcessId, pid, % "ahk_id " this.TVHnd
hProcess := OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ
					   |PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION
					   , false, ProcessId)

; Size := 28 + 3 * A_PtrSize      ; Size of a TVITEM structure
Size := 40 + 5 * A_PtrSize      ; Size of a TVITEMEX structure

_tvi := VirtualAllocEx(hProcess, 0, Size, MEM_COMMIT, PAGE_READWRITE)
_txt := VirtualAllocEx(hProcess, 0, 256,  MEM_COMMIT, PAGE_READWRITE)

; TVITEMEX Structure
VarSetCapacity(tvi, Size, 0)
NumPut(TVIF_TEXT|TVIF_HANDLE, tvi, 0, "UInt")
; NumPut(pItem, tvi, 4, "Ptr")
NumPut(pItem, tvi, A_PtrSize, "Ptr")
; NumPut(_txt, tvi, 12 + A_PtrSize, "Ptr")
NumPut(_txt, tvi, 8 + (A_PtrSize * 2), "Ptr")
; NumPut(127, tvi, 12 + 2 * A_PtrSize, "Uint")
NumPut(127, tvi, 8 + (A_PtrSize * 3), "Uint")

VarSetCapacity(txt, 256, 0)
WriteProcessMemory(hProcess, _tvi, &tvi, Size)
SendMessage TVM_GETITEM, 0, _tvi, ,  % "ahk_id " this.TVHnd
ReadProcessMemory(hProcess, _txt, txt, 256)

VirtualFreeEx(hProcess, _txt, 0, MEM_RELEASE)
VirtualFreeEx(hProcess, _tvi, 0, MEM_RELEASE)
CloseHandle(hProcess)

return txt
} ;</06.03.07.000003>

}

{ ;<06.03.08>: GDIControl		(2)
;<06.03.08.000001>
ControlCreateGradient(Handle, Colors*) {																	;-- draws a gradient as background picture
	GuiControlGet, C, Pos, %Handle%
	ColorCnt := Colors.Length()
	Size := ColorCnt * 2 * 4
	VarSetCapacity(Bits, Size, 0)
	Addr := &Bits
	For Each, Color In Colors
	Addr := Numput(Color, NumPut(Color, Addr + 0, "UInt"), "UInt")
	HBMP := DllCall("CreateBitmap", "Int", 2, "Int", ColorCnt, "UInt", 1, "UInt", 32, "Ptr", 0, "Ptr")
	HBMP := DllCall("CopyImage", "Ptr", HBMP, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x2008, "Ptr")
	DllCall("SetBitmapBits", "Ptr", HBMP, "UInt", Size, "Ptr", &Bits)
	HBMP := DllCall("CopyImage", "Ptr", HBMP, "UInt", 0, "Int", CW, "Int", CH, "UInt", 0x2008, "Ptr")
	DllCall("SendMessage", "Ptr", Handle, "UInt", 0x0172, "Ptr", 0, "Ptr", HBMP, "Ptr")
Return True
} ;</06.03.08.000001>
;<06.03.08.000002>
AddGraphicButtonPlus(ImgPath, Options="", Text="") {											;-- GDI+ add a graphic button to a gui

	hGdiPlus := DllCall("LoadLibrary", "Str", "gdiplus.dll")
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "UIntP", pToken, "UInt", &si, "UInt", 0)
	VarSetCapacity(wFile, StrLen(ImgPath)*2+2)
	DllCall("kernel32\MultiByteToWideChar", "UInt", 0, "UInt", 0, "Str", ImgPath, "Int", -1, "UInt", &wFile, "Int", VarSetCapacity(wFile)//2)
	DllCall("gdiplus\GdipCreateBitmapFromFile", "UInt", &wFile, "UIntP", pBitmap)
	if (pBitmap) {
	DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "UInt", pBitmap, "UIntP", hBM, "UInt", 0)
	DllCall("gdiplus\GdipDisposeImage", "Uint", pBitmap)
	}
	DllCall("gdiplus\GdiplusShutdown" , "UInt", pToken)
	DllCall("FreeLibrary", "UInt", hGdiPlus)

	if Text =
	{
	VarSetCapacity(oBM, 24)
	DllCall("GetObject","uint",hBM,"int",24,"uint",&oBM)
	Options := "W" NumGet(oBM,4,"int") " H" NumGet(oBM,8,"int") " +128 " Options
	}

	Gui, Add, Button, %Options% hwndhwnd, %Text%

	SendMessage, 0xF7, 0, hBM,, ahk_id %hwnd%  ; BM_SETIMAGE
	if ErrorLevel ; delete previous image
	DllCall("DeleteObject", "uint", ErrorLevel)

return hBM
} ;</06.03.08.000002>

}

{ ;<06.03.09>: Scrollbars			(1)
;<06.03.09.000001>
UpdateScrollBars(GuiNum, GuiWidth, GuiHeight) {                                                 	;-- immediate update of the window content when using a scrollbar

	/*	DESCRIPTION OF FUNCTION: -- UpdateScrollBars --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	immediate update of the window content when using a scrollbar
	Link              	:	https://autohotkey.com/board/topic/95488-help-with-gui-window-scrollingresizing/
	Author         	:	Lexikos
	Date             	:	July 13, 2013
	AHK-Version	:	AHK_L
	Remark(s)    	:	there are libraries can do the same like Scroller.ahk
	Dependencies	:	OnScroll
	KeyWords    	:	gui,scrollbar,OnMessage
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	#NoEnv

	OnMessage(0x115, "OnScroll") ; WM_VSCROLL
	OnMessage(0x114, "OnScroll") ; WM_HSCROLL

	Gui, +Resize +MaxSize420x675 +0x300000 ; WS_VSCROLL | WS_HSCROLL

	Loop 8
	Gui, Add, Edit, R5 W400, Edit %A_Index%
	Gui, Add, Button,, Do absolutely nothing
	Gui, Show, W200 H200

	Gui, +LastFound
	GroupAdd, MyGui, % "ahk_id " . WinExist()
	return

	GuiSize:
	UpdateScrollBars(A_Gui, A_GuiWidth, A_GuiHeight)
	return

	GuiClose:
	ExitApp

	#IfWinActive ahk_group MyGui
	WheelUp::
	WheelDown::
	+WheelUp::
	+WheelDown::
		; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
		OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, WinExist())
	return
	#IfWinActive

	*/

	static SIF_RANGE=0x1, SIF_PAGE=0x2, SIF_DISABLENOSCROLL=0x8, SB_HORZ=0, SB_VERT=1

	Gui, %GuiNum%:Default
	Gui, +LastFound

	; Calculate scrolling area.
	Left := Top := 9999
	Right := Bottom := 0
	WinGet, ControlList, ControlList
	Loop, Parse, ControlList, `n
	{
	GuiControlGet, c, Pos, %A_LoopField%
	if (cX < Left)
		Left := cX
	if (cY < Top)
		Top := cY
	if (cX + cW > Right)
		Right := cX + cW
	if (cY + cH > Bottom)
		Bottom := cY + cH
	}
	Left -= 8
	Top -= 8
	Right += 8
	Bottom += 8
	ScrollWidth := Right-Left
	ScrollHeight := Bottom-Top

	; Initialize SCROLLINFO.
	VarSetCapacity(si, 28, 0)
	NumPut(28, si) ; cbSize
	NumPut(SIF_RANGE | SIF_PAGE, si, 4) ; fMask

	; Update horizontal scroll bar.
	NumPut(ScrollWidth, si, 12) ; nMax
	NumPut(GuiWidth, si, 16) ; nPage
	DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_HORZ, "uint", &si, "int", 1)

	; Update vertical scroll bar.
	;     NumPut(SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, si, 4) ; fMask
	NumPut(ScrollHeight, si, 12) ; nMax
	NumPut(GuiHeight, si, 16) ; nPage
	DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_VERT, "uint", &si, "int", 1)

	if (Left < 0 && Right < GuiWidth)
	x := Abs(Left) > GuiWidth-Right ? GuiWidth-Right : Abs(Left)
	if (Top < 0 && Bottom < GuiHeight)
	y := Abs(Top) > GuiHeight-Bottom ? GuiHeight-Bottom : Abs(Top)
	if (x || y)
	DllCall("ScrollWindow", "uint", WinExist(), "int", x, "int", y, "uint", 0, "uint", 0)
	OnScroll(wParam, lParam, msg, hwnd) {
	static SIF_ALL=0x17, SCROLL_STEP=10

	bar := msg=0x115 ; SB_HORZ=0, SB_VERT=1

	VarSetCapacity(si, 28, 0)
	NumPut(28, si) ; cbSize
	NumPut(SIF_ALL, si, 4) ; fMask
	if !DllCall("GetScrollInfo", "uint", hwnd, "int", bar, "uint", &si)
	return

	VarSetCapacity(rect, 16)
	DllCall("GetClientRect", "uint", hwnd, "uint", &rect)

	new_pos := NumGet(si, 20) ; nPos

	action := wParam & 0xFFFF
	if action = 0 ; SB_LINEUP
	new_pos -= SCROLL_STEP
	else if action = 1 ; SB_LINEDOWN
	new_pos += SCROLL_STEP
	else if action = 2 ; SB_PAGEUP
	new_pos -= NumGet(rect, 12, "int") - SCROLL_STEP
	else if action = 3 ; SB_PAGEDOWN
	new_pos += NumGet(rect, 12, "int") - SCROLL_STEP
	else if (action = 5 || action = 4) ; SB_THUMBTRACK || SB_THUMBPOSITION
	new_pos := wParam>>16
	else if action = 6 ; SB_TOP
	new_pos := NumGet(si, 8, "int") ; nMin
	else if action = 7 ; SB_BOTTOM
	new_pos := NumGet(si, 12, "int") ; nMax
	else
	return

	min := NumGet(si, 8, "int") ; nMin
	max := NumGet(si, 12, "int") - NumGet(si, 16) ; nMax-nPage
	new_pos := new_pos > max ? max : new_pos
	new_pos := new_pos < min ? min : new_pos

	old_pos := NumGet(si, 20, "int") ; nPos

	x := y := 0
	if bar = 0 ; SB_HORZ
	x := old_pos-new_pos
	else
	y := old_pos-new_pos
	; Scroll contents of window and invalidate uncovered area.
	DllCall("ScrollWindow", "uint", hwnd, "int", x, "int", y, "uint", 0, "uint", 0)

	; Update scroll bar.
	NumPut(new_pos, si, 20, "int") ; nPos
	DllCall("SetScrollInfo", "uint", hwnd, "int", bar, "uint", &si, "int", 1)
} ;</06.03.08.000001>

}
}

{ ;<06.03.10>: MonthCal      	(2)

}
}
;|                                                                                      COMBOBOX CONTROL functions                                                                                	|
;|   GetComboBoxChoice(01)        	|   LB_GetItemHeight(02)              	|   LB_SetItemHeight(03)               	|
;|                                                                                           EDIT CONTROL functions                                                                                       	|
;|   Edit_Standard_Params(01)      	|  Edit_TextIsSelected(02)              	|   Edit_GetSelection(03)               	|   Edit_Select(04)                          	|
;|   Edit_SelectLine(05)                  	|  Edit_DeleteLine(06)                   	|
;|                                                                                                GDI control functions                                                                                         	|
;|   ControlCreateGradient(01)      	|   AddGraphicButtonPlus(02)       	|
;|                                                                                                IMAGELIST functions                                                                                          	|
;|   IL_LoadIcon(01)                       	|   IL_GuiButtonIcon(02)                	|
;|                                                                                                  LISTBOX functions                                                                                            	|
;|   LB_AdjustItemHeight(01)         	|
;|                                                                                                 LISTVIEW functions                                                                                           	|
;|   LV_GetCount(01)                     	|   LV_SetSelColors(02)                 	|   LV_Select(03)                            	|   LV_GetItemText(04)                  	|
;|   LV_GetText(05)                        	|   LV_SetBackgroundUrl(06)        	|   LV_MoveRow(07)                     	|   LV_MoveRow(08)                     	|
;|   LV_Find(09)                             	|   LV_GetSelectedText(10)            	|   LV_Notification(11)                  	|   LV_IsChecked(12)                     	|
;|   LV_HeaderFontSet(13)             	|   LV_SetCheckState(14)              	|   LV_SetItemState(15)                 	|   LV_SubitemHitTest(16)             	|
;|   LV_EX_FindString(17)              	|   LV_RemoveSelBorder(18)         	|   LV_SetExplorerTheme(19)         	|   LV_Update(20)                         	|
;|   LV_RedrawItem(21)                 	|   LV_SetExStyle(22)                     	|   LV_GetExStyle(23)                    	|   LV_IsItemVisible(24)                 	|
;|   LV_SetIconSpacing(25)            	|   LV_GetIconSpacing(26)            	|   LV_GetItemPos(27)                   	|   LV_SetItemPos(28)                   	|
;|   LV_MouseGetCellPos(29)         	|   LV_GetColOrderLocal(30)         	|   LV_GetColOrder(31)                 	|   LV_SetColOrderLocal(32)         	|
;|   LV_GetCheckedItems(34)         	|   LV_ClickRow(35)                      	|   LV_HeaderFontSet(36)              	|   LV_SetSI(37)                             	|
;|   LVM_CalculateSize(38)            	|   LV_RemoveSelBorder(39)         	|   LVM_GetItemText(40)               	|   LV_EX_SetTileViewLines(41)      	|
;|                                                                                            TABCONTROL functions                                                                                        	|
;|   TabCtrl_GetCurSel(01)             	|   TabCtrl_GetItemText(02)          	|
;|                                                                                               TREEVIEW functions                                    	|	                                                	|
;|   TV_Find(01)	                            	|   TV_Load(02)	                            	|   TV_GetItemText(03)                 	|
;|                                                      |                                      SCROLLBAR functions                                   	|	                                                	|
;|   UpdateScrollBars(01)               	|


{ ;gui - get informations (82) -- get informations from windows and screens --                                          	baseID: <06.04>

{ ;<06.04.01> screen get 						(02)
screenDims() {                                                                                                          	;-- returns informations of active screen (size, DPI and orientation)

	W := A_ScreenWidth
	H := A_ScreenHeight
	DPI := A_ScreenDPI
	Orient := (W>H)?"L":"P"
	;MsgBox % "W: "W "`nH: "H "`nDPI: "DPI
	return {W:W, H:H, DPI:DPI, OR:Orient}

}

DPIFactor() {                                                                                                            	;-- determines the Windows setting to the current DPI factor

	RegRead, DPI_value, HKEY_CURRENT_USER, Control Panel\Desktop\WindowMetrics, AppliedDPI
	; the reg key was not found - it means default settings
	; 96 is the default font size setting
	if (errorlevel=1) OR (DPI_value=96 )
		return 1
	else
		Return  DPI_Value/96

}

}

{ ;<06.04.02> control get 					(30)
;<06.04.02.00001>
ControlExists(class) {                                                                                                	;-- true/false for ControlClass
  WinGet, WinList, List  ;gets a list of all windows
  Loop, % WinList
  {
    temp := "ahk_id " WinList%A_Index%
    ControlGet, temp, Hwnd,, %class%, %temp%
    if !ErrorLevel  ;errorlevel is set to 1 if control doesn't exist
      return temp
  }
  return 0
} ;</06.04.02.00001>
;<06.04.02.00002>
GetFocusedControl()  {                                                                                            	;-- retrieves the ahk_id (HWND) of the active window's focused control.

        ; This script requires Windows 98+ or NT 4.0 SP3+.
        /*
        typedef struct tagGUITHREADINFO {
        DWORD cbSize;
        DWORD flags;
        HWND  hwndActive;
        HWND  hwndFocus;
        HWND  hwndCapture;
        HWND  hwndMenuOwner;
        HWND  hwndMoveSize;
        HWND  hwndCaret;
        RECT  rcCaret;
        } GUITHREADINFO, *PGUITHREADINFO;
        */

    guiThreadInfoSize := 8 + 6 * A_PtrSize + 16
   VarSetCapacity(guiThreadInfo, guiThreadInfoSize, 0)
   NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
   ; DllCall("RtlFillMemory" , "PTR", &guiThreadInfo, "UInt", 1 , "UChar", guiThreadInfoSize)   ; Below 0xFF, one call only is needed
   if (DllCall("GetGUIThreadInfo" , "UInt", 0   ; Foreground thread
         , "PTR", &guiThreadInfo) = 0)
   {
      ErrorLevel := A_LastError   ; Failure
      Return 0
   }
   focusedHwnd := NumGet(guiThreadInfo,8+A_PtrSize, "Ptr") ; *(addr + 12) + (*(addr + 13) << 8) +  (*(addr + 14) << 16) + (*(addr + 15) << 24)

	Return focusedHwnd
} ;</06.04.02.00002>
;<06.04.02.00003>
GetControls(hwnd, controls="") {                                                                            	;-- returns an array with ClassNN, Hwnd and text of all controls of a window

	if !isobject(controls)
		controls:=[]

	if isobject(hwnd){
		for k,v in hwnd
			controls:=GetControls(v, controls)
		return controls
	}

	winget,classnn,ControlList,ahk_id %hwnd%
	winget,controlId,controllisthwnd,ahk_id %hwnd%
	loop,parse,classnn,`n
	{
		controls[a_index]:=[]
		controls[a_index]["ClassNN"]:=a_loopfield
	}

	loop,parse,controlId,`n
	{
		controls[a_index]["Hwnd"]:=a_loopfield
		controlgetText,txt,,ahk_id %a_loopfield%
		controls[a_index]["text"]:=txt
	}
	return controls

} ;</06.04.02.00003>
;<06.04.02.00004>
GetOtherControl(refHwnd,shift,controls,type="hwnd") {                                        	;--
	for k,v in controls
		if v[type]=refHwnd
			return controls[k+shift].hwnd
} ;</06.04.02.00004>
;<06.04.02.00005>
ListControls(hwnd, obj=0, arr="") {                                                                         	;-- similar function to GetControls but returns a comma seperated list

	if !isobject(arr)
		arr:=[]

	if isobject(hwnd){
		for k,v in hwnd
			arr:=ListControls(v, 1, arr)
		goto ListControlsReturn
	}

	str=
	arr:=GetControls(hwnd)
ListControlsReturn:
	if obj
		return arr

	for k,v in arr
		str.="""" v["Hwnd"] """,""" v["ClassNN"] """,""" v["text"] """`n"
	return str

} ;</06.04.02.00005>
;<06.04.02.00006>
Control_GetClassNN( hWnd, hCtrl ) {  																		;-- no-loop

	; SKAN: www.autohotkey.com/forum/viewtopic.php?t=49471
	 WinGet, CH, ControlListHwnd, ahk_id %hWnd%
	 WinGet, CN, ControlList, ahk_id %hWnd%
	 LF:= "`n",  CH:= LF CH LF, CN:= LF CN LF,  S:= SubStr( CH, 1, InStr( CH, LF hCtrl LF ) )
	 StringReplace, S, S,`n,`n, UseErrorLevel
	 StringGetPos, P, CN, `n, L%ErrorLevel%
	 Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )

} ;</06.04.02.00006>
;<06.04.02.00007>
ControlGetClassNN(hWndWindow,hWndControl) {													;-- with loop

	; https://autohotkey.com/board/topic/45627-function-control-getclassnn-get-a-control-classnn/
	DetectHiddenWindows, On
	WinGet, ClassNNList, ControlList, ahk_id %hWndWindow%
	Loop, PARSE, ClassNNList, `n
	{
		ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hWndWindow%
		if (hWnd = hWndControl)
			return A_LoopField
	}

} ;</06.04.02.00007>
;<06.04.02.00008>
ControlGetClassNN( control="", Window="", Text="", ExWin="", ExText="" ) {	    	;-- different method is used here in compare to the already existing functions in this collection

	WinGet, cl, ControlList, % Window, % Text, % ExWin, % ExText
	WinGet, hl, ControlListHWND, % Window, % Text, % ExWin, % ExText
	ControlGet, ch, hwnd,, % control, % Window, % Text, % ExWin, % ExText
	If ErrorLevel
		return
	StringSplit, cl, cl, `n
	Loop, Parse, hl, `n
		If (A_LoopField = ch)
			return cl%A_Index%
	return 0
} ;</06.04.02.00008>
;<06.04.02.00009>
GetClassName( hwnd ) { 																						    	;-- returns HWND's class name without its instance number, e.g. "Edit" or "SysListView32"
		;https://autohotkey.com/board/topic/45515-remap-hjkl-to-act-like-left-up-down-right-arrow-keys/#entry283368
		VarSetCapacity( buff, 256, 0 )
		DllCall("GetClassName", "uint", hwnd, "str", buff, "int", 255 )
return buff
} ;</06.03.09.000001>
;<06.04.02.000010>
Control_GetFont(hWnd, ByRef Name, ByRef Size, ByRef Style, 									;-- get the currently used font of a control
IsGDIFontSize := 0) {

    SendMessage 0x31, 0, 0, , ahk_id %hWnd% ; WM_GETFONT
    If (ErrorLevel == "FAIL") {
        Return
    }

    hFont := Errorlevel
    VarSetCapacity(LOGFONT, LOGFONTSize := 60 * (A_IsUnicode ? 2 : 1 ))
    DllCall("GetObject", "UInt", hFont, "Int", LOGFONTSize, "UInt", &LOGFONT)

    Name := DllCall("MulDiv", "Int", &LOGFONT + 28, "Int", 1, "Int", 1, "Str")

    Style := Trim((Weight := NumGet(LOGFONT, 16, "Int")) == 700 ? "Bold" : (Weight == 400) ? "" : " w" . Weight
    . (NumGet(LOGFONT, 20, "UChar") ? " Italic" : "")
    . (NumGet(LOGFONT, 21, "UChar") ? " Underline" : "")
    . (NumGet(LOGFONT, 22, "UChar") ? " Strikeout" : ""))

    Size := IsGDIFontSize ? -NumGet(LOGFONT, 0, "Int") : Round((-NumGet(LOGFONT, 0, "Int") * 72) / A_ScreenDPI)
} ;</06.04.02.00011>
;<06.04.02.00011>
IsControlFocused(hwnd) {																							;-- true/false if a specific control is focused
    VarSetCapacity(GuiThreadInfo, 48) , NumPut(48, GuiThreadInfo, 0)
    Return DllCall("GetGUIThreadInfo", uint, 0, str, GuiThreadInfo) ? (hwnd = NumGet(GuiThreadInfo, 12)) ? True : False : False
} ;</06.04.02.00012>
;<06.04.02.00012>
getControlNameByHwnd(winHwnd,controlHwnd) {													;-- self explaining

	bufSize=1024
	winget,processID,pid,ahk_id %winHwnd%
	VarSetCapacity(var1,bufSize)
	getName:=DllCall( "RegisterWindowMessage", "str", "WM_GETCONTROLNAME" )
	dwResult:=DllCall("GetWindowThreadProcessId", "UInt", winHwnd)
	hProcess:=DllCall("OpenProcess", "UInt", 0x8 | 0x10 | 0x20, "Uint", 0, "UInt", processID)
	otherMem:=DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", bufSize, "UInt", 0x3000, "UInt", 0x0004, "Ptr")

	SendMessage,%getName%,%bufSize%,%otherMem%,,ahk_id %controlHwnd%
	DllCall("ReadProcessMemory","UInt",hProcess,"UInt",otherMem,"Str",var1,"UInt",bufSize,"UInt *",0)
	DllCall("CloseHandle","Ptr",hProcess)
	DllCall("VirtualFreeEx","Ptr", hProcess,"UInt",otherMem,"UInt", 0, "UInt", 0x8000)
	return var1

} ;</06.04.02.00013>
;<06.04.02.00013>
getByControlName(winHwnd,name) {																		;-- search by control name return hwnd

	winget,controlList,controlListhwnd,ahk_id %winHwnd%
    arr:=[]
    ,bufSize=1024
	winget,processID,pid,ahk_id %winHwnd%
	VarSetCapacity(var1,bufSize)
	if !(getName:=DllCall( "RegisterWindowMessage", "str", "WM_GETCONTROLNAME" ))
        return []
	if !(dwResult:=DllCall("GetWindowThreadProcessId", "UInt", winHwnd))
        return []
	if !(hProcess:=DllCall("OpenProcess", "UInt", 0x8 | 0x10 | 0x20, "Uint", 0, "UInt", processID))
        return []
    if !(otherMem:=DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", bufSize, "UInt", 0x3000, "UInt", 0x0004, "Ptr"))
        return []

	loop,parse,controlList,`n
	{
        SendMessage,%getName%,%bufSize%,%otherMem%,,ahk_id %a_loopfield%
        if errorlevel=FAIL
            return []
        if !DllCall("ReadProcessMemory","UInt",hProcess,"UInt",otherMem,"Str",var1,"UInt",bufSize,"UInt *",0)
            return []
        if (var1==name)
            arr.insert(a_loopfield)
            ,var1:=""
	}

    DllCall("VirtualFreeEx","Ptr", hProcess,"UInt",otherMem,"UInt", 0, "UInt", 0x8000)
	DllCall("CloseHandle","Ptr",hProcess)
    return arr

} ;</06.04.02.00013>
;<06.04.02.00014>
getNextControl(winHwnd, controlName="", accName="", classNN="", accHelp="") {	;-- I'm not sure if this feature works could be an AHK code for the Control.GetNextControl method for System.Windows.Forms

	winget, list, controllisthwnd, ahk_id %winHwnd%

	bufSize=1024
	winget, processID, pid, ahk_id %winHwnd%
	VarSetCapacity(var1,bufSize)
	getName:=DllCall( "RegisterWindowMessage", "str", "WM_GETCONTROLNAME" )
	dwResult:=DllCall("GetWindowThreadProcessId", "UInt", winHwnd)
	hProcess:=DllCall("OpenProcess", "UInt", 0x8 | 0x10 | 0x20, "Uint", 0, "UInt", processID)
	otherMem:=DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", bufSize, "UInt", 0x3000, "UInt", 0x0004, "Ptr")

	count=0
	;~ static hModule := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
	;~ static hModule2 := DllCall("LoadLibrary", "Str", "Kernel32", "Ptr")
	;~ static AccessibleObjectFromWindowProc := DllCall("GetProcAddress", Ptr, DllCall("GetModuleHandle", Str, "oleacc", "Ptr"), AStr, "AccessibleObjectFromWindow", "Ptr")
	;~ static ReadProcessMemoryProc:=DllCall("ReadProcessMemory", Ptr, DllCall("GetModuleHandle", Str, "Kernel32", "Ptr"), AStr, "AccessibleChildren", "Ptr")
	;~ msgbox % AccessibleObjectFromWindowProc
	;~ static idObject:=-4
	loop,parse,list,`n
	{
		SendMessage,%getName%,%bufSize%,%otherMem%,,ahk_id %a_loopfield%
        DllCall("ReadProcessMemory","UInt",hProcess,"UInt",otherMem,"Str",var1,"UInt",bufSize,"UInt *",0)

		;~ acc:=acc_objectfromwindow2(a_loopfield)

		;~ if !DllCall(AccessibleObjectFromWindowProc, "Ptr", a_loopfield, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)
			;~ acc:=ComObjEnwrap(9,pacc,1)
		;~ else
			;~ acc:=""


	;&&(accParentHwnd=""||acc_windowfromobject(acc.accParent)=accParentHwnd)
		if ((var1&&var1=controlName)&&(accName=""||(acc:=Acc_ObjectFromWindow(a_loopfield)).accName=accName)){
			WinGetClass,cl,ahk_id %a_loopfield%
			if (instr(cl,classNN)=1&&(accHelp=""||acc.accHelp=accHelp)) {
				ret:=a_loopfield
				break
			}
		}

		var1:=""
	}

    DllCall("VirtualFreeEx","Ptr", hProcess,"UInt",otherMem,"UInt", 0, "UInt", 0x8000)
	DllCall("CloseHandle","Ptr",hProcess)
	DllCall("FreeLibrary", "Ptr", hModule)
	return ret

} ;</06.04.02.00014>
;<06.04.02.00015>
IsControlUnderCursor(ControlClass) {																			;-- Checks if a specific control is under the cursor and returns its ClassNN if it is.
	MouseGetPos, , , , control
	if (InStr(Control, ControlClass))
		return control
	return false
} ;</06.04.02.00015>
;<06.04.02.00016>
GetFocusedControl(Option := "") {																				;-- get focused control from active window -multi Options[ClassNN \ Hwnd \ Text \ List \ All] available

	; https://autohotkey.com/boards/viewtopic.php?f=6&t=23987 from V for Vendetta
	;"Options": ClassNN \ Hwnd \ Text \ List \ All or Nothing

	GuiWindowHwnd := WinExist("A")		;stores the current Active Window Hwnd id number in "GuiWindowHwnd" variable
					;"A" for Active Window

	ControlGetFocus, FocusedControl, ahk_id %GuiWindowHwnd%	;stores the  classname "ClassNN" of the current focused control from the window above in "FocusedControl" variable
							;"ahk_id" searches windows by Hwnd Id number

	if Option = ClassNN
		return, FocusedControl

	ControlGet, FocusedControlId, Hwnd,, %FocusedControl%, ahk_id %GuiWindowHwnd%	;stores the Hwnd Id number of the focused control found above in "FocusedControlId" variable

	if Option = Hwnd
		return, FocusedControlId

	if (Option = "Text") or (Option = "All")
	ControlGetText, FocusedControlText, , ahk_id %FocusedControlId%		;stores the focused control texts in "FocusedControlText" variable
								;"ahk_id" searches control by Hwnd id number

	if Option = Text
		return, FocusedControlText

	if (Option = "List") or (Option = "All")
		ControlGet, FocusedControlList, List, , , ahk_id %FocusedControlId%	;"List", retrieves  all the text from a ListView, ListBox, or ComboBox controls

	if Option = List
		return, FocusedControlList

	return, FocusedControl " - " FocusedControlId "`n`n____Text____`n`n" FocusedControlText "`n`n____List____`n`n" FocusedControlList
} ;</06.04.02.00016>
;<06.04.02.00017>
ControlGetTextExt(hControl, hWinTitle)  {                                                       			;-- 3 different variants are tried to determine the text of a control

	/*                                                   	DESCRIPTION

				;Replaces the AHK function ControlGetText, which sometimes does not work.
				; cf.: http://de.autohotkey.com/forum/viewtopic.php?t=7366&postdays=0&postorder=asc&start=0
				;SYNTAX: VText := ControlGetTextExt("Static8", "StarMoney Business 4.0")
				;SYNTAX: Erg := ControlGetTextExt("#327701", "Date and Time")

	*/

	DetectHiddenText, on
   ; 1. Step. Normal ControlGetText with AHK:
   ControlGetText, ControlText, %hControl%, %hWinTitle%
   If (StrLen(Controltext)=0) {
      ; 2. Step. DllCall with "GetWindowText":
      ControlGet, ControlHWND, Hwnd,, %hControl%, %hWinTitle%
      ControlTextSize = 512
      VarSetCapacity(ControlText, ControlTextSize)
      Result := DllCall("GetWindowText", "uint", ControlHWND, "str", ControlText, "int", ControlTextSize)
      If (StrLen(Controltext)=0)
         ; 3. Step. SendMessage with WM_GETTEXT (0xD):
         SendMessage, 0xD, ControlTextSize, &ControlText, %hControl%, %hWinTitle%
   }
   Return ControlText
} ;</06.04.02.00017>
;<06.04.02.00018>
getControlInfo(type="button", text="", ret="w", fontsize="", fontmore="") {			;-- get width and heights of controls
	static test
	Gui, wasteGUI:New
	Gui, wasteGUI:Font, % fontsize, % fontmore
	Gui, wasteGUI:Add, % type, vtest, % text
	GuiControlGet, test, wasteGUI:pos
	Gui, wasteGUI:Destroy
	if ret=w
		return testw
	if ret=h
		return testh
} ;</06.04.02.00018>
;<06.04.02.00019>
FocusedControl() { 																								    	;-- returns the HWND of the currently focused control, or 0 if there was a problem
	;https://autohotkey.com/board/topic/45515-remap-hjkl-to-act-like-left-up-down-right-arrow-keys/#entry283368
	NumPut(VarSetCapacity( gti, 48, 0 ), gti, 0, "int")
	if DllCall("GetGUIThreadInfo", "uint", 0, "str", gti)
		return NumGet(gti, 12, "uint")
	return 0

} ;</06.04.02.00019>
;<06.04.02.00020>
Control_GetFont( hwnd ,ByRef Name,ByRef Style,ByRef Size) { 									;-- retrieves the used font of a control
; www.autohotkey.com/forum/viewtopic.php?p=465438#465438
; https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-11
; Mod by nothing
 SendMessage 0x31, 0, 0, , ahk_id %hwnd% ; WM_GETFONT
 IfEqual,ErrorLevel,FAIL, Return
 hFont := Errorlevel, VarSetCapacity( LF, szLF := 60*( A_IsUnicode ? 2:1 ) ), DllCall("GetObject", UInt,hFont, Int,szLF, UInt,&LF ) , hDC := DllCall( "GetDC", UInt,hwnd ), DPI := DllCall( "GetDeviceCaps", UInt,hDC, Int,90 ) , DllCall( "ReleaseDC", Int,0, UInt,hDC )
 Name := DllCall( "MulDiv",Int,&LF+28, Int,1,Int,1, Str )
 Style := Trim(((W:=NumGet(LF,16,"Int"))=700 ? " Bold" : W=400 ? "" : " w" W ) . (NumGet(LF,20,"UChar") ? " Italic" : "") . (NumGet(LF,21,"UChar") ? " Underline" : "") . (NumGet(LF,22,"UChar") ? " StrikeOut" : ""))
 Size := Round( ( -NumGet( LF,0,"Int" )*72 ) / DPI )
} ;</06.04.02.00020>
;<06.04.02.00021>
WinForms_GetClassNN(WinID, fromElement, ElementName) {                              	;-- Check which ClassNN an element has

	; function by Ixiko 2018 last_change 28.01.02.2018
	/* Funktionsinfo: Deutsch
		;Achtung: da manchmal 2 verschiedene Elemente den gleichen Namen enthalten können hat die Funktion einen zusätzlichen Parameter: "fromElement"
		;die Funktion untersucht ob das hier angebene Element im ClassNN enthalten ist zb. Button in WindowsForms10.BUTTON.app.0.378734a2
		;die Groß- und Kleinschreibung ist nicht zu beachten
	*/

	/* function info: english
		;Caution: sometimes 2 and more different elements in a gui can contain the same name, therefore the function has an additional parameter: "fromElement"
		;it examines whether the element specified here is contained in the ClassNN, eg. Button in WindowsForms10.BUTTON.app.0.378734a2
		;this function is: case-insensitive
	*/

	WinGet, CtrlList, ControlList, ahk_id %WinID%

	Loop, Parse, CtrlList, `n
	{
			classnn:= A_LoopField
			ControlGetText, Name, %classnn% , ahk_id %WinID%
			If Instr(Name, ElementName, false) and Instr(classnn, fromElement, false)
																				break
			;sleep, 2000
		}


return classNN
} ;</06.04.02.00021>
;<06.04.02.00022>
GetExtraStyle(hWnd) {                                                                                             	;-- get Extra Styles from a control

    WinGetClass Class, ahk_id %hWnd%

    If (Class == "SysListView32") {
        Message := 0x1037 ; LVM_GETEXTENDEDLISTVIEWSTYLE
    } Else If (Class == "SysTreeView32") {
        Message := 0x112D ; TVM_GETEXTENDEDSTYLE
    } Else If (Class == "SysTabControl32") {
        Message := 0x1335 ; TCM_GETEXTENDEDSTYLE
    } Else If (Class == "ToolbarWindow32") {
        Message := 0x455 ; TB_GETEXTENDEDSTYLE
    } Else If (Class == "ComboBox" && g_Style & 0x10) {
        Message := 0x409 ; CBEM_GETEXTENDEDSTYLE
    }

    SendMessage %Message%, 0, 0,, ahk_id %hWnd%
    Return Format("0x{:08X}", ErrorLevel)

} ;</06.04.02.00022>
;<06.04.02.00023>
GetToolbarItems(hToolbar) {                                                                                    	;-- retrieves the text/names of all items of a toolbar

    WinGet PID, PID, ahk_id %hToolbar%

    If !(hProc := DllCall("OpenProcess", "UInt", 0x438, "Int", False, "UInt", PID, "Ptr")) {
        Return
    }

    If (A_Is64bitOS) {
        Try DllCall("IsWow64Process", "Ptr", hProc, "int*", Is32bit := true)
    } Else {
        Is32bit := True
    }

    RPtrSize := Is32bit ? 4 : 8
    TBBUTTON_SIZE := 8 + (RPtrSize * 3)

    SendMessage 0x418, 0, 0,, ahk_id %hToolbar% ; TB_BUTTONCOUNT
    ButtonCount := ErrorLevel

    IDs := [] ; Command IDs
    Loop %ButtonCount% {
        Address := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "uPtr", TBBUTTON_SIZE, "UInt", 0x1000, "UInt", 4, "Ptr")

        SendMessage 0x417, % A_Index - 1, Address,, ahk_id %hToolbar% ; TB_GETBUTTON
        If (ErrorLevel == 1) {
            VarSetCapacity(TBBUTTON, TBBUTTON_SIZE, 0)
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", Address, "Ptr", &TBBUTTON, "uPtr", TBBUTTON_SIZE, "Ptr", 0)
            IDs.Push(NumGet(&TBBUTTON, 4, "Int"))
        }

        DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", Address, "UPtr", 0, "UInt", 0x8000) ; MEM_RELEASE
    }

    ToolbarItems := []
    Loop % IDs.Length() {
        ButtonID := IDs[A_Index]
        ;SendMessage 0x44B, %ButtonID% , 0,, ahk_id %hToolbar% ; TB_GETBUTTONTEXTW
        ;BufferSize := ErrorLevel * 2
        BufferSize := 128

        Address := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "uPtr", BufferSize, "UInt", 0x1000, "UInt", 4, "Ptr")

        SendMessage 0x44B, %ButtonID%, Address,, ahk_id %hToolbar% ; TB_GETBUTTONTEXTW

        VarSetCapacity(Buffer, BufferSize, 0)
        DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", Address, "Ptr", &Buffer, "uPtr", BufferSize, "Ptr", 0)

        ToolbarItems.Push({"ID": IDs[A_Index], "String": Buffer})

        DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", Address, "UPtr", 0, "UInt", 0x8000) ; MEM_RELEASE
    }

    DllCall("CloseHandle", "Ptr", hProc)

    Return ToolbarItems
} ;</06.04.02.00023>
;<06.04.02.00024>
ControlGetTabs(hTab) {                                                                                            	;-- retrieves the text of tabs in a tab control

    ; https://autohotkey.com/board/topic/70727-ahk-l-controlgettabs/
	; a Lexikos function

	; Parameters:
	; Control - the HWND, ClassNN or text of the control.
	;WinTitle - same as ControlGet, but unused if Control is a HWND.
	; WinText - as above.

	; Returns:
	; An array of strings on success.
	;An empty string on failure.

	; Requirements:
	; AutoHotkey v1.1.
	; A compatible tab control

    Static MAX_TEXT_LENGTH := 260
         , MAX_TEXT_SIZE := MAX_TEXT_LENGTH * (A_IsUnicode ? 2 : 1)

    WinGet PID, PID, ahk_id %hTab%

    ; Open the process for read/write and query info.
    ; PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION
    If !(hProc := DllCall("OpenProcess", "UInt", 0x438, "Int", False, "UInt", PID, "Ptr")) {
        Return
    }

    ; Should we use the 32-bit struct or the 64-bit struct?
    If (A_Is64bitOS) {
        Try DllCall("IsWow64Process", "Ptr", hProc, "int*", Is32bit := true)
    } Else {
        Is32bit := True
    }

    RPtrSize := Is32bit ? 4 : 8
    TCITEM_SIZE := 16 + RPtrSize * 3

    ; Allocate a buffer in the (presumably) remote process.
    remote_item := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0
                         , "uPtr", TCITEM_SIZE + MAX_TEXT_SIZE
                         , "UInt", 0x1000, "UInt", 4, "Ptr") ; MEM_COMMIT, PAGE_READWRITE
    remote_text := remote_item + TCITEM_SIZE

    ; Prepare the TCITEM structure locally.
    VarSetCapacity(TCITEM, TCITEM_SIZE, 0)
    NumPut(1, TCITEM, 0, "UInt") ; mask (TCIF_TEXT)
    NumPut(remote_text, TCITEM, 8 + RPtrSize) ; pszText
    NumPut(MAX_TEXT_LENGTH, TCITEM, 8 + RPtrSize * 2, "Int") ; cchTextMax

    ; Write the local structure into the remote buffer.
    DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &TCITEM, "uPtr", TCITEM_SIZE, "Ptr", 0)

    Tabs := []
    VarSetCapacity(TabText, MAX_TEXT_SIZE)

    SendMessage 0x1304, 0, 0,, ahk_id %hTab% ; TCM_GETITEMCOUNT
    Loop % (ErrorLevel != "FAIL") ? ErrorLevel : 0 {
        ; Retrieve the item text.
        SendMessage, % (A_IsUnicode) ? 0x133C : 0x1305, A_Index - 1, remote_item,, ahk_id %hTab% ; TCM_GETITEM
        If (ErrorLevel == 1) { ; Success
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_text, "Ptr", &TabText, "uPtr", MAX_TEXT_SIZE, "Ptr", 0)
        } Else {
            TabText := ""
        }

        Tabs[A_Index] := TabText
    }

    ; Release the remote memory and handle.
    DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", remote_item, "UPtr", 0, "UInt", 0x8000) ; MEM_RELEASE
    DllCall("CloseHandle", "Ptr", hProc)

    Return Tabs
} ;</06.04.02.00024>
;<06.04.02.00025>
GetHeaderInfo(hHeader) {                                                                                       	;-- Returns an object containing width and text for each item of a remote header control
    ; Returns an object containing width and text for each item of a remote header control
    Static MAX_TEXT_LENGTH := 260
         , MAX_TEXT_SIZE := MAX_TEXT_LENGTH * (A_IsUnicode ? 2 : 1)

    WinGet PID, PID, ahk_id %hHeader%

    ; Open the process for read/write and query info.
    ; PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION
    If !(hProc := DllCall("OpenProcess", "UInt", 0x438, "Int", False, "UInt", PID, "Ptr")) {
        Return
    }

    ; Should we use the 32-bit struct or the 64-bit struct?
    If (A_Is64bitOS) {
        Try DllCall("IsWow64Process", "Ptr", hProc, "int*", Is32bit := true)
    } Else {
        Is32bit := True
    }

    RPtrSize := Is32bit ? 4 : 8
    cbHDITEM := (4 * 6) + (RPtrSize * 6)

    ; Allocate a buffer in the (presumably) remote process.
    remote_item := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0
                         , "uPtr", cbHDITEM + MAX_TEXT_SIZE
                         , "UInt", 0x1000, "UInt", 4, "Ptr") ; MEM_COMMIT, PAGE_READWRITE
    remote_text := remote_item + cbHDITEM

    ; Prepare the HDITEM structure locally.
    VarSetCapacity(HDITEM, cbHDITEM, 0)
    NumPut(0x3, HDITEM, 0, "UInt") ; mask (HDI_WIDTH | HDI_TEXT)
    NumPut(remote_text, HDITEM, 8, "Ptr") ; pszText
    NumPut(MAX_TEXT_LENGTH, HDITEM, 8 + RPtrSize * 2, "Int") ; cchTextMax

    ; Write the local structure into the remote buffer.
    DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &HDITEM, "uPtr", cbHDITEM, "Ptr", 0)

    HDInfo := {}
    VarSetCapacity(HDText, MAX_TEXT_SIZE)

    SendMessage 0x1200, 0, 0,, ahk_id %hHeader% ; HDM_GETITEMCOUNT
    Loop % (ErrorLevel != "FAIL") ? ErrorLevel : 0 {
        ; Retrieve the item text.
        SendMessage, % (A_IsUnicode) ? 0x120B : 0x1203, A_Index - 1, remote_item,, ahk_id %hHeader% ; HDM_GETITEMW
        If (ErrorLevel == 1) { ; Success
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &HDITEM, "uPtr", MAX_TEXT_SIZE, "Ptr", 0)
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_text, "Ptr", &HDText, "uPtr", MAX_TEXT_SIZE, "Ptr", 0)
        } Else {
            TabText := ""
        }

        HDInfo.Push({"Width": NumGet(HDITEM, 4, "UInt"), "Text": HDText})
    }

    ; Release the remote memory and handle.
    DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", remote_item, "UPtr", 0, "UInt", 0x8000) ; MEM_RELEASE
    DllCall("CloseHandle", "Ptr", hProc)

    Return HDInfo
} ;</06.04.02.00025>
;<06.04.02.00026>
WinSaveCheckboxes(hWin) {                                                                                     	;-- save the status of checkboxes in other apps

	/*    	DESCRIPTION of function WinSaveCheckboxes() ID: 06.04.02.00026
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	save the status of checkboxes in other apps (this version matches only checkboxes in normal windows gui's)
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=59542
			Author         	:	Ixiko
			Date	            	:	01.12.2018
			AHK-Version	:	AHK_L V1*
			License         	:	none
			Parameter(s)	:	only the handle to the window
			Remark(s)    	:	returns an key-value object with key is ClassNN name of checkbox and value is 1 or 0 (for is checked or not)
			Dependencies	:	GetButtonType()  ID: 06.04.02.00027, KeyValueObjectFromLists()  ID: 12.01.00004, List2Array() ID: 13.01.05.00010
			KeyWords    	:	get info from Gui, Checkbox
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			#NoEnv
			SetBatchlines -1
			SetTitleMatchMode, 2
			DetectHiddenWindows, On
			DetectHiddenText, On

			CheckboxObj:= Object()

			^LButton::
				MouseGetPos,,, hWin
				WinGetTitle, WinTitle, % "ahk_id " hWin
				checkList:= "the retrieved status for the checkboxes in window:`n""" WinTitle """`n`n"
				CheckboxObj:= WinSaveCheckboxes(hWin)

				If !IsObject(CheckboxObj)
				{
							checkList.=  "This window doesnt contain any checkboxes!"
				}
					else
				{
							For key, val in CheckboxObj
							{
								status:= (val=1) ? "checked      ": "unchecked "
								cText:= SubStr(ControlGetText(key, "ahk_id " . hWin), 1, 20) . "`.`.`."
								RegExMatch(key, "\d+", digits)
								If (StrLen(digits)=1)
									 more:=3
								else
									more:=1
								checkList.= SubStr(key . "   ", 1, StrLen(key)+more) . " is " . status . " (" cText ")`n"
							}
				}
				MsgBox, % checkList
			return

			Esc::ExitApp
			return


	*/

	cArrT1:= cArrT2:= [], idx:=0
	oControls1:= Object()
	oControls2:= Object()

	WinGet, cClasses, ControlList, % "ahk_id " hWin
	WinGet, cHwnds, ControlListHwnd, % "ahk_id " hWin

	oControls1:= KeyValueObjectFromLists(cClasses, cHwnds, "`n", "Button", "[A-Za-z]+", "", "")

	For key, val in oControls1
	{
			If InStr(GetButtonType(val), "Checkbox") {
					status:= ControlGet("checked",,, "ahk_id " . val)
					oControls2[(key)]:= status
					idx++
			}
	}

	If !idx
		return 0

return oControls2
} ;</06.04.02.00026>
;<06.04.02.00027>
GetButtonType(hwndButton) {                                                                                 	;-- uses the style of a button to get it's name

	/*    	DESCRIPTION of function GetButtonType() ID: 06.04.02.00027
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	uses the style of a button to get it's name
			Link              	:	https://autohotkey.com/board/topic/101341-getting-type-of-control/
			Author         	:	Linear Spoon
			Date             	:	03.02.2014
			AHK-Version	:	AHK_L (tested)
			License         	:
			Parameter(s)	:	only a hwnd to a button
			Return value	:
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	button, gui, check, style, winget
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)

			;Gui with various controls for quick testing...
			;Borders are added for convenience to show control bounds
			Gui, Add, Picture, w200 h50 +Border, image.jpg
			Gui, Add, Text, w200 h50 +Border, This is a text control
			Gui, Add, Edit, w200 h50 +Border, This is an edit control
			Gui, Add, Checkbox, w200 h50 +Border, This is a checkbox control
			Gui, Add, Radio, w200 h50 +Border, This is a radio control
			Gui, Add, Button, w200 h50 +Border, This is a button control
			Gui, Add, Groupbox, w200 h50 +Border, This is a groupbox control
			Gui, Show

			SetTimer, UpdateTooltip, 75
			return

			GuiClose:
			  ExitApp
			return

			UpdateTooltip:
			  MouseGetPos, x, y,, controlHwnd, 2
			  if (controlHwnd = "")
			  {
				tooltip No control
				return
			  }
			  ;Get class name (could have done it with MouseGetPos directly, but that appends the control number..)
			  WinGetClass, controlClass, ahk_id %controlHwnd%
			  if (controlClass = "Button")
				tooltip % "Type: " GetButtonType(controlHwnd)
			  else
				tooltip % "Type: " controlClass
			return

	*/

  static types := [ "Button"        ;BS_PUSHBUTTON
                     	, "Button"        ;BS_DEFPUSHBUTTON
                     	, "Checkbox"      ;BS_CHECKBOX
                     	, "Checkbox"      ;BS_AUTOCHECKBOX
                     	, "Radio"         ;BS_RADIOBUTTON
                     	, "Checkbox"      ;BS_3STATE
                     	, "Checkbox"      ;BS_AUTO3STATE
                     	, "Groupbox"      ;BS_GROUPBOX
                     	, "NotUsed"       ;BS_USERBUTTON
                     	, "Radio"         ;BS_AUTORADIOBUTTON
                     	, "Button"        ;BS_PUSHBOX
                     	, "AppSpecific"   ;BS_OWNERDRAW
                     	, "SplitButton"   ;BS_SPLITBUTTON    (vista+)
                     	, "SplitButton"   ;BS_DEFSPLITBUTTON (vista+)
                     	, "CommandLink"   ;BS_COMMANDLINK    (vista+)
                     	, "CommandLink"]  ;BS_DEFCOMMANDLINK (vista+)

  WinGet, btnStyle, Style, ahk_id %hwndButton%
  return types[1+(btnStyle & 0xF)]
} ;</06.04.02.00027>
;<06.04.02.00028>
HWNDToClassNN(hwnd) {                                                                                      	;-- a different approach to get classNN from handle

	/*	DESCRIPTION OF FUNCTION: -- HWNDToClassNN --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	this one returns numbered classNN , it's only a different approach to retrieve such information
	AHK-Version	:	AHK_L
	KeyWords    	:	control,gui,controlget

	*/

	win := DllCall("GetParent", "PTR", hwnd, "PTR")
	WinGet ctrlList, ControlList, ahk_id %win%
	; Built an array indexing the control names by their hwnd
	Loop Parse, ctrlList, `n
	{
		ControlGet hwnd1, Hwnd, , %A_LoopField%, ahk_id %win%
		if(hwnd1=hwnd)
			return A_LoopField
	}
} ;</06.04.02.00028>
;<06.04.02.00029>
IsCheckboxStyle(style) {                                                                                           	;-- checks style(code) if it's a checkbox

	/*	DESCRIPTION OF FUNCTION: -- IsCheckboxStyle --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	checks style(code) if it's a checkbox
	Link              	:	ootsby <ootsby@gmail.com>
	Author         	:
	Date             	:
	AHK-Version	:
	License         	:	MIT License Copyright (c) 2017
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	static types := [ "Button"        	;BS_PUSHBUTTON
                  , "Button"                	;BS_DEFPUSHBUTTON
                  , "Checkbox"      		;BS_CHECKBOX
                  , "Checkbox"      		;BS_AUTOCHECKBOX
                  , "Radio"                 	;BS_RADIOBUTTON
                  , "Checkbox"      		;BS_3STATE
                  , "Checkbox"      		;BS_AUTO3STATE
                  , "Groupbox"      		;BS_GROUPBOX
                  , "NotUsed"       		;BS_USERBUTTON
                  , "Radio"                 	;BS_AUTORADIOBUTTON
                  , "Button"                	;BS_PUSHBOX
                  , "AppSpecific"   		;BS_OWNERDRAW
                  , "SplitButton"           	;BS_SPLITBUTTON    (vista+)
                  , "SplitButton"           	;BS_DEFSPLITBUTTON (vista+)
                  , "CommandLink"   	;BS_COMMANDLINK    (vista+)
                  , "CommandLink"]  	;BS_DEFCOMMANDLINK (vista+)

	If( types[1+(style & 0xF)] = "Checkbox" )
        Return True

	Return False
} ;</06.04.02.00029>
 ;<06.04.02.00030>
Control_GetFont(hwnd) {                                                                                         	;-- Given an handle to a GuiControl, Control_GetFont() will return the Fontname & Fontsize

	/*	DESCRIPTION OF FUNCTION: -- Control_GetFont --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Given an handle to a GuiControl, Control_GetFont() will return the Fontname & Fontsize
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-10
								www.autohotkey.com/forum/viewtopic.php?p=465438#465438 By SKAN
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	gui,controls,font
	-------------------------------------------------------------------------------------------------------------------
	<	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	 SendMessage 0x31, 0, 0, , ahk_id %hwnd% ; WM_GETFONT                 Created: 27-Apr-2011
	 IfEqual,ErrorLevel,FAIL, Return
	 hFont := Errorlevel, VarSetCapacity( LF, szLF := 60*( A_IsUnicode ? 2:1 ) )
	 DllCall("GetObject", UInt,hFont, Int,szLF, UInt,&LF )
	 hDC := DllCall( "GetDC", UInt,hwnd ), DPI := DllCall( "GetDeviceCaps", UInt,hDC, Int,90 )
	 DllCall( "ReleaseDC", Int,0, UInt,hDC ), S := Round( ( -NumGet( LF,0,"Int" )*72 ) / DPI )
Return DllCall( "MulDiv",Int,&LF+28, Int,1,Int,1, Str ), DllCall( "SetLastError", UInt,S )
} ;</06.04.02.00030>
}

{ ;<06.04.03> gui + window get/find 	(44)
;<06.04.03.00001>
IsOverTitleBar(x, y, hWnd) { 																						;-- WM_NCHITTEST wrapping: what's under a screen point?

	; This function is from http://www.autohotkey.com/forum/topic22178.html
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   if ErrorLevel in 2,3,8,9,20,21
      return true
   else
      return false
} ;</06.04.03.00001>
;<06.04.03.00002>
WinGetPosEx(hWindow,ByRef X="",ByRef Y="",ByRef Width="", 								;-- gets the position, size, and offset of a window
ByRef Height="", ByRef Offset_X="",ByRef Offset_Y="")  {

	/*								Function: WinGetPosEx
	;
	; Description:
	;
	;   Gets the position, size, and offset of a window. See the *Remarks* section
	;   for more information.
	;
	; Parameters:
	;
	;   hWindow - Handle to the window.
	;
	;   X, Y, Width, Height - Output variables. [Optional] If defined, these
	;       variables contain the coordinates of the window relative to the
	;       upper-left corner of the screen (X and Y), and the Width and Height of
	;       the window.
	;
	;   Offset_X, Offset_Y - Output variables. [Optional] Offset, in pixels, of the
	;       actual position of the window versus the position of the window as
	;       reported by GetWindowRect.  If moving the window to specific
	;       coordinates, add these offset values to the appropriate coordinate
	;       (X and/or Y) to reflect the true size of the window.
	;
	; Returns:
	;
	;   If successful, the address of a RECTPlus structure is returned.  The first
	;   16 bytes contains a RECT structure that contains the dimensions of the
	;   bounding rectangle of the specified window.  The dimensions are given in
	;   screen coordinates that are relative to the upper-left corner of the screen.
	;   The next 8 bytes contain the X and Y offsets (4-byte integer for X and
	;   4-byte integer for Y).
	;
	;   Also if successful (and if defined), the output variables (X, Y, Width,
	;   Height, Offset_X, and Offset_Y) are updated.  See the *Parameters* section
	;   for more more information.
	;
	;   If not successful, FALSE is returned.
	;
	; Requirement:
	;
	;   Windows 2000+
	;
	; Remarks, Observations, and Changes:
	;
	; * Starting with Windows Vista, Microsoft includes the Desktop Window Manager
	;   (DWM) along with Aero-based themes that use DWM.  Aero themes provide new
	;   features like a translucent glass design with subtle window animations.
	;   Unfortunately, the DWM doesn't always conform to the OS rules for size and
	;   positioning of windows.  If using an Aero theme, many of the windows are
	;   actually larger than reported by Windows when using standard commands (Ex:
	;   WinGetPos, GetWindowRect, etc.) and because of that, are not positioned
	;   correctly when using standard commands (Ex: gui Show, WinMove, etc.).  This
	;   function was created to 1) identify the true position and size of all
	;   windows regardless of the window attributes, desktop theme, or version of
	;   Windows and to 2) identify the appropriate offset that is needed to position
	;   the window if the window is a different size than reported.
	;
	; * The true size, position, and offset of a window cannot be determined until
	;   the window has been rendered.  See the example script for an example of how
	;   to use this function to position a new window.
	;
	; * 20150906: The "dwmapi\DwmGetWindowAttribute" function can return odd errors
	;   if DWM is not enabled.  One error I've discovered is a return code of
	;   0x80070006 with a last error code of 6, i.e. ERROR_INVALID_HANDLE or "The
	;   handle is invalid."  To keep the function operational during this types of
	;   conditions, the function has been modified to assume that all unexpected
	;   return codes mean that DWM is not available and continue to process without
	;   it.  When DWM is a possibility (i.e. Vista+), a developer-friendly messsage
	;   will be dumped to the debugger when these errors occur.
	;
	; * 20160105 (Ben Allred): Adjust width and height for offset calculations if
	;   DPI is in play.
	;
	; Credit:
	;
	;   Idea and some code from *KaFu* (AutoIt forum)
	;
	;-------------------------------------------------------------------------------
		*/

    Static Dummy5693
          ,RECTPlus
          ,S_OK:=0x0
          ,DWMWA_EXTENDED_FRAME_BOUNDS:=9

    ;-- Workaround for AutoHotkey Basic
    PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"

    ;-- Get the window's dimensions
    ;   Note: Only the first 16 bytes of the RECTPlus structure are used by the
    ;   DwmGetWindowAttribute and GetWindowRect functions.
    VarSetCapacity(RECTPlus,24,0)
    DWMRC:=DllCall("dwmapi\DwmGetWindowAttribute"
        ,PtrType,hWindow                                ;-- hwnd
        ,"UInt",DWMWA_EXTENDED_FRAME_BOUNDS             ;-- dwAttribute
        ,PtrType,&RECTPlus                              ;-- pvAttribute
        ,"UInt",16)                                     ;-- cbAttribute

    if (DWMRC<>S_OK)
        {
        if ErrorLevel in -3,-4  ;-- Dll or function not found (older than Vista)
            {
            ;-- Do nothing else (for now)
            }
         else
            outputdebug,
               (ltrim join`s
                Function: %A_ThisFunc% -
                Unknown error calling "dwmapi\DwmGetWindowAttribute".
                RC=%DWMRC%,
                ErrorLevel=%ErrorLevel%,
                A_LastError=%A_LastError%.
                "GetWindowRect" used instead.
               )

        ;-- Collect the position and size from "GetWindowRect"
        DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus)
        }

    ;-- Populate the output variables
    X:=Left :=NumGet(RECTPlus,0,"Int")
    Y:=Top  :=NumGet(RECTPlus,4,"Int")
    Right   :=NumGet(RECTPlus,8,"Int")
    Bottom  :=NumGet(RECTPlus,12,"Int")
    Width   :=Right-Left
    Height  :=Bottom-Top
    OffSet_X:=0
    OffSet_Y:=0

    ;-- If DWM is not used (older than Vista or DWM not enabled), we're done
    if (DWMRC<>S_OK)
        Return &RECTPlus

    ;-- Collect dimensions via GetWindowRect
    VarSetCapacity(RECT,16,0)
    DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECT)
    GWR_Width :=NumGet(RECT,8,"Int")-NumGet(RECT,0,"Int")
        ;-- Right minus Left
    GWR_Height:=NumGet(RECT,12,"Int")-NumGet(RECT,4,"Int")
        ;-- Bottom minus Top

    ;-- Adjust width and height for offset calculations if DPI is in play
    ;   See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
    ;   The current version of AutoHotkey is PROCESS_SYSTEM_DPI_AWARE (contains "<dpiAware>true</dpiAware>" in its manifest)
    ;   DwmGetWindowAttribute returns DPI scaled sizes
    ;   GetWindowRect does not
    ; get monitor handle where the window is at so we can get the monitor name
    hMonitor := DllCall("MonitorFromRect",PtrType,&RECT,UInt,2) ; MONITOR_DEFAULTTONEAREST = 2 (Returns a handle to the display monitor that is nearest to the rectangle)
    ; get monitor name so we can get a handle to the monitor device context
    VarSetCapacity(MONITORINFOEX,104)
    NumPut(104,MONITORINFOEX)
    DllCall("GetMonitorInfo",PtrType,hMonitor,PtrType,&MONITORINFOEX)
    monitorName := StrGet(&MONITORINFOEX+40)
    ; get handle to monitor device context so we can get the dpi adjusted and actual screen sizes
    hdc := DllCall("CreateDC",Str,monitorName,PtrType,0,PtrType,0,PtrType,0)
    ; get dpi adjusted and actual screen sizes
    dpiAdjustedScreenHeight := DllCall("GetDeviceCaps",PtrType,hdc,Int,10) ; VERTRES = 10 (Height, in raster lines, of the screen)
    actualScreenHeight := DllCall("GetDeviceCaps",PtrType,hdc,Int,117) ; DESKTOPVERTRES = 117
    ; delete hdc as instructed
    DllCall("DeleteDC",PtrType,hdc)
    ; calculate dpi adjusted width and height
    dpiFactor := actualScreenHeight/dpiAdjustedScreenHeight ; this will be 1.0 if DPI is 100%
    dpiAdjusted_Width := Ceil(Width/dpiFactor)
    dpiAdjusted_Height := Ceil(Height/dpiFactor)

    ;-- Calculate offsets and update output variables
    NumPut(Offset_X:=(dpiAdjusted_Width-GWR_Width)//2,RECTPlus,16,"Int")
    NumPut(Offset_Y:=(dpiAdjusted_Height-GWR_Height)//2,RECTPlus,20,"Int")
    Return &RECTPlus
} ;<06.04.03.00002>
;<06.04.03.00003>
GetParent(hWnd) {																										;-- get parent win handle of a window

	return DllCall("GetParent", "Ptr", hWnd, "Ptr")

} ;</06.04.03.00003>
;<06.04.03.00004>
GetWindow(hWnd,uCmd) {																							;-- DllCall wrapper for GetWindow function

	return DllCall( "GetWindow", "Ptr", hWnd, "uint", uCmd, "Ptr")

} ;</06.04.03.00004>
;<06.04.03.00005>
GetForegroundWindow() {																							;-- returns handle of the foreground window
	return DllCall("GetForeGroundWindow", "Ptr")
} ;</06.04.02.000010>
;<06.04.000006>
IsWindowVisible(hWnd) {																							;-- self explaining
	return DllCall("IsWindowVisible", "Ptr", hWnd)
} ;</06.04.000006>
;<06.04.000007>
IsFullScreen(hwnd) {																									;-- specific window is a fullscreen window?

  WinGet, Style, Style, ahk_id %hwnd%
  return !(Style & 0x40000) ; 0x40000 = WS_SIZEBOX

} ;</06.04.000007>
;<06.04.000008>
IsClosed(win, wait) {																										;-- AHK function (WinWaitClose) wrapper

	WinWaitClose, ahk_id %win%,, %wait%
	return ((ErrorLevel = 1) ? False : True)

} ;</06.04.000008>
;<06.04.000009>
GetClassLong(hWnd, Param) {																					;--

    Static GetClassLong := A_PtrSize == 8 ? "GetClassLongPtr" : "GetClassLong"
    Return DllCall(GetClassLong, "Ptr", hWnd, "int", Param)

} ;</06.04.000009>
;<06.04.000010>
GetWindowLong(hWnd, Param) {																				;--

    ;GetWindowLong := A_PtrSize == 8 ? "GetWindowLongPtr" : "GetWindowLong"
    Return DllCall("GetWindowLong", "Ptr", hWnd, "int", Param)

} ;</06.04.000010>
;<06.04.000011>
GetClassStyles(Style) {																									;--

    Static CS := {0x1: "CS_VREDRAW"
    , 0x2: "CS_HREDRAW"
    , 0x8: "CS_DBLCLKS"
    , 0x20: "CS_OWNDC"
    , 0x40: "CS_CLASSDC"
    , 0x80: "CS_PARENTDC"
    , 0x200: "CS_NOCLOSE"
    , 0x800: "CS_SAVEBITS"
    , 0x1000: "CS_BYTEALIGNCLIENT"
    , 0x2000: "CS_BYTEALIGNWINDOW"
    , 0x4000: "CS_GLOBALCLASS"
    , 0x10000: "CS_IME"
    , 0x20000: "CS_DROPSHADOW"}

    Styles := " ("
    For k, v in CS {
        If (Style & k) {
            Styles .= v ", "
        }
    }

    Return RTrim(Styles, ", ") . ")"

} ;</06.04.000011>
;<06.04.000012>
GetTabOrderIndex(hWnd) {																						;--

    hParent := GetAncestor(hWnd)

    WinGet ControlList, ControlListHwnd, ahk_id %hParent%
    Index := 1
    Loop Parse, ControlList, `n
    {
        If (!IsWindowVisible(A_LoopField)) {
            Continue
        }

        WinGet Style, Style, ahk_id %A_LoopField%
        If !(Style & 0x10000) { ; WS_TABSTOP
            Continue
        }

        If (A_LoopField == hWnd) {
            Return Index
        }

        Index++
    }

    Return 0
} ;</06.04.000012>
;<06.04.000013>
GetCursor(CursorHandle) {																							;--

    Cursor := Cursors[CursorHandle]
    Return (Cursor != "") ? Cursor : CursorHandle

} ;</06.04.000013>
;<06.04.000014>
GetClientCoords(hWnd, ByRef x, ByRef y) {																	;--
    VarSetCapacity(POINT, 8, 0)
    NumPut(x, POINT, 0, "Int")
    NumPut(y, POINT, 4, "Int")
    hParent := GetParent(hWnd)
    DllCall("ScreenToClient", "Ptr", (hParent == 0 ? hWnd : hParent), "Ptr", &POINT)
    x := NumGet(POINT, 0, "Int")
    y := NumGet(POINT, 4, "Int")
} ;</06.04.000014>
;<06.04.000015>
GetClientSize(hwnd, ByRef w, ByRef h) {																		;-- get size of window without border
	; https://autohotkey.com/board/topic/91733-command-to-get-gui-client-areas-sizes/
    VarSetCapacity(rc, 16)
    DllCall("GetClientRect", "uint", hwnd, "uint", &rc)
    w := NumGet(rc, 8, "int")
    h := NumGet(rc, 12, "int")
} ;</06.04.000015>
;<06.04.000016>
GetWindowCoords(hWnd, ByRef x, ByRef y) {																;--
    hParent := GetParent(hWnd)
    WinGetPos px, py,,, % "ahk_id" . (hParent == 0 ? hWnd : hParent)
    x := x - px
    y := y - py
} ;</06.04.000016>
;<06.04.000017>
GetWindowPos(hWnd, ByRef X, ByRef Y, ByRef W, ByRef H) {										;--
    VarSetCapacity(RECT, 16, 0)
    DllCall("GetWindowRect", "Ptr", hWnd, "Ptr", &RECT)
    DllCall("MapWindowPoints", "Ptr", 0, "Ptr", GetParent(hWnd), "Ptr", &RECT, "UInt", 2)
    X := NumGet(RECT, 0, "Int")
    Y := NumGet(RECT, 4, "Int")
    w := NumGet(RECT, 8, "Int") - X
    H := NumGet(RECT, 12, "Int") - Y
} ;</06.04.000017>
;<06.04.000018>
GetWindowPlacement(hWnd) {																					;-- Gets window position using workspace coordinates (-> no taskbar), returns an object
    VarSetCapacity(WINDOWPLACEMENT, 44, 0)
    NumPut(44, WINDOWPLACEMENT)
    DllCall("GetWindowPlacement", "Ptr", hWnd, "Ptr", &WINDOWPLACEMENT)
    Result := {}
    Result.x := NumGet(WINDOWPLACEMENT, 7 * 4, "UInt")
    Result.y := NumGet(WINDOWPLACEMENT, 8 * 4, "UInt")
    Result.w := NumGet(WINDOWPLACEMENT, 9 * 4, "UInt") - Result.x
    Result.h := NumGet(WINDOWPLACEMENT, 10 * 4, "UInt") - Result.y
    Result.showCmd := NumGet(WINDOWPLACEMENT, 8, "UInt")
    ; 1 = normal, 2 = minimized, 3 = maximized
    Return Result
} ;</06.04.000018>
;<06.04.000019>
GetWindowInfo(hWnd) {                                                                                         	;-- returns an Key:Val Object with the most informations about a window (Pos, Client Size, Style, ExStyle, Border size...)
    NumPut(VarSetCapacity(WINDOWINFO, 60, 0), WINDOWINFO)
    DllCall("GetWindowInfo", "Ptr", hWnd, "Ptr", &WINDOWINFO)
    wi := Object()
    wi.WinX := NumGet(WINDOWINFO, 4, "Int")
    wi.WinY := NumGet(WINDOWINFO, 8, "Int")
    wi.WinW := NumGet(WINDOWINFO, 12, "Int") - wi.WindowX
    wi.WinH := NumGet(WINDOWINFO, 16, "Int") - wi.WindowY
    wi.cX := NumGet(WINDOWINFO, 20, "Int")
    wi.cY := NumGet(WINDOWINFO, 24, "Int")
    wi.cW := NumGet(WINDOWINFO, 28, "Int") - wi.ClientX
    wi.cH := NumGet(WINDOWINFO, 32, "Int") - wi.ClientY
    wi.Style   := NumGet(WINDOWINFO, 36, "UInt")
    wi.ExStyle := NumGet(WINDOWINFO, 40, "UInt")
    wi.Active  := NumGet(WINDOWINFO, 44, "UInt")
    wi.BorderW := NumGet(WINDOWINFO, 48, "UInt")
    wi.BorderH := NumGet(WINDOWINFO, 52, "UInt")
    wi.Atom    := NumGet(WINDOWINFO, 56, "UShort")
    wi.Version := NumGet(WINDOWINFO, 58, "UShort")
    Return wi
} ;</06.04.000019>
;<06.04.000020>
GetOwner(hWnd) {                                                                                                  	;--
    Return DllCall("GetWindow", "Ptr", hWnd, "UInt", 4) ; GW_OWNER
} ;</06.04.000020>
;<06.04.000021>
FindWindow(WinTitle, WinClass:="", WinText:="", ParentTitle:="",                        	;-- Finds the requested window,and return it's ID
ParentClass:="", DetectHiddenWins:="off", DectectHiddenTexts:="off") {

	; 0 if it wasn't found or chosen from a list
	; originally from Evan Casey Copyright (c) under MIT License.
	; changed for my purposes for Addendum for AlbisOnWindows by Ixiko on 04-06-2018
	; this version searches for ParentWindows if there is no WinText to check changed on 04-27-2018

	HWins:= A_DetectHiddenWindows
	HText:= A_DetectHiddenText
	DetectHiddenWindows, %DetectHiddenWins%
	DetectHiddenText, %DetectHiddenTexts%

		If Instr(WinClass, "Afx:") {
				SetTitleMatchMode, RegEx
		} else {
				SetTitleMatchMode, RegEx
		}

	if (WinClass = "")
		sSearchWindow := WinTitle
	else
		sSearchWindow := WinTitle . " ahk_class " . WinClass

	WinGet, nWindowArray, List, %sSearchWindow%, %WinText%

	;Loop for more windows - this is looks for ParentWindow
	if (nWindowArray > 1) {

		Loop %nWindowArray% {

			prev := DllCall("GetWindow", "ptr", hwnd, "uint", GW_HWNDPREV:=3, "ptr")			;GetParentWindowID
					if prev {
									DetectHiddenWindows On
									WinGetTitle title, ahk_id %prev%
									WinGetClass class, ahk_id %prev%
									If (titel == ParentTitle) AND (class == ParentClass) {
										sSelectedWinID := % nWindowArray%A_Index%
										break
									}

						}
		}

	} else if (nWindowArray == 1) {
		sSelectedWinID := nWindowArray1
	} else if (nWindowArray == 0) {
		sSelectedWinID := 0
	}

	DetectHiddenWindows, %HWins%
	DetectHiddenText, %HTexts%

	return sSelectedWinID
} ;</06.04.000021>
;<06.04.000022>
FindWindow(title, class="", style="", exstyle="", processname="",                          	;-- Finds the first window matching specific criterias.
allowempty = false) {

	WinGet, id, list,,, Program Manager
	Loop, %id%
	{
		this_id := id%A_Index%
		WinGetClass, this_class, ahk_id %this_id%
		if (class && class!=this_class)
			Continue
		WinGetTitle, this_title, ahk_id %this_id%
		if (title && title!=this_title)
			Continue
		WinGet, this_style, style, ahk_id %this_id%
		if (style && style!=this_style)
			Continue
		WinGet, this_exstyle, exstyle, ahk_id %this_id%
		if (exstyle && exstyle!=this_exstyle)
			Continue
		WinGetPos ,,,w,h,ahk_id %this_id%
		if (!allowempty && (w=0 || h=0))
			Continue
		WinGet, this_processname, processname, ahk_id %this_id%
		if (processname && processname!=this_processname)
			Continue
		return this_id
	}
	return 0
} ;</06.04.000022>
;<06.04.000023>
ShowWindow(hWnd, nCmdShow := 1) {	                                                                	;-- uses a DllCall to show a window
    DllCall("ShowWindow", "Ptr", hWnd, "Int", nCmdShow)
} ;</06.04.000023>
;<06.04.000024>
IsWindow(hWnd) {																										;-- wrapper for IsWindow DllCall
    Return DllCall("IsWindow", "Ptr", hWnd)
} ;</06.04.000024>
;<06.04.000025>
GetClassName(hWnd) {																								;-- wrapper for AHK WinGetClass function
	WinGetClass Class, ahk_id %hWnd%
    Return Class
} ;</06.04.000025>
;<06.04.000026>
FindChildWindow(Parent, Child, DetectHiddenWindow="On") {								;--finds childWindow Hwnds of the parent window

/*       	DESCRIPTION of function FindChildWindow

			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
			Description:			finds childWindow handles from a parent window by using Name and/or class or only the WinID of the parentWindow
			Link: 					https://autohotkey.com/board/topic/46786-enumchildwindows/
			Author: 				mickey
			second Author:	modified by IXIKO
			Date:					May 09, 2018
			last change: 		27.10.2018 - if there was no title or text for the childwindow the returned value was empty, so this function can handle now a new search parameter  -Class or ClassNN-,
															 therefore the child parameter becomes an object
			Parameter:			both are objects.
										Pass the following {Key:Value} pairs like this for Parent: {title: "Name of window", class: "Class (NN) Name", ID: ParentWinID}
										for child : title, class - is available
										for further informations look at example(s)
			return value:		a comma separated list of hwnds or nothing if there's no match
			Dependencies:		EnumChildWindow(06.04.000027), GetClassNN(06.04.000043), GetClassNN_EnumChildProc(06.04.000044)
			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

*/

/*		EXAMPLE(s)

		hMdi:= FindChildWindow({Class: "OptoAppClass"}, {Class: "MDIClient"}, "Off")
		HEXhwnd:= Format("0x{:x}", hMdi)
		MsgBox, % HEXhwnd

		hWZ:= FindChildWindow({Class: "OptoAppClass"}, {Title: "Wartezimmer"}, "Off")
		HEXhwnd:= Format("0x{:x}", hWZ)
		MsgBox, % HEXhwnd

*/

		detect:= A_DetectHiddenWindows
		global SearchChildTitle, SearchChildClass, active_id
		global ChildHwnds =

		;build ParentWinTitle parameter from ParentObject
		If Parent.WinID {
				ParentWinTitle:= "ahk_id " . Parent.ID
		} else {
			ParentWinTitle:= Parent.Title
			If Parent.Class
					ParentWinTitle.= " ahk_class " Parent.Class
		}

		SearchChildTitle := Child.Title
		SearchChildClass := Child.class

		WinGet, active_id, ID, %ParentWinTitle%

		DetectHiddenWindows %DetectHiddenWindows%  ; Due to fast-mode, this setting will go into effect for the callback too.

		; For performance and memory conservation, call RegisterCallback() only once for a given callback:
		if not EnumAddress  ; Fast-mode is okay because it will be called only from this thread:
			EnumAddress := RegisterCallback("EnumChildWindow") ; , "Fast")

		result:= DllCall("EnumChildWindows", UInt, active_id, UInt, EnumAddress, UInt, 0)

		DetectHiddenWindows %detect%
		ChildHwnds:= SubStr(ChildHwnds, 1, StrLen(ChildHwnds)-1)

		return ChildHwnds
} ;</06.04.000026>
;<06.04.000027>
EnumChildWindow(hwnd, lParam) { 																			;-- sub function of FindChildWindow

	global ChildHwnds
	global SearchChildTitle, SearchChildClass, active_id

	WinGetTitle, childtitle, ahk_id %hwnd%
	childclassNN:= GetClassNN(hwnd, active_id)

	If (InStr(childtitle, SearchChildTitle) and InStr(childclassNN, SearchChildClass))
	{
			ChildHwnds.= hwnd . "`;"
	}

    return true  ; Tell EnumWindows() to continue until all windows have been enumerated.
} ;</06.04.000027>
;<06.04.000028>
WinGetMinMaxState(hwnd) {																						;-- get state if window ist maximized or minimized

	/*	DESCRIPTION OF FUNCTION: -- WinGetMinMaxState --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:
	Link              	:	https://autohotkey.com/board/topic/13020-how-to-maximize-a-childdocument-window/
	Author         	:
	Date             	:
	AHK-Version	:
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:	it returns z for maximized("zoomed") or i for minimized("iconic")
	Remark(s)    	:	it's also work on MDI Windows - use hwnd you can get from FindChildWindow()
	Dependencies	:
	KeyWords    	:
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/
	zoomed := DllCall("IsZoomed", "UInt", hwnd)
	; Check if minimized
	iconic := DllCall("IsIconic", "UInt", hwnd)

	return (zoomed>iconic) ? "z":"i"
} ;</06.04.000028>
;<06.04.000029>
GetBgBitMapHandle(hPic)	{																						;-- returns the handle of a background bitmap in a gui
	;found at: https://autohotkey.com/boards/viewtopic.php?t=27128
	SendMessage, 0x173, 0, 0,, ahk_id %hPic%
	return ErrorLevel
} ;</06.04.000029>
;<06.04.000030>
GetLastActivePopup(hwnd) {																						;-- passes the handle of the last active pop-up window of a parent window
	return DLLCall("GetLastActivePopup", "uint", hwnd)
} ;</06.04.000030>
;<06.04.000031>
GetFreeGuiNum(start, prefix = "") {																				;-- gets a free gui number.
	/* Group: About
	o v0.81 by majkinetor.
	o Licenced under BSD <http://creativecommons.org/licenses/BSD/>
*/
	loop {
		Gui %prefix%%start%:+LastFoundExist
		IfWinNotExist
			return prefix start
		start++
		if (start = 100)
			return 0
	}
	return 0
} ;</06.04.000031>
;<06.04.000032>
IsWindowUnderCursor(hwnd) {                                                                               	;-- Checks if a specific window is under the cursor.
	MouseGetPos, , , win
	if hwnd is number
		return win = hwnd
	else
		return InStr(WinGetClass("ahk_class " win), hwnd)
} ;</06.04.000032>
;<06.04.000033>
GetCenterCoords(guiW) {                                                                                        	;-- ?center a gui between 2 monitors?

	;https://github.com/number1nub/CreoWindows

	SysGet, numMons, MonitorCount
	SysGet, leftMon1, Monitor, 1
	leftMon := round(leftMon1Right)
	bottomMon := round(leftmon1bottom)
	If (numMons>1)
	{
		SysGet, totalMon, Monitor, 2
		rightMon := round(totalMonRight - leftMon)
		If (rightMon < 0)
		{
			leftMon  := round(leftMon+rightMon)
			rightMon := round(rightmon*-1)
		}
	}
	return { limit: leftMon, left: round((leftMon/2)-(guiW/2)), right: round((leftMon + (rightMon/2))-(guiW/2)) }
} ;</06.04.000033>
;<06.04.000034>
RMApp_NCHITTEST() {                                                                                            	;-- Determines what part of a window the mouse is currently over

	/*                         	DESCRIPTON
		Function: RMApp_NCHITTEST()
		Determines what part of a window the mouse is currently over.
	*/

	CoordMode, Mouse, Screen
	MouseGetPos, x, y, z
	SendMessage, 0x84, 0, (x&0xFFFF)|(y&0xFFFF)<<16,, ahk_id %z%
	RegExMatch("ERROR TRANSPARENT NOWHERE CLIENT CAPTION SYSMENU SIZE MENU HSCROLL VSCROLL MINBUTTON MAXBUTTON LEFT RIGHT TOP TOPLEFT TOPRIGHT BOTTOM BOTTOMLEFT BOTTOMRIGHT BORDER OBJECT CLOSE HELP", "(?:\w+\s+){" ErrorLevel+2&0xFFFFFFFF "}(?<AREA>\w+\b)", HT)
	Return HTAREA
} ;</06.04.000034>
;<06.04.000035>
GetCPA_file_name( p_hw_target ) {                                                                         	;-- retrieves Control Panel applet icon

   WinGet, pid_target, PID, ahk_id %p_hw_target%
   hp_target := DllCall( "OpenProcess", "uint", 0x18, "int", false, "uint", pid_target, "Ptr")
   hm_kernel32 := GetModuleHandle("kernel32.dll")
   pGetCommandLine := DllCall( "GetProcAddress", "Ptr", hm_kernel32, "Astr", A_IsUnicode ? "GetCommandLineW"  : "GetCommandLineA")
   buffer_size := 6
   VarSetCapacity( buffer, buffer_size )
   DllCall( "ReadProcessMemory", "Ptr", hp_target, "uint", pGetCommandLine, "uint", &buffer, "uint", buffer_size, "uint", 0 )
   loop, 4
      ppCommandLine += ( ( *( &buffer+A_Index ) ) << ( 8*( A_Index-1 ) ) )
   buffer_size := 4
   VarSetCapacity( buffer, buffer_size, 0 )
   DllCall( "ReadProcessMemory", "Ptr", hp_target, "uint", ppCommandLine, "uint", &buffer, "uint", buffer_size, "uint", 0 )
   loop, 4
      pCommandLine += ( ( *( &buffer+A_Index-1 ) ) << ( 8*( A_Index-1 ) ) )
   buffer_size := 260
   VarSetCapacity( buffer, buffer_size, 1 )
   DllCall( "ReadProcessMemory", "Ptr", hp_target, "uint", pCommandLine, "uint", &buffer, "uint", buffer_size, "uint", 0 )
   DllCall( "CloseHandle", "Ptr", hp_target )
   IfInString, buffer, desk.cpl ; exception to usual string format
     return, "C:\WINDOWS\system32\desk.cpl"

   ix_b := InStr( buffer, "Control_RunDLL" )+16
   ix_e := InStr( buffer, ".cpl", false, ix_b )+3
   StringMid, CPA_file_name, buffer, ix_b, ix_e-ix_b+1
   if ( ix_e )
      return, CPA_file_name
   else
      return, false
} ;</06.04.000035>
;<06.04.000036>
WinGetClientPos( Hwnd ) {												        									;-- gives back the coordinates of client area inside a gui/window - with DpiFactor correction

	/*                         EXAMPLE
			global dpifactor:=DPIFactor()

			Gui New, +HwndhGUI +LabelGui_ +Resize
			Gui %hGUI%:Show, w500 h500
			MsgBox The Gui client area will now be covered with a new black gui
			Gui New, +HwndhGUI2 -Caption +ToolWindow +AlwaysOnTop
			Gui %hGUI2%:Color, 000000
			Client := WinGetClientPos( hGUI )
			Gui %hGUI2%:Show, % "x" Client.X " y" Client.Y " w" Client.W " h" Client.H
			OnMessage( 0x03, "GuiChanged" )
			OnMessage( 0x05, "GuiChanged" )
			return

			Gui_Close:
				ExitApp

			GuiChanged() {
					global hGUI,hGUI2
					Client := WinGetClientPos( hGUI )
					Gui %hGUI2%:Show, % "x" Client.X " y" Client.Y " w" Client.W " h" Client.H
			}

	*/

	; https://autohotkey.com/boards/viewtopic.php?f=6&t=484
	VarSetCapacity( size, 16, 0 )
	DllCall( "GetClientRect", UInt, Hwnd, Ptr, &size )
	DllCall( "ClientToScreen", UInt, Hwnd, Ptr, &size )
	x := NumGet(size, 0, "Int")
	y := NumGet(size, 4, "Int")
	w := NumGet( size, 8, "Int" ) // dpifactor
	h := NumGet( size, 12, "Int" ) // dpifactor
	return { X: x, Y: y, W: w, H: h }
} ;</06.04.000036>
;<06.04.000037>
CheckWindowStatus(hwnd, timeout=100) {																;-- check's if a window is responding or not responding (hung or crashed) -

 /* 									Description

					check's if a window is responding or not responding (hung or crashed)
					 timeout milliseconds to wait before deciding it is not responding - 100 ms seems reliable under 100% usage
					 WM_NULL =0x0000
					 SMTO_ABORTIFHUNG =0x0002


					;  * SendMessageTimeout values
					;
					; #define SMTO_NORMAL         0x0000
					; #define SMTO_BLOCK          0x0001
					; #define SMTO_ABORTIFHUNG    0x0002
					; #if (WINVER >= 0x0500)
					; #define SMTO_NOTIMEOUTIFNOTHUNG 0x0008
					; #endif /* WINVER >= 0x0500 */
					; #endif /* !NONCMESSAGES */
					;
					;
					; SendMessageTimeout(
					;     __in HWND hWnd,
					;     __in UINT Msg,
					;     __in WPARAM wParam,
					;     __in LPARAM lParam,
					;     __in UINT fuFlags,
					;     __in UINT uTimeout,
					;     __out_opt PDWORD_PTR lpdwResult);
*/

	NR_temp =0 ; init
	return DllCall("SendMessageTimeout", "UInt", hwnd, "UInt", 0x0000, "Int", 0, "Int", 0, "UInt", 0x0002, "UInt", TimeOut, "UInt *", NR_temp)
} ;</06.04.000037>
;<06.04.000038>
GetWindowOrder(hwnd="",visibleWin=1) {                                                            	;-- determines the window order for a given (parent-)hwnd
	if !hwnd
		hwnd:=winexist("ahk_pid " DllCall("GetCurrentProcessId"))

	arr1:=[]
	arr2:=[]

	hwndP:=hwnd
	loop {
		hwndP:=GetNextWindow(hwndP,1,visibleWin)
		if(hwndP=hwnd || !hwndP)
			break
		else
			arr1.insert(hwndP)
	}

	hwndN:=hwnd
	loop {
		hwndN:=GetNextWindow(hwndN,1,visibleWin)
		if(hwndN=hwnd || !hwndP)
			break
		else
			arr2.insert(hwndN)
	}

	arr:=[],max:=arr1.maxIndex()
	loop % max
		arr.insert(arr1[max+1-a_index])
	for k,v in arr2
		arr.insert(v)

	return {array: arr, index: max+1}

} ;</06.04.000038>
;<06.04.000039>
EnumWindows(hWnd := 0, HiddenWindows := true, Flags := "") {								;-- Get a list with all the top-level windows on the screen or controls in the window

	/*                              	DESCRIPTION

			Get a list with all the top-level windows on the screen or controls in the window
			Syntax: 						EnumWindows ([hWnd], [HiddenWindows], [Flags])
			---------------------------- Parameters -------------------------
			hWnd:	 						specify the hWnd of a window to get a list with all its controls
			HiddenWindows: 		set false to not recover hidden windows. by default it obtains all the windows.
			Flags: 							additional filter options. Specify an object with one or more of the following keys and their respective value.
												ProcessPath = 			specify the path of the file to which the process belongs.
												ProcessName = 			specify the name of the file to which the process belongs.
												WindowClass = 			class of the window.
												WindowTitle = 			title of the window.
												ProcessId = 				PID of the window process.
			 Return: 						returns an array with all hWnds
			------------------------------ Notes -----------------------------
			in WIN_8  only the top-level windows of desktop applications are retrieved.
			When using the 3rd parameter, when checking strings such as WindowClass, WindowTitle, it is not case sensitive, use StringCaseSense to change this.
			Example: get a list with all the windows whose path of the executable file matches explorer.exe
	       	-------------------------------------------------------------------
			EXAMPLE(s)
			for k, v in EnumWindows(0x0, false, )
					MsgBox % GetWindowClass(v) "`n" GetWindowTitle(v)

	*/

	EnumAddress := RegisterCallback("EnumWindowsProc", "Fast", 2)
	, _gethwnd(hWnd), Data := {List: [], HiddenWindows: HiddenWindows, Flags: Flags}
	, DllCall("User32.dll\EnumChildWindows", "Ptr", hWnd, "Ptr", EnumAddress, "Ptr", &Data)
	return Data.List, GlobalFree(EnumAddress)
} EnumWindowsProc(hWnd, Data) { ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms633494(v=vs.85).aspx
	if !(Data := Object(Data)) || ((Data.HiddenWindows = 0) && !WinVisible(hWnd))
		return true
	if IsObject(Data.Flags) {
		if Data.Flags.HasKey("WindowTitle") && (GetWindowTitle(hWnd) != Data.Flags.WindowTitle)
			return true
		if Data.Flags.HasKey("WindowClass") && (GetWindowClass(hWnd) != Data.Flags.WindowClass)
			return true
		if Data.Flags.HasKey("ProcessPath") || Data.Flags.HasKey("ProcessId") || Data.Flags.HasKey("ProcessName") {
			GetWindowThreadProcessId(hWnd, ProcessId)
			if Data.Flags.HasKey("ProcessPath") || Data.Flags.HasKey("ProcessName") {
				ProcessPath := GetModuleFileName("/" ProcessId)
				if Data.Flags.HasKey("ProcessPath") && (ProcessPath != Data.Flags.ProcessPath)
					return true
				if Data.Flags.HasKey("ProcessName") {
					SplitPath, ProcessPath, ProcessName
					if (ProcessName != Data.Flags.ProcessName)
						return true
			}	} if Data.Flags.HasKey("ProcessId") && (ProcessId != Data.Flags.ProcessId)
				return true
	}	} return true, Data.List.Push(hWnd)
}  ;</06.04.000039> ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms633493(v=vs.85).aspx
;<06.04.000040>
WinEnum(hwnd:=0, lParam:=0) {                                                                            	;-- wrapper for Enum(Child)Windows from cocobelgica. a different solution to that one I collected before

	/* DESCRIPTION of function: WinEnum

			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
			Description:     	Wrapper for Enum(Child)Windows [http://goo.gl/5eCy9 | http://goo.gl/FMXit]
			Author:            	cocobelgica
			Date:                	15 Nov 2014
			Link:                 	https://github.com/cocobelgica/AutoHotkey-Util/blob/master/WinEnum.ahk
			License:            	WTFPL [http://wtfpl.net/]
			Syntax:             	windows := WinEnum( [ hwnd ] )
			Parameter(s)
			/Return Value: 	windows	[retval] 	- 	an array of window handles
										hwnd     	[in, opt] 	- 	parent window. If specified, EnumChildWindows is called.
																			Accepts a window handle or any string that match the WinTitle[http://goo.gl/NdhybZ] parameter.
										lParam                 	-	internal, used by callback
			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

	*/

	/*	EXAMPLE(s) of function: WinEnum

			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
			win := WinEnum()                    	; calls EnumWindows
			children := WinEnum("A")     	; enumerate child windows of the active window
			------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

	 */

	static pWinEnum := "X"
	if (A_EventInfo != pWinEnum) {
		if (pWinEnum == "X")
			pWinEnum := RegisterCallback(A_ThisFunc, "F", 2)
		if hwnd {

			;// not a window handle, could be a WinTitle parameter
			if !DllCall("IsWindow", "Ptr", hwnd) {

				prev_DHW := A_DetectHiddenWindows
				prev_TMM := A_TitleMatchMode
				DetectHiddenWindows On
				SetTitleMatchMode 2
				hwnd := WinExist(hwnd)
				DetectHiddenWindows %prev_DHW%
				SetTitleMatchMode %prev_TMM%

			}
		}
		out := []
		if hwnd
			DllCall("EnumChildWindows", "Ptr", hwnd, "Ptr", pWinEnum, "Ptr", &out)
		else
			DllCall("EnumWindows", "Ptr", pWinEnum, "Ptr", &out)
		return out
	}

	;// Callback - EnumWindowsProc / EnumChildProc
	static ObjPush := Func(A_AhkVersion < "2" ? "ObjInsert" : "ObjPush")
	%ObjPush%(Object(lParam + 0), hwnd)
	return true
} ;</06.04.000040>
;<06.04.000041>
WinWaitProgress(Progress = 100, WinTitle = "", WinText = "", Timeout = "") {     	;-- Waits for the progress bar on a window to reach (>=) a given value (a Lexikos function)

	/*    	DESCRIPTION of function WinWaitProgress()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Waits for the progress bar on a window to reach (>=) a given value
			Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=4761
			Author         	:	Lexikos
			Date             	:	02.10.2014
			AHK-Version	:	AHK_V1, AHK_V2
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	Works with AutoHotkey v1.1 and probably v1.0. For v2.0, change = to := and FAIL to ERROR.
                                    	Returns immediately if the progress bar isn't found.
			Dependencies	:	ControlGetProgress()
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			if WinWaitProgress(100, "Piriform CCleaner")
				MsgBox Done cleaning.
			else if (ErrorLevel = "FAIL")
				MsgBox Error
			else
				MsgBox Timeout; progress=%ErrorLevel%

	*/

	began_at := A_TickCount
	While (n := ControlGetProgress("msctls_progress321", WinTitle, WinText)) != "FAIL"
		&& n < Progress && (Timeout = "" || (A_TickCount-began_at)/1000 < Timeout)
		Sleep 100
	return (ErrorLevel + 0) >= Progress
} ;</06.04.000041>
;<06.04.000042>
ControlGetProgress(Control, WinTitle = "", WinText = "") {                                     	;-- sub function of WinWaitProgress
	SendMessage 0x408,,, %Control%, %WinTitle%, %WinText%
	return ErrorLevel
}  ;</06.04.000042>
;<06.04.000043>
GetClassNN(Chwnd, Whwnd) {                                                                               	;-- sub function of FindChildWindow
	global _GetClassNN := {}
	_GetClassNN.Hwnd := Chwnd
	Detect := A_DetectHiddenWindows
	WinGetClass, Class, ahk_id %Chwnd%
	_GetClassNN.Class := Class
	DetectHiddenWindows, On
	EnumAddress := RegisterCallback("GetClassNN_EnumChildProc")
	DllCall("EnumChildWindows", "uint",Whwnd, "uint",EnumAddress)
	DetectHiddenWindows, %Detect%
	return, _GetClassNN.ClassNN, _GetClassNN:=""
} ;</06.04.000043>
;<06.04.000044>
GetClassNN_EnumChildProc(hwnd, lparam) {                                                         	;-- sub function of FindChildWindow
	static N
	global _GetClassNN
	WinGetClass, Class, ahk_id %hwnd%
	if _GetClassNN.Class == Class
		N++
	return _GetClassNN.Hwnd==hwnd? (0, _GetClassNN.ClassNN:=_GetClassNN.Class N, N:=0):1
} ;</06.04.000044>
}

{ ;<06.04.04> gui + miscallaneous 		(06)
;<06.04.04.000001>
ChooseColor(ByRef Color, hOwner := 0) {																	;--		what is this for?
    rgbResult := ((Color & 0xFF) << 16) + (Color & 0xFF00) + ((Color >> 16) & 0xFF)

    VarSetCapacity(CUSTOM, 64, 0)
    NumPut(VarSetCapacity(CHOOSECOLOR, A_PtrSize * 9, 0), CHOOSECOLOR, 0)
    NumPut(hOwner, CHOOSECOLOR, A_PtrSize)
    NumPut(rgbResult, CHOOSECOLOR, A_PtrSize * 3)
    NumPut(&CUSTOM, CHOOSECOLOR, A_PtrSize * 4) ; COLORREF *lpCustColors
    NumPut(0x103, CHOOSECOLOR, A_PtrSize * 5) ; Flags: CC_ANYCOLOR | CC_RGBINIT | CC_FULLOPEN

    RetVal := DllCall("comdlg32\ChooseColorA", "Str", CHOOSECOLOR)
    If (ErrorLevel != 0 || RetVal == 0) {
        Return False
    }

    rgbResult := NumGet(CHOOSECOLOR, A_PtrSize * 3)
    Color := (rgbResult & 0xFF00) + ((rgbResult & 0xFF0000) >> 16) + ((rgbResult & 0xFF) << 16)
    Color := Format("0x{:06X}", Color)
    Return True
} ;</06.04.04.000001>
;<06.04.04.000002>
GetWindowIcon(hWnd, Class, TopLevel := False) {														;--

	Static Classes := {0:0
    , "#32770": 3
    , "Button": 4
    , "CheckBox": 5
    , "ComboBox": 6
    , "SysDateTimePick32": 7
    , "Edit": 8
    , "GroupBox": 9
    , "msctls_hotkey32": 10
    , "Icon": 11
    , "SysLink": 12
    , "ListBox": 13
    , "SysListView32": 14
    , "SysMonthCal32": 15
    , "Picture": 16
    , "msctls_progress32": 17
    , "Radio": 18
    , "RebarWindow32": 25
    , "RichEdit": 19
    , "Separator": 20
    , "msctls_trackbar32": 21
    , "msctls_statusbar32": 22
    , "SysTabControl32": 23
    , "Static": 24
    , "ToolbarWindow32": 25
    , "tooltips_class32": 26
    , "SysTreeView32": 27
    , "msctls_updown32": 28
    , "Internet Explorer_Server": 29
    , "Scintilla": 30
    , "ScrollBar": 31
    , "SysHeader32": 32}

    If (Class == "Button") {
        WinGet Style, Style, ahk_id %hWnd%
        Type := Style & 0xF
        If (Type == 7) {
            Class := "GroupBox"
        } Else If (Type ~= "2|3|5|6") {
            Class := "CheckBox"
        } Else If (Type ~= "4|9") {
            Class := "Radio"
        } Else {
            Class := "Button"
        }
    } Else If (Class == "Static") {
        WinGet Style, Style, ahk_id %hWnd%
        Type := Style & 0x1F ; SS_TYPEMASK
        If (Type == 3) {
            Class := "Icon"
        } Else If (Type == 14) {
            Class := "Picture"
        } Else If (Type == 0x10) {
            Class := "Separator"
        } Else {
            Class := "Static"
        }
    } Else If (InStr(Class, "RICHED", True) == 1) {
        Class := "RichEdit" ; RICHEDIT50W
    }

    Icon := Classes[Class]
    If (Icon != "") {
        Return Icon
    }

    SendMessage 0x7F, 2, 0,, ahk_id %hWnd% ; WM_GETICON, ICON_SMALL2
    hIcon := ErrorLevel

    If (hIcon == 0 && TopLevel) {
        WinGet ProcessPath, ProcessPath, ahk_id %hWnd%
        hIcon := GetFileIcon(ProcessPath)
    }

    IconIndex := (hIcon) ? IL_Add(ImageList, "HICON: " . hIcon) : 1
    Return IconIndex
} ;</06.04.04.000002>
;<06.04.04.000003>
GetStatusBarText(hWnd) {																							;--
    SB_Text := ""
    hParentWnd := GetParent(hWnd)

    SendMessage 0x406, 0, 0,, ahk_id %hWnd% ; SB_GETPARTS
    Count := ErrorLevel
    If (Count != "FAIL") {
        Loop %Count% {
            StatusBarGetText PartText, %A_Index%, ahk_id %hParentWnd%
            SB_Text .= PartText . "|"
        }
    }

    Return SubStr(SB_Text, 1, -1)
} ;</06.04.04.000003>
;<06.04.04.000004>
GetAncestor(hWnd, Flag := 2) {																					;--
    Return DllCall("GetAncestor", "Ptr", hWnd, "UInt", Flag)
} ;</06.04.04.000004>
;<06.04.04.000005>
OnMessage(0x24, "MinMaxInfo")
MinMaxInfo(W, L, M, H) {																							;--
	Static MIEX := 0, Dummy := NumPut(VarSetCapacity(MIEX, 40 + (32 << !!A_IsUnicode)), MIEX, 0, "UInt")
	Critical
	If (HMON := DllCall("User32.dll\MonitorFromWindow", "Ptr", H, "UInt", 0, "UPtr")) {
		If DllCall("User32.dll\GetMonitorInfo", "Ptr", HMON, "Ptr", &MIEX) {
			W := NumGet(MIEX, 28, "Int") - NumGet(MIEX, 20, "Int")
			H := NumGet(MIEX, 32, "Int") - NumGet(MIEX, 24, "Int")
			NumPut(W - NumGet(L + 16, "Int"), L + 8, "Int")
			NumPut(H - NumGet(L + 20, "Int"), L + 12, "Int")
		}
	}
} ;</06.04.04.000005>
;<06.04.04.000006>
GetMouseTaskButton(ByRef hwnd) {                                                                          	;-- Gets the index+1 of the taskbar button which the mouse is hovering over

	/* Lexikos' Function :

		Link: 	https://autohotkey.com/board/topic/58215-middle-click-titlebartaskbar-close-windows-semi-solved/
		; Gets the index+1 of the taskbar button which the mouse is hovering over.
		; Returns an empty string if the mouse is not over the taskbar's task toolbar.
		;
		; Some code and inspiration from Sean's TaskButton.ahk
	*/

	CoordMode, Mouse, Screen
    MouseGetPos, x, y, win, ctl, 2
		; Check if hovering over taskbar.
    WinGetClass, cl, ahk_id %win%
    if (cl != "Shell_TrayWnd")
        return
		; Check if hovering over a Toolbar.
    WinGetClass, cl, ahk_id %ctl%
    if (cl != "ToolbarWindow32")
        return
		; Check if hovering over task-switching buttons (specific toolbar).
    hParent := DllCall("GetParent", "Uint", ctl)
    WinGetClass, cl, ahk_id %hParent%
    if (cl != "MSTaskSwWClass")
        return

    WinGet, pidTaskbar, PID, ahk_class Shell_TrayWnd

    hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
    pRB := DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 20, "Uint", 0x1000, "Uint", 0x4)

    VarSetCapacity(pt, 8, 0)
    NumPut(x, pt, 0, "int")
    NumPut(y, pt, 4, "int")

		; Convert screen coords to toolbar-client-area coords.
    DllCall("ScreenToClient", "uint", ctl, "uint", &pt)

		; Write POINT into explorer.exe.
    DllCall("WriteProcessMemory", "uint", hProc, "uint", pRB+0, "uint", &pt, "uint", 8, "uint", 0)

		; SendMessage, 0x447,,,, ahk_id %ctl%  ; TB_GETHOTITEM
    SendMessage, 0x445, 0, pRB,, ahk_id %ctl%  ; TB_HITTEST
    btn_index := ErrorLevel
		; Convert btn_index to a signed int, since result may be -1 if no 'hot' item.
    if btn_index > 0x7FFFFFFF
        btn_index := -(~btn_index) - 1


    if (btn_index > -1)  {
			; Get button info.
        SendMessage, 0x417, btn_index, pRB,, ahk_id %ctl%   ; TB_GETBUTTON

        VarSetCapacity(btn, 20)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pRB, "Uint", &btn, "Uint", 20, "Uint", 0)

        state := NumGet(btn, 8, "UChar")  ; fsState
        pdata := NumGet(btn, 12, "UInt")  ; dwData

        ret := DllCall("ReadProcessMemory", "Uint", hProc
            , "Uint", pdata, "UintP", hwnd, "Uint", 4, "Uint", 0)
    } else {
        hwnd = 0
	}

    DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pRB, "Uint", 0, "Uint", 0x8000)
    DllCall("CloseHandle", "Uint", hProc)


    ; Negative values indicate seperator items. (abs(btn_index) is the index)
    return btn_index > -1 ? btn_index+1 : 0
} ;</06.04.04.000006>

}

}
;|   screenDims(1)                           	|   DPIFactor(2)                             	|

;|   ControlExists(1)                       	|   GetFocusedControl(2)               	|   GetControls(3)                          	|   GetOtherControl(4)                  	|
;|   ListControls(5)                         	|   Control_GetClassNN(6)            	|   ControlGetClassNN(7,8)           	|   GetClassName(9)                     	|
;|   Control_GetFont(10)                	|   IsControlFocused(11)                	|   getControlNameByHwnd(12)   	|   getByControlName(13)            	|
;|   getNextControl(14)                 	|   IsControlUnderCursor(15)        	|   GetFocusedControl(16)            	|   ControlGetTextExt(17)              	|
;|   getControlInfo(18)                   	|   FocusedControl(19)                  	|   Control_GetFont(20)                	|   WinForms_GetClassNN(21)      	|
;|   GetExtraStyle(22)                    	|   GetToolbarItems(23)                	|   ControlGetTabs(24)                  	|   GetHeaderInfo(25)                   	|
;|   WinSaveCheckboxes(26)         	|   GetButtonType(27)                   	|   HWNDToClassNN(28)             	|   IsCheckboxStyle(29)                 	|
;|   Control_GetFont(30)                	|

;|   IsOverTitleBar(1)                     	|   WinGetPosEx(2)                        	|   GetParent(3)                            	|   GetWindow(4)                          	|
;|   GetForegroundWindow(5)       	|   IsWindowVisible(6)                  	|   IsFullScreen(7)                          	|   IsClosed(8)                               	|
;|   GetClassLong(9)                      	|   GetWindowLong(10)                	|   GetClassStyles(11)                    	|   GetTabOrderIndex(12)              	|
;|   GetCursor(13)                           	|   GetClientCoords(14)                	|   GetClientSize(15)                     	|   GetWindowCoords(16)             	|
;|   GetWindowPos(17)                  	|   GetWindowPlacement(18)       	|   GetWindowInfo(19)                  	|   GetOwner(20)                          	|
;|   FindWindow(21,22)                 	|   ShowWindow(23)                    		|   IsWindow(24)                           	|   GetClassName(25)                   	|
;|   FindChildWindow(26)              	|   WinGetMinMaxState(28)          	|   GetBgBitMapHandle(29)          	|   GetLastActivePopup(30)           	|
;|   GetFreeGuiNum(31)                	|   IsWindowUnderCursor(32)       	|   GetCenterCoords(33)               	|   RMApp_NCHITTEST(34)           	|
;|   GetCPA_file_name(35)             	|   WinGetClientPos(36)                	|   CheckWindowStatus(37)          	|   GetWindowOrder(38)               	|
;|   EnumWindows(39)                  	|   WinEnum(40)                           	|   WinWaitProgress(41)               	|	ControlGetProgress(42)            	|
;|   GetClassNN(43)                       	|   GetClassNN_EnumChildProc(44)	|

;|   ChooseColor(1)                       	|   GetWindowIcon(2)                   	|   GetStatusBarText(3)                 	|   GetAncestor(4)                         	|
;|   MinMaxInfo(5)                         	|	GetMouseTaskButton(6)           	|

{ ;gui - interacting (46) -- other functions to interact with windows --                                                         	baseID: <06.05>

;<06.05.000001>
SureControlClick(CName, WinTitle, WinText="") { 														;--Window Activation + ControlDelay to -1 + checked if control received the click
		;by Ixiko 2018
		Critical
		WinActivate, %WTitle%, %WinText%
			WinWaitActive, %WTitle%, %WinText%, 3

		SetControlDelay -1
			ControlClick, %CName%, %WinTitle%, %WinText%,,, NA		;If the click does not work then he tries a little differently
				If ErrorLevel
					ControlClick, %CName%, %WinTitle%, %WinText%

		SetControlDelay 20


	return ErrorLevel
} ;</06.05.000001>
;<06.05.000002>
SureControlCheck(CName, WinTitle, WinText="") { 													;-- Window Activation + ControlDelay to -1 + Check if the control is really checked now
	;by Ixiko 2018
	;BlockInput, On
		Critical
		WinActivate, %WTitle%, %WinText%
			WinWaitActive, %WTitle%, %WinText%, 1

		SetControlDelay -1
			Loop {
				Control, Check, , %CName%, %WinTitle%, %WinText%
					sleep, 10
				ControlGet, isornot, checked, ,  %CName%, %WinTitle%, %WinText%
			} until (isornot = 1)

		SetControlDelay 20

	;BlockInput, Off

	return ErrorLevel
} ;</06.05.000002>
;<06.05.000003>
ControlClick2(X, Y, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")  {		;-- ControlClick Double Click

  hwnd:=ControlFromPoint(X, Y, WinTitle, WinText, cX, cY
                             , ExcludeTitle, ExcludeText)
  PostMessage, 0x201, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONDOWN
  PostMessage, 0x202, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONUP
  PostMessage, 0x203, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONDBLCLCK
  PostMessage, 0x202, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONUP
} ;</06.05.000003>
;<06.05.000004>
ControlFromPoint(X, Y, WinTitle="", WinText="", ByRef cX="", ByRef cY="",           	;--  returns the hwnd of a control at a specific point on the screen
ExcludeTitle="", ExcludeText="") {

	/*                              	DESCRIPTION

			 https://autohotkey.com/board/topic/71988-simulating-a-double-click/

			 Retrieves the control at the specified point.
			 X         [in]    X-coordinate relative to the top-left of the window.
			 Y         [in]    Y-coordinate relative to the top-left of the window.
			 WinTitle  [in]    Title of the window whose controls will be searched.
			 WinText   [in]
			 cX        [out]   X-coordinate relative to the top-left of the control.
			 cY        [out]   Y-coordinate relative to the top-left of the control.
			 ExcludeTitle [in]
			 ExcludeText  [in]
			 Return Value:     The hwnd of the control if found, otherwise the hwnd of the window.

	*/


    static EnumChildFindPointProc=0
    if !EnumChildFindPointProc
        EnumChildFindPointProc := RegisterCallback("EnumChildFindPoint","Fast")

    if !(target_window := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText))
        return false

    VarSetCapacity(rect, 16)
    DllCall("GetWindowRect","uint",target_window,"uint",&rect)
    VarSetCapacity(pah, 36, 0)
    NumPut(X + NumGet(rect,0,"int"), pah,0,"int")
    NumPut(Y + NumGet(rect,4,"int"), pah,4,"int")
    DllCall("EnumChildWindows","uint",target_window,"uint",EnumChildFindPointProc,"uint",&pah)
    control_window := NumGet(pah,24) ? NumGet(pah,24) : target_window
    DllCall("ScreenToClient","uint",control_window,"uint",&pah)
    cX:=NumGet(pah,0,"int"), cY:=NumGet(pah,4,"int")
    return control_window
} ;</06.05.000004>
;<06.05.000005>
EnumChildFindPoint(aWnd, lParam) {																			;-- this function is required by ControlFromPoint

	; this was ported from AutoHotkey::script2.cpp::EnumChildFindPoint()
    if !DllCall("IsWindowVisible","uint",aWnd)
        return true
    VarSetCapacity(rect, 16)
    if !DllCall("GetWindowRect","uint",aWnd,"uint",&rect)
        return true
    pt_x:=NumGet(lParam+0,0,"int"), pt_y:=NumGet(lParam+0,4,"int")
    rect_left:=NumGet(rect,0,"int"), rect_right:=NumGet(rect,8,"int")
    rect_top:=NumGet(rect,4,"int"), rect_bottom:=NumGet(rect,12,"int")
    if (pt_x >= rect_left && pt_x <= rect_right && pt_y >= rect_top && pt_y <= rect_bottom)
    {
        center_x := rect_left + (rect_right - rect_left) / 2
        center_y := rect_top + (rect_bottom - rect_top) / 2
        distance := Sqrt((pt_x-center_x)**2 + (pt_y-center_y)**2)
        update_it := !NumGet(lParam+24)
        if (!update_it)
        {
            rect_found_left:=NumGet(lParam+8,0,"int"), rect_found_right:=NumGet(lParam+8,8,"int")
            rect_found_top:=NumGet(lParam+8,4,"int"), rect_found_bottom:=NumGet(lParam+8,12,"int")
            if (rect_left >= rect_found_left && rect_right <= rect_found_right
                && rect_top >= rect_found_top && rect_bottom <= rect_found_bottom)
                update_it := true
            else if (distance < NumGet(lParam+28,0,"double")
                && (rect_found_left < rect_left || rect_found_right > rect_right
                 || rect_found_top < rect_top || rect_found_bottom > rect_bottom))
                 update_it := true
        }
        if (update_it)
        {
            NumPut(aWnd, lParam+24)
            DllCall("RtlMoveMemory","uint",lParam+8,"uint",&rect,"uint",16)
            NumPut(distance, lParam+28, 0, "double")
        }
    }
    return true
} ;</06.05.000005>
;<06.05.000006>
ControlDoubleClick(ctrl,win,bttn:="Left",x:=1,y:=1) {                                                 	;-- simulates a double click on a control with left/middle or right mousebutton

	;https://github.com/Lateralus138/Task-Lister/blob/master/TLLib.ahk
    id:=WinExist(win)?WinExist(win):0
	If bttn IN Left,left,l,L
		a.="0x201",b.="0x202",c.="0x203"
	If bttn IN Right,right,r,R
		a.="0x204",b.="0x205",c.="0x206"
	If bttn IN Middle,middle,m,M
		a.="0x207",b.="0x208",c.="0x209"
    If !(id && a && b && c)
        Return 0
    lParam:=x & 0xFFFF | (y & 0xFFFF) << 16
	WinActivate,ahk_id %id%
	PostMessage,%a%,1,%lParam%,%ctrl%,ahk_id %id%
	PostMessage,%b%, ,%lParam%,%ctrl%,ahk_id %id%
    PostMessage,%c%,1,%lParam%,%ctrl%,ahk_id %id%
    Return id
} ;</06.05.000006>
;<06.05.000007>
WinWaitForMinimized(ByRef winID, timeOut = 1000) {												;-- waits until the window is minimized
  ; Function:  WinWaitForMinimized
;              waits for the window winID to minimize or until timeout,
;              whichever comes first (used to delay other actions until a
;              minimize message is handled and completed)
; Parm1:     winID - ID of window to wait for minimization
; Parm2:     timeOut - optional - timeout in milliseconds to wait
; wait until minimized (or timeOut)
   iterations := timeOut/10
   loop,%iterations%
   {
      WinGet,winMinMax,MinMax,ahk_id %winID%
      if (winMinMax = -1)
         break
      sleep 10
   }
} ;</06.05.000007>
;<06.05.000008>
CenterWindow(aWidth,aHeight) {																				;-- Given a the window's width and height, calculates where to position its upper-left corner so that it is centered EVEN IF the task bar is on the left side or top side of the window

	/*	DESCRIPTION OF FUNCTION: -- CenterWindow() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Given a the window's width and height, calculates where to position its upper-left corner
                               	so that it is centered EVEN IF the task bar is on the left side or top side of the window.
                               	This does not currently handle multi-monitor systems explicitly, since those calculations
                               	require API functions that don't exist in Win95/NT (and thus would have to be loaded
                               	dynamically to allow the program to launch).  Therefore, windows will likely wind up
                               	being centered across the total dimensions of all monitors, which usually results in
                               	half being on one monitor and half in the other.  This doesn't seem too terrible and
                               	might even be what the user wants in some cases (i.e. for really big windows).
	Link              	:	--
	Author         	:	--
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	--
	KeyWords    	:	gui, screen, center
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	static rect:=Struct("left,top,right,bottom"),SPI_GETWORKAREA:=48,pt:=Struct("x,y")
	DllCall("SystemParametersInfo","Int",SPI_GETWORKAREA,"Int", 0,"PTR", rect[],"Int", 0)  ; Get desktop rect excluding task bar.
	; Note that rect.left will NOT be zero if the taskbar is on docked on the left.
	; Similarly, rect.top will NOT be zero if the taskbar is on docked at the top of the screen.
	pt.x := rect.left + (((rect.right - rect.left) - aWidth) / 2)
	pt.y := rect.top + (((rect.bottom - rect.top) - aHeight) / 2)

return pt
} ;</06.05.000008>
;<06.05.000009>
GuiCenterButtons(strWindow, intInsideHorizontalMargin := 10, 								;-- Center and resize a row of buttons automatically
intInsideVerticalMargin := 0, intDistanceBetweenButtons := 20, arrControls*) {
; This is a variadic function. See: http://ahkscript.org/docs/Functions.htm#Variadic
; https://autohotkey.com/boards/viewtopic.php?t=3963 from JnLlnd

	/*				EXAMPLE

		Gui, New, , MyWindow

		Gui, Add, Text, , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras rutrum nisi et metus porttitor non tristique est euismod. Maecenas accumsan, ante at tempus tempor, lorem elit mollis mauris, vitae tempor massa odio eget libero.

		Gui, Font
		Gui, Add, Button, y+20 vMyButton1 gGuiClose, Close
		Gui, Add, Button, yp vMyButton2 gGuiClose, Lonnger Button Name
		GuiCenterButtons("MyWindow", 10, 5, 30, "MyButton1", "MyButton2")

		Gui, Show, Autosize Center

		return


		GuiClose:
		ExitApp

	*/

	DetectHiddenWindows, On
	Gui, Show, Hide
	WinGetPos, , , intWidth, , %strWindow%

	intMaxControlWidth := 0
	intMaxControlHeight := 0
	for intIndex, strControl in arrControls
	{
		GuiControlGet, arrControlPos, Pos, %strControl%
		if (arrControlPosW > intMaxControlWidth)
			intMaxControlWidth := arrControlPosW
		if (arrControlPosH > intMaxControlHeight)
			intMaxControlHeight := arrControlPosH
	}

	intMaxControlWidth := intMaxControlWidth + intInsideHorizontalMargin
	intButtonsWidth := (arrControls.MaxIndex() * intMaxControlWidth) + ((arrControls.MaxIndex()  - 1) * intDistanceBetweenButtons)
	intLeftMargin := (intWidth - intButtonsWidth) // 2

	for intIndex, strControl in arrControls
		GuiControl, Move, %strControl%
			, % "x" . intLeftMargin + ((intIndex - 1) * intMaxControlWidth) + ((intIndex - 1) * intDistanceBetweenButtons)
			. " w" . intMaxControlWidth
			. " h" . intMaxControlHeight + intInsideVerticalMargin
} ;</06.05.000009>
;<06.05.0000010>
CenterControl(hWnd,hCtrl,X=1,Y=1) {																		;-- Centers one control
;------------------------------------------------------------------------------------------------------------------------
;Function:    CenterControl (by Banane: http://de.autohotkey.com/forum/viewtopic.php?p=67802#67802)
;Parameters:  hWnd  = Handle of a Window (can be obtained using "WinExist()")
;             hCtrl = Handle of a Control (can be obtained using the "Hwnd" option when creating the control)
;             X     = Center the Control horizontally if X is 1
;             Y     = Center the Control vertically if Y is 1
;Description: Moves the specified control within the center of the specified window
;Returnvalue: 0 - Invalid Window / Control Handle, or the Window / Control has a size of 0
;------------------------------------------------------------------------------------------------------------------------

 static Border,CaptionSmall,CaptionNormal

  ;Retrieve Size of Border and Caption, if this is the first time this function is called
  If (!CaptionNormal) {
    SysGet, Border, 5        ;Border Width
    SysGet, CaptionNormal, 4 ;Window Caption
    SysGet, CaptionSmall, 51 ;Window Caption with Toolwindow Style
  }

  ;Only continue if valid handles passed
  If (!hWnd || !hCtrl)
    Return 0

  ;Retrieve the size of the control and window
  ControlGetPos,,, cW, cH,, % "ahk_id " hCtrl
  WinGetPos,,, wW, wH, % "ahk_id " hWnd
  ;Only continue if the control and window are visible (and don't have a size of 0)
  If ((cW = "" || cH = "") || (wW = "" || wH = ""))
    Return 0

  ;Retrieve the window styles
  WinGet, Styles, Style, % "ahk_id " hWnd
  WinGet, ExStyles, ExStyle, % "ahk_id " hWnd

  ;Calculate the offset
  If (Styles & 0xC00000) ;If window has the "Caption" flag
    If (ExStyles & 0x00000080) ;If window has the "Toolwindow" flag
      Caption := CaptionSmall
    Else Caption := CaptionNormal
  Else Caption := 1

  ;Calculate the new position and apply it to the control
  ControlMove,, % (X = 1) ? Round((wW - cW + Border) / 2) : "", % (Y = 1) ? Round((wH - cH + Caption) / 2) : "",,, % "ahk_id " hCtrl

  ;Redraw the windows content
  WinSet, Redraw,, % "ahk_id " hWnd

  Return 1
} ;</06.05.0000010>
;<06.05.000011>
SetWindowIcon(hWnd, Filename, Index := 1) {															;--
    Local hIcon := LoadPicture(Filename, "w16 Icon" . Index, ErrorLevel)
    SendMessage 0x80, 0, hIcon,, ahk_id %hWnd% ; WM_SETICON
    Return ErrorLevel
} ;</06.05.000011>
;<06.05.000012>
SetWindowPos(hWnd, x, y, w, h, hWndInsertAfter := 0, uFlags := 0x40) {					;--
    Return DllCall("SetWindowPos", "Ptr", hWnd, "Ptr", hWndInsertAfter, "Int", x, "Int", y, "Int", w, "Int", h, "UInt", uFlags)
} ;</06.05.000012>
;<06.05.000013>
TryKillWin(win) {																											;--
	static funcs := ["Win32_SendMessage", "Win32_TaskKill", "Win32_Terminate"]

	if (IsClosed(win, 0.5)) {
		IdleGui("Window is already closed", "", 3, true)
		return
	}

	for i, v in funcs {
		IdleGui("Trying " . v . "...", "Closing...", 10, false)
		if (%v%(win)) {
			IdleGuiClose()
			return true
		}
	}
	return false
} ;</06.05.000013>
;<06.05.000014>
Win32_SendMessage(win) {																						;-- Closing a window through sendmessage command
	static wm_msgs := {"WM_CLOSE":0x0010, "WM_QUIT":0x0012, "WM_DESTROY":0x0002}
	for k, v in wm_msgs {
		SendMessage, %v%, 0, 0,, ahk_id %win%
		if (IsClosed(win, 1))
			break
	}
	if (IsClosed(win, 1))
		return true
	return false
} ;</06.05.000014>
;<06.05.000015>
Win32_TaskKill(win) {																									;--
	WinGet, win_pid, PID, ahk_id %win%
	cmdline := "taskkill /pid " . win_pid . " /f"
	Run, %cmdline%,, Hide UseErrorLevel
	if (ErrorLevel != 0 or !IsClosed(win, 5))
		return false
	return true
} ;</06.05.000015>
;<06.05.000016>
Win32_Terminate(win) {																								;--
	WinGet, win_pid, PID, ahk_id %win%
	handle := DllCall("Kernel32\OpenProcess", UInt, 0x0001, UInt, 0, UInt, win_pid)
	if (!handle)
		return false
	result := DllCall("Kernel32\TerminateProcess", UInt, handle, Int, 0)
	if (!result)
		return false
	return IsClosed(win, 5)
} ;</06.05.000016>
;<06.05.000017>
TabActivate(no) {																											;--
	global GuiWinTitle
	SendMessage, 0x1330, %no%,, SysTabControl321, %GuiWinTitle%
	Sleep 50
	SendMessage, 0x130C, %no%,, SysTabControl321, %GuiWinTitle%
	return
} ;</06.05.000017>
;<06.05.000018>
FocuslessScroll(Function inside) {																				;--
;Directives
#NoEnv
#SingleInstance Force
#MaxHotkeysPerInterval 100 ;Avoid warning when mouse wheel turned very fast
;Autoexecute code
MinLinesPerNotch := 1
MaxLinesPerNotch := 5
AccelerationThreshold := 100
AccelerationType := "L" ;Change to "P" for parabolic acceleration
StutterThreshold := 10
;Function definitions
;See above for details
FocuslessScroll(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType, StutterThreshold) {
	SetBatchLines, -1 ;Run as fast as possible
	CoordMode, Mouse, Screen ;All coords relative to screen

	;Stutter filter: Prevent stutter caused by cheap mice by ignoring successive WheelUp/WheelDown events that occur to close together.
	if (A_TimeSincePriorHotkey < StutterThreshold) ;Quickest succession time in ms
		if (A_PriorHotkey = "WheelUp" Or A_PriorHotkey ="WheelDown")
			Return

	MouseGetPos, m_x, m_y,, ControlClass2, 2
	ControlClass1 := DllCall( "WindowFromPoint", "int64", (m_y << 32) | (m_x & 0xFFFFFFFF), "Ptr") ;32-bit and 64-bit support

	lParam := (m_y << 16) | (m_x & 0x0000FFFF)
	wParam := (120 << 16) ;Wheel delta is 120, as defined by MicroSoft

	;Detect WheelDown event
	if (A_ThisHotkey = "WheelDown" Or A_ThisHotkey = "^WheelDown" Or A_ThisHotkey = "+WheelDown" Or A_ThisHotkey = "*WheelDown")
		wParam := -wParam ;If scrolling down, invert scroll direction

	;Detect modifer keys held down (only Shift and Control work)
	if (GetKeyState("Shift","p"))
		wParam := wParam | 0x4
	if (GetKeyState("Ctrl","p"))
		wParam := wParam | 0x8

	;Adjust lines per notch according to scrolling speed
	Lines := LinesPerNotch(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType)

	if (ControlClass1 != ControlClass2)
	{
		Loop %Lines%
		{
			SendMessage, 0x20A, wParam, lParam,, ahk_id %ControlClass1%
			SendMessage, 0x20A, wParam, lParam,, ahk_id %ControlClass2%
		}
	}
	Else ;Avoid using Loop when not needed (most normal controls). Greately improves momentum problem!
	{
		SendMessage, 0x20A, wParam * Lines, lParam,, ahk_id %ControlClass1%
	}
}
LinesPerNotch(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType) {
	T := A_TimeSincePriorHotkey
	;All parameters are the same as the parameters of FocuslessScroll()
	;Return value: Returns the number of lines to be scrolled calculated from the current scroll speed.
	;Normal slow scrolling, separationg between scroll events is greater than AccelerationThreshold miliseconds.
	if ((T > AccelerationThreshold) Or (T = -1)) ;T = -1 if this is the first hotkey ever run
	{
		Lines := MinLinesPerNotch
	}
	;Fast scrolling, use acceleration
	Else
	{
		if (AccelerationType = "P")
		{
			;Parabolic scroll speed curve
			;f(t) = At^2 + Bt + C
			A := (MaxLinesPerNotch-MinLinesPerNotch)/(AccelerationThreshold**2)
			B := -2 * (MaxLinesPerNotch - MinLinesPerNotch)/AccelerationThreshold
			C := MaxLinesPerNotch
			Lines := Round(A*(T**2) + B*T + C)
		}
		Else
		{
			;Linear scroll speed curve
			;f(t) = Bt + C
			B := (MinLinesPerNotch-MaxLinesPerNotch)/AccelerationThreshold
			C := MaxLinesPerNotch
			Lines := Round(B*T + C)
		}
	}
	Return Lines
}
;All hotkeys with the same parameters can use the same instance of FocuslessScroll(). No need to have separate calls unless each hotkey requires different parameters (e.g. you want to disable acceleration for Ctrl-WheelUp and Ctrl-WheelDown).
;If you want a single set of parameters for all scrollwheel actions, you can simply use *WheelUp:: and *WheelDown:: instead.
#MaxThreadsPerHotkey 6 ;Adjust to taste. The lower the value, the lesser the momentum problem on certain smooth-scrolling GUI controls (e.g. AHK helpfile main pane, WordPad...), but also the lesser the acceleration feel. The good news is that this setting does no affect most controls, only those that exhibit the momentum problem. Nice.
;Scroll with acceleration
WheelUp::
WheelDown::FocuslessScroll(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType, StutterThreshold)
;Ctrl-Scroll zoom with no acceleration (MaxLinesPerNotch = MinLinesPerNotch).
^WheelUp::
^WheelDown::FocuslessScroll(MinLinesPerNotch, MinLinesPerNotch, AccelerationThreshold, AccelerationType, StutterThreshold)
;If you want zoom acceleration, replace above line with this:
;FocuslessScroll(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType, StutterThreshold)
#MaxThreadsPerHotkey 1 ;Restore AHK's default  value i.e. 1
;End: Focusless Scroll
} ;</06.05.000018>
;<06.05.000019>
FocuslessScrollHorizontal(MinLinesPerNotch, MaxLinesPerNotch, 							;--
AccelerationThreshold, AccelerationType, StutterThreshold) {

	;https://autohotkey.com/board/topic/99405-hoverscroll-verticalhorizontal-scroll-without-focus-scrollwheel-acceleration/page-5

    SetBatchLines, -1 ;Run as fast as possible
    CoordMode, Mouse, Screen ;All coords relative to screen

    ;Stutter filter: Prevent stutter caused by cheap mice by ignoring successive WheelUp/WheelDown events that occur to close together.
    if (A_TimeSincePriorHotkey < StutterThreshold) ;Quickest succession time in ms
        if (A_PriorHotkey = "WheelUp" Or A_PriorHotkey ="WheelDown")
            Return

    MouseGetPos, m_x, m_y,, ControlClass2, 2
    ControlClass1 := DllCall( "WindowFromPoint", "int64", (m_y << 32) | (m_x & 0xFFFFFFFF), "Ptr") ;32-bit and 64-bit support

    ctrlMsg := 0x114    ; WM_HSCROLL
    wParam := 0         ; Left

    ;Detect WheelDown event
    if (A_ThisHotkey = "WheelDown" Or A_ThisHotkey = "^WheelDown" Or A_ThisHotkey = "+WheelDown" Or A_ThisHotkey = "*WheelDown")
        wParam := 1 ; Right

    ;Adjust lines per notch according to scrolling speed
    Lines := LinesPerNotch(MinLinesPerNotch, MaxLinesPerNotch, AccelerationThreshold, AccelerationType)

    Loop %Lines%
    {
        SendMessage, ctrlMsg, wParam, 0,, ahk_id %ControlClass1%
        if (ControlClass1 != ControlClass2)
            SendMessage, ctrlMsg, wParam, 0,, ahk_id %ControlClass2%
    }
} ;</06.05.000019>
;<06.05.000020>
Menu_Show( hMenu, hWnd=0, mX="", mY="", Flags=0x1 ) {									;-- alternate to Menu, Show , which can display menu without blocking monitored messages...
 ; http://ahkscript.org/boards/viewtopic.php?p=7088#p7088
 ; Flags: TPM_RECURSE := 0x1, TPM_RETURNCMD := 0x100, TPM_NONOTIFY := 0x80
 VarSetCapacity( POINT, 8, 0 ), DllCall( "GetCursorPos", UInt,&Point )
 mX := ( mX <> "" ) ? mX : NumGet( Point,0 )
 mY := ( mY <> "" ) ? mY : NumGet( Point,4 )
Return DllCall( "TrackPopupMenu", UInt,hMenu, UInt,Flags ; TrackPopupMenu()  goo.gl/CosNig
               , Int,mX, Int,mY, UInt,0, UInt,hWnd ? hWnd : WinActive("A"), UInt,0 )

/*
..but the catch is: To get handle ( hMenu ) for a Menuname, it has to be attached to a MenuBar.
There already is a function from lexikos, which does this: MI_GetMenuHandle(), and can be used as follows:

hViewmenu := MI_GetMenuHandle( "view" ) ; Get it from: http://www.autohotkey.net/~Lexikos/lib/MI.ahk
...
...
GuiContextMenu:
 Menu_Show( hViewMenu )
Return
*/
} ;</06.05.000020>
;<06.05.000021>
CatMull_ControlMove( px0, py0, px1, py1, px2, py2, 													;-- Moves the mouse through 4 points (without control point "gaps")
px3, py3, Segments=8, Rel=0, Speed=2 ) {
; Function by [evandevon]. Moves the mouse through 4 points (without control point "gaps"). Inspired by VXe's
;cubic bezier curve function (with some borrowed code).
   MouseGetPos, px0, py0
   If Rel
      px1 += px0, px2 += px0, px3 += px0, py1 += py0, py2 += py0, py3 += py0
   Loop % Segments - 1
   {
	;CatMull Rom Spline - Working
	  u := 1 - t := A_Index / Segments
	  cmx := Round(0.5*((2*px1) + (-px0+px2)*t + (2*px0 - 5*px1 +4*px2 - px3)*t**2 + (-px0 + 3*px1 - 3*px2 + px3)*t**3) )
	  cmy := Round(0.5*((2*py1) + (-py0+py2)*t + (2*py0 - 5*py1 +4*py2 - py3)*t**2 + (-py0 + 3*py1 - 3*py2 + py3)*t**3) )

	  MouseMove, cmx, cmy, Speed,

   }
   MouseMove, px3, py3, Speed
} ;</06.05.000021> CatMull_MouseMove( px1, py1, px2, py2, px3, py3, Segments=5, Rel=0, Speed=2 ) -------------------
;<06.05.000022>
GUI_AutoHide(Hide_Direction, Gui_Num_To_Hide_Clone=1, 									;-- Autohide the GUI function
Delay_Before_Hide=3000, Number_Of_Offset_Pixels=5, Enabled_Disabled_Flag=1) {


	;                   Original Author: jpjazzy            Link: http://www.autohotkey.com/forum/viewtopic.php?p=485853#485853
	; =====================================================================================================================================================
	;   GUI_AutoHide(Hide direction, [Gui # to hide, Delay in milliseconds before hiding, Number of pixels to display while hidden (offset), Enabled/Disabled Flag])
	; =====================================================================================================================================================
	; Required parameters: Hide direction (LEFT="L", RIGHT="R", UP="U", DOWN="D")
	; Defaults for optional parameters: GUI # = 1, Delay in ms = 3000 = 3 seconds, Number of pixels to display while hidden = 5, Enabled/Disabled Flag = 1 (Enabled=1 Disabled=0)
	; =====================================================================================================================================================
	; NOTES:
	; * Functions work with expressions, so make sure you use quotes when inputting settings unless the setting is contained within a variable
	; * Function must be placed directly after the GUI you are using it for
	; * Function will make the GUI AlwaysOnTop so the user can activate it from the autohide
	; * Specifying 0 for the Enabled/Disabled Flag will return the GUI to it's original position before deactivating autohide
	; * The window must be hidden and docked to the side of the screen before the effects of the autohide take place
	; * The titlebar sometimes gets in the way of reactivating the hidden GUI if there is one... To get around this either remove the caption/border or Set a higher pixel offset
	; =====================================================================================================================================================
	; LIMITATIONS:
	; - Using this on multiple GUIs most likely will cause problems due to the hide overlapping
	; =====================================================================================================================================================

	; ========================================= (AUTOHIDE FUNCTIONS) ==========================================

	SetBatchLines, -1

   global ; Assume global
   Gui_Num_To_Hide := Gui_Num_To_Hide_Clone
   Gui, %Gui_Num_To_Hide%: +LastFound +AlwaysOnTop ; Set GUI settings so we can obtain it's settings and give it an alwaysontop attribute to make the user be able to unhide it

   ; ** OBTAIN  AND SET VARIABLES **
   StringUpper, Hide_Direction, Hide_Direction ; Capitalize it just in case the user didn't for the label
   If ( Enabled_Disabled_Flag = 0 )
   {
   %Gui_Num_To_Hide%_Enabled_Disabled_Flag := 0
    WinMove, % %Gui_Num_To_Hide%_Gui_Title,, % %Gui_Num_To_Hide%_GUIX, % %Gui_Num_To_Hide%_GUIY
    return
   }

   WinGetPos, %Gui_Num_To_Hide%_GUIX, %Gui_Num_To_Hide%_GUIY, %Gui_Num_To_Hide%_GUIW, %Gui_Num_To_Hide%_GUIH, A
   WinGetTitle, %Gui_Num_To_Hide%_Gui_Title, A
   %Gui_Num_To_Hide%_TimeLapse := A_TickCount                           ; Set the specified variables with respect to which GUI the settings go to
   %Gui_Num_To_Hide%_Enabled_Disabled_Flag := Enabled_Disabled_Flag
   %Gui_Num_To_Hide%_Number_Of_Offset_Pixels := Number_Of_Offset_Pixels
   %Gui_Num_To_Hide%_Delay_Before_Hide := Delay_Before_Hide
   %Gui_Num_To_Hide%_Hide_Direction := Hide_Direction
    ;MsgBox % %Gui_Num_To_Hide%_Gui_Title


   ; ** Place message for GUI **
   OnMessage(0x200,"WM_MOUSEMOVE") ; Message to send when the mouse is over the GUI
   SetTimer, HideGUI%Hide_Direction%, 500 ; Set timer to hide the GUI in whatever direction you chose
   return

      ; ** HideGUI Settings **
   HideGUIU:
   ;~ ;MsgBox % "If (" A_TickCount - %Gui_Num_To_Hide%_TimeLapse " < " %Gui_Num_To_Hide%_Delay_Before_Hide ") "
   If (%Gui_Num_To_Hide%_Enabled_Disabled_Flag != 1)
      return
   If (A_TickCount - %Gui_Num_To_Hide%_TimeLapse < %Gui_Num_To_Hide%_Delay_Before_Hide)         ; If the mouse was over the GUI within the last 3 seconds, don't hide it
      return

      WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title ; Get the position of the GUI
      Loop
      {
         ; MsgBox % "If (" %Gui_Num_To_Hide%_GUIY+%Gui_Num_To_Hide%_GUIH " > " %Gui_Num_To_Hide%_Number_Of_Offset_Pixels ")"
         If (GUIY + %Gui_Num_To_Hide%_GUIH > %Gui_Num_To_Hide%_Number_Of_Offset_Pixels)     ; If the GUI is not hidden hide it then break
         {
            ;~ ;MsgBox % "WinMove,"  %Gui_Num_To_Hide%_Gui_Title ",, " GUIX ", " GUIY-(A_Index)
            WinMove, % %Gui_Num_To_Hide%_Gui_Title,, %GUIX%, % GUIY-(A_Index)
            WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title
            ;MsgBox % "WinGetPos,  " GUIX ", " GUIY ",,, "  %Gui_Num_To_Hide%_Gui_Title
         }
         else
            break
      }

   If ((GUIY + %Gui_Num_To_Hide%_GUIH) < (%Gui_Num_To_Hide%_Number_Of_Offset_Pixels-1)) ; Failsafe if the GUI moves too far
   {
      WinMove, % %Gui_Num_To_Hide%_Gui_Title,, %GUIX%, % (-%Gui_Num_To_Hide%_GUIH+%Gui_Num_To_Hide%_Number_Of_Offset_Pixels)
   }
   SetTimer, HideGUIU, OFF
   return

      HideGUID:
   ;~ ;MsgBox % "If (" A_TickCount - %Gui_Num_To_Hide%_TimeLapse " < " %Gui_Num_To_Hide%_Delay_Before_Hide ") "
      If (%Gui_Num_To_Hide%_Enabled_Disabled_Flag != 1)
      return
   If (A_TickCount - %Gui_Num_To_Hide%_TimeLapse < %Gui_Num_To_Hide%_Delay_Before_Hide)         ; If the mouse was over the GUI within the last 3 seconds, don't hide it
      return

      WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title ; Get the position of the GUI
      Loop
      {
         ; MsgBox % "If (" %Gui_Num_To_Hide%_GUIY+%Gui_Num_To_Hide%_GUIH " > " %Gui_Num_To_Hide%_Number_Of_Offset_Pixels ")"
         If (GUIY < A_ScreenHeight-%Gui_Num_To_Hide%_Number_Of_Offset_Pixels)     ; If the GUI is not hidden hide it then break
         {
            ;~ ;MsgBox % "WinMove,"  %Gui_Num_To_Hide%_Gui_Title ",, " GUIX ", " GUIY-(A_Index)
            WinMove, % %Gui_Num_To_Hide%_Gui_Title,, %GUIX%, % GUIY+(A_Index)
            WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title
            ;MsgBox % "WinGetPos,  " GUIX ", " GUIY ",,, "  %Gui_Num_To_Hide%_Gui_Title
         }
         else
            break
      }

   If (GUIY > A_ScreenHeight-(%Gui_Num_To_Hide%_Number_Of_Offset_Pixels-1)) ; Failsafe if the GUI moves too far
   {
      WinMove, % %Gui_Num_To_Hide%_Gui_Title,, %GUIX%, % (A_ScreenHeight - %Gui_Num_To_Hide%_Number_Of_Offset_Pixels)
   }
   SetTimer, HideGUID, OFF
   return

   HideGUIR:
      If (%Gui_Num_To_Hide%_Enabled_Disabled_Flag != 1)
      return
   ;~ ;MsgBox % "If (" A_TickCount - %Gui_Num_To_Hide%_TimeLapse " < " %Gui_Num_To_Hide%_Delay_Before_Hide ") "
   If (A_TickCount - %Gui_Num_To_Hide%_TimeLapse < %Gui_Num_To_Hide%_Delay_Before_Hide)         ; If the mouse was over the GUI within the last 3 seconds, don't hide it
      return

      WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title ; Get the position of the GUI
      Loop
      {
         ; MsgBox % "If (" %Gui_Num_To_Hide%_GUIY+%Gui_Num_To_Hide%_GUIH " > " %Gui_Num_To_Hide%_Number_Of_Offset_Pixels ")"
         If (GUIX < A_ScreenWidth-%Gui_Num_To_Hide%_Number_Of_Offset_Pixels)     ; If the GUI is not hidden hide it then break
         {
            ;~ ;MsgBox % "WinMove,"  %Gui_Num_To_Hide%_Gui_Title ",, " GUIX ", " GUIY-(A_Index)
            WinMove, % %Gui_Num_To_Hide%_Gui_Title,, % GUIX+A_Index, %GUIY%
            WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title
            ;MsgBox % "WinGetPos,  " GUIX ", " GUIY ",,, "  %Gui_Num_To_Hide%_Gui_Title
         }
         else
            break
      }

   If (GUIX > A_ScreenWidth-%Gui_Num_To_Hide%_Number_Of_Offset_Pixels) ; Failsafe if the GUI moves too far
   {
      WinMove, % %Gui_Num_To_Hide%_Gui_Title,, % A_ScreenWidth-%Gui_Num_To_Hide%_Number_Of_Offset_Pixels, %GUIY%
   }
   SetTimer, HideGUIR, OFF
   return

      HideGUIL:
   ;~ ;MsgBox % "If (" A_TickCount - %Gui_Num_To_Hide%_TimeLapse " < " %Gui_Num_To_Hide%_Delay_Before_Hide ") "
      If (%Gui_Num_To_Hide%_Enabled_Disabled_Flag != 1)
      return
   If (A_TickCount - %Gui_Num_To_Hide%_TimeLapse < %Gui_Num_To_Hide%_Delay_Before_Hide)         ; If the mouse was over the GUI within the last 3 seconds, don't hide it
      return

      WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title ; Get the position of the GUI
      Loop
      {
         ; MsgBox % "If (" %Gui_Num_To_Hide%_GUIY+%Gui_Num_To_Hide%_GUIH " > " %Gui_Num_To_Hide%_Number_Of_Offset_Pixels ")"
         If (GUIX+%Gui_Num_To_Hide%_GUIW > %Gui_Num_To_Hide%_Number_Of_Offset_Pixels)     ; If the GUI is not hidden hide it then break
         {
            ;~ ;MsgBox % "WinMove,"  %Gui_Num_To_Hide%_Gui_Title ",, " GUIX ", " GUIY-(A_Index)
            WinMove, % %Gui_Num_To_Hide%_Gui_Title,, % GUIX-A_Index, %GUIY%
            WinGetPos,  GUIX, GUIY,,, % %Gui_Num_To_Hide%_Gui_Title
            ;MsgBox % "WinGetPos,  " GUIX ", " GUIY ",,, "  %Gui_Num_To_Hide%_Gui_Title
         }
         else
            break
      }

   If (GUIX+%Gui_Num_To_Hide%_GUIW < %Gui_Num_To_Hide%_Number_Of_Offset_Pixels) ; Failsafe if the GUI moves too far
   {
      WinMove, % %Gui_Num_To_Hide%_Gui_Title,, % -%Gui_Num_To_Hide%_GUIW+%Gui_Num_To_Hide%_Number_Of_Offset_Pixels, %GUIY%
   }
   SetTimer, HideGUIL, OFF
   return

} ;</06.05.000022>
{ ; sub
WM_MOUSEMOVE(wParam,lParam) { ; Action to take if the mouse moves over the GUI

   If (%A_Gui%_Enabled_Disabled_Flag = 1)
   {
      RestartGUIActivate:
      LabelDir := %A_Gui%_Hide_Direction
      SetTimer, HideGUI%LabelDir%, Off ; Turn off the label while the mouse is over the GUI
      WinGetPos,  GUIX, GUIY,,, % %A_Gui%_Gui_Title ; Get the position of the GUI if your cursor is over it.

      ; DO ACTION BASED ON WHAT DIRECTION THE GUI IS SET TO
      If (%A_Gui%_Hide_Direction == "U")
      {
         Loop
         {
            If (GUIY+%A_Gui%_GUIH < %A_Gui%_GUIH) ; If the GUI is hidden, show it then break
            {
               WinMove, % %A_Gui%_Gui_Title,, %GUIX%, % GUIY+(A_Index)
               WinGetPos,  GUIX, GUIY,,, % %A_Gui%_Gui_Title
            }
            else
               break
         }
      }
      Else If (%A_Gui%_Hide_Direction == "D")
      {
         Loop
         {
            If (GUIY > A_ScreenHeight-%A_Gui%_GUIH) ; If the GUI is hidden, show it then break
            {
               WinMove, % %A_Gui%_Gui_Title,, %GUIX%, % GUIY-(A_Index)
               WinGetPos,  GUIX, GUIY,,, % %A_Gui%_Gui_Title
            }
            else
               break
         }
      }
      Else If (%A_Gui%_Hide_Direction == "R")
      {
         Loop
         {
            If (GUIX+%A_Gui%_GUIW > A_ScreenWidth+%A_Gui%_Number_Of_Offset_Pixels) ; If the GUI is hidden, show it then break
            {
               WinMove, % %A_Gui%_Gui_Title,, GUIX-A_Index, %GUIY%
               WinGetPos,  GUIX, GUIY,,, % %A_Gui%_Gui_Title
            }
            else
               break
         }
      }
      Else If (%A_Gui%_Hide_Direction == "L")
      {
         Loop
         {
            If (GUIX+%A_Gui%_Number_Of_Offset_Pixels < 0) ; If the GUI is hidden, show it then break
            {
               WinMove, % %A_Gui%_Gui_Title,, GUIX+A_Index, %GUIY%
               WinGetPos,  GUIX, GUIY,,, % %A_Gui%_Gui_Title
            }
            else
               break
         }
      }

      CoordMode, Mouse, Screen         ;get the mouse position in SCREEN MODE because your GUI is relative to the screen
      MouseGetPos, MX, MY
      CoordMode, Mouse, Relative
      If (%A_Gui%_Hide_Direction == "U" && MX >= %A_Gui%_GUIX && MX <= %A_Gui%_GUIX+%A_Gui%_GUIW && MY >= 0 && MY <= %A_Gui%_GUIH) ; Check if your mouse is still over the GUI (U)
      {
       goto, RestartGUIActivate  ;Restart if it is
      }
      Else If (%A_Gui%_Hide_Direction == "D" && MX >= %A_Gui%_GUIX && MX <= %A_Gui%_GUIX+%A_Gui%_GUIW && MY >= A_ScreenHeight-%A_Gui%_GUIH && MY-%A_Gui%_GUIH <= A_ScreenHeight) ; Check if your mouse is still over the GUI (D)
      {
       goto, RestartGUIActivate  ;Restart if it is
      }
      Else If (%A_Gui%_Hide_Direction == "R" && MX >= A_ScreenWidth-%A_Gui%_GUIW && MX <= A_ScreenWidth && MY >= %A_Gui%_GUIY && MY <= %A_Gui%_GUIY+%A_Gui%_GUIH) ; Check if your mouse is still over the GUI (R)
      {
       goto, RestartGUIActivate  ;Restart if it is
      }
      Else If (%A_Gui%_Hide_Direction == "L" && MX >= 0 && MX <= %A_Gui%_GUIW && MY >= %A_Gui%_GUIY && MY <= %A_Gui%_GUIY+%A_Gui%_GUIH) ; Check if your mouse is still over the GUI (L)
      {
       goto, RestartGUIActivate  ;Restart if it is
      }

      else ; If your mouse is not over the GUI, prepare to hide it.
      {
      %A_Gui%_TimeLapse := A_TickCount
      SetTimer, HideGUI%LabelDir%, 1000
      }
   }
}

}
;<06.05.000023>
SetButtonF(p*) {																											;-- Set a button control to call a function instead of a label subroutine

	/*			FUNCTION: SetButtonF
		_________________________________________________________________________________________

		FUNCTION: SetButtonF
		DESCRIPTION: Set a button control to call a function instead of a label subroutine
		PARAMETER(s):
			hButton := Button control's handle
			FunctionName := Name of fucntion to associate with button
		USAGE:
			Setting a button:
				SetButtonF(hButton, FunctionName)

			Retrieving the function name associated with a particular button:
				Func := SetButtonF(hButton) ; note: 2nd parameter omitted

			Disabling a function for a particular button(similar to "GuiControl , -G" option):
				SetButtonF(hButton, "") ; note: 2nd parameter not omitted but explicitly blank

			Disabling all functions for all buttons:
				SetButtonF() ; No parameters
		NOTES:
			The function/handler must have atleast two parameters, this function passes the
			GUI's hwndas the 1st parameter and the button's hwnd as the 2nd.
			Forum: http://www.autohotkey.com/board/topic/88553-setbuttonf-set-button-to-call-function/
		_________________________________________________________________________________________

	*/

	static WM_COMMAND := 0x0111 , BN_CLICKED := 0x0000
	static IsRegCB := false , oldNotify := {CBA: "", FN: ""} , B := [] , tmr := []
	if (A_EventInfo == tmr.CBA) { ; Call from timer
		DllCall("KillTimer", "UInt", 0, "UInt", tmr.tmr) ; Kill timer, one time only
		, tmr.func.(tmr.params*) ; Call function
		return DllCall("GlobalFree", "Ptr", tmr.CBA, "Ptr") , tmr := []
	}
	if (p.3 <> WM_COMMAND) { ; Not a Windows message ; call from user
		if !ObjHasKey(p, 1) { ; No passed parameter ; Clear all button-function association
			if IsRegCB {
				if B.MinIndex()
					B.Remove(B.MinIndex(), B.MaxIndex())
				, IsRegCB := false
				, OnMessage(WM_COMMAND, oldNotify.FN) ; reset to previous handler(if any)
				, oldNotify.CBA := "" , oldNotify.FN := "" ; reset
				return true
			}
		}
		if !WinExist("ahk_id " p.1) ; or !DllCall("IsWindow", "Ptr", p.1) ; Check if handle is valid
			return false ; Not a valid handle, control does not exist
		WinGetClass, c, % "ahk_id " p.1 ; Check if it's a button control
		if (c == "Button") {
			if p.2 { ; function name/reference has been specified, store/associate it
				if IsFunc(p.2) ; Function name is specified
					B[p.1, "F"] := Func(p.2)
				if (IsObject(p.2) && IsFunc(p.2.Name)) ; Function reference/object is specified
					B[p.1, "F"] := p.2
				if !IsRegCB { ; No button(s) has been set yet , callback has not been registered
					fn := OnMessage(WM_COMMAND, A_ThisFunc)
					if (fn <> A_ThisFunc) ; if there's another handler
						oldNotify.CBA := RegisterCallback((oldNotify.FN := fn)) ; store it
					IsRegCB := true
				}
			} else { ; if 2nd parameter(Function name) is explicitly blank or omitted
				if ObjHasKey(B, p.1) { ; check if button is in the list
					if !ObjHasKey(p, 2) ; Omitted
						return B[p.1].F.Name ; return Funtion Name associated with button
					else { ; Explicitly blank
						B.Remove(p.1, "") ; Disassociate button with function, remove from internal array
						if !B.MinIndex() ; if last button in array
							SetButtonF() ; Reset everything
					}
				}
			}
			return true ; successful
		} else
			return false ; not a button control
	} else { ; WM_COMMAND
		if ObjHasKey(B, p.2) { ; Check if control is in internal array
			lo := p.1 & 0xFFFF ; Control identifier
			hi := p.1 >> 16 ; notification code
			if (hi == BN_CLICKED) { ; Normal, left button
				tmr := {func: B[p.2].F, params: [p.4, p.2]} ; store button's associated function ref and params
				, tmr.CBA := RegisterCallback(A_ThisFunc, "F", 4) ; create callback address
				; Create timer, this allows the function to finish processing the message immediately
				, tmr.tmr := DllCall("SetTimer", "UInt", 0, "UInt", 0, "Uint", 120, "UInt", tmr.CBA)
			}
		} else { ; Other control(s)
			if (oldNotify.CBA <> "") ; if there is a previous handler for WM_COMMAND, call it
				DllCall(oldNotify.CBA, "UInt", p.1, "UInt", p.2, "UInt", p.3, "UInt", p.4)
		}
	}
} ;</06.05.000023>
;<06.05.000024>
AddToolTip(hControl,p_Text)  {                                                                              		;-- Add/Update tooltips to GUI controls.


    /*      Description

        Function: AddToolTip

        Description:

          Add/Update tooltips to GUI controls.

        Parameters:

          hControl - Handle to a GUI control.

          p_Text - Tooltip text.

        Returns:

          Handle to the tooltip control.

        Remarks:

        * This function accomplishes this task by creating a single Tooltip control
          and then creates, updates, or delete tools which are/were attached to the
          individual GUI controls.

        * This function returns the handle to the Tooltip control so that, if desired,
          additional actions can be performed on the Tooltip control outside of this
          function.  Once created, this function reuses the same Tooltip control.
          If the tooltip control is destroyed outside of this function, subsequent
          calls to this function will fail.  If desired, the tooltip control can be
          destroyed just before the script ends.

        Credit and History:

        * Original author: Superfraggle
          Post: <http://www.autohotkey.com/board/topic/27670-add-tooltips-to-controls/>

        * Updated to support Unicode: art
          Post: <http://www.autohotkey.com/board/topic/27670-add-tooltips-to-controls/page-2#entry431059>

        * Additional: jballi
          Bug fixes.  Added support for x64.  Removed Modify parameter.  Added
          additional functionality, documentation, and constants.

*/

    Static hTT

          ;-- Misc. constants
          ,CW_USEDEFAULT:=0x80000000
          ,HWND_DESKTOP :=0
          ,WS_EX_TOPMOST:=0x8

          ;-- Tooltip styles
          ,TTS_ALWAYSTIP:=0x1
                ;-- Indicates that the ToolTip control appears when the cursor
                ;   is on a tool, even if the ToolTip control's owner window is
                ;   inactive. Without this style, the ToolTip appears only when
                ;   the tool's owner window is active.

          ,TTS_NOPREFIX:=0x2
                ;-- Prevents the system from stripping ampersand characters from
                ;   a string or terminating a string at a tab character. Without
                ;   this style, the system automatically strips ampersand
                ;   characters and terminates a string at the first tab
                ;   character. This allows an application to use the same string
                ;   as both a menu item and as text in a ToolTip control.

          ;-- TOOLINFO uFlags
          ,TTF_IDISHWND:=0x1
                ;-- Indicates that the uId member is the window handle to the
                ;   tool.  If this flag is not set, uId is the identifier of the
                ;   tool.

          ,TTF_SUBCLASS:=0x10
                ;-- Indicates that the ToolTip control should subclass the
                ;   window for the tool in order to intercept messages, such
                ;   as WM_MOUSEMOVE. If you do not set this flag, you must use
                ;   the TTM_RELAYEVENT message to forward messages to the
                ;   ToolTip control.  For a list of messages that a ToolTip
                ;   control processes, see TTM_RELAYEVENT.

          ;-- Messages
          ,TTM_ADDTOOLA      :=0x404                    ;-- WM_USER + 4
          ,TTM_ADDTOOLW      :=0x432                    ;-- WM_USER + 50
          ,TTM_DELTOOLA      :=0x405                    ;-- WM_USER + 5
          ,TTM_DELTOOLW      :=0x433                    ;-- WM_USER + 51
          ,TTM_GETTOOLINFOA  :=0x408                    ;-- WM_USER + 8
          ,TTM_GETTOOLINFOW  :=0x435                    ;-- WM_USER + 53
          ,TTM_SETMAXTIPWIDTH:=0x418                    ;-- WM_USER + 24
          ,TTM_UPDATETIPTEXTA:=0x40C                    ;-- WM_USER + 12
          ,TTM_UPDATETIPTEXTW:=0x439                    ;-- WM_USER + 57

    ;-- Workarounds for AutoHotkey Basic and x64
    PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"
    PtrSize:=A_PtrSize ? A_PtrSize:4

    ;-- Save/Set DetectHiddenWindows
    l_DetectHiddenWindows:=A_DetectHiddenWindows
    DetectHiddenWindows On

    ;-- Tooltip control exists?
    if not hTT
        {
        ;-- Create Tooltip window
        hTT:=DllCall("CreateWindowEx"
            ,"UInt",WS_EX_TOPMOST                       ;-- dwExStyle
            ,"Str","TOOLTIPS_CLASS32"                   ;-- lpClassName
            ,"UInt",0                                   ;-- lpWindowName
            ,"UInt",TTS_ALWAYSTIP|TTS_NOPREFIX          ;-- dwStyle
            ,"UInt",CW_USEDEFAULT                       ;-- x
            ,"UInt",CW_USEDEFAULT                       ;-- y
            ,"UInt",CW_USEDEFAULT                       ;-- nWidth
            ,"UInt",CW_USEDEFAULT                       ;-- nHeight
            ,"UInt",HWND_DESKTOP                        ;-- hWndParent
            ,"UInt",0                                   ;-- hMenu
            ,"UInt",0                                   ;-- hInstance
            ,"UInt",0                                   ;-- lpParam
            ,PtrType)                                   ;-- Return type

        ;-- Disable visual style
        DllCall("uxtheme\SetWindowTheme",PtrType,hTT,PtrType,0,"UIntP",0)

        ;-- Set the maximum width for the tooltip window
        ;   Note: This message makes multi-line tooltips possible
        SendMessage TTM_SETMAXTIPWIDTH,0,A_ScreenWidth,,ahk_id %hTT%
        }

    ;-- Create/Populate TOOLINFO structure
    uFlags:=TTF_IDISHWND|TTF_SUBCLASS
    cbSize:=VarSetCapacity(TOOLINFO,8+(PtrSize*2)+16+(PtrSize*3),0)
    NumPut(cbSize,      TOOLINFO,0,"UInt")              ;-- cbSize
    NumPut(uFlags,      TOOLINFO,4,"UInt")              ;-- uFlags
    NumPut(HWND_DESKTOP,TOOLINFO,8,PtrType)             ;-- hwnd
    NumPut(hControl,    TOOLINFO,8+PtrSize,PtrType)     ;-- uId

    VarSetCapacity(l_Text,4096,0)
    NumPut(&l_Text,     TOOLINFO,8+(PtrSize*2)+16+PtrSize,PtrType)
        ;-- lpszText

    ;-- Check to see if tool has already been registered for the control
    SendMessage
        ,A_IsUnicode ? TTM_GETTOOLINFOW:TTM_GETTOOLINFOA
        ,0
        ,&TOOLINFO
        ,,ahk_id %hTT%

    RegisteredTool:=ErrorLevel

    ;-- Update TOOLTIP structure
    NumPut(&p_Text,TOOLINFO,8+(PtrSize*2)+16+PtrSize,PtrType)
        ;-- lpszText

    ;-- Add, Update, or Delete tool
    if RegisteredTool
        {
        if StrLen(p_Text)
            SendMessage
                ,A_IsUnicode ? TTM_UPDATETIPTEXTW:TTM_UPDATETIPTEXTA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%
         else
            SendMessage
                ,A_IsUnicode ? TTM_DELTOOLW:TTM_DELTOOLA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%
        } ;</06.05.000024>
    else
        if StrLen(p_Text)
            SendMessage
                ,A_IsUnicode ? TTM_ADDTOOLW:TTM_ADDTOOLA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%

    ;-- Restore DetectHiddenWindows
    DetectHiddenWindows %l_DetectHiddenWindows%

    ;-- Return the handle to the tooltip control
    Return hTT
}
;<06.05.000025>
HelpToolTips( _Delay = 300, _Duration = 0 ) {                                                       		;--  To show defined GUI control help tooltips on hover.
    _fn := Func( "WM_MOUSEMOVE" ).Bind( _Delay, _Duration )
    OnMessage( 0x200, _fn )
} ;</06.05.000025>
{ ;sub
WM_MOUSEMOVE( _Delay = 300, _Duration = 0 ) {
    static CurrControl, PrevControl, _TT
    CurrControl := A_GuiControl
    if ( CurrControl != PrevControl ) {
        SetTimer, DisplayToolTip, % _Delay
        if ( _Duration )
            SetTimer, RemoveToolTip, % _Delay + _Duration
        PrevControl := CurrControl
    }
    return

    DisplayToolTip:
        SetTimer, DisplayToolTip, Off
        try
            ToolTip % %CurrControl%_TT
        catch
            ToolTip
    return

    RemoveToolTip:
        SetTimer, RemoveToolTip, Off
        ToolTip
    return
}
}
;<06.05.000026>
DisableFadeEffect() {																									;-- disabling fade effect on gui animations

	/*				DESCRIPTION

		You can put that code top of your script and you dont need to call that again...
		It removes bad fade effect on gui when we use Imaged Button Class/imaged buttons/checks/radios/progress bars....

		Source : https://autohotkey.com/boards/viewtopic ... 23#p129823

	*/

	; SPI_GETCLIENTAREAANIMATION = 0x1042
	DllCall("SystemParametersInfo", "UInt", 0x1042, "UInt", 0, "UInt*", isEnabled, "UInt", 0)

	if isEnabled {
		; SPI_SETCLIENTAREAANIMATION = 0x1043
		DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 0, "UInt", 0)
		Progress, 10:P100 Hide
		Progress, 10:Off
		DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 1, "UInt", 0)
	}

} ;</06.05.000026>
;<06.05.000027>
SetWindowTransistionDisable(hwnd,onOff) {																;-- disabling fade effect only the window of choice

	/*				DESCRIPTION

		DWMWA_TRANSITIONS_FORCEDISABLED=3
		Use with DwmSetWindowAttribute. Enables or forcibly disables DWM transitions.
		The pvAttribute parameter points to a value of TRUE to disable transitions or FALSE to enable transitions.

		This only affects the windows of choise, while
			SystemParametersInfo wrote:
			Retrieves or sets the value of one of the system-wide parameters.

	*/

	/*				EXAMPLE

			#SingleInstance, force
			Gui, new, +hwndguiId
			Dwm_SetWindowAttributeTransistionDisable(guiId,1)
			Gui, show, w300 h200
			Sleep,2000
			Gui,destroy
			Exitapp

	*/

	dwAttribute:=3
	cbAttribute:=4
	VarSetCapacity(pvAttribute,4,0)
	NumPut(onOff,pvAttribute,0,"Int")
	hr:=DllCall("Dwmapi.dll\DwmSetWindowAttribute", "Uint", hwnd, "Uint", dwAttribute, "Uint", &pvAttribute, "Uint", cbAttribute)
	return hr
} ;</06.05.000027>
;<06.05.000028>
DisableMinimizeAnim(disable) {                                                                              	;-- disables or restores original minimize anim setting

	static original,lastcall
	if (disable && !lastcall) ;Backup original value if disabled is called the first time after a restore call
	{
		lastcall := 1
		RegRead, original, HKCU, Control Panel\Desktop\WindowMetrics , MinAnimate
	}
	else if (!disable) ;this is a restore call, on next disable backup may be created again
		lastcall := 0
	;Disable Minimize/Restore animation
	VarSetCapacity(struct, 8, 0)
	NumPut(8, struct, 0, "UInt")
	if (disable || !original)
		NumPut(0, struct, 4, "Int")
	else
		NumPut(1, struct, 4, "UInt")
	DllCall("SystemParametersInfo", "UINT", 0x0049,"UINT", 8,"Ptr", &struct,"UINT", 0x0003) ;SPI_SETANIMATION            0x0049 SPIF_SENDWININICHANGE 0x0002
} ;</06.05.000028>
;<06.05.000029>
DisableCloseButton(hWnd) {																						;-- to disable/grey out the close button
	; Skan (https://autohotkey.com/board/topic/80593-how-to-disable-grey-out-the-close-button/)
	hSysMenu:=DllCall("GetSystemMenu","Int",hWnd,"Int",FALSE)
	nCnt:=DllCall("GetMenuItemCount","Int",hSysMenu)
	DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-1,"Uint","0x400")
	DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-2,"Uint","0x400")
	DllCall("DrawMenuBar","Int",hWnd)
} ;</06.05.000029>
;<06.05.000030>
AutoCloseBlockingWindows(WinID, autoclose:=2) {													;-- close all open popup (childwindows), without knowing their names, of a parent window

	;by Ixiko 2018 - https://autohotkey.com/boards/viewtopic.php?f=6&t=52418

/* 								Beschreibung

		Parameterliste
		1. autoclose = 0
			ausschließlich Rückgabe eines Objektes mit zwei Key:Value Paaren, a) true/false für ist blockiert und b) Name des blockierenden Fensters
		2. autoclose = 1
			Rückgabe des oben genannten Objektes und sendet eine Nachfrage an den User ob die blockierenden Fenster geschlossen werden dürfen
        3. autoclose = 2
			alle blockierenden Fenster werden ohne Rückfrage geschlossen, es werden keine Werte zurück gegeben

 		von der Funktion AutoCloseBlockingWindows() bekommt sie den Rückgabewert (errorStr), den sie an die aufrufende Prozeß weiter reicht.
		Dieser String gibt den Erfolg oder Mißerfolg zurück , damit der Prozeß Fehler erkennen kann um sich wenn notwendig zu beenden oder
        andere Maßnahmen einzuleiten die zum Erfolg führen könnten
*/

/*                              	DESCRIPTION

			The function offers 3 possibilities
			1. autoclose = 0
				only returning an object with two Key: Value pairs, "isblocked":  true / false for is blocked and "blockWinT": name of the blocking window,
				"errorStr": is allways empty in this case
			2. autoclose = 1
				Returns the above object and sends an inquiry to the user if the blocking windows may be closed
			3. autoclose = 2
				all blocking windows are closed without further inquiry, no values ​​are returned

			It gets it return value (errorStr) from function AutoCloseBlockingWindows() , which it passes on to the calling process.
			This string returns the success or failure, so that the process can detect errors, to terminate itself, if necessary, or
			        to take other actions that could lead to success

*/

	errorStr:=""
	 ; WS_DISABLED:= 0x8000000
	WinGet, Style, Style, ahk_id %WinID%
	blocked:= (Style & 0x8000000) ? true : false
	;which window is blocking this window hwnd
	phwnd:= DLLCall("GetLastActivePopup", "uint", WinID)
	WinGetTitle, title, ahk_id %phwnd%


	if (autoclose=1) {
			MsgBox, 4, Note, Your main window is blocked`n by one or more popup windows.`n`nShould all windows be closed now?
			IfMsgBox, Yes
				gosub WinCloseLastActivePopup
	} else if (autoclose=2) {
			gosub WinCloseLastActivePopups
	}

	return {"isblocked": blocked, "blockWinT": title, "errorStr": errorStr}

WinCloseLastActivePopups:

	Loop {

				WinGet, Style, Style, ahk_id %WinID%
				blocked:= (Style & 0x8000000) ? true : false
				if !blocked
				{
						errorStr:=""
						break
				}

				phwnd:= DLLCall("GetLastActivePopup", "uint", WinID)
					;3 different attempts to close the window from "gentle" to "powerful"
				PostMessage, 0x112, 0xF060,,, ahk_id %phwnd%  ; 0x112 = WM_SYSCOMMAND, 0xF060 = SC_CLOSE
				If ErrorLevel
					WinClose, ahk_id %pHwnd%
				If ErrorLevel
						WinKill, ahk_id %pHwnd%
				If ErrorLevel {
					WinGetTitle, title, ahk_id %pHwnd%
					throw Exception("Can not close entire window : '" . title . "' `n. The function AutoCloseBlockingWindows stops here.", -1)
					errorStr:="noClose"
					break
				}

				sleep 200

			}

return

} ;</06.05.000030>
;<06.05.000031>
WinActivateEx(WinTitle, WinText="", Seconds=30, Keys="", OnlyIfExist = false) {		;-- Activate a Window, with extra Error Checking and More Features

	/*                              	DESCRIPTION

			Func: WinActivateEx
			Activate a Window, with extra Error Checking and More Features

			<paste FunctionNameEx>DetectHiddenWindows On

			<paste WinProcParams>Keys := CmdSwitch(WinTitle, "-k", Keys)

	*/


   ;   SetTitleMatchMode Regex
   ; Kill Vista Thumbnails.  These hang around a lot, and they're never what you want to activate.

   if (Seconds == "")
      Seconds := 30

   if (OnlyIfExist && !WinExist(WinTitle))
      return false

   WinWait %WinTitle%, %WinText%, %Seconds%
   AssertNoError(ProcList("WinActivateEx - Waiting", WinTitle, WinText, Seconds))

   WinShow %WinTitle%
   WinActivate %WinTitle%, %WinText%
   WinWaitActive %WinTitle%, %WinText%
   AssertNoError(ProcList("WinActivateEx - WaitActive", WinTitle, WinText, Seconds))

   if (Keys)
      SendInput %Keys%

   return true
} ;</06.05.000031>
;<06.05.000032>
ClickOK(Window="") {																									;-- function that search for any button in a window that might be an 'Ok' button to close a window dialog

	/*                              	DESCRIPTION

			-------------------------------------------------------------------------------------------------------------
			 Func: ClickOK
			 Click on the OK, Yes, Save, whatever button that passes for OK on this form.  It's a handy function that I
			 bind to something like \c nter or \c Enter that basically clicks the \c OK button in a dialog box. I have
			 a list of buttons that are generally considered OK like buttons, and I click on the first one that can be
			 found. You can extend the list as necessary.

			 You can also specify a window that you want this to apply to. If you do so, then that window will be given
			 focus before the button is clicked.  If it's  not found the whole action is called off.  If you do not specify a
			 window, then the window that has focus is used. This is by far the more common case, the case where you pass
			 a window is a quick and dirty way to add support for clicking on the OK button in a script without having to
			 figure out what the OK button is.

			 Parameters:
			 Window -     Window to click on. If this is passed, this window will be the one that gets clicked. The
			              timeout is set to 10 seconds.

			 Returns:
			 \c True if the OK button was clicked on. It is not actually mean that the OK button's action was
			 successful... just that we found an OK like button, and clicked on it.

			 Note:
			 The initial list of OK-Like buttons includes
			 <c>OK,Save,Accept,Open,Yes,Save and Close,Connect,Send,Next,Finish,Find Next,&Save,&Yes</c>, and you can
			 edit it to add more.
			-------------------------------------------------------------------------------------------------------------

	*/


   ; Common delimited list of keys that could pass as an OK button
   Keys := "OK,Save,Accept,Open,Yes,Save and Close,Connect,Send,Next,Finish,Find Next,&Save,&Yes, Ja, &Ja"

   ; If this is for a specific window, wait up to 10 seconds for it
   if (Window) {

      WinWait %Window%, , 10
      if (ErrorLevel)
         Return
      WinActivate %Window%
   }

   ; Parse the list of keys in the order in which they appear, and for each key see if we can find button. If
   ; we find button, then click on it. Note that the processing for finding the button seems little
   ; convoluted. This is necessary to get to work in a lot of MDI windows.
   Loop, Parse, Keys, `,
   {
      ControlGet Handle, hWnd, , %A_LoopField%, A
      if (Handle)
      {
         ControlGet En, Enabled, , %A_LoopField%, A
         if (En)
         {
            ControlClick %A_LoopField%, A
            Return true
         }
      }
   }

   Return false
} ;</06.05.000032>
;<06.05.000033>
ControlSelectTab(Index, Ctl, Win) {																				;-- SendMessage wrapper to select the current tab on a MS Tab Control.
	/*                              	DESCRIPTION

			 Func: ControlSelectTab
			 Select the current tab on a MS Tab Control.

			 Parameters:
			 Index  - Tab index to select.  0 is the first tab.
			 Ctl    - Name of the control as detected via Window Spy
			 Win    - Window to send it to

			 Returns:
			 Appropriate tab selected.

	*/

   SendMessage, 0x1330, %Index%,, %Ctl%, %Win%
} ;</06.05.000033>
;<06.05.000034>
SetParentByClass(Window_Class, Gui_Number) { 														;-- set parent window by using its window class
	;Code by sidola
	;https://autohotkey.com/boards/viewtopic.php?t=26809
	Parent_Handle := DllCall( "FindWindowEx", "uint",0, "uint",0, "str", Window_Class, "uint",0)
	Gui, %Gui_Number%: +LastFound
	Return DllCall( "SetParent", "uint", WinExist(), "uint", Parent_Handle )
} ;</06.05.000034>
;<06.05.000035>
MoveTogether(wParam, lParam, _, hWnd) { 																;-- move 2 windows together - using DllCall to DeferWindowPos

	/*                              	DESCRIPTION

				Link: https://autohotkey.com/boards/viewtopic.php?t=43192
				AutoExec in Script or inside function
				;---------------------------------------------
			    CoordMode, Mouse, Screen    ; for MouseGetPos
			    SetBatchLines, -1           ; for onMessage
			    SetWinDelay, -1             ; for WinActivate
			    ;---------------------------------------------

				 call MoveTogether(Handles) with an array of handles
				 to set up a bundle of AHK Gui's that move together

				 https://autohotkey.com/boards/viewtopic.php?p=199402#p199402
				 version 2018.02.08
	*/

	/*                              	EXAMPLE(s)

			NoEnv
			SingleInstance Force
			Include, MoveTogether.ahk

			    Handles := []

			    Loop, 3
			        Gui, %A_Index%: New, hwndhWin%A_Index%, Window %A_Index%
			        Gui, Show, % "x" A_Index * 280 " y100 w250 h200"
			        Handles.Push(hWin%A_Index%)


			Return

			GuiClose:
			ExitApp

	*/

    static init := OnMessage(0xA1, "MoveTogether") ; WM_NCLBUTTONDOWN
    static Handles

	If IsObject(wParam)             ; detect a set up call
		Return, Handles := wParam   ; store the array of handles

    If (wParam != 2) ; HTCAPTION
        Return

    ; changing AHK settings here will have no side effects
    CoordMode, Mouse, Screen    ; for MouseGetPos
    SetBatchLines, -1           ; for onMessage
    SetWinDelay, -1             ; for WinActivate, WinMove

    M_old_X := lParam & 0xFFFF, M_old_Y := lParam >> 16 & 0xFFFF
    WinActivate, ahk_id %hWnd%

    Win := {}
    For each, Handle in Handles {
        WinGetPos, X, Y, W, H, ahk_id %Handle%
        Win[Handle] := {X: X, Y: Y, W: W, H: H}
    }

    While GetKeyState("LButton", "P") {
        MouseGetPos, M_new_X, M_new_Y
        dX := M_new_X - M_old_X, M_old_X := M_new_X
      , dY := M_new_Y - M_old_Y, M_old_Y := M_new_Y

        If GetKeyState("Shift", "P")
            WinMove, ahk_id %hWnd%,, Win[hWnd].X += dX, Win[hWnd].Y += dY

        Else { ; DeferWindowPos cycle
            hDWP := DllCall("BeginDeferWindowPos", "Int", Handles.Length(), "Ptr")
            For each, Handle in Handles
                hDWP := DllCall("DeferWindowPos", "Ptr", hDWP
                    , "Ptr", Handle, "Ptr", 0
                    , "Int", Win[Handle].X += dX
                    , "Int", Win[Handle].Y += dY
                    , "Int", Win[Handle].W
                    , "Int", Win[Handle].H
                    , "UInt", 0x214, "Ptr")
            DllCall("EndDeferWindowPos", "Ptr", hDWP)
        }
    }
} ;</06.05.000035>
;<06.05.000036>
WinWaitCreated( WinTitle:="", WinText:="", Seconds:=0, 											;-- Wait for a window to be created, returns 0 on timeout and ahk_id otherwise
ExcludeTitle:="", ExcludeText:="" ) {

	/*                              	DESCRIPTION

			Wait for a window to be created, returns 0 on timeout and ahk_id otherwise
			Parameter are the same as WinWait, see http://ahkscript.org/docs/commands/WinWait.htm
			Link: 					http://ahkscript.org/boards/viewtopic.php?f=6&t=1274&p=8517#p8517
			Dependencies: 	none

	*/


    ; HotKeyIt - http://ahkscript.org/boards/viewtopic.php?t=1274
    static Found := 0, _WinTitle, _WinText, _ExcludeTitle, _ExcludeText
         , init := DllCall( "RegisterShellHookWindow", "UInt",A_ScriptHwnd )
         , MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" )
         , cleanup:={base:{__Delete:"WinWaitCreated"}}
  If IsObject(WinTitle)   ; cleanup
    return DllCall("DeregisterShellHookWindow","PTR",A_ScriptHwnd)
  else if (Seconds <> MsgNum){ ; User called the function
    Start := A_TickCount, _WinTitle := WinTitle, _WinText := WinText
    ,_ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText
    ,OnMessage( MsgNum, A_ThisFunc ),  Found := 0
    While ( !Found && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) )
      Sleep 16
    Return Found,OnMessage( MsgNum, "" )
  }
  If ( WinTitle = 1   ; window created, check if it is our window
    && ExcludeTitle = A_ScriptHwnd
    && WinExist( _WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText))
    WinWait % "ahk_id " Found := WinText ; wait for window to be shown
} ;</06.05.000036>
;<06.05.000037>
closeContextMenu() {																									;-- a smart way to close a context menu

	;https://autohotkey.com/board/topic/23859-how-to-detect-and-close-a-context-menu/
	GuiThreadInfoSize = 48
	VarSetCapacity(GuiThreadInfo, 48)
	NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
	if not DllCall("GetGUIThreadInfo", uint, 0, str, GuiThreadInfo)
	{
		MsgBox GetGUIThreadInfo() indicated a failure.
		return
	}
	; GuiThreadInfo contains a DWORD flags at byte 4
	; Bit 4 of this flag is set if the thread is in menu mode. GUI_INMENUMODE = 0x4
	if (NumGet(GuiThreadInfo, 4) & 0x4)
		send {escape}
} ;</06.05.000037>
;<06.05.000038>
SetWindowTheme(handle) {																						;-- set Windows UI Theme by window handle

	; https://github.com/jNizM/ahk_pi-hole/blob/master/src/pi-hole.ahk
	 ; https://msdn.microsoft.com/en-us/library/bb759827(v=vs.85).aspx
	global WINVER

	if (WINVER >= 0x0600) {
		VarSetCapacity(ClassName, 1024, 0)
		if (DllCall("user32\GetClassName", "ptr", handle, "str", ClassName, "int", 512, "int"))
			if (ClassName = "SysListView32") || (ClassName = "SysTreeView32")
				if !(DllCall("uxtheme\SetWindowTheme", "ptr", handle, "wstr", "Explorer", "ptr", 0))
					return true
	}
	return false
} ;</06.05.000038>
;<06.05.000039>
HideFocusBorder(wParam, lParam := "", Msg := "", handle := "") {								;-- hides the focus border for the given GUI control or GUI and all of its children

	/*                              	DESCRIPTION

			 by 'just me'
			 Hides the focus border for the given GUI control or GUI and all of its children.
			 Call the function passing only the HWND of the control / GUI in wParam as only parameter.
			 WM_UPDATEUISTATE  -> msdn.microsoft.com/en-us/library/ms646361(v=vs.85).aspx
			 The Old New Thing -> blogs.msdn.com/b/oldnewthing/archive/2013/05/16/10419105.aspx

	*/
	/*                              	EXAMPLE(s)

			NoEnv
			SetBatchLines, -1
			Menu, File, Add, &Quit, GuiCLose
			Menu, MenuBar, Add, &File, :File
			Gui, HwndHGUI
			Gui, Menu, MenuBar
			Gui, Add, Text, , Slider:
			Gui, Add, Slider, xp%0 w200 NoTicks ToolTip hwndHSL
			Gui, Show, , Test
			HideFocusBorder(HGUI)
			Return
			GuiClose:
			ExitApp

	*/

	static Affected         := []
	static WM_UPDATEUISTATE := 0x0128
	static SET_HIDEFOCUS    := 0x00010001 ; UIS_SET << 16 | UISF_HIDEFOCUS
	static init             := OnMessage(WM_UPDATEUISTATE, Func("HideFocusBorder"))

	if (Msg = WM_UPDATEUISTATE) {
		if (wParam = SET_HIDEFOCUS)
			Affected[handle] := true
		else if Affected[handle]
			DllCall("user32\PostMessage", "ptr", handle, "uint", WM_UPDATEUISTATE, "ptr", SET_HIDEFOCUS, "ptr", 0)
	}
	else if (DllCall("IsWindow", "ptr", wParam, "uint"))
		DllCall("user32\PostMessage", "ptr", wParam, "uint", WM_UPDATEUISTATE, "ptr", SET_HIDEFOCUS, "ptr", 0)
} ;</06.05.000039>
;<06.05.000040>
unmovable() {																												;-- makes Gui unmovable
	; make Gui unmovable -code by SKAN-
Gui 2:+LastFound
Gui1 := WinExist()
hSysMenu:=DllCall("GetSystemMenu","Int",Gui1,"Int",FALSE)
nCnt:=DllCall("GetMenuItemCount","Int",hSysMenu)
DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-6,"Uint","0x400")
DllCall("DrawMenuBar","Int",Gui1)
; end block
} ;</06.05.000040>
;<06.05.000041>
movable() {																													;-- makes Gui movable
Gui 2:+LastFound
Gui1 := WinExist()
 DllCall( "GetSystemMenu", UInt,Gui1, Int,True )
Return DllCall( "DrawMenuBar", UInt,Gui1 ) ? 1 : 0
} ;</06.05.000041>
;<06.05.000042>
GuiDisableMove(handle) {                       																	;-- to fix a gui/window to its coordinates
    hMenu := DllCall("user32\GetSystemMenu", "ptr", handle, "int", false, "ptr")
    DllCall("user32\RemoveMenu", "ptr", hMenu, "uint", 0xf010, "uint", 0x0)
    return DllCall("user32\DrawMenuBar", "ptr", handle)
} ;</06.05.000042>
;<06.05.000043>
WinInsertAfter(hwnd, afterHwnd) {																				;-- insert a window after a specific window handle
	return DllCall("SetWindowPos", "UINT", hwnd, "UINT", afterHwnd, "INT", 0, "INT", 0, "INT", 0, "INT", 0, "UINT", 0x0013)
} ;</06.05.000043>
;{ sub WinInsertAfter
;first=top
WinStack(ByRef arr){
	for k,v in arr {
		if(k=1)
			winactivate,% v
		else if (v)
			WinInsertAfter(v, last)
		last:=v?v:last

	}
}
;}
;<06.05.000044>
CenterWindow(hWnd, Pos := "") {																				;-- center a window or set position optional by using Top, Left, Right, Bottom or a combination of it

	/*                              	DESCRIPTION

			Syntax: CenterWindow ([ID], [Position])
			Position: can be combined
			Center = center window.
				Top | Bottom = position up. position down.
				Left | Right = position to the left. position to the right.
			Notes:
			• if the window is maximized, the width or height is modified depending on the position.
					--> if it is positioned up or down, the height is modified	(A_ScreenHeight/2-10%).
					--> if it is positioned to the left or to the right, the width is modified (A_ScreenWidth/2-10%).
			• the window fits the visible screen, regardless of the position of the taskbar (the window is not blocked by the taskbar)

	*/

	/*                              	EXAMPLE(s)

			   WindowActive(WinExist("ahk_class Notepad"), true)
				MsgBox % "Center window: " CenterWindow(WinExist("ahk_class Notepad"))
				MsgBox % "Position up on the left: " CenterWindow(WinExist("ahk_class Notepad"), "Top Left")
				MsgBox % "Position up on the right: " CenterWindow(WinExist("ahk_class Notepad"), "Top Right")
				MsgBox % "Position down to the left: " CenterWindow(WinExist("ahk_class Notepad"), "Bottom Left")
				MsgBox % "Position down to the right: " CenterWindow(WinExist("ahk_class Notepad"), "Bottom Right")
				MsgBox % "Position up and center: " CenterWindow(WinExist("ahk_class Notepad"), "Top Center")
				MsgBox % "Position down and center: " CenterWindow(WinExist("ahk_class Notepad"), "Bottom Center")
				MsgBox % "Position to the left and center it: " CenterWindow(WinExist("ahk_class Notepad"), "Left Center")
				MsgBox % "Position to the right and center it: " CenterWindow(WinExist("ahk_class Notepad"), "Right Center")

	*/


	_gethwnd(hWnd), GetWindowPos(hWnd, x, y, w, h)
	, m := GetMonitorInfo(MonitorFromWindow(hWnd)), mx := m.wLeft, my := m.wTop, mw := m.wRight-mx, mh := m.wBottom-my
	, T := InStr(Pos, "Top"), B := InStr(Pos, "Bottom"), L := InStr(Pos, "Left"), R := InStr(Pos, "Right"), C := InStr(Pos, "Center")
	if WinMax(hWnd)
		w := (L||R)?Percent(mw/2, 10):mw, h := (T||B)?Percent(mh/2, 10):mh
	if (T) || (B) || (L) || (R)
		return MoveWindow(hWnd, (L?0:R?(mw-w):C?((mw/2)-(w/2)):x) +mx, (T?0:B?(mh-h):C?((mh/2)-(h/2)):y) +my, w, h)
	return MoveWindow(hWnd, ((mw/2) - (w/2)) +mx, ((mh/2) - (h/2)) +my, w, h)
} ;</06.05.000044>
;<06.05.000045>
SetHoverText(CtrlHwnd, HoverText = "", msg = "", hwnd = "") {                               	;-- change control's text on mouseover

		/*    	DESCRIPTION of function SetHoverText()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Change control's text on mouseover
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=1767
			Author         	:	tmplinshi
			Date	            	:	29-Jan-2014
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	Gui, Controls, MouseMove
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			Gui, Add, GroupBox, hwndhctrl, test
			SetHoverText(hctrl, "New text")
			Gui, Add, Button, hwndhctrl, abc
			SetHoverText(hctrl, "123")
			Gui, Show
			Return

			GuiClose:
				ExitApp
			Return

	*/


	static CtrlArray       := []
	static WM_MOUSEMOVE    := OnMessage( 0x200, "SetHoverText" )
	static WM_NCMOUSELEAVE := OnMessage( 0x2A2, "SetHoverText" )
	static ChangedHwnd

	; Setup hover control
	if !msg ; Called from fuction, not OnMessage.
	{
		ControlGetText, OrigText,, ahk_id %CtrlHwnd% ; GuiControl can't get the control's text of a non-default GUI.
		GuiHwnd := DllCall("GetParent", "UInt", CtrlHwnd)
		CtrlArray[CtrlHwnd] := { OrigText: OrigText, HoverText: HoverText, GuiHwnd: GuiHwnd }

		SetTimer, __CheckIfMouseIsOutsideGui, 100 ; WM_NCMOUSELEAVE won't execute when mouse moving too fast.
		Return
	}

	MouseGetPos,,,, hwnd, 2 ; Button / Radio / Checkbox don't need this line.

	if CtrlArray.HasKey(hwnd) ; Mouse is over at a defined control.
	{
		if !ChangedHwnd ; Button's text only change once, when mouse moving inside the control.
		{
			GuiControl,, %hwnd%, % CtrlArray[hwnd]["HoverText"]
			ChangedHwnd := hwnd
		}
	}
	else if ChangedHwnd
	{
		GuiControl,, %ChangedHwnd%, % CtrlArray[ChangedHwnd]["OrigText"]
		ChangedHwnd := ""
	}

	Return

	__CheckIfMouseIsOutsideGui:
		if !ChangedHwnd
			Return

		MouseGetPos,,, hWin
		if ( hWin != CtrlArray[ChangedHwnd]["GuiHwnd"] )
		{
			GuiControl,, %ChangedHwnd%, % CtrlArray[ChangedHwnd]["OrigText"]
			ChangedHwnd := ""
		}
	Return
} ;</06.05.000045>
;<06.05.000046>
SetTextAndResize(controlHwnd, newText) {                                                           	;-- resizes a control to adapt to updated values

	/*	DESCRIPTION OF FUNCTION: -- SetTextAndResize --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	resize a control to adapt to updated values
	Link              	:	https://stackoverflow.com/questions/49335431/autohotkey-dynamic-resize-control-based-on-text
	Author         	:	Josh Brobst
	Date             	:	March 19, 2018
	AHK-Version	:	AHK_L
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:	gui,control,resize,responsive
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
		FormatTime, time,
		Gui, Add, Text, HwndTimeHwnd vcTime,
		SetTextAndResize(TimeHwnd, time)
		Gui, Show, NoActivate Center AutoSize
	*/

	;
    dc := DllCall("GetDC", "Ptr", controlHwnd)

    ; 0x31 = WM_GETFONT
    SendMessage 0x31,,,, ahk_id %controlHwnd%
    hFont := ErrorLevel
    oldFont := 0
    if (hFont != "FAIL")
        oldFont := DllCall("SelectObject", "Ptr", dc, "Ptr", hFont)

    VarSetCapacity(rect, 16, 0)
    ; 0x440 = DT_CALCRECT | DT_EXPANDTABS
    h := DllCall("DrawText", "Ptr", dc, "Ptr", &newText, "Int", -1, "Ptr", &rect, "UInt", 0x440)
    ; width = rect.right - rect.left
    w := NumGet(rect, 8, "Int") - NumGet(rect, 0, "Int")

    if oldFont
        DllCall("SelectObject", "Ptr", dc, "Ptr", oldFont)
    DllCall("ReleaseDC", "Ptr", controlHwnd, "Ptr", dc)

    GuiControl,, %controlHwnd%, %newText%
    GuiControl, Move, %controlHwnd%, % "h" h " w" w
} ;</06.05.000046>


}
;|   SureControlClick(01)               	|   SureControlCheck(02)              	|   ControlClick2(03)                     	|   ControlFromPoint(04)              	|
;|   EnumChildFindPoint(05)         	|   ControlDoubleClick(06)            	|   WinWaitForMinimized(07)       	|   CenterWindow(08)                   	|
;|   GuiCenterButtons(09)              	|   CenterControl(10)                    	|   SetWindowIcon(11)                  	|   SetWindowPos(12)                   	|
;|   TryKillWin(13)                         	|   W in32_SendMessage(14)        	|   Win32_TaskKill(15)                  	|   Win32_Terminate(16)              	|
;|   TabActivate(17)                       	|   FocuslessScroll(18)                   	|   FocuslessScrollHorizontal(19)   	|   Menu_Show(20)                       	|
;|   CatMull_ControlMove(21)        	|   Gui_AutoHide(22)                    	|   SetButtonF(23)                         	|   AddToolTip(24)                        	|
;|   HelpToolTips(25)                      	|   DisableFadeEffect(26)              	|   SetWindowTransistionDisable(27)   DisableMinimizeAnim(28)        	|
;|   DisableCloseButton(29)           	|   AutoCloseBlockingWindows(30)	|   WinActivateEx(31)                    	|   ClickOK(32)                              	|
;|   ControlSelectTab(32)               	|   SetParentByClass(33)               	|   MoveTogether(35)                    	|   WinWaitCreated(36)                	|
;|   closeContextMenu(37)             	|   SetWindowTheme(38)              	|   HideFocusBorder(39)                	|   unmovable(40)                         	|
;|   movable(41)                             	|   GuiDisableMove(42)                 	|   WinInsertAfter(43)                   	|   CenterWindow(44)                   	|
;|   SetHoverText(45)                     	|   SetTextAndResize(46)               	|

{ ;gui - menu (15) -- read, set and interact with menu's --                                                                          	baseID: <06.06>
;<06.06.000001>
GetMenu(hWnd) {																										;-- returns hMenu handle
	;; only wraps DllCall(GetMenu)
    Return DllCall("GetMenu", "Ptr", hWnd)
} ;</06.06.000001>
;<06.06.000002>
GetSubMenu(hMenu, nPos) {																						;--
    Return DllCall("GetSubMenu", "Ptr", hMenu, "Int", nPos)
} ;</06.06.000002>
;<06.06.000003>
GetMenuItemCount(hMenu) {									     												;--
    Return DllCall("GetMenuItemCount", "Ptr", hMenu)
} ;</06.06.000003>
;<06.06.000004>
GetMenuItemID(hMenu, nPos) {																					;--
    Return DllCall("GetMenuItemID", "Ptr", hMenu, "Int", nPos)
} ;</06.06.000004>
;<06.06.000005>
GetMenuString(hMenu, uIDItem) {																				;--
    ; uIDItem: the zero-based relative position of the menu item
    Local lpString, MenuItemID
    VarSetCapacity(lpString, 4096)
    If !(DllCall("GetMenuString", "Ptr", hMenu, "UInt", uIDItem, "Str", lpString, "Int", 4096, "UInt", 0x400)) {
        MenuItemID := GetMenuItemID(hMenu, uIDItem)
        If (MenuItemID > -1) {
            Return "SEPARATOR"
        } Else {
            Return (GetSubMenu(hMenu, uIDItem)) ? "SUBMENU" : "ERROR"
        }
    }
    Return lpString
} ;</06.06.000005>
;<06.06.000006>
MenuGetAll(hwnd) {																									;-- this function and MenuGetAll_sub return all Menu commands from the choosed menu

    if !menu := DllCall("GetMenu", "ptr", hwnd, "ptr")
        return ""
    MenuGetAll_sub(menu, "", cmds)
    return cmds

} ;</06.06.000006>
;<06.06.000007>
MenuGetAll_sub(menu, prefix, ByRef cmds) {																;-- described above

    Loop % DllCall("GetMenuItemCount", "ptr", menu) {

        VarSetCapacity(itemString, 2000)

        if !DllCall("GetMenuString", "ptr", menu, "int", A_Index-1, "str", itemString, "int", 1000, "uint", 0x400)
            continue

        StringReplace itemString, itemString, &
        itemID := DllCall("GetMenuItemID", "ptr", menu, "int", A_Index-1)
        if (itemID = -1)
        if subMenu := DllCall("GetSubMenu", "ptr", menu, "int", A_Index-1, "ptr") {

            MenuGetAll_sub(subMenu, prefix itemString " > ", cmds)
            continue

        }
        cmds .= itemID "`t" prefix RegExReplace(itemString, "`t.*") "`n"
    }
} ;</06.06.000007>
;<06.06.000008>
; these 3 belongs together -->
GetContextMenuState(hWnd, Position) {																	;-- returns the state of a menu entry
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;We need to allocate a struct
  VarSetCapacity(MenuItemInfo, 60, 0)
  ;Set Size of Struct to the first member
  InsertInteger(48, MenuItemInfo, 0, 4)
  ;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
  InsertInteger(1, MenuItemInfo, 4, 4)

  ;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes != 0
     return -1

  ;Get Flag from struct
  GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 12, false, 4)
  /*
  IsEnabled = 1
  if GetMenuItemInfoRes > 0
     IsEnabled = 0
  return IsEnabled
  */
  return GetMenuItemInfoRes
} ;</06.06.000008>
;<06.06.000009>
GetContextMenuID(hWnd, Position) {																		;-- returns the ID of a menu entry
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;UINT GetMenuItemID(          HMENU hMenu,    int nPos);
  InfoRes := DllCall("user32.dll\GetMenuItemID",UInt,hMenu, Uint, Position)

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes != 0
     return -1

  return InfoRes
} ;</06.06.000009>
;<06.06.000010>
GetContextMenuText(hWnd, Position) {																		;-- returns the text of a menu entry (standard windows context menus only!!!)
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;We need to allocate a struct
  VarSetCapacity(MenuItemInfo, 200, 0)
  ;Set Size of Struct (48) to the first member
  InsertInteger(48, MenuItemInfo, 0, 4)
  ;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
  InsertInteger(64, MenuItemInfo, 4, 4)
  ;Set type - Get only size of string we need to allocate
  ;InsertInteger(0, MenuItemInfo, 8, 4)
  ;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
  if InfoRes = 0
     return -1

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes <> 0
     return -1

  ;Get size of string from struct
  GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 40, false, 4)
  ;If menu is empty return
  If GetMenuItemInfoRes = 0
     return "{Empty String}"

  ;+1 should be enough, we'll use 2
  GetMenuItemInfoRes += 2
  ;Set capacity of string that will be filled by windows
  VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)
  ;Set Size plus 0 terminator + security ;-)
  InsertInteger(GetMenuItemInfoRes, MenuItemInfo, 40, 4)
  InsertInteger(&PopupText, MenuItemInfo, 36, 4)

  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
  if InfoRes = 0
     return -1

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes <> 0
     return -1

  return PopupText
} ;</06.06.000010>
;<06.06.000011>
Menu_AssignBitmap(p_menu, p_item, p_bm_unchecked,                                         	;-- assign bitmap to any item in any AHk menu
p_unchecked_face=false, p_bm_checked=false,p_checked_face=false)   {
	/*                              	DESCRIPTION

				Thanks to shimanov for this function
			    Details under http://www.autohotkey.com/forum/viewtopic.php?p=44577

			    p_menu            = "MenuName" (e.g., Tray, etc.)
			    p_item            = "MenuItemNumber" (e.g. 1, ...)
			    p_bm_unchecked,
			    p_bm_checked      = path to bitmap for unchecked 'n' checked menu entry/false
			    p_unchecked_face,
			    p_checked_face    = true/false (i.e., true = pixels with same color as
			                                    first pixel are transparent)

	*/

	/*                              	EXAMPLE(s)

		**---Work with context menu---*

			Menu, menuEmpty, Add

			Menu, menuContext$Level2, Add, :menuEmpty
				Menu_AssignBitmap( "menuContext$Level2", 1, "coffee.bmp", true )
			Menu, menuContext$Level2, Add, empty, :menuEmpty
			Menu, menuContext$Level2, Add, world, :menuEmpty
				Menu_AssignBitmap( "menuContext$Level2", 3, "coffee.bmp", true )

			Menu, menuContext, Add, empty 1, :menuEmpty
			Menu, menuContext, Add, empty 2, :menuEmpty
				Menu, menuContext, Check, empty 2
				Menu_AssignBitmap( "menuContext", 2, "coffee.bmp", true, "coffee.bmp", false )
			Menu, menuContext, Add, :menuContext$Level2

			Gui, Show, x50 y50 w400 h200
			return

			GuiContextMenu:
				Menu, menuContext, Show
			return

		**---Work with Tray menu:---**

			Menu, menuEmpty, Add
			Menu, Tray, NoStandard
			Menu, Tray, Add, Hello, :menuEmpty
				Menu_AssignBitmap( "Tray", 1, "coffee.bmp", true )
			Menu, Tray, Add
			Menu, Tray, Standard

		**---Work with Window menu bar--**

			Menu, menuEmpty, Add
			Menu, menuFile, Add, Hello, :menuEmpty
				Menu_AssignBitmap( "menuFile", 1, "coffee.bmp", false )
			Menu, menuMain, Add, File, :menuFile
			Gui, Menu, menuMain
			Gui, Show, x50 y50 w400 h200

	*/

    static   menu_list, h_menuDummy

    If h_menuDummy=
    {
      menu_list = |

      ; Save current 'DetectHiddenWindows' mode to reset it later
      Old_DetectHiddenWindows := A_DetectHiddenWindows
      DetectHiddenWindows, on

      ; Retrieve scripts PID
      Process, Exist
      pid_this := ErrorLevel

      ; Create menuDummy and assign to Gui99
      Menu, menuDummy, Add
      Menu, menuDummy, DeleteAll

      Gui, 99:Menu, menuDummy

      ; Retrieve menu handle (menuDummy)
      h_menuDummy := DllCall( "GetMenu", "uint", WinExist( "ahk_class AutoHotkeyGUI ahk_pid " pid_this ) )

      ; Remove menu bar 'menuDummy'
      Gui, 99:Menu

      ; Reset 'DetectHiddenWindows' mode to old setting
      DetectHiddenWindows, %Old_DetectHiddenWindows%
    }

    ; Assign p_menu to menuDummy and retrieve menu handle
    If (! InStr(menu_list, "|" p_menu ",", false))
      {
        Menu, menuDummy, Add, :%p_menu%
        menu_ix := DllCall( "GetMenuItemCount", "uint", h_menuDummy ) - 1
        menu_list = %menu_list%%p_menu%,%menu_ix%|
      }
    Else
      {
        menu_ix := InStr(menu_list, ",", false, InStr( menu_list, "|" p_menu ",", false)) + 1
        StringMid, menu_ix, menu_list, menu_ix, InStr(menu_list, "|", false, menu_ix) - menu_ix
      }

    h_menu := DllCall("GetSubMenu", "uint", h_menuDummy, "int", menu_ix)

    ; Load bitmap for unchecked menu entries
    If (p_bm_unchecked)
      {
        hbm_unchecked := DllCall( "LoadImage"
                                , "uint", 0
                                , "str", p_bm_unchecked
                                , "uint", 0                             ; IMAGE_BITMAP
                                , "int", 0
                                , "int", 0
                                , "uint", 0x10|(0x20*p_unchecked_face)) ; LR_LOADFROMFILE|LR_LOADTRANSPARENT

        If (ErrorLevel or ! hbm_unchecked)
          {
             MsgBox, [Menu_AssignBitmap: LoadImage: unchecked] failed: EL = %ErrorLevel%
             Return, false
          }
      }

    ; Load bitmap for checked menu entries
    If (p_bm_checked)
      {
        hbm_checked := DllCall( "LoadImage"
                              , "uint", 0
                              , "str", p_bm_checked
                              , "uint", 0                               ; IMAGE_BITMAP
                              , "int", 0
                              , "int", 0
                              , "uint", 0x10|(0x20*p_checked_face))     ; LR_LOADFROMFILE|LR_LOADTRANSPARENT

        If (ErrorLevel or ! hbm_checked)
          {
             MsgBox, [Menu_AssignBitmap: LoadImage: checked] failed: EL = %ErrorLevel%
             Return, false
          }
      }

    ; On success assign image to menu entry
    success := DllCall( "SetMenuItemBitmaps"
                      , "uint", h_menu
                      , "uint", p_item-1
                      , "uint", 0x400                                   ; MF_BYPOSITION
                      , "uint", hbm_unchecked
                      , "uint", hbm_checked )

    If (ErrorLevel or ! success)
      {
        MsgBox, [Menu_AssignBitmap: SetMenuItemBitmaps] failed: EL = %ErrorLevel%
        Return, false
      }

    Return, true
  } ;</06.06.000011>
;<06.06.000012>
InvokeVerb(path, menu, validate=True) {																	;-- executes the context menu item of the given path
	/*                              	DESCRIPTION

				by A_Samurai
				Link: 					https://autohotkey.com/board/topic/73010-invokeverb/
				Doc:						v 1.0.1 http://sites.google.com/site/ahkref/custom-functions/invokeverb
				Dependencies: 	WindowProc and CoHelper.ahk
	*/


	/*                              	EXAMPLE(s)

			Persistent
			;this is the same as right clicking on the folder and selecting Copy.
			if InvokeVerb(A_MyDocuments "\AutoHotkey", "Copy")
			    msgbox copied
			else
			    msgbox not copied

			;Opens the property window of Recycle Bin
			InvokeVerb("::", "Properties")


			path := A_ScriptDir "\Test"
			FileCreateDir, % path
			;this is the same as right clicking on the folder and selecting Delete.
			InvokeVerb(path, "Delete")

	*/


    objShell := ComObjCreate("Shell.Application")
    if InStr(FileExist(path), "D") || InStr(path, "::{") {
        objFolder := objShell.NameSpace(path)
        objFolderItem := objFolder.Self
    } else {
        SplitPath, path, name, dir
        objFolder := objShell.NameSpace(dir)
        objFolderItem := objFolder.ParseName(name)
    }
    if validate {
        colVerbs := objFolderItem.Verbs
        loop % colVerbs.Count {
            verb := colVerbs.Item(A_Index - 1)
            retMenu := verb.name
            StringReplace, retMenu, retMenu, &
            if (retMenu = menu) {
                verb.DoIt
                Return True
            }
        }
        Return False
    } else
        objFolderItem.InvokeVerbEx(Menu)
}
;{ sub
WindowProc(hWnd, nMsg, wParam, lParam) {
Critical
  Global   pcm, pcm2, pcm3, WPOld
  If (nMsg = 287) ; WM_MENUSELECT
  {  MenuItem := wParam & 65535
     VarSetCapacity(sHelp,257,79)
     DllCall(NumGet(NumGet(1*pcm)+20), "Uint", pcm, "Uint", MenuItem-3, "Uint", GCS_HELPTEXTA:=1, "Uint", 0, "str", sHelp, "Uint", 256) ; GetCommandString
     if sHelp = %SbText%
        MsgBox, Hey
  }
  If pcm3
  { If !DllCall(NumGet(NumGet(1*pcm3)+28), "Uint", pcm3, "Uint", nMsg, "Uint", wParam, "Uint", lParam, "UintP", lResult)
    Return lResult
  }
  Else If pcm2
  { If !DllCall(NumGet(NumGet(1*pcm2)+24), "Uint", pcm2, "Uint", nMsg, "Uint", wParam, "Uint", lParam)
      Return 0
  }
  Return   DllCall("user32.dll\CallWindowProcA", "Uint", WPOld, "Uint", hWnd, "Uint", nMsg, "Uint", wParam, "Uint", lParam,"Uint")
} ;</06.06.000012>
;}
;<06.06.000013>
Menu_Show( hMenu, hWnd=0, mX="", mY="", Flags=0x1 ) {                                	;-- its an alternative to Menu, Show, which can display menu without blocking monitored messages

		/*    	DESCRIPTION of function Menu_Show()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	is an alternate to Menu, Show, which can display menu without blocking monitored messages
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=971
			                        	http://ahkscript.org/boards/viewtopic.php?p=7088#p7088
			Author         	:	SKAN
			Date             	:	13 Dec 2013, 07:01
			AHK-Version	:	AHK_L
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	..but the catch is: To get handle ( hMenu ) for a Menuname, it has to be attached to a MenuBar.
								    	There already is a function from lexikos, which does this: MI_GetMenuHandle(), and can be used as follows
										hViewmenu := MI_GetMenuHandle( "view" ) ; Get it from: http://www.autohotkey.net/~Lexikos/lib/MI.ahk
			Dependencies	:	non
			KeyWords    	:	menu, show
        	-------------------------------------------------------------------------------------------------------------------
	*/

	 ; Flags: TPM_RECURSE := 0x1, TPM_RETURNCMD := 0x100, TPM_NONOTIFY := 0x80
	 VarSetCapacity( POINT, 8, 0 ), DllCall( "GetCursorPos", UInt,&Point )
	 mX := ( mX <> "" ) ? mX : NumGet( Point,0 )
	 mY := ( mY <> "" ) ? mY : NumGet( Point,4 )

Return DllCall( "TrackPopupMenu", UInt,hMenu, UInt,Flags, Int,mX, Int,mY, UInt,0, UInt,hWnd ? hWnd : WinActive("A"), UInt,0 ) ; TrackPopupMenu()  goo.gl/CosNig
} ;</06.06.000013>
;<06.06.000014>
CreateMenu(MenuDefinitionVar, MenuName="MyMenu", 										;-- creates menu from a string in which each item is placed in new line and hierarchy is defined by Tab character on the left (indentation)
MenuSub="MenuSub") {

	/*    	DESCRIPTION of function CreateMenu()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Creates menu from a string in which each item is placed in new line and hierarchy is defined by Tab character on the left (indentation)
			Link              	:	https://autohotkey.com/board/topic/57647-function-createmenu/
			Author         	:	Learning one
			Date             	:	05 Sep 2010
			AHK-Version	:
			License         	:
			Syntax          	:
			Parameter(s)	:	Item icon parameters (FileName | IconNumber | IconWidth) can be added after one or more Tab characters after item name. To create separator, specify at least 3 minuses (---) but follow indentation
			Return value	:
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	menu, create menu
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			MenuDefinitionVar=
			(
			File
				New
				Open
				Save
				Save as...
				Exit
			Edit
				Undo
				Cut
				Copy
				Paste
				Delete
			View
				Full screen
				Zoom
					100
					200
			Help
			)

			CreateMenu(MenuDefinitionVar)
			Menu, MyMenu, show
			return

			MButton::Menu, MyMenu, show

			MenuSub:
			MsgBox,, You selected:, % "Item:`n" A_ThisMenuItem "`n`nFrom menu:`n" A_ThisMenu
			return

			MenuDefinitionVar=
			(
			AHK						%A_AhkPath%|1
				Suspend				%A_AhkPath%|-206
				Pause				%A_AhkPath%|-207
				Suspend and pause	%A_AhkPath%|-208
				---
				Big exe				%A_AhkPath%|1|48
				Big file			%A_AhkPath%|2|48
			Favorites				C:\Your icon.ico
				File 1
				File 2
				---
				Folder 1
				Folder 2
			Help					C:\Your icon.ico||32
			)

			CreateMenu(MenuDefinitionVar, "Test", "TestSub")
			Menu, Test, show
			return

			MButton::Menu, Test, show

			TestSub:
			MsgBox,, You selected:, % "Item:`n" A_ThisMenuItem "`n`nFrom menu:`n" A_ThisMenu
			return

	*/

	MenuNames := {}, ItemNames := {}, Items := {}, BaseMenuName := MenuName, Depth := 0, LastLevel := 1
	Loop, parse, MenuDefinitionVar, `n, `r
	{
		if A_LoopField is space							; ignore
			continue
		ItemInfo := RTrim(A_LoopField, A_Space A_Tab), ItemInfo := LTrim(ItemInfo, A_Space), Level := 1		; refine, reset
		While (SubStr(ItemInfo,1,1) = A_Tab)			; get current Level and ItemInfo
			Level += 1,	ItemInfo := SubStr(ItemInfo, 2)
		RegExMatch(ItemInfo,  "([^`t]*)([`t]*)([^`t]*)", match)		; match1 = ItemName, match3 = ItemIconOptions
		ItemName := Trim(match1), ItemIconOptions := Trim(match3)	; ItemIconOptions exa:  %A_AhkPath%|1|48
		if (IsObject(Items["L" Level]) = 0)				; if object which will contain items for this level doesn't exist yet
			Items["L" Level] := [], Depth += 1			; create it, and increase Depth of this menu
		if (Level=1)
			MenuName := BaseMenuName					; Exa Level1: "MyMenu"
		else
			MenuName := MenuNames["L" Level-1] "_" ItemNames["L" Level-1]	; Exa Level2: "MyMenu_Edit", Exa Level3: "MyMenu_View_Zoom"
		MenuNames["L" Level] := MenuName, ItemNames["L" Level] := ItemName	; store last
		Items["L" Level].Insert([MenuName, ItemName, MenuSub, ItemIconOptions])	; Insert new item object in this level. Item structure: [MenuName,ItemName,LabelOrSubmenu,ItemIconOptions]
		if (Level > LastLevel)	; this is the 1. item in submenu - set this menu as last higher item's submenu
			Max := Items["L" Level-1].MaxIndex(), Items["L" Level-1][Max].3 := ":" MenuName	; set this menu as last higher item's submenu. Exa: ":MyMenu_Edit"
		LastLevel := Level	; store last level
	}
	Loop, % Depth
	{
		Level := (A_index = 1) ? Depth : Depth - A_Index + 1		; from reverse - from deepest to highest level
		For k,v in Items["L" Level]	; v = item. Item structure: [MenuName,ItemName,LabelOrSubmenu,ItemIconOptions] ; MsgBox % v.1 "`n" v.2 "`n" v.3 "`n" v.4
		{
			if (SubStr(v.2, 1, 3) = "---")	; this is a separator
				Menu, % v.1, Add			; Menu, MenuName, add
			else {							; normal item
				if (v.4 = "")				; no ItemIconOptions
					Menu, % v.1, Add, % v.2, % v.3	; Menu, MenuName, add, ItemName, LabelOrSubmenu
				else {						; with ItemIconOptions. v.4 structure: FileName|IconNumber|IconWidth
					ItemIconOptions := v.4	; Exa: %A_AhkPath%|1|48
					Transform, ItemIconOptions, Deref, % ItemIconOptions	; deref things like %A_AhkPath%, %A_ScriptDir%, etc.
					StringSplit, param, ItemIconOptions, |
					Menu, % v.1, Add, % v.2, % v.3													; Menu, MenuName, Add, ItemName, LabelOrSubmenu
					Att := FileExist(param1), Att := (Att = "") ? "" : (InStr(Att, "D") > 0) ? "folder" : "file"	; check is param1 a file
					if (Att="file")
						Menu, % v.1, Icon, % v.2, % Trim(param1), % Trim(param2), % Trim(param3)	; Menu, MenuName, Icon, ItemName, FileName [, IconNumber, IconWidth]
					param1 := "", param2 := "", param3 := ""	; clear for next loop
				}
			}
		}
	}
} ;</06.06.000014>
;<06.06.000015>
CreateDDMenu(MenuDefinitionVar, MenuName="MyMenu", 									;-- Creates menu from a string in which each item is placed in new line and hierarchy is defined by Tab character on the left (indentation)
MenuSub="MenuSub",ReturnMenu="") {

		/*    	DESCRIPTION of function CreateMenu()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Creates menu from a string in which each item is placed in new line and hierarchy is defined by Tab character on the left (indentation)
			Link              	:	https://autohotkey.com/board/topic/57647-function-createmenu/
			Author         	:	Learning one
			Date             	:	05 Sep 2010
			AHK-Version	:
			License         	:
			Syntax          	:
			Parameter(s)	:	Item icon parameters (FileName | IconNumber | IconWidth) can be added after one or more Tab characters after item name. To create separator, specify at least 3 minuses (---) but follow indentation
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	dropdown menu, menu
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			MenuDefinitionVar=
			(
			File
				New
				Open
				---
				Save
				Save as...
				Exit
			Edit
				Undo
				Cut
				Copy
				Paste
				Delete
			View
				Full screen
				Zoom
					100
					200
			Help
			)

			CreateDDMenu(MenuDefinitionVar,"MyMenu","MenuSub")
			Menu, MyMenu, show
			return

			MButton::Menu, MyMenu, show

			MenuSub:
			MsgBox,,, %A_ThisMenu%`n%A_ThisMenuItem%, 1
			return

	*/


	; With CreateDDMenu(), you can easily create drop-down menus by using indentation - %A_Tab%.
	; Line without tabs on the left creates item in main menu. One tab on the left creates subitem, two tabs sub-sub item, and so on.
	; To create separator, specify at least 3 minuses --- (but follow indentation).
	; ReturnMenu parameter: if 1, function will not actually create menu, but will return its definition. You can redirect that return
	; to clipboard and paste your menu in script.

	Level0MenuName := MenuName, LabOrSub := MenuSub, MaxDepth := 0
	Loop, parse, MenuDefinitionVar, `n
	{
		CurLevel := 0, Field := A_LoopField
		if Field is space						; blank
		Continue
		while (SubStr(Field,0,1) = A_space or SubStr(Field,0,1) = A_Tab or SubStr(Field,0,1) = "`r")
		StringTrimRight, Field, Field, 1
		var := Field
		while (SubStr(var,1,1) = A_Tab)
		{
			StringTrimLeft, var, var, 1
			CurLevel++
		}
		if (MaxDepth < CurLevel)
		MaxDepth := CurLevel
		lplus := CurLevel + 1, Level%lplus%MenuName := var, CurMenuName := Level%CurLevel%MenuName
		Level%CurLevel%ic .= CurMenuName "|" var "|" LabOrSub "`n"
		if (CurLevel > 0)
		{
			lminus := CurLevel - 1, icToChange := Level%lminus%ic
			StringTrimRight, icToChange, icToChange, 1
			LastLineLen := "", LastLine := ""
			Loop
			{
				LastChar := SubStr(icToChange,0,1)
				if (LastChar = "`n" or LastChar = "")
				break
				else
				{
					LastLine := LastChar LastLine
					StringTrimRight, icToChange, icToChange, 1
				}
			}
			StringSplit, v, LastLine, |
			LastLine := v1 "|" v2 "|:" v2 "`n"
			icToChange .= LastLine
			Level%lminus%ic := icToChange
		}
	}
	MaxDepth += 1
	Loop, %MaxDepth%
	{
		if A_index = 1
		CurLevel := MaxDepth - 1
		else
		CurLevel -= 1
		CurIc := Level%CurLevel%ic
		While (SubStr(CurIc,0) = "`n")
		StringTrimRight, CurIc, CurIc, 1
		if ReturnMenu
		{
			Loop, %CurLevel%
			Indentation .= A_Tab
		}
		Loop, parse, CurIc, `n
		{
			StringSplit, v, A_LoopField, |
			if ReturnMenu
			{
				if (SubStr(v2,1,3) = "---")
				ToReturn .= Indentation "Menu, " v1 ", add`n"
				else
				ToReturn .= Indentation "Menu, " v1 ", add, " v2 ", " v3 "`n"
			}
			else
			{
				if (SubStr(v2,1,3) = "---")
				Menu, %v1%, add
				else
				Menu, %v1%, add, %v2%, %v3%
			}
		}
		Indentation := ""
	}
	if ReturnMenu
	{
		While (SubStr(ToReturn,0) = "`n")
		StringTrimRight, ToReturn, ToReturn, 1
		return ToReturn
	}
} ;</06.06.000015>

}
;|   GetMenu(01)                           	|   GetSubMenu(02)                      	|   GetMenuItemCount(03)           	|   GetMenuItemID(04)                 	|
;|   GetMenuString(05)                  	|   MenuGetAll(06)                        	|   MenuGetAll_sub(07)                 	|   GetContextMenuState(08)        	|
;|   GetContextMenuID(09)           	|   GetContextMenuText(10)         	|   Menu_AssignBitmap(11)          	|   InvokeVerb(12)                         	|
;|   Menu_Show(13)                       	|   CreateMenu(14)                       	|   CreateDDMenu(15)                  	|

{ ;gui - icon (4) -                                                                                                                                               	baseID: <06.07>
;<06.07.00001>
ExtractIcon(Filename, IconNumber, IconSize=0) {                                            	;-- extract icon from a resource file

	/*    	DESCRIPTION of function ExtractIcon() - ID: 06.07.00001
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	extract icon from a resource file
			Link              	:	https://autohotkey.com/board/topic/20338-transparent-background-problem-with-images/#entry133445
			Author         	:	Lexikos
			Date             	:
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:	hIcon - handle
			Remark(s)    	:	function is copied from my (Lexikos') Menu Icons script
			Dependencies	:
			KeyWords    	:	icon, hIcon, load resources, extract
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)



	*/

    static SmallIconSize, LargeIconSize
    if (!SmallIconSize) {
        SysGet, SmallIconSize, 49  ; 49, 50  SM_CXSMICON, SM_CYSMICON
        SysGet, LargeIconSize, 11  ; 11, 12  SM_CXICON, SM_CYICON
    }


    VarSetCapacity(phicon, 4, 0)
    h_icon = 0

    ; If possible, use PrivateExtractIcons, which supports any size of icon.
    if A_OSVersion in WIN_VISTA,WIN_2003,WIN_XP,WIN_2000
    {
        VarSetCapacity(piconid, 4, 0)

        ; MSDN: "... this function is deprecated ..." (oh well)
        ret := DllCall("PrivateExtractIcons"
            , "str", Filename
            , "int", IconNumber-1   ; zero-based index of the first icon to extract
            , "int", IconSize
            , "int", IconSize
            , "str", phicon         ; pointer to an array of icon handles...
            , "str", piconid        ; piconid - won't be used
            , "uint", 1             ; nIcons - number of icons to extract
            , "uint", 0, "uint")    ; flags

        if (ret && ret != 0xFFFFFFFF)
            h_icon := NumGet(phicon)
    }
    else
    {   ; Use ExtractIconEx, which only returns 16x16 or 32x32 icons.
        VarSetCapacity(phiconSmall, 4, 0)

        ; Extract the icon from an executable, DLL or icon file.
        if DllCall("shell32.dll\ExtractIconExA"
            , "str", Filename
            , "int", IconNumber-1   ; zero-based index of the first icon to extract
            , "str", phicon         ; pointer to an array of icon handles...
            , "str", phiconSmall
            , "uint", 1)
        {
            ; Use the best-fit size; clean up the other.
            if (IconSize <= SmallIconSize) {
                DllCall("DestroyIcon", "uint", NumGet(phicon))
                h_icon := NumGet(phiconSmall)
            } else {
                DllCall("DestroyIcon", "uint", NumGet(phiconSmall))
                h_icon := NumGet(phicon)
            }
        }
    }

    return h_icon
} ;</06.07.00001>
;<06.07.00002>
GetIconSize(h_icon, ByRef width, ByRef height) {                                               	;-- determines the size of the icon (Lexikos function)

	/*    	DESCRIPTION of function GetIconSize() ID: 06.07.00002
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	determines the size of the icon (Lexikos function)
			Link              	:	https://autohotkey.com/board/topic/20338-transparent-background-problem-with-images/#entry133445
			Author         	:	Lexikos
			Date             	:	15.08.2007
			AHK-Version	:	??
			License         	:	??
			Parameter(s)	:	h_Icon          	- handle to a loaded icon file
			                        	width, height 	- known width and height of that icon - use GetBitmapSize() to determine it
			Return value	:	Icon size in ?bytes?
			Remark(s)    	:	function is copied from my (Lexikos') Menu Icons script
			Dependencies	:	GetBitmapSize() ID: 05.01.00053
			KeyWords    	:	icon, hIcon, load resources, extract
        	-------------------------------------------------------------------------------------------------------------------
	*/

    VarSetCapacity(ii, 20, 0)

    if (DllCall("GetIconInfo", "UInt", h_icon, "UInt", &ii))
    {
        hbmColor := NumGet(ii, 16)
        hbmMask  := NumGet(ii, 12)

        ret := GetBitmapSize(hbmColor, width, height)

        DllCall("DeleteObject", "UInt", hbmColor)
        DllCall("DeleteObject", "UInt", hbmMask)

        return ret
    }
    return false
} ;</06.07.00002>
;<06.07.00003>
Gdip_GetHICONDimensions(hIcon, ByRef Width, ByRef Height) {                   	;-- get icon dimensions

	/*    	DESCRIPTION of function Gdip_GetHICONDimensions() ID: 06.07.00003
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	get icon dimensions from hIcon (handle to an icon)
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=59456
			Author         	:	swagfag
			Date	            	:	Last edited by swagfag on 01 Dec 2018, 21:32, edited 2 times in total.
			AHK-Version	:	AHK V1 and ??V2??
			Remark        	:	Width and Height set to 0, if an error occurred
			License         	:	unknown
			Dependencies	:	none
			KeyWords    	:	icon, hIcon, gdip, dimensions
        	-------------------------------------------------------------------------------------------------------------------
	*/


    Ptr := A_PtrSize ? "Ptr" : "UInt"
    Width := Height := 0

    VarSetCapacity(ICONINFO, size := 16 + 2 * A_PtrSize, 0)

    if !DllCall("User32\GetIconInfo", Ptr, hIcon, Ptr, &ICONINFO)
        return

    hbmMask := NumGet(&ICONINFO, 16, Ptr)
    hbmColor := NumGet(&ICONINFO, 16 + A_PtrSize, Ptr)
    VarSetCapacity(BITMAP, size, 0)

    if DllCall("Gdi32\GetObject", Ptr, hbmColor, "Int", size, Ptr, &BITMAP)
    {
	    Width := NumGet(&BITMAP, 4, "Int")
	    Height := NumGet(&BITMAP, 8, "Int")
    }

    DllCall("Gdi32\DeleteObject", Ptr, hbmMask)
    DllCall("Gdi32\DeleteObject", Ptr, hbmColor)
} ;</06.07.00003>
;<06.07.00004>
SetTrayIcon( Gui0=0 ) {                                                                                      	;-- sets a hex coded icon to as try icon
	/*    	DESCRIPTION of function SetTrayIcon() ID: 06.07.0004
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	sets a hex coded icon to as try icon
			Link              	:	from AHKScriptMaster by
			Author         	:	SKAN
			Date             	:	29-Nov-2008
			AHK-Version	:	AHK-basic? V1?
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	icon, tray, process
        	-------------------------------------------------------------------------------------------------------------------
	*/
 Hex := "W1Y1Z10101X1Y4Z2801X16V28V1U2T1Y4RCKMFF9C9CZFFA2A2ZFFAAAAZFFB0BYFFB4B4ZFFBABAZFF"
 . "BFBFZFFC4C4ZFFCACAZFFD1D1ZFFD6D6ZFFDDDDZFFE4E4ZFFEBEBZFFFFFFKWBDVCEVADVCEV9DVCEV7BVCE"
 . "V5AVCDV37ABA988ACV246765458AV13V58V12V37V12V25V12V24V22V23KYFFFFXC3C3XC3C3XC3C3XC3C3X"
 . "C3C3XCZ3XCZ3XCZ3XCZ3XC3C3XC3C3XC3C3XC3C3XC3C3XFFFFX"
 VarSetCapacity(Z,512,48), Nums:="512|256|128|64|32|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2"
 Loop, Parse, Nums, |                                  ;  uncompressing nulls in hex data
  StringReplace,hex,hex,% Chr(70+A_Index),% SubStr(Z,1,A_LoopField),All
 VarSetCapacity( IconData,( nSize:=StrLen(Hex)//2) )
 Loop %nSize%
   NumPut( "0x" . SubStr(Hex,2*A_Index-1,2), IconData, A_Index-1, "Char" )
 hICon := DllCall( "CreateIconFromResourceEx", UInt,&IconData+22, UInt,0, Int,1
                   ,UInt,196608, Int,16, Int,16, UInt,0 )
 PID := DllCall("GetCurrentProcessId"), VarSetCapacity( NID,444,0 ), NumPut( 444,NID )
 NumPut( Gui0,NID,4 ), NumPut( 1028,NID,8 ), NumPut( 2,NID,12 ), NumPut( hIcon,NID,20 )
 Menu, Tray, Icon,,, 1
 DllCall( "shell32\Shell_NotifyIcon", UInt,0x1, UInt,&NID )
} ;</06.07.00004>

}
;|                                                   	|                                                   	|                                                   	|                                                   	|
;|   ExtractIcon(1)                          	|   GetIconSize(2)                           	|   Gdip_GetHICONDimensions(3)	|   SetTrayIcon(4)                          	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Filesystem (39) -                                                                                                                                       	baseID: <07>
;<07.01.000001>
InvokeVerb(path, menu, validate=True) {											                                                                    	;-- Executes the context menu item of the given path

    ;by A_Samurai
    ;v 1.0.1 http://sites.google.com/site/ahkref/custom-functions/invokeverb

	/*											Description

		Executes the context menu item of the given path.

		Remarks
		This should be used with #Persistent since closing the script causes an unexpected termination of the invoked action, such as when invoking
		the Copy menu item, if the script exits, the copied item will be canceled. Invoking Properties behaves similarly.

		Requirements
		AutoHotkey_L Revision 53 or later.

		License
		Public Domain.

		Format
		InvokeVerb(path, menu, validate=True)
		Parameters
		path: the path of the file / directory to invoke the context menu.
		menu: the menu item to invoke.
		validate: if this is set to True, the function checks if the given menu item exists. It's True by default.

		Return Value
		True if the menu item is invoked; otherwise, False. If the validate option is set to False, nothing will be returned.

	*/

	/*											Example

		#persistent
		;this is the same as right clicking on the folder and selecting Copy.
		if InvokeVerb(A_MyDocuments "\AutoHotkey", "Copy")
			msgbox copied
		else
			msgbox not copied

		;Opens the property window of Recycle Bin
		InvokeVerb("::{645ff040-5081-101b-9f08-00aa002f954e}", "Properties")


		path := A_ScriptDir "\Test"
		FileCreateDir, % path
		;this is the same as right clicking on the folder and selecting Delete.
		InvokeVerb(path, "Delete")

	*/

    objShell := ComObjCreate("Shell.Application")
    if InStr(FileExist(path), "D") || InStr(path, "::{") {
        objFolder := objShell.NameSpace(path)
        objFolderItem := objFolder.Self
    } else {
        SplitPath, path, name, dir
        objFolder := objShell.NameSpace(dir)
        objFolderItem := objFolder.ParseName(name)
    }
    if validate {
        colVerbs := objFolderItem.Verbs
        loop % colVerbs.Count {
            verb := colVerbs.Item(A_Index - 1)
            retMenu := verb.name
            StringReplace, retMenu, retMenu, &
            if (retMenu = menu) {
                verb.DoIt
                Return True
            }
        }
        Return False
    } else
        objFolderItem.InvokeVerbEx(Menu)

} ;</07.01.000001>
;<07.01.000002>
Function_Eject(Drive){																			                                                                    	;-- ejects a drive medium
	Try
	{

		hVolume := DllCall("CreateFile"
		    , Str, "\\.\" . Drive
		    , UInt, 0x80000000 | 0x40000000  ; GENERIC_READ | GENERIC_WRITE
		    , UInt, 0x1 | 0x2  ; FILE_SHARE_READ | FILE_SHARE_WRITE
		    , UInt, 0
		    , UInt, 0x3  ; OPEN_EXISTING
		    , UInt, 0, UInt, 0)
		if hVolume <> -1
		{
		    DllCall("DeviceIoControl"
		        , UInt, hVolume
		        , UInt, 0x2D4808   ; IOCTL_STORAGE_EJECT_MEDIA
		        , UInt, 0, UInt, 0, UInt, 0, UInt, 0
		        , UIntP, dwBytesReturned  ; Unused.
		        , UInt, 0)
		    DllCall("CloseHandle", UInt, hVolume)

		}

		Return 1
	}
	Catch
	{

		Return 0
	}
} ;</07.01.000002>
;<07.01.000003>
FileGetDetail(FilePath, Index) { 															                                                                    	;-- Get specific file property by index
   Static MaxDetails := 350
   SplitPath, FilePath, FileName , FileDir
   If (FileDir = "")
      FileDir := A_WorkingDir
   Shell := ComObjCreate("Shell.Application")
   Folder := Shell.NameSpace(FileDir)
   Item := Folder.ParseName(FileName)
   Return Folder.GetDetailsOf(Item, Index)
} ;</07.01.000003>
;<07.01.000004>
FileGetDetails(FilePath) { 																	                                                                    	;-- Create an array of concrete file properties
   Static MaxDetails := 350
   Shell := ComObjCreate("Shell.Application")
   Details := []
   SplitPath, FilePath, FileName , FileDir
   If (FileDir = "")
      FileDir := A_WorkingDir
   Folder := Shell.NameSpace(FileDir)
   Item := Folder.ParseName(FileName)
   Loop, %MaxDetails% {
      If (Value := Folder.GetDetailsOf(Item, A_Index - 1))
         Details[A_Index - 1] := [Folder.GetDetailsOf(0, A_Index - 1), Value]
   }
   Return Details
} ;</07.01.000004>
;<07.01.000005>
DirExist(dirPath) {																				                                                                    	;-- Checks if a directory exists
   return InStr(FileExist(dirPath), "D") ? 1 : 0
} ;</07.01.000005>
;<07.01.000006>
GetDetails() { 																						                                                                    	;-- Create an array of possible file properties
   Static MaxDetails := 350
   Shell := ComObjCreate("Shell.Application")
   Details := []
   Folder := Shell.NameSpace(A_ScriptDir)
   Loop, %MaxDetails% {
      If (Value := Folder.GetDetailsOf(0, A_Index - 1)) {
         Details[A_Index - 1] := Value
         Details[Value] := A_Index - 1
      }
   }
   Return Details
} ;</07.01.000006>
;<07.01.000007>
Start(Target, Minimal = false, Title = "") { 											                                                                    	;-- Start programs or scripts easier
   cPID = -1
   if Minimal
      Run %ComSpec% /c "%Target%", A_WorkingDir, Min UseErrorLevel, cPID
   else
      Run %ComSpec% /c "%Target%", A_WorkingDir, UseErrorLevel, cPID
   if ErrorLevel = 0
   {
      if (Title <> "")
      {
         WinWait ahk_pid %cPID%,,,2
         WinSetTitle, %Title%
      }
      return, 0
   }
   else
      return, -1
} ;</07.01.000007>
;<07.01.000008>
IsFileEqual(filename1, filename2) { 														                                                                    	;-- Returns whether or not two files are equal
    ;TODO make this work for big files, too (this version reads it all into memory first)
   FileRead, file1, %filename1%
   FileRead, file2, %filename2%

   return file1==file2
} ;</07.01.000008>
;<07.01.000009>
WatchDirectory(p*) {  																			                                                                    	;-- Watches a directory/file for file changes

    ;By HotKeyIt
    ;Docs: http://www.autohotkey.com/forum/viewtopic.php?p=398565#398565

    global _Struct
   ;Structures
   static FILE_NOTIFY_INFORMATION:="DWORD NextEntryOffset,DWORD Action,DWORD FileNameLength,WCHAR FileName[1]"
   static OVERLAPPED:="ULONG_PTR Internal,ULONG_PTR InternalHigh,{struct{DWORD offset,DWORD offsetHigh},PVOID Pointer},HANDLE hEvent"
   ;Variables
   static running,sizeof_FNI=65536,WatchDirectory:=RegisterCallback("WatchDirectory","F",0,0) ;,nReadLen:=VarSetCapacity(nReadLen,8)
   static timer,ReportToFunction,LP,nReadLen:=VarSetCapacity(LP,(260)*(A_PtrSize/2),0)
   static @:=Object(),reconnect:=Object(),#:=Object(),DirEvents,StringToRegEx="\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*"
   ;ReadDirectoryChanges related
   static FILE_NOTIFY_CHANGE_FILE_NAME=0x1,FILE_NOTIFY_CHANGE_DIR_NAME=0x2,FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4
         ,FILE_NOTIFY_CHANGE_SIZE=0x8,FILE_NOTIFY_CHANGE_LAST_WRITE=0x10,FILE_NOTIFY_CHANGE_CREATION=0x40
         ,FILE_NOTIFY_CHANGE_SECURITY=0x100
   static FILE_ACTION_ADDED=1,FILE_ACTION_REMOVED=2,FILE_ACTION_MODIFIED=3
         ,FILE_ACTION_RENAMED_OLD_NAME=4,FILE_ACTION_RENAMED_NEW_NAME=5
   static OPEN_EXISTING=3,FILE_FLAG_BACKUP_SEMANTICS=0x2000000,FILE_FLAG_OVERLAPPED=0x40000000
         ,FILE_SHARE_DELETE=4,FILE_SHARE_WRITE=2,FILE_SHARE_READ=1,FILE_LIST_DIRECTORY=1
   If p.MaxIndex(){
      If (p.MaxIndex()=1 && p.1=""){
         for i,folder in #
            DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent)
            ,@.Remove(folder)
         #:=Object()
         DirEvents:=new _Struct("HANDLE[1000]")
         DllCall("KillTimer","Uint",0,"Uint",timer)
         timer=
         Return 0
      } else {
         if p.2
            ReportToFunction:=p.2
         If !IsFunc(ReportToFunction)
            Return -1 ;DllCall("MessageBox","Uint",0,"Str","Function " ReportToFunction " does not exist","Str","Error Missing Function","UInt",0)
         RegExMatch(p.1,"^([^/\*\?<>\|""]+)(\*)?(\|.+)?$",dir)
         if (SubStr(dir1,0)="\")
            StringTrimRight,dir1,dir1,1
         StringTrimLeft,dir3,dir3,1
         If (p.MaxIndex()=2 && p.2=""){
            for i,folder in #
               If (dir1=SubStr(folder,1,StrLen(folder)-1))
                  Return 0 ,DirEvents[i]:=DirEvents[#.MaxIndex()],DirEvents[#.MaxIndex()]:=0
                           @.Remove(folder),#[i]:=#[#.MaxIndex()],#.Remove(i)
            Return 0
         }
      }
      if !InStr(FileExist(dir1),"D")
         Return -1 ;DllCall("MessageBox","Uint",0,"Str","Folder " dir1 " does not exist","Str","Error Missing File","UInt",0)
      for i,folder in #
      {
         If (dir1=SubStr(folder,1,StrLen(folder)-1) || (InStr(dir1,folder) && @[folder].sD))
               Return 0
         else if (InStr(SubStr(folder,1,StrLen(folder)-1),dir1 "\") && dir2){ ;replace watch
            DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent),reset:=i
         }
      }
      LP:=SubStr(LP,1,DllCall("GetLongPathName","Str",dir1,"Uint",&LP,"Uint",VarSetCapacity(LP))) "\"
      If !(reset && @[reset]:=LP)
         #.Insert(LP)
      @[LP,"dir"]:=LP
      @[LP].hD:=DllCall("CreateFile","Str",StrLen(LP)=3?SubStr(LP,1,2):LP,"UInt",0x1,"UInt",0x1|0x2|0x4
                  ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0)
      @[LP].sD:=(dir2=""?0:1)

      Loop,Parse,StringToRegEx,|
         StringReplace,dir3,dir3,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A
      StringReplace,dir3,dir3,%A_Space%,\s,A
      Loop,Parse,dir3,|
      {
         If A_Index=1
            dir3=
         pre:=(SubStr(A_LoopField,1,2)="\\"?2:0)
         succ:=(SubStr(A_LoopField,-1)="\\"?2:0)
         dir3.=(dir3?"|":"") (pre?"\\\K":"")
               . SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ)
               . ((!succ && !InStr(SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ),"\"))?"[^\\]*$":"") (succ?"$":"")
      }
      @[LP].FLT:="i)" dir3
      @[LP].FUNC:=ReportToFunction
      @[LP].CNG:=(p.3?p.3:(0x1|0x2|0x4|0x8|0x10|0x40|0x100))
      If !reset {
         @[LP].SetCapacity("pFNI",sizeof_FNI)
         @[LP].FNI:=new _Struct(FILE_NOTIFY_INFORMATION,@[LP].GetAddress("pFNI"))
         @[LP].O:=new _Struct(OVERLAPPED)
      }
      @[LP].O.hEvent:=DllCall("CreateEvent","Uint",0,"Int",1,"Int",0,"UInt",0)
      If (!DirEvents)
         DirEvents:=new _Struct("HANDLE[1000]")
      DirEvents[reset?reset:#.MaxIndex()]:=@[LP].O.hEvent
      DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI
               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0)
      Return timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory)
   } else {
      Sleep, 0
      for LP in reconnect
      {
         If (FileExist(@[LP].dir) && reconnect.Remove(LP)){
            DllCall("CloseHandle","Uint",@[LP].hD)
            @[LP].hD:=DllCall("CreateFile","Str",StrLen(@[LP].dir)=3?SubStr(@[LP].dir,1,2):@[LP].dir,"UInt",0x1,"UInt",0x1|0x2|0x4
                  ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0)
            DllCall("ResetEvent","UInt",@[LP].O.hEvent)
            DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI
               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0)
         }
      }
      if !( (r:=DllCall("MsgWaitForMultipleObjectsEx","UInt",#.MaxIndex()
               ,"UInt",DirEvents[],"UInt",0,"UInt",0x4FF,"UInt",6))>=0
               && r<#.MaxIndex() ){
         return
      }
      DllCall("KillTimer", UInt,0, UInt,timer)
      LP:=#[r+1],DllCall("GetOverlappedResult","UInt",@[LP].hD,"UInt",@[LP].O[],"UIntP",nReadLen,"Int",1)
      If (A_LastError=64){ ; ERROR_NETNAME_DELETED - The specified network name is no longer available.
         If !FileExist(@[LP].dir) ; If folder does not exist add to reconnect routine
            reconnect.Insert(LP,LP)
      } else
         Loop {
            FNI:=A_Index>1?(new _Struct(FILE_NOTIFY_INFORMATION,FNI[]+FNI.NextEntryOffset)):(new _Struct(FILE_NOTIFY_INFORMATION,@[LP].FNI[]))
            If (FNI.Action < 0x6){
               FileName:=@[LP].dir . StrGet(FNI.FileName[""],FNI.FileNameLength/2,"UTF-16")
               If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME)
                     FileFromOptional:=FileName
               If (@[LP].FLT="" || RegExMatch(FileName,@[LP].FLT) || FileFrom)
                  If (FNI.Action=FILE_ACTION_ADDED){
                     FileTo:=FileName
                  } else If (FNI.Action=FILE_ACTION_REMOVED){
                     FileFrom:=FileName
                  } else If (FNI.Action=FILE_ACTION_MODIFIED){
                     FileFrom:=FileTo:=FileName
                  } else If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME){
                     FileFrom:=FileName
                  } else If (FNI.Action=FILE_ACTION_RENAMED_NEW_NAME){
                     FileTo:=FileName
                  }
          If (FNI.Action != 4 && (FileTo . FileFrom) !="")
                  @[LP].Func(FileFrom=""?FileFromOptional:FileFrom,FileTo)
            }
         } Until (!FNI.NextEntryOffset || ((FNI[]+FNI.NextEntryOffset) > (@[LP].FNI[]+sizeof_FNI-12)))
      DllCall("ResetEvent","UInt",@[LP].O.hEvent)
      DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI
               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0)
      timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory)
      Return
   }
   Return
} ;</07.01.000009>
;<07.01.000010>
WatchDirectory(WatchFolder="", WatchSubDirs=true) {					                                                                    	;-- it's different from above not tested

	;--https://autohotkey.com/board/topic/41653-watchdirectory/page-2

	/*				DESCRIPTION
	;Parameters
	; WatchFolder - Specify a valid path to watch for changes in.
	; - can be directory or drive (e.g. c:\ or c:\Temp)
	; - can be network path e.g. \\192.168.2.101\Shared)
	; - can include last backslash. e.g. C:\Temp\ (will be reported same form)
	;
	; WatchSubDirs - Specify whether to search in subfolders
	;
	;StopWatching - THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST (OnExit)
	; Call WatchDirectory() without parameters to stop watching all directories
	;
	;ReportChanges
	; Call WatchDirectory("ReportingFunctionName") to process registered changes.
	; Syntax of ReportingFunctionName(Action,Folder,File)
	*/

	/*					EXAMPLE

	#Persistent
	OnExit,Exit
	WatchDirectory("C:\Windows",1)
	SetTimer,WatchFolder,100
	Return
	WatchFolder:
	WatchDirectory("RegisterChanges")
	Return
	RegisterChanges(action,folder,file){
	static
	#1:="New File", #2:="Deleted", #3:="Modified", #4:="Renamed From", #5:="Renamed To"
	ToolTip % #%Action% "`n" folder . (SubStr(folder,0)="" ? "" : "") . file
	}
	Exit:
	WatchDirectory()
	ExitApp

	*/

	static
	local hDir, hEvent, r, Action, FileNameLen, pFileName, Restart, CurrentFolder, PointerFNI, option
	static nReadLen := 0, _SizeOf_FNI_:=65536
	If (Directory=""){
		Gosub, StopWatchingDirectories
		SetTimer,TimerDirectoryChanges,Off
	} else if (Directory=Chr(2) or IsFunc(Directory) or IsLabel(Directory)){
		Gosub, ReportDirectoryChanges
	} else {
		Loop % (DirIdx) {
			If InStr(Directory, Dir%A_Index%Path){
				If (Dir%A_Index%Subdirs)
					Return
			} else if InStr(Dir%A_Index%Path, Directory) {
				If (SubDirs){
					DllCall( "CloseHandle", UInt,Dir%A_Index% )
					DllCall( "CloseHandle", UInt,NumGet(Dir%A_Index%Overlapped, 16) )
					Restart := DirIdx, DirIdx := A_Index
				}
			}
		}
		If !Restart
			DirIdx += 1
		r:=DirIdx
		hDir := DllCall( "CreateFile"
					 , Str  , Directory
					 , UInt , ( FILE_LIST_DIRECTORY := 0x1 )
					 , UInt , ( FILE_SHARE_READ     := 0x1 )
							| ( FILE_SHARE_WRITE    := 0x2 )
							| ( FILE_SHARE_DELETE   := 0x4 )
					 , UInt , 0
					 , UInt , ( OPEN_EXISTING := 0x3 )
					 , UInt , ( FILE_FLAG_BACKUP_SEMANTICS := 0x2000000  )
							| ( FILE_FLAG_OVERLAPPED       := 0x40000000 )
					 , UInt , 0 )
		Dir%r%         := hDir
		Dir%r%Path     := Directory
		Dir%r%Subdirs  := SubDirs
		If (options!="")
			Loop,Parse,options,%A_Space%
				If (option:= SubStr(A_LoopField,1,1))
					Dir%r%%option%:= SubStr(A_LoopField,2)
		VarSetCapacity( Dir%r%FNI, _SizeOf_FNI_ )
		VarSetCapacity( Dir%r%Overlapped, 20, 0 )
		DllCall( "CloseHandle", UInt,hEvent )
		hEvent := DllCall( "CreateEvent", UInt,0, Int,true, Int,false, UInt,0 )
		NumPut( hEvent, Dir%r%Overlapped, 16 )
		if ( VarSetCapacity(DirEvents) < DirIdx*4 and VarSetCapacity(DirEvents, DirIdx*4 + 60))
			Loop %DirIdx%
			{
				If (SubStr(Dir%A_Index%Path,1,1)!="-"){
					action++
					NumPut( NumGet( Dir%action%Overlapped, 16 ), DirEvents, action*4-4 )
				}
			}
		NumPut( hEvent, DirEvents, DirIdx*4-4)
		Gosub, ReadDirectoryChanges
		If Restart
			DirIdx = %Restart%
		If (Dir%r%T!="")
			SetTimer,TimerDirectoryChanges,% Dir%r%T
	}
	Return
	TimerDirectoryChanges:
		WatchDirectory(Chr(2))
	Return
	ReportDirectoryChanges:
		r := DllCall("MsgWaitForMultipleObjectsEx", UInt, DirIdx, UInt, &DirEvents, UInt, -1, UInt, 0x4FF, UInt, 0x6) ;Timeout=-1
		if !(r >= 0 && r < DirIdx)
			Return
		r += 1
		CurrentFolder := Dir%r%Path
		PointerFNI := &Dir%r%FNI
		DllCall( "GetOverlappedResult", UInt, hDir, UInt, &Dir%r%Overlapped, UIntP, nReadLen, Int, true )
		Loop {
			pNext   	:= NumGet( PointerFNI + 0  )
			Action      := NumGet( PointerFNI + 4  )
			FileNameLen := NumGet( PointerFNI + 8  )
			pFileName :=       ( PointerFNI + 12 )
			If (Action < 0x6){
				VarSetCapacity( FileNameANSI, FileNameLen )
				DllCall( "WideCharToMultiByte",UInt,0,UInt,0,UInt,pFileName,UInt,FileNameLen,Str,FileNameANSI,UInt,FileNameLen,UInt,0,UInt,0)
				path:=CurrentFolder . (SubStr(CurrentFolder,0)="\" ? "" : "\") . SubStr( FileNameANSI, 1, FileNameLen/2 )
				SplitPath,path,,,EXT
				SplitPath,frompath,,,EXTFrom
				If ((FileExist(path) and InStr(FileExist(path),"D") and Dir%r%E!="" and Dir%r%E!="?") or (Dir%r%A!="" and !InStr(Dir%r%A, action)) or (FileExist(path) and !InStr(FileExist(path),"D") and Dir%r%E="?")){
					If (!pNext or pNext = 4129024)
						Break
					Else
						frompath:=path, PointerFNI := (PointerFNI + pNext)
					Continue
				}
				option:=Dir%r%E="" ? "|" : Dir%r%E
				Loop,Parse,option,.
					If (Dir%r%E="" or Dir%r%E="?" or Dir%r%E="*" or A_LoopField=EXT or A_LoopField=ExtFrom){
						If action in 2,3
							before:=path,after:=(action=3 ? path : "")
						else if action in 1,5
							before:=(action=5 ? frompath : ""),after:=path
						If (Directory and IsFunc(Directory))
							%Directory%(action,path)
						else if (action!=4){
							If IsFunc(Dir%r%F){
								F:=Dir%r%F
								%F%(before,after)
							}
						}
						If IsLabel(Dir%r%G){
								ErrorLevel:=action . "|" . path
								Gosub % Dir%r%G
							}
						break
					}
			}
			If (!pNext or pNext = 4129024)
				Break
			Else
				frompath:=path, PointerFNI := (PointerFNI + pNext)
		}
		DllCall( "ResetEvent", UInt,NumGet( Dir%r%Overlapped, 16 ) )
		Gosub, ReadDirectoryChanges
	Return
	StopWatchingDirectories:
		Loop % (DirIdx) {
			DllCall( "CloseHandle", UInt,Dir%A_Index% )
			DllCall( "CloseHandle", UInt,NumGet(Dir%A_Index%Overlapped, 16) )
			DllCall( "CloseHandle", UInt, NumGet(Dir%A_Index%Overlapped,16) )
			VarSetCapacity(Dir%A_Index%Overlapped,0)
			Dir%A_Index%=
			Dir%A_Index%Path=
			Dir%A_Index%Subdirs=
			Dir%A_Index%FNI=
		}
		DirIdx=
		VarSetCapacity(DirEvents,0)
	Return
	ReadDirectoryChanges:
		DllCall( "ReadDirectoryChangesW"
			, UInt , Dir%r%
			, UInt , &Dir%r%FNI
			, UInt , _SizeOf_FNI_
			, UInt , Dir%r%SubDirs
			, UInt , ( FILE_NOTIFY_CHANGE_FILE_NAME   := 0x1   )
					| ( FILE_NOTIFY_CHANGE_DIR_NAME    := 0x2   )
					| ( FILE_NOTIFY_CHANGE_ATTRIBUTES  := 0x4   )
					| ( FILE_NOTIFY_CHANGE_SIZE        := 0x8   )
					| ( FILE_NOTIFY_CHANGE_LAST_WRITE  := 0x10  )
					| ( FILE_NOTIFY_CHANGE_CREATION    := 0x40  )
					| ( FILE_NOTIFY_CHANGE_SECURITY    := 0x100 )
			, UInt , 0
			, UInt , &Dir%r%Overlapped
			, UInt , 0  )
	Return
} ;</07.01.000010>
;<07.01.000011>
GetFileIcon(File, SmallIcon := 1) {                                                                                                                            	;--

    VarSetCapacity(SHFILEINFO, cbFileInfo := A_PtrSize + 688)
    If (DllCall("Shell32.dll\SHGetFileInfoW"
        , "WStr", File
        , "UInt", 0
        , "Ptr" , &SHFILEINFO
        , "UInt", cbFileInfo
        , "UInt", 0x100 | SmallIcon)) { ; SHGFI_ICON
        Return NumGet(SHFILEINFO, 0, "Ptr")
    }
} ;</07.01.000011>
;<07.01.000012>
ExtractAssociatedIcon(ByRef ipath, ByRef idx) {									                                                                    	;-- Extracts the associated icon's index for the file specified in path

	; http://msdn.microsoft.com/en-us/library/bb776414(VS.85).aspx
	; shell32.dll
	; Extracts the associated icon's index for the file specified in path
	; Requires path and icon index
	; Icon must be destroyed when no longer needed (see below)

		hInst=0	; reserved, must be zero
		hIcon := DllCall("ExtractAssociatedIcon", "UInt", hInst, "UInt", &ipath, "UShortP", idx)
		return ErrorLevel

} ;</07.01.000012>
;<07.01.000013>
ExtractAssociatedIconEx(ByRef ipath, ByRef idx, ByRef iID) {				                                                                    	;-- Extracts the associated icon's index and ID for the file specified in path

		; http://msdn.microsoft.com/en-us/library/bb776415(VS.85).aspx
		; shell32.dll
		; Extracts the associated icon's index and ID for the file specified in path
		; Requires path, icon index and ID
		; Icon must be destroyed when no longer needed (see below)

			hInst=0	; reserved, must be zero
			hIcon := DllCall("ExtractAssociatedIconEx", "UInt", hInst, "UInt", &ipath, "UShortP", idx, "UShortP", iID)
			return ErrorLevel
} ;</07.01.000013>
;<07.01.000014>
DestroyIcon(hIcon) {																			                                                                    	;--
	DllCall("DestroyIcon", UInt, hIcon)
} ;</07.01.000014>
;<07.01.000015>
listfunc(file){																							                                                                     	;-- list all functions inside ahk scripts

	fileread, z, % file
	StringReplace, z, z, `r, , All			; important
	z := RegExReplace(z, "mU)""[^`n]*""", "") ; strings
	z := RegExReplace(z, "iU)/\*.*\*/", "") ; block comments
	z := RegExReplace(z, "m);[^`n]*", "")  ; single line comments
	p:=1 , z := "`n" z
	while q:=RegExMatch(z, "iU)`n[^ `t`n,;``\(\):=\?]+\([^`n]*\)[ `t`n]*{", o, p)
		lst .= Substr( RegExReplace(o, "\(.*", ""), 2) "`n"
		, p := q+Strlen(o)-1

	Sort, lst
	return lst
} ;</07.01.000015>
;<07.01.000016>
CreateOpenWithMenu(FilePath, Recommended := True, 					                                                                    	;-- creates an 'open with' menu for the passed file.
ShowMenu := False, MenuName := "OpenWithMenu", Others := "Others") {

	; ==================================================================================================================================
	; Creates an 'open with' menu for the passed file.
	; Parameters:
	;     FilePath    -  Fully qualified path of a single file.
	;     Recommended -  Show only recommended apps (True/False).
	;                    Default: True
	;     ShowMenu    -  Immediately show the menu (True/False).
	;                    Default: False
	;     MenuName    -  The name of the menu.
	;                    Default: OpenWithMenu
	;     Others      -  Name of the submenu holding not recommended apps (if Recommended has been set to False).
	;                    Default: Others
	; Return values:
	;     On success the function returns the menu's name unless ShowMenu has been set to True.
	;     If the menu couldn't be created, the function returns False.
	; Remarks:
	;     Requires AHK 1.1.23.07+ and Win Vista+!!!
	;     The function registers itself as the menu handler.
	; Credits:
	;     Based on code by querty12 -> autohotkey.com/boards/viewtopic.php?p=86709#p86709.
	;     I hadn't even heard anything about the related API functions before.
	; MSDN:
	;     SHAssocEnumHandlers -> msdn.microsoft.com/en-us/library/bb762109%28v=vs.85%29.aspx
	;     SHCreateItemFromParsingName -> msdn.microsoft.com/en-us/library/bb762134%28v=vs.85%29.aspx
	; ==================================================================================================================================


   Static RecommendedHandlers := []
        , OtherHandlers := []
        , HandlerID := A_TickCount
        , HandlerFunc := 0
        , ThisMenuName := ""
        , ThisOthers := ""
   ; -------------------------------------------------------------------------------------------------------------------------------
   Static IID_IShellItem := 0, BHID_DataObject := 0, IID_IDataObject := 0
        , Init := VarSetCapacity(IID_IShellItem, 16, 0) . VarSetCapacity(BHID_DataObject, 16, 0)
          . VarSetCapacity(IID_IDataObject, 16, 0)
          . DllCall("Ole32.dll\IIDFromString", "WStr", "{43826d1e-e718-42ee-bc55-a1e261c37bfe}", "Ptr", &IID_IShellItem)
          . DllCall("Ole32.dll\IIDFromString", "WStr", "{B8C0BD9F-ED24-455c-83E6-D5390C4FE8C4}", "Ptr", &BHID_DataObject)
          . DllCall("Ole32.dll\IIDFromString", "WStr", "{0000010e-0000-0000-C000-000000000046}", "Ptr", &IID_IDataObject)
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; Handler call
   If (Recommended = HandlerID) {
      AssocHandlers := A_ThisMenu = ThisMenuName ? RecommendedHandlers : OtherHandlers
      If (AssocHandler := AssocHandlers[A_ThisMenuItemPos]) && FileExist(FilePath) {
         AssocHandlerInvoke := NumGet(NumGet(AssocHandler + 0, "UPtr"), A_PtrSize * 8, "UPtr")
         If !DllCall("Shell32.dll\SHCreateItemFromParsingName", "WStr", FilePath, "Ptr", 0, "Ptr", &IID_IShellItem, "PtrP", Item) {
            BindToHandler := NumGet(NumGet(Item + 0, "UPtr"), A_PtrSize * 3, "UPtr")
            If !DllCall(BindToHandler, "Ptr", Item, "Ptr", 0, "Ptr", &BHID_DataObject, "Ptr", &IID_IDataObject, "PtrP", DataObj) {
               DllCall(AssocHandlerInvoke, "Ptr", AssocHandler, "Ptr", DataObj)
               ObjRelease(DataObj)
            }
            ObjRelease(Item)
         }
      }
      Try Menu, %ThisMenuName%, DeleteAll
      For Each, AssocHandler In RecommendedHandlers
         ObjRelease(AssocHandler)
      For Each, AssocHandler In OtherHandlers
         ObjRelease(AssocHandler)
      RecommendedHandlers:= []
      OtherHandlers:= []
      Return
   }
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; User call
   If !FileExist(FilePath)
      Return False
   ThisMenuName := MenuName
   ThisOthers := Others
   SplitPath, FilePath, , , Ext
   For Each, AssocHandler In RecommendedHandlers
      ObjRelease(AssocHandler)
   For Each, AssocHandler In OtherHandlers
      ObjRelease(AssocHandler)
   RecommendedHandlers:= []
   OtherHandlers:= []
   Try Menu, %ThisMenuName%, DeleteAll
   Try Menu, %ThisOthers%, DeleteAll
   ; Try to get the default association
   Size := VarSetCapacity(FriendlyName, 520, 0) // 2
   DllCall("Shlwapi.dll\AssocQueryString", "UInt", 0, "UInt", 4, "Str", "." . Ext, "Ptr", 0, "Str", FriendlyName, "UIntP", Size)
   HandlerID := A_TickCount
   HandlerFunc := Func(A_ThisFunc).Bind(FilePath, HandlerID)
   Filter := !!Recommended ; ASSOC_FILTER_NONE = 0, ASSOC_FILTER_RECOMMENDED = 1
   ; Enumerate the apps and build the menu
   If DllCall("Shell32.dll\SHAssocEnumHandlers", "WStr", "." . Ext, "UInt", Filter, "PtrP", EnumHandler)
      Return False
   EnumHandlerNext := NumGet(NumGet(EnumHandler + 0, "UPtr"), A_PtrSize * 3, "UPtr")
   While (!DllCall(EnumHandlerNext, "Ptr", EnumHandler, "UInt", 1, "PtrP", AssocHandler, "UIntP", Fetched) && Fetched) {
      VTBL := NumGet(AssocHandler + 0, "UPtr")
      AssocHandlerGetUIName := NumGet(VTBL + 0, A_PtrSize * 4, "UPtr")
      AssocHandlerGetIconLocation := NumGet(VTBL + 0, A_PtrSize * 5, "UPtr")
      AssocHandlerIsRecommended := NumGet(VTBL + 0, A_PtrSize * 6, "UPtr")
      UIName := ""
      If !DllCall(AssocHandlerGetUIName, "Ptr", AssocHandler, "PtrP", StrPtr, "UInt") {
         UIName := StrGet(StrPtr, "UTF-16")
         DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
      }
      If (UIName <> "") {
         If !DllCall(AssocHandlerGetIconLocation, "Ptr", AssocHandler, "PtrP", StrPtr, "IntP", IconIndex := 0, "UInt") {
            IconPath := StrGet(StrPtr, "UTF-16")
            DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
         }
         If (SubStr(IconPath, 1, 1) = "@") {
            VarSetCapacity(Resource, 4096, 0)
            If !DllCall("Shlwapi.dll\SHLoadIndirectString", "WStr", IconPath, "Ptr", &Resource, "UInt", 2048, "PtrP", 0)
               IconPath := StrGet(&Resource, "UTF-16")
         }
         ItemName := StrReplace(UIName, "&", "&&")
         If (Recommended || !DllCall(AssocHandlerIsRecommended, "Ptr", AssocHandler, "UInt")) {
            If (UIName = FriendlyName) {
               If RecommendedHandlers.Length() {
                  Menu, %ThisMenuName%, Insert, 1&, %ItemName%, % HandlerFunc
                  RecommendedHandlers.InsertAt(1, AssocHandler)
               }
               Else {
                  Menu, %ThisMenuName%, Add, %ItemName%, % HandlerFunc
                  RecommendedHandlers.Push(AssocHandler)
               }
               Menu, %ThisMenuName%, Default, %ItemName%
            }
            Else {
               Menu, %ThisMenuName%, Add, %ItemName%, % HandlerFunc
               RecommendedHandlers.Push(AssocHandler)
            }
            Try Menu, %ThisMenuName%, Icon, %ItemName%, %IconPath%, %IconIndex%
         }
         Else {
            Menu, %ThisOthers%, Add, %ItemName%, % HandlerFunc
            OtherHandlers.Push(AssocHandler)
            Try Menu, %ThisOthers%, Icon, %ItemName%, %IconPath%, %IconIndex%
         }
      }
      Else
         ObjRelease(AssocHandler)
   }
   ObjRelease(EnumHandler)
   ; All done
   If !RecommendedHandlers.Length() && !OtherHandlers.Length()
      Return False
   If OtherHandlers.Length()
      Menu, %ThisMenuName%, Add, %ThisOthers%, :%ThisOthers%
   If (ShowMenu)
      Menu, %ThisMenuName%, Show
   Else
      Return ThisMenuName
} ;</07.01.000016>
;<07.01.000017>
FileCount(filter) {																					                                                                    	;-- count matching files in the working directory

   loop,files,%filter%
     Count := A_Index
   return Count

} ;</07.01.000017>
;<07.01.000018>
GetImageTypeW(File) {																		                                                                    	;-- Identify the image type (UniCode)

/* Description: Identify the image type

	; AHK version: B:1.0.48.5 L:1.0.92.0
	; Language: Chinese/English, Platform: Win7, Author: Pirate <healthlolicon@gmail.com>,

	;Type 0 Unknow
	;Type 1 BMP *.bmp
	;Type 2 JPEG *.jpg *.jpeg
	;Type 3 PNG *.png
	;Type 4 gif *.gif
	;Type 5 TIFF *.tif

*/


	hFile:=FileOpen(File,"r")
	hFile.seek(0)
	FileHead_hex:=hfile.ReadUint()
	hFile.Close()

	If FileHead_hex = 0x474E5089; small end of the actual data is 89 50 4E 47 under the same PNG file header actually has 8 bytes
	    Type=3 ; png
	Else If FileHead_hex=0x38464947 ; gif file header 6 bytes
	    Type=4 ; gif
	Else
	{
	    Filehead_hex&=0xFFFF
	    If FileHead_hex=0x4D42; BMP file header only 2 bytes
	        Type=1 ; bmp
	    Else if FileHead_hex=0xD8FF ; JPG file header is only 2 bytes
	        Type=2 ; jpg/jpeg
	    Else If FileHead_hex=0x4949 ; TIFF file header 2 bytes II
	        Type=5 ; tif
	    Else If FileHead_hex=0x4D4D ;MM
	        Type=5 ; tif
	    Else
	        Type=0 ; Unknow
	    }

Return,Type
} ;</07.01.000018>
;<07.01.000019>
FileWriteLine( _File, _Data = "", _Linenum = 1, _Replace = true ) {                                                                         		;-- to write data at specified line in a file.

    FileRead, _FileData, % _File
    _DataBefore := Substr( _FileData, 1, Instr( _FileData, "`r`n", false, 1, _Linenum - 1 ) )
    _DataAfter := Substr( _FileData, Instr( _FileData, "`r`n", false, 1, ( _Replace ? _Linenum : _Linenum - 1 ) ) )
    _FileData := _DataBefore . _Data . _DataAfter
    FileDelete, % _File
    FileAppend, % _FileData, % _File
} ;</07.01.000019>
;<07.01.000020>
FileMD5( sFile = "", cSz = 4 ) {            													                                                                    	;-- file MD5 hashing

    cSz := ( cSz<0 || cSz>8 ) ? 2**22 : 2**( 18+cSz ), VarSetCapacity( Buffer, cSz, 0 )
    hFil := DllCall( "CreateFile", Str, sFile, UInt, 0x80000000, Int, 1, Int, 0, Int, 3, Int, 0, Int, 0 )
    IfLess, hFil, 1, return, hFil
    DllCall( "GetFileSizeEx", UInt, hFil, Str, Buffer ), fSz := NumGet( Buffer, 0, "Int64" )
    VarSetCapacity( MD5_CTX, 104, 0 ), DllCall( "advapi32\MD5Init", Str, MD5_CTX )
    Loop % ( fSz//cSz+!!Mod( fSz, cSz ) )
        DllCall( "ReadFile", UInt, hFil, Str, Buffer, UInt, cSz, UIntP, bytesRead, UInt, 0 )
        , DllCall( "advapi32\MD5Update", Str, MD5_CTX, Str, Buffer, UInt, bytesRead )
    DllCall( "advapi32\MD5Final", Str, MD5_CTX ), DllCall( "CloseHandle", UInt, hFil )
    Loop % StrLen( Hex := "123456789ABCDEF0" )
        N := NumGet( MD5_CTX, 87+A_Index, "Char" ), MD5 .= SubStr( Hex, N>>4, 1 ) . SubStr( Hex, N&15, 1 )
    return MD5
} ;</07.01.000020>
;<07.01.000021>
FileCRC32(sFile="",cSz=4) {																	                                                                    	;-- computes and returns CRC32 hash for a File passed as parameter

	; by SKAN www.autohotkey.com/community/viewtopic.php?t=64211
	cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity( Buffer,cSz,0 ) ; 10-Oct-2009
	hFil := DllCall( "CreateFile", Str,sFile,UInt,0x80000000, Int,3,Int,0,Int,3,Int,0,Int,0 )
	IfLess,hFil,1, Return,hFil
	hMod := DllCall( "LoadLibrary", Str,"ntdll.dll" ), CRC32 := 0
	DllCall( "GetFileSizeEx", UInt,hFil, UInt,&Buffer ),    fSz := NumGet( Buffer,0,"Int64" )
	Loop % ( fSz//cSz + !!Mod( fSz,cSz ) )
		DllCall( "ReadFile", UInt,hFil, UInt,&Buffer, UInt,cSz, UIntP,Bytes, UInt,0 )
		, CRC32 := DllCall( "NTDLL\RtlComputeCrc32", UInt,CRC32, UInt,&Buffer, UInt,Bytes, UInt )
	DllCall( "CloseHandle", UInt,hFil )
	SetFormat, Integer, % SubStr( ( A_FI := A_FormatInteger ) "H", 0 )
	CRC32 := SubStr( CRC32 + 0x1000000000, -7 ), DllCall( "CharUpper", Str,CRC32 )
	SetFormat, Integer, %A_FI%
	Return CRC32, DllCall( "FreeLibrary", UInt,hMod )
} ;</07.01.000021>
;<07.01.000022>
FindFreeFileName(FilePath) {																                                                                    	;-- Finds a non-existing filename for Filepath by appending a number in brackets to the name

	SplitPath, FilePath,, dir, extension, filename
	Testpath := FilePath ;Return path if it doesn't exist
	i := 1
	while FileExist(TestPath)
	{
		i++
		Testpath := dir "\" filename " (" i ")" (extension = "" ? "" : "." extension)
	}
	return TestPath
} ;</07.01.000022>
;<07.01.000023>
CountFilesR(Folder) {																			                                                                    	;-- count files recursive in specific folder (uses COM method)
	static Counter=0,  fso
	fso := fso?fso:ComObjCreate("Scripting.FileSystemObject")
	Folder := fso.GetFolder(Folder)	, Counter += Counter?0:CountFiles(Folder.path)
	For Subfolder in Folder.SubFolders
		Counter += CountFiles(Subfolder.path) , CountFilesR(Subfolder.path)
	return Counter
} ;</07.01.000023>
;<07.01.000024>
CountFiles(Folder) {                                                                                                                                                 	;-- count files in specific folder (uses COM method)
	fso := ComObjCreate("Scripting.FileSystemObject")
	Folder := fso.GetFolder(Folder)
	return fso.GetFolder(Folder).Files.Count
} ;</07.01.000024>
;<07.01.000025>
PathInfo(ByRef InputVar) {																	                                                                    	;-- splits a given path to return as object
	SplitPath, InputVar, f, d, e, n, dr
	return	Object("FileName",f,"Dir",d,"Extension",e,"NameNoExt",n,"Drive",dr)
} ;</07.01.000025>
;<07.01.000026>
DriveSpace(Drv="", Free=1) { 																                                                                    	;-- retrieves the DriveSpace
	; www.autohotkey.com/forum/viewtopic.php?p=92483#92483
	Drv := Drv . ":\",  VarSetCapacity(SPC, 30, 0), VarSetCapacity(BPS, 30, 0)
	VarSetCapacity(FC , 30, 0), VarSetCapacity(TC , 30, 0)
	DllCall( "GetDiskFreeSpaceA", Str,Drv, UIntP,SPC, UIntP,BPS, UIntP,FC, UIntP,TC )
	Return Free=1 ? (SPC*BPS*FC) : (SPC*BPS*TC) ; Ternary Operator requires 1.0.46+
} ;</07.01.000026>
;<07.01.000027>
GetBinaryType(FileName) {																	                                                                    	;-- determines the bit architecture of an executable program
  IfNotExist, %FileName%, Return "File not found"
  Binary:=DllCall("GetBinaryType","Str", FileName, "UInt *", RetVal)
  IfEqual, Binary, 0, Return "Not Executable"
  BinaryTypes := "32-Bit|DOS|16-Bit|PIF|POSIX|OS2-16-Bit|64-Bit"
  StringSplit, BinaryType , BinaryTypes, |
  BinaryType:="BinaryType" . RetVal + 1
Return (%BinaryType%)
} ;</07.01.000027>
;<07.01.000028>
GetFileAttributes(Filename, ByRef Attrib := "", ByRef Path := "", ByRef Type := "") {											    	;-- get attributes of a file or folder

	/*                              	DESCRIPTION

			get attributes of a file or folder
			Syntax: GetFileAttributes ([File / Folder], [out Attrib], [out Path], [out Type])
			Parameters:
			Attrib: returns a value that reproduces the attributes.
			Path: returns the complete path.
			Type: if it is a file, it returns "F", if it is a directory it returns "D".
			Return:
			0 = ERROR
			[attributes] = OK
			R = read only
			A = file | modified
			S = system
			H = hidden
			N = normal
			O = offline
			T = temporary
			C = compressed
			D = directory | binder
			E = encrypted
			V = virtual

	*/


	Path := GetFullPathName(Filename), Path := (StrLen(Path) > 260 ? "\\?\" : "") Path (StrLen(Path) > 2 ? "" : "\")
	if ((Attrib := DllCall("Kernel32.dll\GetFileAttributesW", "Ptr", &Path)) = -1)
		return false
	for k, v in {"R": 0x1, "A": 0x20, "S": 0x4, "H": 0x2, "N": 0x80, "D": 0x10, "O": 0x1000, "C": 0x800, "T": 0x100, "E": 0x4000, "V": 0x10000}
		if (Attrib & v)
			OutputVar .= k
	if IsByRef(Type)
		Type := Attrib&0x10?"D":"F"
	return OutputVar
} ;</07.01.000028>
;<07.01.000029>
SetFileTime(Time := "", FilePattern := "", WhichTimeMCA := "M", OperateOnFolders := false, Recurse := false) {		;-- to set the time
	if IsObject(Time)
		for k, v in Time
			FileSetTime, %v%, %FilePattern%, % k=1?"M":k=2?"C":k=3?"A":k, %OperateOnFolders%, %Recurse%
	else Loop, Parse, % WhichTimeMCA
		FileSetTime, %Time%, %FilePattern%, %A_LoopField%, %OperateOnFolders%, %Recurse%
	return !ErrorLevel
} ;</07.01.000029>
;<07.01.000030>
SetFileAttributes(Attributes, Filename, Mode := "FD") {																								;-- set attributes of a file or folder

	/*                              	DESCRIPTION

				change attribute (s) to folder (s) and / or file (s).
				Syntax: SetFileAttributes ([/ - / Attrib], [Filename], [Mode])
				Parameters:
				Mode: F = include files | D = include directories | R = include subdirectories.
				Attrib: specify one or more of the following letters. to remove use "-", to add use "", to alternate use ", to replace do not specify anything.
							R = read only
							A = file | modified
							S = system
							H = hidden
							N = normal
							O = offline
							T = temporary
							[value] = specify a value that represents the attributes to replace.
							Example: MsgBox% SetFileAttributes ("HS-R?", A_Desktop "\ test.txt")

	*/


	static A := {R: 0x1, A: 0x20, S: 0x4, H: 0x2, N: 0x80, O: 0x1000, T: 0x100}
	if InStr(Mode, "R") || InStr(Filename, "*") || InStr(Filename, "?") {
		Loop, Files, % Filename, % Mode
			Ok += !!SetFileAttributes(Attributes, A_LoopFileFullPath)
		return Ok
	} if !StrLen(Attributes + 0) {
		if (GetFileAttributes(Filename, Attrib, Filename) = 0)
			return false
		Loop, Parse, % Attributes,, % A_Space A_Tab
			if A[A_LoopField]
				Attrib := _cvtvalue(Attrib, P A[A_LoopField])
			else P := A_LoopField
	} else Attrib := Attributes, Filename := (StrLen(Filename) > 260 ? "\\?\" : "") Filename
	return DllCall("Kernel32.dll\SetFileAttributesW", "Ptr",  &Filename, "UInt", Attrib)
} ;</07.01.000030>
;<07.01.000031>
FileSetSecurity(Path, Trustee := "", AccessMask := 0x1F01FF, Flags := 1, AccesFlag := 0) { 										;--  set security for the file / folder

	/*                              	DESCRIPTION

			; set security for the file / folder
			; Syntax: FileSetSecurity ([file], [User], [permissions], [options], [access])
			; Parameters:
			; File: specify the file or folder to modify
			; User: specify the SID of the user that inherits the permissions or Domain \ User. if not specified, use the current user
			; Note: to obtain a list of users with information, use UserAccountsEnum ()
			; Permissions: specify the desired access
			; 0x1F01FF = TOTAL CONTROL (F)
			; 0x120089 = READING (R)
			; 0x120116 = WRITING (W)
			; 0x1200a0 = EXECUTION (X)
			; 0x00010000 = DISPOSAL (D)
			; 0x1301BF = MODIFICATION (M)
			; Options:
			; 0 = directories
			; 1 = directories and files
			; 2 = directories and sub-directories
			; 3 = directories, sub-directories and files
			; Access: https://msdn.microsoft.com/en-us/library/windows/desktop/aa772244(v=vs.85).aspx
			; 0 = allow
			; 1 = deny
			;Notes:
			; permissions can be viewed by clicking on file properties, security tab.
			; permissions can be changed with ICACLS in CMD: icacls [file] / grant * [user]: ([permissions, letter], WDAC)
			; the function sets the owner, since it is required to change the permissions
			The invoking process must have administrator permissions to modify the permissions
			;Example:
			; MsgBox% "Take Ownership:" FileSetOwner (A_SysDir () "\ calc.exe") first take ownership
			; MsgBox% "Total Control:" FileSetSecurity (A_SysDir () "\ calc.exe"); second modify permissions
			; Return: 0 | 1

	*/


	Trustee := Trustee=""?A_UserNameEx():Trustee, Path := GetFullPathName(Path)
	, oADsSecurityUtility := ComObjCreate("ADsSecurityUtility")
	, oADsSecurityDescriptor := oADsSecurityUtility.GetSecurityDescriptor(Path, 1, 1)
	, Owner := oADsSecurityDescriptor.Owner
	if !(Trustee=Owner) && !(Owner="") && !(Trustee="")
		FileSetOwner(Path, Trustee)
	oDiscretionaryAcl := oADsSecurityDescriptor.DiscretionaryAcl
	, oAccessControlEntry := ComObjCreate("AccessControlEntry")
	, oAccessControlEntry.Trustee := Trustee
	, oAccessControlEntry.AccessMask := AccessMask
	, oAccessControlEntry.AceFlags := Flags
	, oAccessControlEntry.AceType := AccesFlag
	, oDiscretionaryAcl.AddAce(oAccessControlEntry)
	, oADsSecurityUtility.SetSecurityDescriptor(Path, 1, oADsSecurityDescriptor, 1)
} ;</07.01.000031>
;<07.01.000032>
FileSetOwner(Path, Owner := "") {																																;-- set the owner to file / directory

	/*                              	DESCRIPTION

			; set the owner to file / directory
			; Syntax: FileSetOwner ([file], [user])
			; Parameters:
			; User: specify the domain \ user or user's SID. by default it uses the current user.

	*/


	Owner := Owner=""?A_UserNameEx():Owner
	, oADsSecurityUtility := ComObjCreate("ADsSecurityUtility")
	, oADsSecurityUtility.SecurityMask := 0x1
	, oADsSecurityDescriptor := oADsSecurityUtility.GetSecurityDescriptor(Path:=GetFullPathName(Path), 1, 1)
	, oADsSecurityDescriptor.Owner := Owner
	, oADsSecurityUtility.SetSecurityDescriptor(Path, 1, oADsSecurityDescriptor, 1)
} ;</07.01.000032>
;<07.01.000033>
FileGetOwner(Path) { 																																					;-- get the owner to file / directory

	/*                              	DESCRIPTION

			get the domain and username
			; Syntax: FileGetOwner ([file])
			; Return: domain \ user

	*/


	oADsSecurityUtility := ComObjCreate("ADsSecurityUtility")
	, oADsSecurityUtility.SecurityMask := 0x1
	, oADsSecurityDescriptor := oADsSecurityUtility.GetSecurityDescriptor(GetFullPathName(Path), 1, 1)
	return oADsSecurityDescriptor.Owner
} ;</07.01.000033>
;<07.01.000034>
GetFileFormat(file) {                                                                                                                                                 	;-- retreaves the codepage format of a file

  static BOM:={254_255:"UTF-16 BE",255_254:"UTF-16 LE",239_187_191:"UTF-8",247_100_76:"UTF-1",14_254_255:"SCSU",251_238_40:"BOCU-1"
              ,0_0_254_255:"UTF-32 BE",255_254_0_0:"UTF-32 LE",43_47_118_43:"UTF-7",43_47_118_47:"UTF-7",43_47_118_56:"UTF-7"
              ,43_47_118_57:"UTF-7",221_115_102_115:"UTF-EBCDIC",132_49_149_51:"GB 18030"}
  If !FileExist(file)
		return
	FileRead,text,*c %file%

  BOM2:=NumGet(&text,"UChar") "_" NumGet(&text+1,"UChar"), BOM3:=BOM2 "_" NumGet(&text+2,"UChar"), BOM4:=BOM3 "_" NumGet(&text+3,"UChar")
  If BOM.HasKey(BOM4)
    return BOM[BOM4]
  else if BOM.HasKey(BOM3)
    return BOM[BOM3]
  else if BOM.HasKey(BOM2)
    return BOM[BOM2]
  FileGetSize,size,%file%
  return StrLen(StrGet(&text,"UTF-8"))=size?"ANSI":"UTF-8 no BOM"
} ;</07.01.000034>
;<07.01.000035>
HashFile(filePath,hashType=2)  {	                                                                                                                            	;-- calculate hashes (MD2,MD5,SH1,SHA256, SHA384, SHA512) from file

	/*    	DESCRIPTION of function HashFile()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	calculate hashes (MD2,MD5,SH1,SHA256, SHA384, SHA512) from file
			Link              	:	http://www.autohotkey.com/forum/viewtopic.php?t=71133
			Author         	:	Deo
			Date             	:	24 Apr 2011
			AHK-Version	:	AHK_L
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	hash, MD, SHA, compare, file, crypt
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			filePath := "C:\Windows\notepad.exe"

			msgbox % "MD5:`n" HashFile(filePath,2)
			msgbox % "SHA:`n" HashFile(filePath,3)
			msgbox % "SHA512:`n" HashFile(filePath,6)

	*/

   PROV_RSA_AES                 	:= 24
   CRYPT_VERIFYCONTEXT     	:= 0xF0000000
   BUFF_SIZE                         	:= 1024 * 1024 ; 1 MB
   HP_HASHVAL                     	:= 0x0002
   HP_HASHSIZE                     	:= 0x0004

   HASH_ALG := (hashType = 1 OR hashType = "MD2") ? (CALG_MD2 := 32769) : HASH_ALG
   HASH_ALG := (hashType = 2 OR hashType = "MD5") ? (CALG_MD5 := 32771) : HASH_ALG
   HASH_ALG := (hashType = 3 OR hashType = "SHA") ? (CALG_SHA := 32772) : HASH_ALG
   HASH_ALG := (hashType = 4 OR hashType = "SHA256") ? (CALG_SHA_256 := 32780) : HASH_ALG   ;Vista+ only
   HASH_ALG := (hashType = 5 OR hashType = "SHA384") ? (CALG_SHA_384 := 32781) : HASH_ALG   ;Vista+ only
   HASH_ALG := (hashType = 6 OR hashType = "SHA512") ? (CALG_SHA_512 := 32782) : HASH_ALG   ;Vista+ only

   f := FileOpen(filePath,"r","CP0")
   if !IsObject(f)
      return 0
   if !hModule := DllCall( "GetModuleHandleW", "str", "Advapi32.dll", "Ptr" )
      hModule := DllCall( "LoadLibraryW", "str", "Advapi32.dll", "Ptr" )
   if !dllCall("Advapi32\CryptAcquireContextW"
            ,"Ptr*",hCryptProv
            ,"Uint",0
            ,"Uint",0
            ,"Uint",PROV_RSA_AES
            ,"UInt",CRYPT_VERIFYCONTEXT )
      Gosub,HashTypeFreeHandles

   if !dllCall("Advapi32\CryptCreateHash"
            ,"Ptr",hCryptProv
            ,"Uint",HASH_ALG
            ,"Uint",0
            ,"Uint",0
            ,"Ptr*",hHash )
      Gosub, HashTypeFreeHandles

   VarSetCapacity(read_buf,BUFF_SIZE,0)

    hCryptHashData := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "CryptHashData", "Ptr")
   While (cbCount := f.RawRead(read_buf, BUFF_SIZE))
   {
      if (cbCount = 0)
         break

      if !dllCall(hCryptHashData
               ,"Ptr",hHash
               ,"Ptr",&read_buf
               ,"Uint",cbCount
               ,"Uint",0 )
         Gosub, HashTypeFreeHandles
   }

   if !dllCall("Advapi32\CryptGetHashParam"
            ,"Ptr",hHash
            ,"Uint",HP_HASHSIZE
            ,"Uint*",HashLen
            ,"Uint*",HashLenSize := 4
            ,"UInt",0 )
      Gosub, HashTypeFreeHandles

   VarSetCapacity(pbHash,HashLen,0)
   if !dllCall("Advapi32\CryptGetHashParam"
            ,"Ptr",hHash
            ,"Uint",HP_HASHVAL
            ,"Ptr",&pbHash
            ,"Uint*",HashLen
            ,"UInt",0 )
      Gosub, HashTypeFreeHandles

   SetFormat,integer,Hex
   loop,%HashLen%
   {
      num := numget(pbHash,A_index-1,"UChar")
      hashval .= substr((num >> 4),0) . substr((num & 0xf),0)
   }
   SetFormat,integer,D

HashTypeFreeHandles:
   f.Close()
   DllCall("FreeLibrary", "Ptr", hModule)
   dllCall("Advapi32\CryptDestroyHash","Ptr",hHash)
   dllCall("Advapi32\CryptReleaseContext","Ptr",hCryptProv,"UInt",0)
   return hashval
} ;</07.01.000035>
;<07.01.000036>
PathCombine(abs, rel) {                                                                                                                                           	;-- combine the 2 routes provided in a single absolute path

		/*    	DESCRIPTION of function PathCombine()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	combine the 2 routes provided in a single absolute path
			Link              	:	https://github.com/Denis-net/SendToNewFolder/blob/master/SendToNewFolder.ahk
			Author         	:	Denis-net                  https://github.com/Denis-net
			Date             	:	23.12.2018
			AHK-Version	:	AHK_L
			License         	:	GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	files, path
        	-------------------------------------------------------------------------------------------------------------------
	*/

    VarSetCapacity(dest, (A_IsUnicode ? 2 : 1) * 260, 1) ; MAX_PATH
    DllCall("Shlwapi.dll\PathCombine", "UInt", &dest, "UInt", &abs, "UInt", &rel)
    Return, dest
} ;</07.01.000036>
;<07.01.000037>
GetParentDir(Dir){                                                                                                                                                   	;-- small RegEx function to get parent dir from a given string
    Return RegExReplace(Dir, "\\[^\\]+$")
} ;</07.01.000037>
;<07.01.000038>
DirGetParent(path,parent:=1) {                                                                                                                                	;-- returns a string containing parent dir, it's possible to set the level of parent dir
	path:=RTrim(path,"\")
	while parent>=idx:=A_Index
			Loop % path, 1
				if (idx=parent)
						return A_LoopFileDir (A_LoopFileDir?"\":"")
				else if path:=A_LoopFileDir
						break
} ;</07.01.000038>
;<07.01.000039>
SelectFolder() {																	                                                										;-- the common File Dialog lets you add controls to it

	/*	DESCRIPTION OF FUNCTION: -- SelectFolder --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	On Vista and later, the Common File Dialog lets you add controls to it. Here's a small modification of just me's SelectFolder that adds a group,
								combo box and two items to the dialog box, and then returns whatever was selected in the combo box.
								The dialog allows for far more customisation than what I've simply done, look at the following for ideas and C++ code:
										https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/HEAD/winui/shell/appplatform/commonfiledialog
										https://www.codeproject.com/Articles/16678/Vista-Goodies-in-C-Using-the-New-Vista-File-Dialog
								If you implement the IFileDialogControlEvents interface, It is also possible to get notifications then and there when a combo box etc. item has
								been selected so that you could, say, change parts of the file dialog on-the-fly, but even if it weren't 04:30 here, I'd still end up half-assing the
								implementation as implementing COM interfaces is not something I particularly enjoy doing and nor am I any good at it anyway :-)
								------------------------------------------------------------------------------------------------------------------------------------------------------------
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=29934
	Author         	:	qwerty12 and just me
	Date             	:	04/01/2017
	AHK-Version	:	AHK_L
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:	Common Item Dialog -> msdn.microsoft.com/en-us/library/bb776913%28v=vs.85%29.aspx
								IFileDialog        -> msdn.microsoft.com/en-us/library/bb775966%28v=vs.85%29.aspx
								IShellItem         -> msdn.microsoft.com/en-us/library/bb761140%28v=vs.85%29.aspx
	Dependencies	:	none
	KeyWords    	:	dialog,gui,file,save,interface
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

   Static OsVersion := DllCall("GetVersion", "UChar")
   Static Show := A_PtrSize * 3
   Static SetOptions := A_PtrSize * 9
   Static GetResult := A_PtrSize * 20
   SelectedFolder := ""
   If (OsVersion < 6) { ; IFileDialog requires Win Vista+
      FileSelectFolder, SelectedFolder
      Return SelectedFolder
   }
   If !(FileDialog := ComObjCreate("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}", "{42f85136-db7e-439c-85f1-e4075d135fc8}"))
      Return ""
   VTBL := NumGet(FileDialog + 0, "UPtr")
   DllCall(NumGet(VTBL + SetOptions, "UPtr"), "Ptr", FileDialog, "UInt", 0x00000028, "UInt") ; FOS_NOCHANGEDIR | FOS_PICKFOLDERS

   try if ((FileDialogCustomize := ComObjQuery(FileDialog, "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}"))) {
		groupId := 616 ; arbitrarily chosen
		comboboxId := 93270
		itemOneId := 015
		itemTwoId := 666

		DllCall(NumGet(NumGet(FileDialogCustomize+0)+26*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", groupId, "WStr", "Gruppe name") ; IFileDialogCustomize::StartVisualGroup
		DllCall(NumGet(NumGet(FileDialogCustomize+0)+6*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", comboboxId) ; IFileDialogCustomize::AddComboBox
		DllCall(NumGet(NumGet(FileDialogCustomize+0)+19*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", comboboxId, "UInt", itemOneId, "WStr", "ZeroQuinze") ; IFileDialogCustomize::AddControlItem
		DllCall(NumGet(NumGet(FileDialogCustomize+0)+19*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", comboboxId, "UInt", itemTwoId, "WStr", "Sosa") ; IFileDialogCustomize::AddControlItem
		DllCall(NumGet(NumGet(FileDialogCustomize+0)+25*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", comboboxId, "UInt", itemOneId) ; IFileDialogCustomize::SetSelectedControlItem
		DllCall(NumGet(NumGet(FileDialogCustomize+0)+27*A_PtrSize), "Ptr", FileDialogCustomize) ; IFileDialogCustomize::EndVisualGroup
	}

   If !DllCall(NumGet(VTBL + Show, "UPtr"), "Ptr", FileDialog, "Ptr", 0, "UInt") {
      If !DllCall(NumGet(VTBL + GetResult, "UPtr"), "Ptr", FileDialog, "PtrP", ShellItem, "UInt") {
         GetDisplayName := NumGet(NumGet(ShellItem + 0, "UPtr"), A_PtrSize * 5, "UPtr")
         If !DllCall(GetDisplayName, "Ptr", ShellItem, "UInt", 0x80028000, "PtrP", StrPtr) ; SIGDN_DESKTOPABSOLUTEPARSING
            SelectedFolder := StrGet(StrPtr, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
         ObjRelease(ShellItem)

         if (FileDialogCustomize) {
			if (DllCall(NumGet(NumGet(FileDialogCustomize+0)+24*A_PtrSize), "Ptr", FileDialogCustomize, "UInt", comboboxId, "UInt*", selectedItemId) == 0) { ; IFileDialogCustomize::GetSelectedControlItem
				if (selectedItemId == itemOneId)
					MsgBox ,,ZeroQuinze, %SelectedFolder%
				else if (selectedItemId == itemTwoId)
					MsgBox ,,Sosa, %SelectedFolder%
			}
         }
      }
   }
   if (FileDialogCustomize)
		ObjRelease(FileDialogCustomize)

   ObjRelease(FileDialog)
   Return SelectedFolder
} ;</07.01.000039>
;<07.01.000040>
Filexpro( sFile := "", Kind := "", P* ) {                                                                                                                        	;-- retreaves file extended properties Object

	/*	DESCRIPTION OF FUNCTION: -- Filexpro() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	retreaves file extended properties
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=59882&hilit=space+SKAN
	Author         	:	SKAN v.90 on D1CC @ goo.gl/jyXFo9
	Date             	:	11.12.2018
	AHK-Version	:	AHK_L (The function was written in/for Windows 7 + AHK 1.1.30.00)
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	sFile - Filepath. Relative path will be resolved to fullpath. Function will return null if
										   Root drive is passed.
                            	Kind - Optional. The "kind" of file. Eg: Music Picture etc. The function will test for Kind
											before attempting to retrieve properties.
                            	*p 	- Varadic parameters. Pass property names as strings. I'm able to pass 1317
                                    	    element linear array as params. if last variadic parameter is xInfo the function
											will return extra file props like A_LoopFileExt, A_LoopFileFullPath etc
	Return value	:	Object
	Remark(s)    	:	These properties are to meant to be shown in Windows Explorer and searched with
								"Advanced Query Syntax". If Explorer could show all properties for all file formats, it
								would become horribly slow/unusable and may become unstable when trying to
								read a badly written property. These methods use simple lookup and shouldn't be
								compared with professional level software.
	Dependencies	:	none
	KeyWords    	:	file,extended properties
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Example 1:
		Obj := Filexpro( A_AhkPath,, "System.FileFRN" )
		DriveGet, Serial, Serial, % SubStr(A_AhkPath,1,2)
		MsgBox % Format( "{:08X}-{:016X}", Serial, obj["System.FileFRN"] ) ; File ID

	Example 2:
		Obj := Filexpro(A_WinDir . "\Media\chimes.wav",, "System.Audio.ChannelCount"
                                               , "System.Audio.Compression"
                                               , "System.Audio.EncodingBitrate"
                                               , "System.Audio.Format"
                                               , "System.Audio.IsVariableBitRate"
                                               , "System.Audio.PeakValue"
                                               , "System.Audio.SampleRate"
                                               , "System.Audio.SampleSize"
                                               , "System.Audio.StreamName"
                                               , "System.Audio.StreamNumber" )
		MsgBox % obj["System.Audio.EncodingBitrate"]

	Example 3:
		Props := ["Path","Copyright","File description","File version"
        ,"Language","Product name","Product version" ]

		Loop, Files, %A_AhkPath%\..\*.*
		{
			  Obj := Filexpro( A_LoopFileLongPath, "Program", Props* )

			  If ( IsObject(Obj)= 0 )
				Continue

			  L := ""
			  For Key, Val in Obj
				L .= Key A_Tab Val "`n"

			  MsgBox, 0, %A_LoopFileName%,  %L%
		  }
	*/

	Local
	Static xDetails

	  If ( sFile = "" )
		{                                                           ;   Deinit static variable
			xDetails := ""
			Return
		}

	  fex := {}, _FileExt := ""

	  Loop, Files, % RTrim(sfile,"\*/."), DF
		{
			If not FileExist( sFile:=A_LoopFileLongPath )
			  {
				  Return
			  }

			SplitPath, sFile, _FileExt, _Dir, _Ext, _File, _Drv

			If ( p[p.length()] = "xInfo" )                          ;  Last parameter is xInfo
			  {
				  p.Pop()                                           ;         Delete parameter
				  fex.SetCapacity(11)                               ; Make room for Extra info
				  fex["_Attrib"]    := A_LoopFileAttrib
				  fex["_Dir"]       := _Dir
				  fex["_Drv"]       := _Drv
				  fex["_Ext"]       := _Ext
				  fex["_File"]      := _File
				  fex["_File.Ext"]  := _FileExt
				  fex["_FilePath"]  := sFile
				  fex["_FileSize"]  := A_LoopFileSize
				  fex["_FileTimeA"] := A_LoopFileTimeAccessed
				  fex["_FileTimeC"] := A_LoopFileTimeCreated
				  fex["_FileTimeM"] := A_LoopFileTimeModified
			  }
			Break
		}

	  If Not ( _FileExt )                                   ;    Filepath not resolved
		{
			Return
		}


	  objShl := ComObjCreate("Shell.Application")
	  objDir := objShl.NameSpace(_Dir)
	  objItm := objDir.ParseName(_FileExt)

	  If ( VarSetCapacity(xDetails) = 0 )                           ;     Init static variable
		{
			i:=-1,  xDetails:={},  xDetails.SetCapacity(309)

			While ( i++ < 309 )
			  {
				xDetails[ objDir.GetDetailsOf(0,i) ] := i
			  }

			xDetails.Delete("")
		}

	  If ( Kind and Kind <> objDir.GetDetailsOf(objItm,11) )        ;  File isn't desired kind
		{
			Return
		}

	  i:=0,  nParams:=p.Count(),  fex.SetCapacity(nParams + 11)

	  While ( i++ < nParams )
		{
			Prop := p[i]

			If ( (Dot:=InStr(Prop,".")) and (Prop:=(Dot=1 ? "System":"") . Prop) )
			  {
				  fex[Prop] := objItm.ExtendedProperty(Prop)
				  Continue
			  }

			If ( PropNum := xDetails[Prop] ) > -1
			  {
				  fex[Prop] := ObjDir.GetDetailsOf(objItm,PropNum)
				  Continue
			  }
		}

	  fex.SetCapacity(-1)
Return fex
} ;</07.01.000040>

}
;|   InvokeVerb(01)                        	|   Function_Eject(02)                    	|   FileGetDetail(03)                      	|   FileGetDetails(04)                     	|
;|   DirExist()                                 	|   GetDetails()                              	|   Start()                                       	|   IsFileEqual()                             	|
;|   WatchDirectory()	x 2                	|   GetFileIcon()                             	|   ExtractAssociatedIcon()            	|   ExtractAssociatedIconEx()         	|
;|   DestroyIcon()                           	|   listfunc()                                   	|   CreateOpenWithMenu()           	|   FileCount()                               	|
;|   IdentifyImageTypW()               	|   FileWriteLine()                          	|   FileMD5()                                 	|   FileCRC32()                              	|
;|   FindFreeFileName()                 	|   CountFilesR()                            	|   CountFiles()                              	|   PathInfo()                                 	|
;|   DriveSpace()                            	|   GetBinaryType()                       	|   GetFileAttributes()                    	|   SetFileTime()                            	|
;|   SetFileAttributes()                    	|   FileSetSecurity()                       	|   FileSetOwner()                          	|   FileGetOwner()                         	|
;|   GetFileFormat()                        	|   HashFile()                                 	|   PathCombine(36)                     	|   GetParentDir(37)                      	|
;|   DirGetParent(38)                      	|   SelectFolder(39)                         	|   Filexpro(40)                              	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Font things (13) -                                                                                                                                      	baseID: <08>
;<08.01.000001>
CreateFont(pFont="") {                                                                                                 	;-- creates font in memory which can be used with any API function accepting font handles

	/*    	DESCRIPTION of function CreateFont() ID: 08.01.00001
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Creates font in memory which can be used with any API function accepting font handles
			Link              	:	https://autohotkey.com/board/topic/21003-function-createfont/
			Author         	:	majkinetor
			Date             	:
			AHK-Version	:
			License         	:
			Syntax          	:
			Parameter(s)	:	pFont	- AHK font description, "style, face"
			Return value	:	Font handle
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			hFont := CreateFont("s12 italic, Courier New")
	  		SendMessage, 0x30, %hFont%, 1,, ahk_id %hGuiControl%  WM_SETFONT = 0x30

	*/

	;parse font
	italic         	:= InStr(pFont, "italic")    ?  1    :  0
	underline   	:= InStr(pFont, "underline") ?  1    :  0
	strikeout   	:= InStr(pFont, "strikeout") ?  1    :  0
	weight      	:= InStr(pFont, "bold")      ? 700   : 400

	;height
	RegExMatch(pFont, "(?<=[S|s])(\d{1,2})(?=[ ,])", height)
	if (height = "")
	  height := 10
	RegRead, LogPixels, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI, LogPixels
	height := -DllCall("MulDiv", "int", Height, "int", LogPixels, "int", 72)

	;face
	RegExMatch(pFont, "(?<=,).+", fontFace)
	if (fontFace != "")
	   fontFace := RegExReplace( fontFace, "(^\s*)|(\s*$)")      ;trim
	else fontFace := "MS Sans Serif"

	;create font
	hFont   := DllCall("CreateFont", "int",  height, "int",  0, "int",  0, "int", 0
					  ,"int",  weight,   "Uint", italic,   "Uint", underline
					  ,"uint", strikeOut, "Uint", nCharSet, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "str", fontFace)

	return hFont
} ;</08.01.000001>
;<08.01.000002>
GetHFONT(Options := "", Name := "") {                                                                      	;-- gets a handle to a font used in a AHK gui for example

   ; source: https://github.com/aviaryan/Clipjump/blob/master/lib/anticj_func_labels.ahk
   ; dependings: no

   Gui, New
   Gui, Font, % Options, % Name
   Gui, Add, Text, +hwndHTX, Dummy
   HFONT := DllCall("User32.dll\SendMessage", "Ptr", HTX, "UInt", 0x31, "Ptr", 0, "Ptr", 0, "UPtr") ; WM_GETFONT
   Gui, Destroy
   Return HFONT
} ;</08.01.000002>
;<08.01.000003>
MsgBoxFont(Fontstring, title, msg) {                                                                           	;-- style your MsgBox with with your prefered font
; https://autohotkey.com/board/topic/21003-function-createfont/
hFont := CreateFont("s14 italic, Courier New")
	SetTimer, OnTimer, -30
	MsgBox, , %title%, %msg%

return

OnTimer:
	ControlGet, h, HWND, , Static1, My MsgBox
	SendMessage, 0x30, %hFont%, 1,, ahk_id %h%  ;WM_SETFONT = 0x30
return
} ;</08.01.000003>
;<08.01.000004>
GetFontProperties(HFONT) {                                                                                       	;-- to get the current font's width and height

	/* 	DESCRIPTION of function GetFontProperties() ID: 08.01.00004

			Link  	:	https://autohotkey.com/boards/viewtopic.php?t=1979
			            	http://msdn.microsoft.com/en-us/library/dd145037%28v=vs.85%29.aspx
			Author	:	maybe by - just me
	*/
	/*      EXAMPLE(s)

			NoEnv
			   WM_GETFONT := 0x31
			   Gui, Margin, 20, 20
			   Gui, Add, Edit, w400 r5 hwndHED, Edit
			   Gui, Show, , Test
			   SendMessage, %WM_GETFONT%, 0, 0, , ahk_id %HED%
			   Font := GetFontProperties(ErrorLevel)
			   MsgBox, 0, % Font.FaceName, % "Height: " . Font.Height . " - Width: " . Font.Width
			Return
			GuiClose:
			ExitApp

	*/

   ; LOGFONT -> http://msdn.microsoft.com/en-us/library/dd145037%28v=vs.85%29.aspx
   VarSetCapacity(LF, (4 * 5) + 8 + 64) ; LOGFONT Unicode
   Size := DllCall("Gdi32.dll\GetObject", "Ptr", HFONT, "Int", Size, "Ptr", 0)
   DllCall("Gdi32.dll\GetObject", "Ptr", HFONT, "Int", Size, "Ptr", &LF)
   Font := {}
   Font.Height := Round(Abs(NumGet(LF, 0, "Int")) * 72 / A_ScreenDPI, 1)
   Font.Width := Round(Abs(NumGet(LF, 4, "Int")) * 72 / A_ScreenDPI, 1)
   Font.Escapement := NumGet(LF, 8, "Int")
   Font.Orientation := NumGet(LF, 12, "Int")
   Font.Weight := NumGet(LF, 16, "Int")
   Font.Italic := NumGet(LF, 20, "UChar")
   Font.Underline := NumGet(LF, 21, "UChar")
   Font.StrikeOut := NumGet(LF, 22, "UChar")
   Font.CharSet := NumGet(LF, 23, "UChar")
   Font.OutPrecision := NumGet(LF, 24, "UChar")
   Font.ClipPrecision := NumGet(LF, 25, "UChar")
   Font.Quality := NumGet(LF, 26, "UChar")
   Font.PitchAndFamily := NumGet(LF, 27, "UChar")
   Font.FaceName := StrGet(&LF + 28, 32)
   Return Font
} ;</08.01.000004>
;<08.01.000005>
FontEnum(lfCharSet := 1, FontName := "") {                                                               	;-- enumerates all uniquely-named fonts in the system that match the font characteristics specified by the LOGFONT structure

	/*    	DESCRIPTION of function FontEnum() ID: 08.01.00005
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	enumerates all uniquely-named fonts in the system that match the font characteristics specified by the LOGFONT structure
			Link              	:	https://msdn.microsoft.com/en-us/library/dd162620(v=vs.85).aspx
			Author         	:
			Date             	:
			AHK-Version	:
			License         	:
			Syntax          	:	FontEnum ([lfCharSet], [FontName])Example:for k, v in FontEnum ()
			Parameter(s)	:	hFont: 				specify an identifier to a font, you can use FontCreate (). leave it at zero to use the default font.
			                        	FontName: 		name of the source.
			                         	lf CharSet: 		script, value that identifies the set of characters lists all installed sources.
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	font, enumerate, char, charset
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

	    	MsgBox % vNote: to check if a font exists, use the parameters lfCharSet and FontName, if it is not found, return an empty string.

	*/

	hDC := GetDC(), VarSetCapacity(LOGFONT, 92, 0), NumPut(lfCharSet, LOGFONT, 23, "UChar")
	if StrLen(FontName)
		StrPut(FontName, &LOGFONT + 28)
	Address := RegisterCallback("EnumFontFamExProc", "Fast", 4), Data := {List: []}
	, DllCall("Gdi32.dll\EnumFontFamiliesExW", "Ptr", hDC, "Ptr", &LOGFONT, "Ptr", Address, "Ptr", &Data, "UInt", 0)
	return Data.List, ReleaseDC(0, hDC), GlobalFree(Address)
} EnumFontFamExProc(LOGFONT, lpntme, FontType, Data) {
	Data := Object(Data), FontName := StrGet(LOGFONT + 28)
	if !InArray(Data.List, FontName) ;remover fuentes duplicadas
		Data.List.Push(FontName)
	return true
} ;</08.01.000005>
;<08.01.000006>
GetFontTextDimension(hFont, Text, ByRef Width := "", ByRef Height := "", c := 1) {  	;-- calculate the height and width of the text in the specified font

	/*    	DESCRIPTION of function GetFontTextDimension() ID: 08.01.00006
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	calculate the height and width of the text in the specified font
			Link              	:	;https://msdn.microsoft.com/en-us/library/dd144938(v=vs.85).aspx
			Author         	:	?jeeswg?
			Date             	:
			AHK-Version	:	AHK_L
			License         	:
			Syntax          	:	GetFontTextDimension( [hFont], [Text], [out Width], [out Height] )
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	use CreateFont() to get hFont
			Dependencies	:	GetStockObject() ID: 08.01.00007
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

	hFont := hFont?hFont:GetStockObject(17), hDC := GetDC()
	, hSelectObj := SelectObject(hDC, hFont), VarSetCapacity(SIZE, 8, 0)
	if !DllCall("Gdi32.dll\GetTextExtentPoint32W", "Ptr", hDC, "Ptr", &Text, "Int", StrLen(Text), "Ptr", &SIZE, "Int")
		return false, ReleaseDC(0, hDC), Width := Height := 0
	VarSetCapacity(TEXTMETRIC, 60, 0)
	if !DllCall("Gdi32.dll\GetTextMetricsW", "Ptr", hDC, "Ptr", &TEXTMETRIC, "Int") ;https://msdn.microsoft.com/en-us/library/dd144941(v=vs.85).aspx
		return false, ReleaseDC(0, hDC), Width := Height := 0
	SelectObject(hDC, hSelectObj), ReleaseDC(0, hDC), Width := NumGet(SIZE, 0, "Int"), Height := NumGet(SIZE, 4, "Int")
	, Width := Width + NumGet(TEXTMETRIC, 20, "Int") * 3
	, Height := Floor((NumGet(TEXTMETRIC, 0, "Int")*c)+(NumGet(TEXTMETRIC,16, "Int")*(Floor(c+0.5)-1))+0.5)+8
	return true
} ;</08.01.000006>
;<08.01.000007>
GetStockObject(nr) {                                                                                                    	;--subfunction of GetFontTextDimension()

	/*    	DESCRIPTION of function GetStockObject() ID: 08.01.00007
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:
			Link              	:
			Author         	:	?jeeswg?
			Date             	:
			AHK-Version	:
			License         	:
			Syntax          	:	GetFontTextDimension( [hFont], [Text], [out Width], [out Height] )
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	use CreateFont() to get hFont
			Dependencies	:	GetStockObject() ID: 08.01.00007
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/
return DllCall( "GetStockObject", UInt, nr)
} ;</08.01.000007>
;<08.01.000008>
FontClone(hFont) {                                                                                                      	;-- backup hFont in memory for further processing

	/*    	DESCRIPTION of function FontClone() ID: 08.01.00008
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	backup hFont in memory for further processing
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=36461
			Author         	:	jeeswg
			Date	            	:
			AHK-Version	:	AHK_L ???
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			q:: ;control get font, font get average character width
			SendMessage, 0x31, 0, 0, Edit1, ahk_class Notepad ;WM_GETFONT := 0x31
			hFont := ErrorLevel
			hFont2 := JEE_FontClone(hFont)
			MsgBox, % JEE_StrGetDimAvgCharWidth(hFont2)*8
			return
			;iTabLength
			;The size of each tab stop, in units equal to the average character width.
			;(a tab character is 8 times wider than the average character width)

			;e.g. hFontNew := JEE_FontClone(hFont)

	*/



	VarSetCapacity(LOGFONT, 92, 0) ;LOGFONT (Unicode)
	vSize := DllCall("gdi32\GetObject", Ptr,hFont, Int,0, Ptr,0)
	DllCall("gdi32\GetObject", Ptr,hFont, Int,vSize, Ptr,&LOGFONT)
	return DllCall("CreateFontIndirect", Ptr,&LOGFONT, Ptr)
} ;</08.01.000008>
;<08.01.000009>
GuiDefaultFont() {                                                                                                        	;-- returns the default Fontname & Fontsize

	/*    	DESCRIPTION of function GuiDefaultFont() 08.01.00009
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	AutoHotkey uses the 'default GUI font' for controls, if you do not specify one in your script.
                                    	This 'default GUI font' is system wide and the same one being used in MenuBar.
                                    	GuiDefaultFont() returns the Fontname & Fontsize.
			Link              	:	www.autohotkey.com/forum/viewtopic.php?p=465438#465438
			Author         	:	SKAN
			Date	            	:	???
			AHK-Version	:	AHK v1
			License         	:
			Parameter(s)	:	none
			Return value	:	Fontname, A_LastError contains FontSize
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	Font, Gui, DllCall
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			A_GuiFont     := GuiDefaultFont()
			A_GuiFontSize := A_LastError
			MsgBox, %A_GuiFont%`t%A_GuiFontSize%

	*/

	 hFont := DllCall( "GetStockObject", UInt,17 ) ; DEFAULT_GUI_FONT
	 VarSetCapacity( LF, szLF := 60*( A_IsUnicode ? 2:1 ) )
	 DllCall("GetObject", UInt,hFont, Int,szLF, UInt,&LF )
	 hDC := DllCall( "GetDC", UInt,hwnd ), DPI := DllCall( "GetDeviceCaps", UInt,hDC, Int,90 )
	 DllCall( "ReleaseDC", Int,0, UInt,hDC ), S := Round( ( -NumGet( LF,0,"Int" )*72 ) / DPI )
Return DllCall( "MulDiv",Int,&LF+28, Int,1,Int,1, Str ), DllCall( "SetLastError", UInt,S )
} ;</08.01.000009>
;<08.01.000010>
StrGetDimAvgCharWidth(hFont) {                                                                               	;-- average width of a character in pixels

	/*    	DESCRIPTION of function StrGetDimAvgCharWidth() ID: 08.01.00010
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	The size of each tab stop, in units equal to the average character width.
                                     	(a tab character is 8 times wider than the average character width)
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=36461
			Author         	:	jeeswg
			Date	            	:	30 Aug 2017
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	FontClone() ID: 08.01.00008
			KeyWords    	:	Font, Width, DllCall, Gdi
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			q:: ;control get font, font get average character width
        	SendMessage, 0x31, 0, 0, Edit1, ahk_class Notepad ;WM_GETFONT := 0x31
        	hFont := ErrorLevel
        	hFont2 := JEE_FontClone(hFont)
        	MsgBox, % JEE_StrGetDimAvgCharWidth(hFont2)*8
        	return

	*/

	vText := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	hDC := DllCall("user32\GetDC", Ptr,0, Ptr)
	hFontOld := DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFont, Ptr)
	;HWND_DESKTOP := 0
	VarSetCapacity(SIZE, 8, 0)
	DllCall("gdi32\GetTextExtentPoint32", Ptr,hDC, Str,vText, Int,StrLen(vText), Ptr,&SIZE)
	DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFontOld, Ptr)
	DllCall("user32\ReleaseDC", Ptr,0, Ptr,hDC)
	vTextW1 := NumGet(SIZE, 0, "Int") ;cx ;logical units
	vTextW2 := Floor((vTextW1/26+1)/2)
	return vTextW2
} ;</08.01.000010>
;<08.01.000011>
CreateFont(nHeight, nWidth, nEscapement, nOrientation, fnWeight,                        	;-- creates HFont for use with GDI
fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision,
fdwClipPrecision, fdwQuality, fdwPitchAndFamily, lpszFace) {

/*
HFONT CreateFont(
  int nHeight,               // height of font
  int nWidth,                // average character width
  int nEscapement,           // angle of escapement
  int nOrientation,          // base-line orientation angle
  int fnWeight,              // font weight
  DWORD fdwItalic,           // italic attribute option
  DWORD fdwUnderline,        // underline attribute option
  DWORD fdwStrikeOut,        // strikeout attribute option
  DWORD fdwCharSet,          // character set identifier
  DWORD fdwOutputPrecision,  // output precision
  DWORD fdwClipPrecision,    // clipping precision
  DWORD fdwQuality,          // output quality
  DWORD fdwPitchAndFamily,   // pitch and family
  LPCTSTR lpszFace           // typeface name
);
*/

	return DllCall("CreateFont"
				, "Int" , nHeight           , "Int" , nWidth          , "Int" , nEscapement
				, "Int" , nOrientation      , "Int" , fnWeight        , "UInt", fdwItalic
				, "UInt", fdwUnderline      , "UInt", fdwStrikeOut    , "UInt", fdwCharSet
				, "UInt", fdwOutputPrecision, "UInt", fdwClipPrecision, "UInt", fdwQuality
				, "UInt", fdwPitchAndFamily , "Str" , lpszFace)
} ;</08.01.000011>
;<08.01.000012>
MeasureText(Str, FontOpts = "", FontName = "") {                                                      	;--  Measures the single-line width and height of the passed text

		/*    	DESCRIPTION of function MeasureText() ID: 08.01.00012
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Measures the single-line width and height of the passed text
			Link              	:	https://autohotkey.com/board/topic/64366-function-explore-object/
										http://www.autohotkey.com/community/viewtopic.php?f=13&t=88163
			Author         	:	just me
			Date	            	:	1.0.00.00/2012-06-28/just me
			AHK-Version	:	1.1.05+
			License         	:
			Parameter(s)	:	Str         -  String to measure.
                                    	Optional       ---------------------------------------------------------------------------------------------------
                                    	FontOpts	-  	Options used with the Gui, Font, ... command.
                                                           	Default: "" - Default GUI font options
                                                        	FontName	-  	Font name used with the Gui, Font, ... command.
                                                          	Default: "" 	-	Default GUI font
			Return value	:   Object containing two key/value pairs:
                                       	W  -  measured width.
                                    	H  -  measured height.
			Remark(s)    	:	none
			Dependencies	:	none
			KeyWords    	:	gdi, font width, measure,
        	-------------------------------------------------------------------------------------------------------------------
	*/

	Static DT_FLAGS := 0x0520 ; DT_SINGLELINE = 0x20, DT_NOCLIP = 0x0100, DT_CALCRECT = 0x0400
	Static WM_GETFONT := 0x31

	Size := {}
	Gui, New
	If (FontOpts <> "") || (FontName <> "")
		Gui, Font, %FontOpts%, %FontName%
	Gui, Add, Text, hwndHWND
	SendMessage, WM_GETFONT, 0, 0, , ahk_id %HWND%
	HFONT := ErrorLevel
	HDC := DllCall("User32.dll\GetDC", "Ptr", HWND, "Ptr")
	DllCall("Gdi32.dll\SelectObject", "Ptr", HDC, "Ptr", HFONT)
	VarSetCapacity(RECT, 16, 0)
	DllCall("User32.dll\DrawText", "Ptr", HDC, "Str", Str, "Int", -1, "Ptr", &RECT, "UInt", DT_FLAGS)
	DllCall("User32.dll\ReleaseDC", "Ptr", HWND, "Ptr", HDC)
	Gui, Destroy
	Size.W := NumGet(RECT,  8, "Int")
	Size.H := NumGet(RECT, 12, "Int")
	Return Size
} ;</08.01.000012>
;<08.01.000013>
GetFontNamesFromFile(FontFilePath) {                                                                      	;-- get's the name of a font from a .ttf-FontFile

   /*	DESCRIPTION OF FUNCTION: -- GetFontNamesFromFile --
   -------------------------------------------------------------------------------------------------------------------
   Description   	:	get's the name of a font from a .ttf-FontFile
   Link               	:	https://www.autohotkey.com/boards/viewtopic.php?p=85114#p85114
   Author          	:	just me
   Date              	:	May 07, 2016
   AHK-Version 	:	AHK_L
   License          	:	--
   Syntax           	:	--
   Parameter(s) 	:	--
   Return value 	:	--
   Remark(s)     	:	only tested for .ttf files as yet
								www.microsoft.com/en-us/Typography/SpecificationsOverview.aspx
								.otf -> www.microsoft.com/typography/otspec/otff.htm
								Platform ID: 0: Apple Unicode, 1: Macintosh, 2: ISO, 3: Microsoft}
								Name ID: 1: family name, 2: subfamily name (style), 4: full name}
   Dependencies	:	ReadUShortBE(), ReadULongBE(), ReadUTF16BE
   KeyWords     	:	font
   -------------------------------------------------------------------------------------------------------------------
   |	EXAMPLE(s)
   -------------------------------------------------------------------------------------------------------------------
   #NoEnv
	Gui, Add, ListView, w800 r30, File|Family|Style|FullName
	Loop, Files, %A_WinDir%\Fonts\*.ttf
	{
	   If !IsObject(FontName := GetFontNamesFromFile(A_LoopFileLongPath))
		  MsgBox, 16, Error!, Couldn't retrieve font names form file %A_LoopFileName%!
	   Else
		  LV_Add("", A_LoopFileName, FontName.Family, FontName.Style, FontName.FullName)
	}
	Loop, 4
	   LV_ModifyCol(A_Index, "AutoHdr")
	Gui, Show, , % "Font names from files (" . LV_GetCount() . ")"
	Return
	GuiCLose:
	ExitApp
   */

   If !(Font := FileOpen(FontFilePath, "r")) {
      MSgBox, 16, %A_ThisFunc%, Error: %A_LastError%`n`nCould not open the file`n%FontFilePath%!
      Return ""
   }
   ; Get the number of tables ------------------------------------------------------------------------------------------------------
   Font.Pos += 4
   NumTables := ReadUShortBE(Font)
   ; Search for the 'name' table ---------------------------------------------------------------------------------------------------
   NameTableOffset := 0
   Font.Pos := 12 ; start of table entries
   NextTableEntry := Font.Pos
   Loop, %NumTables% {
      Font.Pos := NextTableEntry
      NextTableEntry += 16 ; size of a table entry
      Font.RawRead(TableName, 4)
      Name := StrGet(&TableName, 4, "CP0")
      If (Name <> "name")
         Continue
      Font.Pos += 4 ; skip the checkSum field
      NameTableOffset := ReadULongBE(Font)
   } Until (NameTableOffset <> 0)
   If (NameTableOffset = 0) { ; should not happen because the 'name' table is required
      MsgBox, 16, %A_ThisFunc%, Error:`n`nDidn't find the 'name' table entry!
      Return ""
   }
   ; Search for the font family name in the 'name' table entries -------------------------------------------------------------------
   Font.Pos := NameTableOffset
   If (ReadUShortBE(Font) <> 0) { ; format selector must be 0
      MsgBox, 16, %A_ThisFunc%, Error:`n`nInvalid 'name' table!
      Return ""
   }
   NumOfEntries := ReadUShortBE(Font)
   StorageOffset := ReadUShortBE(Font)
   Names := []
   LCSub := []
   LCFull := []
   LCID := 0
   SysLanguage := "0x" . A_Language
   NextTableEntry := Font.pos
   Loop, %NumOfEntries% {
      Font.Pos := NextTableEntry
      NextTableEntry += 12 ; length of a name table entry
      PlatformID := ReadUShortBE(Font)
      If (PlatformID <> 3)
         Continue
      EncodingID := ReadUShortBE(Font)
      LanguageID := ReadUShortBE(Font)
      NameID := ReadUShortBE(Font)
      If NameID In 1,2,4
      {
         StrLength := ReadUShortBE(Font)
         If (StrLength = 0)
            Continue
         StrOffset := ReadUShortBE(Font)
         Font.Pos := NameTableOffset + StorageOffset + StrOffset
         Name := ReadUTF16BE(Font, StrLength // 2)
         If (NameID = 1) && ((LanguageID = SysLanguage) || (LanguageID = 1033)) {
            LCID := LanguageID
            Names["Family"] := Name
         }
         Else If (NameID = 4)
            LCFull[LanguageID] := Name
         Else
            LCSub[LanguageID] := Name
      }
   }
   ; Done --------------------------------------------------------------------------------------------------------------------------
   Font.Close()
   If (LCID) {
      If (Name := LCSub[SysLanguage])
         Names["Style"] := Name
      Else
         Names["Style"] := LCSub[LCID]
      If (Name := LCFull[SysLanguage])
         Names["FullName"] := Name
      Else
         Names["FullName"] := LCFull[LCID]
   }
   Return Names.HasKey("Family") ? Names : ""
}
; Auxiliary functions used because .ttf files are encoded in Motorola (big endian) format
{
ReadUShortBE(Handle) {
   Return (Handle.ReadUChar() << 8) | Handle.ReadUchar()
}
ReadULongBE(Handle) {
   Return (Handle.ReadUChar() << 24) | (Handle.ReadUChar() << 16) | (Handle.ReadUChar() << 8) | Handle.ReadUChar()
}
ReadUTF16BE(Handle, Characters) { ; Characters - the maximum number of characters to read
   Bytes := Characters * 2
   VarSetCapacity(UTF16, Bytes, 0)
   Addr := &UTF16
   MaxAddr := Addr + Bytes
   While (Addr < MaxAddr)
      Addr := NumPut(ReadUShortBE(Handle), Addr + 0, "UShort")
   Return StrGet(&UTF16, Characters, "UTF-16")
} ;</08.01.000013>
}

} ;<\08>
;|   CreateFont()                            	|   GetHFONT()                             	|   MsgBoxFont()                           	|   GetFontProperties()                  	|
;|   FontEnum()                             	|   GetFontTextDimension()          	|   FontClone()                              	|   GuiDefaultFont()                      	|
;|   StrGetDimAvgCharWidth()      	|   CreateFont()                             	|   MeasureText(12)                        	|   GetFontNamesFromFile(13)      	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Hooks/Messaging (9) -                                                                                                                              	baseID: <09>
;<09.01.000001>
OnMessageEx(MsgNumber, params*) {                                          	;-- Allows multiple functions to be called automatically when the script receives the specified message

	/*	DESCRIPTION OF FUNCTION: -- OnMessageEx() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Allows multiple functions to be called automatically when the script receives the specified message.
	Link              	:	http://sites.google.com/site/ahkref/custom-functions/onmessageex
	Author         	:	A_Samurai
	Version        	:	version 1.0.2
	Date             	:	--
	AHK-Version	:	AutoHotkey_L 1.0.97.00 or later.  Tested on: Windows 7 64bit, AutoHotkey 32bit Unicode 1.1.05.01.
	License         	:	Public Domain.
	Syntax          	:	OnMessageEx(MsgNumber, FunctionName=False, Priority=1)
	Parameter(s)	:	MsgNumber	- 	same as the first parameter of OnMessage()
	                        	FunctionName	- 	same as the second parameter of OnMessage(). To remove the function from
							                            	monitoring the system message, specify 0 in the next parameter Priority. To
															remove the function in lowest priority from monitoring the system message,
															specify "" (blank).
	                                                    	Object Method: [v1.0.1+] In order to specify an object method, pass an array
															consisting of three elements. e.g. [&myobj, "MyMethod", False]
	                                                    	Object Address: the address of the object. It can be retrieved with the &
															operator. e.g. &myobj
	                        	MethodName	- 	the name of the method.
	                        	AutoRemove	- 	decides whether to remove the method if the object no longer exists.
                                                        	True to enable it; otherwise, set it to False. False by default.
	                        	Priority         	-	specify a whole number to set the priority of the registering function to be
							                               	called. 1 is the highest and as the number increases the priority gets lowered.
															0 is to remove the function from the list.
	Return value	:	If FunctionName and Priority is omitted, it returns the name of the function of the lowest priority
								in the function list. If FunctionName is explicitly blank (e.g. ""), it returns the name of the removed
								function. If FunctionName has a value and Priority is set to 0, it returns the name of the removed
								function. If FunctionName has a value and it is successfully added in the function list, it returns
								the name of the function of the highest priority in the list before the new function is added.
	Remark(s)    	:	The parameter, MaxThreads, of the original OnMessage() function is not supported.
	Dependencies	:	none
	KeyWords    	:	GUI
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
		#Persistent
		Gui, Font, s20
		Gui, Margin, 30, 30
		Gui, Add, Text,, Click Here
		Gui, Show
		OnMessage(0x200, "MyFuncA")     ;a function registered via OnMessage() will be added in the list when OnMessageEx() is called for the first time.
		OnMessageEx(0x200, "MyFuncB")
		OnMessageEx(0x200, "MyFuncC")
		OnMessageEx(0x201, "MyFuncD")
		OnMessageEx(0x201, "MyFuncE")
		OnMessageEx(0x201, "MyFuncF")
		OnMessageEx(0x201, "MyFuncD")   ;a duplicated item will be removed and the function is inserted again
		Return
		GuiClose:
		ExitApp

		F1::msgbox % "Function Removed: " OnMessageEx(0x200, "")    ;removes the function in the lowest priority for 0x200
		F2::msgbox % "Function Removed: " OnMessageEx(0x201, "")    ;removes the function in the lowest priority for 0x201
		F3::msgbox % "The lowest priority function for 0x200 is: " OnMessageEx(0x200)
		F4::msgbox % "The lowest priority function for 0x201 is: " OnMessageEx(0x201)
		F5::msgbox % "Function Removed: " OnMessageEx(0x201, "MyFuncF", 0)    ;removes MyFuncF from 0x201

		MyFuncA(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex - 200, , 1
			SetTimer, RemoveToolTipA, -1000
			Return
			RemoveToolTipA:
				tooltip,,,,1
			Return
		}
		MyFuncB(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex,, 2
			SetTimer, RemoveToolTipB, -1000
			Return
			RemoveToolTipB:
				tooltip,,,,2
			Return
		}
		MyFuncC(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex + 200 ,, 3
			SetTimer, RemoveToolTipC, -1000
			Return
			RemoveToolTipC:
				tooltip,,,,3
			Return
		}
		MyFuncD(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex - 200, mousey - 80, 4
			SetTimer, RemoveToolTipD, -1000
			Return
			RemoveToolTipD:
				tooltip,,,,4
			Return
		}
		MyFuncE(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex, mousey - 80, 5
			SetTimer, RemoveToolTipE, -1000
			Return
			RemoveToolTipE:
				tooltip,,,,5
			Return
		}
		MyFuncF(wParam, lParam, msg, hwnd) {
			display := A_ThisFunc "`nwParam :`t" wParam "`nlParam :`t`t" lParam "`nMessage :`t" msg "`nHwnd :`t`t" hwnd
			mousegetpos, mousex, mousey
			tooltip, % display, mousex + 200 , mousey - 80, 6
			SetTimer, RemoveToolTipF, -1000
			Return
			RemoveToolTipF:
				tooltip,,,,6
			Return
		}

		more example can be found at page linked above
	*/

	Static Functions := {}

    ;determine whether this is an on-message call
    FunctionName := params.1, OnMessage := True, DHW := A_DetectHiddenWindows
    DetectHiddenWindows, ON
    if ObjMaxIndex(params) <> 3            ;if the number of optional parameters are not three
        OnMessage := False
    else if FunctionName not between 0 and 4294967295    ;if the second parameter is not between 0 to 4294967295
        OnMessage := False
    else if !WinExist("ahk_id " params.3)    ;if the third parameter is not an existing Hwnd of a window/control
        OnMessage := False
    DetectHiddenWindows, % DHW

    if !OnMessage {
    ;if the function is manually called,
        Priority := params.2 ? params.2 : (params.2 = 0) ? 0 : 1
        If FunctionName    {
            ;if FunctionName is specified, it means to register it or if the priority is set to 0, remove it

            ;prepare for the function stack object
            Functions[MsgNumber] := Functions[MsgNumber] ? Functions[MsgNumber] : []

            ;check if there is already the same function in the stack object
            For index, oFunction in Functions[MsgNumber] {
                if (oFunction.Func = FunctionName) {
                    oRemoved := ObjRemove(Functions[MsgNumber], Index)
                    Break
                }
            }
            ;if the priority is 0, it means to remvoe the function
            if (Priority = 0)
                Return oRemoved.Func

            ;check if there is a function already registered for this message
            if (PrevFunc := OnMessage(MsgNumber)) && (PrevFunc <> A_ThisFunc) {
                ;this means there is one, so add this function to the stack object
                ObjInsert(Functions[MsgNumber], {Func: PrevFunc, Priority: 1})
            }

            ;find out the priority in each registered function and insert it before the element of the same priority
            IndexToInsert := 1
            For Index, oFunction in Functions[MsgNumber] {
                IndexToInsert := Index
            } Until (oFunction.Priority = Priority)

            ;retrieve the function name in the first priority for the return value
            FirstFunc := Functions[MsgNumber][ObjMinIndex(Functions[MsgNumber])].Func

            ;insert the given function in the function stack object
            if IsObject(FunctionName) {
                ;an object is passed for the second parameter
                ThisObj := Object(FunctionName.1), ThisMethod := FunctionName.2, AutoRemove := ObjHasKey(FunctionName, 3) ? FunctionName.3 : False
                If IsFunc(ThisObj[ThisMethod])    ;chceck if the method exists
                    ObjInsert(Functions[MsgNumber], IndexToInsert, {Func: FunctionName.2, Priority: Priority, ObjectAddress: FunctionName.1, AutoRemove: AutoRemove})
                else         ;if the passed function name is not a function, return false
                    return False
            } else {
                if IsFunc(FunctionName)    ;chceck if the function exists
                    ObjInsert(Functions[MsgNumber], IndexToInsert, {Func: FunctionName, Priority: Priority})
                else        ;if the passed function name is not a function, return false
                    return False
            }

            ;register it
            if (PrevFunc <> A_ThisFunc)
                OnMessage(MsgNumber, A_ThisFunc)

            Return FirstFunc
        } Else if ObjHasKey(params, 1) && (FunctionName = "") {
            ;if FunctionName is explicitly empty, remove the function and return its name

            ;remove the lowest priority function (the last element) in the object of the specified message.
            oRemoved := ObjRemove(Functions[MsgNumber], ObjMaxIndex(Functions[MsgNumber]))

            ;if there are no more registered functions, remove the registration of this function for this message
            if !ObjMaxIndex(Functions[MsgNumber])
                OnMessage(MsgNumber, "")

            Return oRemoved.Func
        } Else     ;return the registered function of the lowest priority for this message
            Return Functions[MsgNumber][ObjMaxIndex(Functions[MsgNumber])].Func
    } Else {
    ;if this is an on-message call,
        wParam := MsgNumber, lParam := params.1, msg := params.2, Hwnd := params.3
        For Index, Function in Functions[msg] {
            ThisFunc := Function.Func
            if ObjHasKey(Function, "ObjectAddress") {
                ;if it is an object method
                ThisObj := Object(Function.ObjectAddress)
                ThisObj[ThisFunc](wParam, lParam, msg, Hwnd)
                if Function.AutoRemove {        ;this means if the method no longer exists, remove it
                    If !IsFunc(ThisFunc) {
                        ObjRemove(Functions[MsgNumber], ThisFunc)

                        ;if there are no more registered functions, remove the registration of this function for this message
                        if !ObjMaxIndex(Functions[MsgNumber])
                            OnMessage(MsgNumber, "")
                    }
                }
            } else     ;if it is a function
                %ThisFunc%(wParam, lParam, msg, Hwnd)
        }
    }
} ;</09.01.000001>
;<09.01.000002>
ReceiveData(wParam, lParam) {                                                       	;--  By means of OnMessage(), this function has been set up to be called automatically whenever new data arrives on the connection.

   global ShowRecieved
   global ReceivedData

   Gui, Submit, NoHide
   socket := wParam

    ReceivedDataSize = 4096 ; Large in case a lot of data gets buffered due to delay in processing previous data.
    Loop  ; This loop solves the issue of the notification message being discarded due to thread-already-running.
    {
        VarSetCapacity(ReceivedData, ReceivedDataSize, 0)  ; 0 for last param terminates string for use with recv().
        ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
        if ReceivedDataLength = 0  ; The connection was gracefully closed,
            ExitApp  ; The OnExit routine will call WSACleanup() for us.
        if ReceivedDataLength = -1
        {
            WinsockError := DllCall("Ws2_32\WSAGetLastError")
            if WinsockError = 10035  ; WSAEWOULDBLOCK, which means "no more data to be read".
                return 1
            if WinsockError <> 10054 ; WSAECONNRESET, which happens when Network closes via system shutdown/logoff.
                ; Since it's an unexpected error, report it.  Also exit to avoid infinite loop.
                MsgBox % "recv() indicated Winsock error " . WinsockError
            ExitApp  ; The OnExit routine will call WSACleanup() for us.
        }
        ; Otherwise, process the data received.
        ; Msgbox %ReceivedData%
        Loop, parse, ReceivedData, `n, `r
        {
           	ReceivedData=%A_LoopField%
           	if (ReceivedData!="")
           	{
				GoSub ParseData
				GoSub UseData
			}
        }
	}
    return 1  ; Tell the program that no further processing of this message is needed.
} ;</09.01.000002>
;<09.01.000003>
HDrop(fnames,x=0,y=0) {                                                                	;-- Drop files to another app

	/*						Description

		Return a handle to a structure describing files to be droped.
		Use it with PostMessage to send WM_DROPFILES messages to windows.
		fnames is a list of paths delimited by `n or `r`n
		x and y are the coordinates where files are droped in the window.
		Eg. :
		; Open autoexec.bat in an existing Notepad window.
		PostMessage, 0x233, HDrop("C:\autoexec.bat"), 0,, ahk_class Notepad
		PostMessage, 0x233, HDrop(A_MyDocuments), 0,, ahk_class MSPaintApp

	*/
	fns:=RegExReplace(fnames,"\n$")
   fns:=RegExReplace(fns,"^\n")
   hDrop:=DllCall("GlobalAlloc","UInt",0x42,"UInt",20+StrLen(fns)+2)
   p:=DllCall("GlobalLock","UInt",hDrop)
   NumPut(20, p+0)  ;offset
   NumPut(x,  p+4)  ;pt.x
   NumPut(y,  p+8)  ;pt.y
   NumPut(0,  p+12) ;fNC
   NumPut(0,  p+16) ;fWide
   p2:=p+20
   Loop,Parse,fns,`n,`r
   {
      DllCall("RtlMoveMemory","UInt",p2,"Str",A_LoopField,"UInt",StrLen(A_LoopField))
      p2+=StrLen(A_LoopField)+1
   }
   DllCall("GlobalUnlock","UInt",hDrop)
   Return hDrop
} ;</09.01.000003>
;<09.01.000004>
WM_MOVE(wParam, lParam, nMsg, hWnd) {                                  	;-- UpdateLayeredWindow

If   A_Gui
&&   DllCall("UpdateLayeredWindow", "Uint", hWnd, "Uint", 0, "int64P", (lParam<<48>>48)&0xFFFFFFFF|(lParam&0xFFFF0000)<<32>>16, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0)
WinGetPos, GuiX, GuiY,,, WinTitle
if (GuiY)
Gui, 2: Show, x%GuiX% y%GuiY%
else
Gui, 2: Show, Center
Return   0
} ;</09.01.000004>
;<09.01.000005>
WM_WINDOWPOSCHANGING(wParam, lParam) {	                        	;-- two different examples of handling a WM_WINDOWPOSCHANGING

	/*	DESCRIPTION OF FUNCTION: -- OnMessage(0x46, "WM_WINDOWPOSCHANGING") --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	two different examples of handling a WM_WINDOWPOSCHANGING
	Link              	:	--
	Author         	:	--
	Date             	:	--
	AHK-Version	:	--
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	--
	KeyWords    	:	--
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------- -----------
	OnMessage(0x46, "WM_WINDOWPOSCHANGING")
	*/

    if (A_Gui = 1 && !(NumGet(lParam+24) & 0x2)) ; SWP_NOMOVE=0x2
    {
        x := NumGet(lParam+8),  y := NumGet(lParam+12)
        x += 10,  y += 30
        Gui, 2:Show, X%x% Y%y% NA
    }
} ;</09.01.000005>
;<09.01.000006>
WM_WINDOWPOSCHANGING(wParam, lParam) {                           	;-- second examples of handling a WM_WINDOWPOSCHANGING

	global

	If (A_Gui = 1 && !(NumGet(lParam+24) & 0x2))
	{
		x := NumGet(lParam+8),  y := NumGet(lParam+12)

		Result := DllCall("SetWindowPos", "UInt", Gui2, "UInt", Gui1, "Int", x-50, "Int", y-50, "Int", "", "Int", "", "Int", 0x01)
	}
	SetTimer, OnTop, 10

	Result := DllCall("SetWindowPos", "UInt", Gui1, "UInt", Gui2, "Int", "", "Int", "", "Int", "", "Int", "", "Int", 0x03)
	;Tooltip, %Result%
	Return

} ;</09.01.000006>
;<09.01.000007>
CallNextHookEx(nCode, wParam, lParam, hHook = 0) {                 	;-- Passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either before or after processing the hook information
   Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
} ;</09.01.000007>
;<09.01.000008>
WM_DEVICECHANGE( wParam, lParam) {                                       	;-- Detects whether a CD has been inserted instead and also outputs the drive - global drv

Global Drv
 global DriveNotification
 Static DBT_DEVICEARRIVAL := 0x8000 ; http://msdn2.microsoft.com/en-us/library/aa363205.aspx
 Static DBT_DEVTYP_VOLUME := 0x2    ; http://msdn2.microsoft.com/en-us/library/aa363246.aspx

 /*
    When wParam is DBT_DEVICEARRIVAL lParam will be a pointer to a structure identifying the
    device inserted. The structure consists of an event-independent header,followed by event
    -dependent members that describe the device. To use this structure,  treat the structure
    as a DEV_BROADCAST_HDR structure, then check its dbch_devicetype member to determine the
    device type.
 */

 dbch_devicetype := NumGet(lParam+4) ; dbch_devicetype is member 2 of DEV_BROADCAST_HDR

 If ( wParam = DBT_DEVICEARRIVAL AND dbch_devicetype = DBT_DEVTYP_VOLUME )
 {

 ; Confirmed lParam is a pointer to DEV_BROADCAST_VOLUME and should retrieve Member 4
 ; which is dbcv_unitmask

   dbcv_unitmask := NumGet(lParam+12 )

 ; The logical unit mask identifying one or more logical units. Each bit in the mask corres
 ; ponds to one logical drive.Bit 0 represents drive A, Bit 1 represents drive B, and so on

   Loop 32                                           ; Scan Bits from LSB to MSB
     If ( ( dbcv_unitmask >> (A_Index-1) & 1) = 1 )  ; If Bit is "ON"
      {
        Drv := Chr(64+A_Index)                       ; Set Drive letter
        Break
      }
   DriveNotification:=DriveData(Drv)
 }
Return TRUE
} ;</09.01.000008>
;<09.01.000009>
ObjectNameChange(hWinEventHook, event, hwnd,                      	;-- titlebar hook to detect when title changes, (Lexikos' code)
idObject, idChild, thread, time) {

		; a Lexikos function

	  /*		Example

				#NoTrayIcon

				; EVENT_OBJECT_NAMECHANGE = 0x800C
				; WINEVENT_OUTOFCONTEXT = 0x0000
				hook := DllCall("SetWinEventHook", "uint", 0x800C, "uint", 0x800C
					, "uint", 0, "uint", RegisterCallback("ObjectNameChange")
					, "uint", 0, "uint", 0, "uint", 0)
				OnExit, UnHook

				#t::
					active := WinExist("A")+0
					WinGetTitle, title
					InputBox, newtitle, Enter new title:,,,600,100,,,,, %title% ; yay commas
					If !ErrorLevel {
						WinSetTitle, %newtitle%
						Win_%active% := newtitle
					}
				return

				UnHook:
					ExitApp, DllCall("UnhookWinEvent", "uint", hook) ; Yes, this works.
				Return

	  */

	; If the object is a window (OBJID_WINDOW), is not hidden, and is not a child window,
	if (idObject=0) && WinExist("ahk_id " hwnd) && DllCall("GetAncestor","uint",hwnd,"uint",1)=DllCall("GetDesktopWindow")
		If(newtitle := Win_%hwnd%)!=""{
			WinGetTitle, title, ahk_id %hwnd%
			If(title != newtitle)
				WinSetTitle, ahk_id %hwnd%,, %newtitle%
		}
} ;</09.01.000009>
}
;|   OnMessageEx(1)                      	|   ReceiveData(2)                         	|   HDrop(3)                                  	|   WM_MOVE(4)                          	|
;|   WM_WINDOWPOSCHANGING	|   CallNextHookEx(7)                   	|   WM_DEVICECHANGE(8)          	|   ObjectNameChange(9)            	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Internet/Network (26) -                                                                                                                            	baseID: <10>
;<10.01.000001>
DownloadFile(url, file, info="") {											            				;--
    static vt
    if !VarSetCapacity(vt)
    {
        VarSetCapacity(vt, A_PtrSize*11), nPar := "31132253353"
        Loop Parse, nPar
            NumPut(RegisterCallback("DL_Progress", "F", A_LoopField, A_Index-1), vt, A_PtrSize*(A_Index-1))
    }
    global _cu, descr
    SplitPath file, dFile
    SysGet m, MonitorWorkArea, 1
    y := mBottom-62-2, x := mRight-330-2, VarSetCapacity(_cu, 100), VarSetCapacity(tn, 520)
    , DllCall("shlwapi\PathCompactPathEx", "str", _cu, "str", url, "uint", 50, "uint", 0)
    descr := (info = "") ? _cu : info . ": " _cu
    Progress Hide CWFAFAF7 CT000020 CB445566 x%x% y%y% w330 h62 B1 FS8 WM700 WS700 FM8 ZH12 ZY3 C11,, %descr%, AutoHotkeyProgress, Tahoma
    if (0 = DllCall("urlmon\URLDownloadToCacheFile", "ptr", 0, "str", url, "str", tn, "uint", 260, "uint", 0x10, "ptr*", &vt))
        FileCopy %tn%, %file%
    else
        ErrorLevel := -1
    Progress Off
    return ErrorLevel
} ;</10.01.000001>
;<10.01.000002>
NewLinkMsg(VideoSite, VideoName = "") {								            		;--

   global lng

   TmpMsg := % lng.MSG_NEW_LINK_FOUND . VideoSite . "`r`n"
   if (VideoName <> "")
      TmpMsg := TmpMsg . lng.MSG_NEW_LINK_FILENAME . VideoName . "`r`n`r`n"

	MsgBox 36, %ProgramName%, % TmpMsg lng.MSG_NEW_LINK_ASK, 50
	IfMsgBox Yes
		return, 0
	else
		return, -1

} ;</10.01.000002>
;<10.01.000003>
TimeGap(ntp="de.pool.ntp.org")	{								            					;-- Determine by what amount the local system time differs to that of an ntp server

		;Bobo's function
		;https://autohotkey.com/boards/viewtopic.php?f=10&t=34806
		RunWait,% ComSpec " /c w32tm /stripchart /computer:" ntp " /period:1 /dataonly /samples:1 | clip",, Hide ; Query is stored in the clipboard
		array := StrSplit(ClipBoard,"`n")					;disassemble the returned answer after lines
		Return % SubStr(array[4], 10)		                ; difference of time/gap ...

} ;</10.01.000003>
;<10.01.000004>
GetSourceURL( str ) {																            			;--

    FragIdent := RegExReplace( str, "i).*<b.*?>(.*?<!--s\w{11}t-->).*", "$1" )

    For Each, Ident in ( StrSplit( FragIdent, " " ), IdentObj := {} )
        if InStr( Ident, mStr := "SourceURL:" )
            SourceURL := SubStr( Ident, StrLen( mStr )+1 )

    Return SourceURL

} ;</10.01.000004>
;<10.01.000005>
DNS_QueryName(IP, ByRef NameArray := "") {						            			;--

   Static OffRR := (A_PtrSize * 2) + 16 ; offset of resource record (RR) within the DNS_RECORD structure
   HDLL := DllCall("LoadLibrary", "Str", "Dnsapi.dll", "UPtr")
   NameArray := []
   IPArray := StrSplit(IP, ".")
   RevIP := IPArray.4 . "." . IPArray.3 . "." . IPArray.2 . "." . IPArray.1 . ".IN-ADDR.ARPA"
   If !DllCall("Dnsapi.dll\DnsQuery_", "Str", RevIP, "Short", 0x0C, "UInt", 0, "Ptr", 0, "PtrP", PDNSREC, "Ptr", 0, "Int") {
      REC_TYPE := NumGet(PDNSREC + 0, A_PtrSize * 2, "UShort")
      If (REC_TYPE = 0x0C) { ; DNS_TYPE_PTR = 0x0C
         PDR := PDNSREC
         While (PDR) {
            Name := StrGet(NumGet(PDR + 0, OffRR, "UPtr"))
            NameArray.Insert(Name)
            PDR := NumGet(PDR + 0, "UPtr")
         }
      }
      DllCall("Dnsapi.dll\DnsRecordListFree", "Ptr", PDNSREC, "Int", 1) ; DnsFreeRecordList = 1
   }
   DllCall("FreeLibrary", "Ptr", HDLL)
   Return NameArray[1] ; returnes the first name from the NameArray on success, otherwise an empty string

} ;</10.01.000005>
;<10.01.000006>
	;this 4 belong together
GetHTMLFragment() {																            			;--

    FmtArr := EnumClipFormats(), NmeArr := GetClipFormatNames( FmtArr )

    While ( a_index <= NmeArr.Length() && !ClpPtr )
        if ( NmeArr[ a_index ] = "HTML Format" )
            ClpPtr := DllCall( "GetClipboardData", uInt, FmtArr[ a_index ] )

    DllCall( "CloseClipboard" )

    if ( !ClpPtr )
    {
        MsgBox, 0x10, Whoops!, Please Copy Some HTML From a Browser Window!
        Exit
    }

    Return ScrubFragmentIdents( StrGet( ClpPtr, "UTF-8" ) )

} ;</10.01.000006>
;<10.01.000007>
ScrubFragmentIdents( HTMFrag ) {											            			;--

    HTMObj := ComObjCreate( "HTMLFile" ), HTMObj.Write( HTMFrag )
    MarkUp := HTMObj.getElementsByTagName( "HTML" )[ 0 ].OuterHtml

    For Needle, Replace in { "(y>).*?(<\w)" : "$1$2", "<!--(s|e).*?-->" : "" }
        MarkUp := RegExReplace( MarkUp, "si)" Needle, Replace )

    Return MarkUp
} ;</10.01.000007>
;<10.01.000008>
EnumClipFormats() {																            			;--
    FmtArr := [], DllCall( "OpenClipboard" )

    While ( DllCall( "CountClipboardFormats" ) >= a_index )
        FmtArr.Push( fmt := DllCall( "EnumClipboardFormats", uint, a_index = 1 ? 0 : fmt ) )

    Return FmtArr
} ;</10.01.000008>
;<10.01.000009>
GetClipFormatNames( FmtArr ) {													            	;--
    if ( FmtArr.Length() = False )
    {
        DllCall( "CloseClipboard" )
        Throw "Empty Clipboard Format Array!"
    }

    For Each, Fmt in ( FmtArr, FmtNmArr := [], VarSetCapacity( Buf, 256 ) )
    {
        DllCall( "GetClipboardFormatName", uInt, Fmt, str, Buf, int, 128 )

        if ( Asc( StrGet( &buf ) ) != False  )
            FmtNmArr.Push( StrGet( &buf ) )
    }

    Return FmtNmArr
} ;</10.01.000009>
;<10.01.000010>
GoogleTranslate(phrase,LangIn,LangOut) {							            				;--

		Critical
		base := "https://translate.google.com.tw/?hl=en&tab=wT#"
		path := base . LangIn . "/" . LangOut . "/" . phrase
		IE := ComObjCreate("InternetExplorer.Application")
		;~ IE.Visible := true
		IE.Navigate(path)

		While IE.readyState!=4 || IE.document.readyState!="complete" || IE.busy
				Sleep 50

		Result := IE.document.all.result_box.innertext
		IE.Quit

return Result

} ;</10.01.000010>
;<10.01.000011>
getText(byref html) {												            							;-- get text from html

	html:=RegExReplace(html,"[\n\r\t]+","")

	html:=regexreplace(html,"\s{2,}<"," <")
	html:=regexreplace(html,">\s{2,}","> ")
	html:=regexreplace(html,">\s+<","><")

	html:=RegExReplace(html,"is)<script[^>]*>.*?<\s*\/\s*script\s*>","")

	html:=regexreplace(html,"<[^<>]+>","")
	html:=regexreplace(html,"i)&nbsp;"," ")
	return html
} ;</10.01.000011>
;<10.01.000012>
getHtmlById(byref html,id,outer=false) {		            										;--
	RegExMatch(html,"is)<([^>\s]+)[^>]*\sid=(?:(?:""" id """)|(?:'" id "')|(?:" id "))[^>]*>(.*?)<\s*\/\s*\1\s*>",match)
	return outer ? match : match2
} ;</10.01.000012>
;<10.01.000013>
getTextById(byref html,id,trim=true) {                                                         	;--
	return trim ? trim(s:=getText(getHtmlById(html,id))) : s
} ;</10.01.000013>
;<10.01.000014>
getHtmlByTagName(byref html,tagName,outer=false) {		            			;--
	arr:=[]
	i:=0
	while i:=regexmatch(html,"is)<" tagName "(?:\s[^>]*)?>(.*?)<\s*\/\s*" tagName "\s*>",match,i+1)
		outer ? arr.insert(match) : arr.insert(match1)
	return arr
} ;</10.01.000014>
;<10.01.000015>
getTextByTagName(byref html,tagName,trim=true) {		            				;--
	arr:=getHtmlByTagName(html,tagName)
	arr2:=[]
	for k,v in arr
		trim ? arr2.insert(trim(s:=getText(v))) : arr2.insert(s)
	return arr2
} ;</10.01.000015>
;<10.01.000016>
CreateGist(content, description:="", filename:="file1.ahk", 		            		;--
token:="", public:=true) {

	url := "https://api.github.com/gists"
	obj := { "description": description
	       , "public": (public ? "true" : "false")
	       , "files": { (filename): {"content": content} } }

	whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	whr.Open("POST", url)
	whr.SetRequestHeader("Content-Type", "application/json; charset=utf-8")
	if token {
		whr.SetRequestHeader("Authorization", "token " token)
	}
	whr.Send( JSON_FromObj(obj) )

	if retUrl := JSON_ToObj(whr.ResponseText).html_url
		return retUrl
	else
		throw, whr.ResponseText
} ;</10.01.000016>
;<10.01.000017>
GetAllResponseHeaders(Url, RequestHeaders := "",                                   	;-- gets the values of all HTTP headers
NO_AUTO_REDIRECT := false, NO_COOKIES := false) {

	static INTERNET_OPEN_TYPE_DIRECT := 1
	     , INTERNET_SERVICE_HTTP := 3
	     , HTTP_QUERY_RAW_HEADERS_CRLF := 22
	     , CP_UTF8 := 65001
	     , Default_UserAgent := "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"

	hModule := DllCall("LoadLibrary", "str", "wininet.dll", "ptr")

	if !hInternet := DllCall("wininet\InternetOpen", "ptr", &Default_UserAgent, "uint", INTERNET_OPEN_TYPE_DIRECT
		, "str", "", "str", "", "uint", 0)
		return
	; -----------------------------------------------------------------------------------
	if !InStr(Url, "://")
		Url := "http://" Trim(Url)

	regex := "(?P<protocol>\w+)://((?P<user>\w+):(?P<pwd>\w+)@)?(?P<host>[\w.]+)(:(?P<port>\d+))?(?P<path>.*)"
	RegExMatch(Url, regex, v_)

	if (v_protocol = "ftp") {
		throw, "ftp is not supported."
	}
	if (v_port = "") {
		v_port := (v_protocol = "https") ? 443 : 80
	}
	; -----------------------------------------------------------------------------------
	Internet_Flags := 0
	                | 0x400000   ; INTERNET_FLAG_KEEP_CONNECTION
	                | 0x80000000 ; INTERNET_FLAG_RELOAD
	                | 0x20000000 ; INTERNET_FLAG_NO_CACHE_WRITE
	if (v_protocol = "https") {
		Internet_Flags |= 0x1000  ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
		               | 0x2000   ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
		               | 0x800000 ; INTERNET_FLAG_SECURE ; Technically, this is redundant for https
	}
	if NO_AUTO_REDIRECT
		Internet_Flags |= 0x00200000 ; INTERNET_FLAG_NO_AUTO_REDIRECT
	if NO_COOKIES
		Internet_Flags |= 0x00080000 ; INTERNET_FLAG_NO_COOKIES
	; -----------------------------------------------------------------------------------
	hConnect := DllCall("wininet\InternetConnect", "ptr", hInternet, "ptr", &v_host, "uint", v_port
		, "ptr", &v_user, "ptr", &v_pwd, "uint", INTERNET_SERVICE_HTTP, "uint", Internet_Flags, "uint", 0, "ptr")

	hRequest := DllCall("wininet\HttpOpenRequest", "ptr", hConnect, "str", "HEAD", "ptr", &v_path
		, "str", "HTTP/1.1", "ptr", 0, "ptr", 0, "uint", Internet_Flags, "ptr", 0, "ptr")

	nRet := DllCall("wininet\HttpSendRequest", "ptr", hRequest, "ptr", &RequestHeaders, "int", -1
		, "ptr", 0, "uint", 0)

	Loop, 2 {
		DllCall("wininet\HttpQueryInfoA", "ptr", hRequest, "uint", HTTP_QUERY_RAW_HEADERS_CRLF
			, "ptr", &pBuffer, "uint*", bufferLen, "uint", 0)
		if (A_Index = 1)
			VarSetCapacity(pBuffer, bufferLen, 0)
	}
	; -----------------------------------------------------------------------------------
	output := StrGet(&pBuffer, "UTF-8")
	; -----------------------------------------------------------------------------------
	DllCall("wininet\InternetCloseHandle", "ptr", hRequest)
	DllCall("wininet\InternetCloseHandle", "ptr", hConnect)
	DllCall("wininet\InternetCloseHandle", "ptr", hInternet)
	DllCall("FreeLibrary", "Ptr", hModule)

	return output

} ;</10.01.000017>
;<10.01.000018>
NetStat() {                                                                                                    	;--passes information over network connections similar to the netstat -an CMD command.

	/*	Description: a function by jNizM

		https://autohotkey.com/boards/viewtopic.php?t=4372

		this function returns an array:
		- array[x].proto ;(Das Protokoll der Verbindung -> TCP oder UDP)
		- array[x].ipv ;(Die IP-Version -> 4 oder 6)
		- array[x].localIP ;(Lokale IP Adresse)
		- array[x].localPort ;(Lokaler Port)
		- array[x].localScopeId ;(Lokale Scope ID... nur IPv6)
		- array[x].remoteIP ;(Remote IP Adresse... nur TCP)
		- array[x].remotePort ;(Remote Port :HeHe: ... nur TCP)
		- array[x].remoteScopeId ;(nur TCP/IPv6)
		- array[x].status ;(der Status der Verbindung -> LISTEN, ESTABLISHED, TIME-WAIT, etc...)

	*/

	c := 32
	static status := {1:"CLOSED", 2:"LISTEN", 3:"SYN-SENT", 4:"SYN-RECEIVED"
	, 5:"ESTABLISHED", 6:"FIN-WAIT-1", 7:"FIN-WAIT-2", 8:"CLOSE-WAIT"
	, 9:"CLOSING", 10:"LIST-ACK", 11:"TIME-WAIT", 12:"DELETE-TCB"}

	iphlpapi := DllCall("LoadLibrary", "str", "iphlpapi", "ptr")
	list := []

	VarSetCapacity(tbl, 4+(s := (20*c)), 0)
	while (DllCall("iphlpapi\GetTcpTable", "ptr", &tbl, "uint*", s, "uint", 1)=122)
	VarSetCapacity(tbl, 4+s, 0)

	Loop, % NumGet(tbl, 0, "uint")
	{
		o := 4+((A_Index-1)*20)
		t := {proto:"TCP", ipv:4}
		t.localIP := ((dw := NumGet(tbl, o+4, "uint"))&0xff) "." ((dw&0xff00)>>8) "." ((dw&0xff0000)>>16) "." ((dw&0xff000000)>>24)
		t.localPort := (((dw := NumGet(tbl, o+8, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
		t.remoteIP := ((dw := NumGet(tbl, o+12, "uint"))&0xff) "." ((dw&0xff00)>>8) "." ((dw&0xff0000)>>16) "." ((dw&0xff000000)>>24)
		t.remotePort := (((dw := NumGet(tbl, o+16, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
		t.status := status[NumGet(tbl, o, "uint")]
		list.insert(t)
	}

	if (DllCall("GetProcAddress", "ptr", iphlpapi, "astr", "GetTcp6Table", "ptr"))
	{
		VarSetCapacity(tbl, 4+(s := (52*c)), 0)
		while (DllCall("iphlpapi\GetTcp6Table", "ptr", &tbl, "uint*", s, "uint", 1)=122)
			VarSetCapacity(tbl, 4+s, 0)

		Loop, % NumGet(tbl, 0, "uint")
		{
			VarSetCapacity(str, 94, 0)
			o := 4+((A_Index-1)*52)
			t := {proto:"TCP", ipv:6}
			t.localIP := (DllCall("ws2_32\InetNtop", "uint", 23, "ptr", &tbl+o+4, "ptr", &str, "uint", 94)) ? StrGet(&str) : ""
			t.localScopeId := (((dw := NumGet(tbl, o+20, "uint"))&0xff)<<24) | ((dw&0xff00)<<8) | ((dw&0xff0000)>>8) | ((dw&0xff000000)>>24)
			t.localPort := (((dw := NumGet(tbl, o+24, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
			t.remoteIP := (DllCall("ws2_32\InetNtop", "uint", 23, "ptr", &tbl+o+28, "ptr", &str, "uint", 94)) ? StrGet(&str) : ""
			t.remoteScopeId := (((dw := NumGet(tbl, o+44, "uint"))&0xff)<<24) | ((dw&0xff00)<<8) | ((dw&0xff0000)>>8) | ((dw&0xff000000)>>24)
			t.remotePort := (((dw := NumGet(tbl, o+48, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
			t.status := status[NumGet(tbl, o, "uint")]
			list.insert(t)
		}
	}

	VarSetCapacity(tbl, 4+(s := (8*c)), 0)
	while (DllCall("iphlpapi\GetUdpTable", "ptr", &tbl, "uint*", s, "uint", 1)=122)
	VarSetCapacity(tbl, 4+s, 0)

	Loop, % NumGet(tbl, 0, "uint")
	{
		o := 4+((A_Index-1)*20)
		t := {proto:"UDP", ipv:4}
		t.localIP := ((dw := NumGet(tbl, o, "uint"))&0xff) "." ((dw&0xff00)>>8) "." ((dw&0xff0000)>>16) "." ((dw&0xff000000)>>24)
		t.localPort := (((dw := NumGet(tbl, o+4, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
		list.insert(t)
	}

	if (DllCall("GetProcAddress", "ptr", iphlpapi, "astr", "GetUdp6Table", "ptr"))
	{
		VarSetCapacity(tbl, 4+(s := (52*c)), 0)
		while (DllCall("iphlpapi\GetUdp6Table", "ptr", &tbl, "uint*", s, "uint", 1)=122)
			VarSetCapacity(tbl, 4+s, 0)

		Loop, % NumGet(tbl, 0, "uint")
		{
			VarSetCapacity(str, 94, 0)
			o := 4+((A_Index-1)*52)
			t := {proto:"UDP", ipv:6}
			t.localIP := (DllCall("ws2_32\InetNtop", "uint", 23, "ptr", &tbl+o, "ptr", &str, "uint", 94)) ? StrGet(&str) : ""
			t.localScopeId := (((dw := NumGet(tbl, o+16, "uint"))&0xff)<<24) | ((dw&0xff00)<<8) | ((dw&0xff0000)>>8) | ((dw&0xff000000)>>24)
			t.localPort := (((dw := NumGet(tbl, o+20, "uint"))&0xff00)>>8)|((dw&0xff)<<8)
			list.insert(t)
		}
	}
	return list
} ;</10.01.000018>
;<10.01.000019>
ExtractTableData( FilePath, HeadingsArray, Delimiter, SaveDir ) {	            	;-- extracts tables from HTML files

	static htmObj

	if !IsObject( htmObj )
		htmObj := ComObjCreate( "HTMLfile" )
	else
		htmObj.Close()

	tablesArray			:= {}
	tablesDataArray		:= {}

	FileRead, HTML, % FilePath
	htmObj.Write( HTML )
	tablesCollection 	:= htmObj.getElementsByTagName( "table" )
	tablesCount 		:= tablesCollection.length

	For Each, Value in HeadingsArray
	{
		tableNumber 	:= 0
		HeadingName 	:= Each
		HeadingNumbers	:= Value.1
		RowNumbers 		:= Value.2

		loop % tablesCount
		{
			tableObj := tablesCollection[ a_index-1 ]


			if InStr( tableObj.innerText, HeadingName )
			{

				tableNumber++
				tableBodyObj 	 			:= tableObj.getElementsByTagName( "tbody" )
				tableColumnHeadingObj		:= tableBodyObj[ 0 ].firstChild.getElementsByTagName( "th" )
				tableRowObj 	 			:= tableBodyObj[ 0 ].getElementsByTagName( "tr" )

				tableCaption 				:= tableBodyObj[ 0 ].previousSibling.innerText

				tableColumnHeadingCount 	:= tableColumnHeadingObj.length
				tableDataRowCount 	 		:= tableRowObj.length-1 ; table data rows minus the heading row

				loop % tableColumnHeadingCount
				{
					tableColumnHeadingValue := tableColumnHeadingObj[ a_index-1 ].innerText
					columnNumber 			:= a_index-1

					if ( tableColumnHeadingValue ~= "^" HeadingName )
					{
						loop % tableDataRowCount
						{
							tableDataObj 		:= tableRowObj[ a_index ].getElementsByTagName( "td" )
							tableData 			:= tableDataObj[ columnNumber ].innerText

							tablesArray[ RegExReplace( Trim( tableColumnHeadingValue ), "\W", "_" ), tableNumber, a_index ] := { tableData: tableData, tableCaption : tableCaption }
						}
					}
				}
			}
		}

		HeadingName := RegExReplace( HeadingName, "\W", "_" )

		if !( HeadingNumbers.length() || IsObject( HeadingNumbers ) || RowNumbers.length() || IsObject( RowNumbers ) )
		{
			tableCaption 	 := tablesArray[ HeadingName ][ HeadingNumbers ][ RowNumbers ].tableCaption
			tableArrayValue  := tablesArray[ HeadingName ][ HeadingNumbers ][ RowNumbers ].tableData
			tablesDataString .= ( tableArrayValue != "" ? tableCaption " ~ " HeadingName ": " tableArrayValue Delimiter : "" )
		}
		else if ( HeadingNumbers.length() || IsObject( HeadingNumbers ) ) && !(  RowNumbers.length() || IsObject( RowNumbers ) )
 		{
			For i in HeadingNumbers
			{
				tableCaption  	 := tablesArray[ HeadingName ][ i ][ RowNumbers ].tableCaption
				tableArrayValue  := tablesArray[ HeadingName ][ i ][ RowNumbers ].tableData
				tablesDataString .= ( tableArrayValue != "" ? tableCaption " ~ " HeadingName ": " tableArrayValue Delimiter : "" )
			}
		}
		else if !( HeadingNumbers.length() || IsObject( HeadingNumbers ) ) && (  RowNumbers.length() || IsObject( RowNumbers ) )
		{
			For i in RowNumbers
			{
				tableCaption  	 := tablesArray[ HeadingName ][ HeadingNumbers ][ i ].tableCaption
				tableArrayValue  := tablesArray[ HeadingName ][ HeadingNumbers ][ i ].tableData
				tablesDataString .= ( tableArrayValue != "" ? tableCaption " ~ " HeadingName ": " tableArrayValue Delimiter : "" )
			}
		}
		else if ( HeadingNumbers.length() || IsObject( HeadingNumbers ) ) && (  RowNumbers.length() || IsObject( RowNumbers ) )
		{
			For h in HeadingNumbers
			{
				For r in RowNumbers
				{
					tableCaption  	 := tablesArray[ HeadingName ][ h ][ r ].tableCaption
					tableArrayValue  := tablesArray[ HeadingName ][ h ][ r ].tableData
					tablesDataString .= ( tableArrayValue != "" ? tableCaption " ~ " HeadingName ": " tableArrayValue Delimiter : "" )
				}
			}
		}
	}

	SplitPath, % FilePath, FileNameExt,,, FileName

	if !StrLen( tablesDataString )
	{
		Msgbox 0x10, Whoops!, % "No Table Data Found in: " FileNameExt
		return true
	}
	else
	{
		SaveFile := SaveDir "\" FileName ".txt"
		if FileExist( SaveFile )
		{
			FileDelete % SaveFile
		}

		FileAppend, % Trim( tablesDataString, Delimiter ), % SaveFile
		TrayTip,, % "Table Data Written To: " FileName ".txt"
	}

	return tablesDataString
} ;</10.01.000019>
;<10.01.000020>
IsConnected(URL="https://autohotkey.com/boards/") {                            	;-- Returns true if there is an available internet connection
	return DllCall("Wininet.dll\InternetCheckConnection", "Str", URL,"UInt", 1, "UInt",0, "UInt")
} ;</10.01.000020>
;<10.01.000021>
HostToIp(NodeName) {								            										;-- gets the IP address for the given host directly using the WinSock 2.0 dll, without using temp files or third party utilities
	/*                              	DESCRIPTION

			Link: https://autohotkey.com/board/topic/9051-host-to-ip-address-using-winsock-20-dll/
			This function gets the IP address for the given host directly using the WinSock 2.0 dll, without using temp files or third party utilities.
			Multiple addresses are returned, seperated by a newline, if available.

			Note! If a domain has no dedicated IP address because it is run from a server using virtual hosts the IP address of the server is returned.

			The script below is fully functional as given, just copy and paste it (beware of line breaks) into a script file.
			(largely based on functions from the WinLirc script and various other posts in this forum)

	*/
	/*                              	EXAMPLE(s)

			NodeName = www.google.com
			IPs := HostToIp(NodeName)
			DllCall("Ws2_32\WSACleanup") ; always inlude this line after calling to release the socket connection
			if IPs <> -1 ; no error occurred
				Msgbox, %NodeName%`n%IPs%
			else
				MsgBox, Host "%NodeName%" not found

	*/

	 ; returns -1 if unsuccessfull or a newline seperated list of valid IP addresses on success
	VarSetCapacity(wsaData, 32)  ; The struct is only about 14 in size, so 32 is conservative.
	result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
	if ErrorLevel	; check ErrorLevel to see if the OS has Winsock 2.0 available:
	{
		MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
		return -1
	}
	if result  ; Non-zero, which means it failed (most Winsock functions return 0 on success).
	{
		MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") ; %
		return -1
	}
	PtrHostent := DllCall("Ws2_32\gethostbyname", str, Nodename)
	if (PtrHostent = 0)
		Return -1
	VarSetCapacity(hostent,16,0)
	DllCall("RtlMoveMemory",UInt,&hostent,UInt,PtrHostent,UInt,16)
	h_name      := ExtractInteger(hostent,0,false,4)
	h_aliases   := ExtractInteger(hostent,4,false,4)
	h_addrtype  := ExtractInteger(hostent,8,false,2)
	h_length    := ExtractInteger(hostent,10,false,2)
	h_addr_list := ExtractInteger(hostent,12,false,4)
	; Retrieve official name
	VarSetCapacity(Name,64,0)
	DllCall("RtlMoveMemory",UInt,&Name,UInt,h_name,UInt,64)
	; Retrieve Aliases
	VarSetCapacity(Aliases,12,0)
	DllCall("RtlMoveMemory", UInt, &Aliases, UInt, h_aliases, UInt, 12)
	Loop, 3
	{
	   offset := ((A_Index-1)*4)
	   PtrAlias%A_Index% := ExtractInteger(Aliases,offset,false,4)
	   If (PtrAlias%A_Index% = 0)
	      break
	   VarSetCapacity(Alias%A_Index%,64,0)
	   DllCall("RtlMoveMemory",UInt,&Alias%A_Index%,UInt,PtrAlias%A_Index%,Uint,64)
	}
	VarSetCapacity(AddressList,12,0)
	DllCall("RtlMoveMemory",UInt,&AddressList,UInt,h_addr_list,UInt,12)
	Loop, 3
	{
	   offset := ((A_Index-1)*4)
	   PtrAddress%A_Index% := ExtractInteger(AddressList,offset,false,4)
	   If (PtrAddress%A_Index% =0)
	      break
	   VarSetCapacity(address%A_Index%,4,0)
	   DllCall("RtlMoveMemory" ,UInt,&address%A_Index%,UInt,PtrAddress%A_Index%,Uint,4)
	   i := A_Index
	   Loop, 4
	   {
	      if Straddress%i%
	         Straddress%i% := Straddress%i% "." ExtractInteger(address%i%,(A_Index-1 ),false,1)
	      else
	         Straddress%i% := ExtractInteger(address%i%,(A_Index-1 ),false,1)
	   }
		Straddress0 = %i%
	}
	loop, %Straddress0% ; put them together and return them
	{
		_this := Straddress%A_Index%
		if _this <>
			IPs = %IPs%%_this%
		if A_Index = %Straddress0%
			break
		IPs = %IPs%`n
	}
	return IPs
} ;</10.01.000021>
;{ sub
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4) {
	Loop %pSize%
	  result += *(&pSource+pOffset+A_Index-1) << 8*A_Index-8
	Return result
}
;}
;<10.01.000022>
LocalIps() {										            													;-- with small changes to HostToIP() this can be used to retrieve all LocalIP's
	/*                              	DESCRIPTION

			Link: https://autohotkey.com/board/topic/9051-host-to-ip-address-using-winsock-20-dll/

	*/
	/*                              	EXAMPLE(s)

			IPs := LocalIps()
			DllCall("Ws2_32\WSACleanup") ; always inlude this line after calling to release the socket connection
			Msgbox, %IPs%


	*/

	 ; returns -1 if unsuccessfull or a newline seperated list of valid IP addresses on success
   VarSetCapacity(wsaData, 32)  ; The struct is only about 14 in size, so 32 is conservative.
   result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
   if ErrorLevel   ; check ErrorLevel to see if the OS has Winsock 2.0 available:
   {
      MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
      return -1
   }
   if result  ; Non-zero, which means it failed (most Winsock functions return 0 on success).
   {
      MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") ; %
      return -1
   }
   ; convert ip to Inet Address
   Inet_address := DllCall("Ws2_32\inet_addr", Str, "0")
   PtrHostent := DllCall("Ws2_32\gethostbyaddr", "int *", %Inet_address%, "int", 4, "int", 2)
   if (PtrHostent = 0)
      Return -1
   VarSetCapacity(hostent,16,0)
   DllCall("RtlMoveMemory",UInt,&hostent,UInt,PtrHostent,UInt,16)
   h_addr_list := ExtractInteger(hostent,12,false,4)

   VarSetCapacity(AddressList,12,0)
   DllCall("RtlMoveMemory",UInt,&AddressList,UInt,h_addr_list,UInt,12)
   Loop, 3
   {
      offset := ((A_Index-1)*4)
      PtrAddress%A_Index% := ExtractInteger(AddressList,offset,false,4)
      If (PtrAddress%A_Index% =0)
         break
      VarSetCapacity(address%A_Index%,4,0)
      DllCall("RtlMoveMemory" ,UInt,&address%A_Index%,UInt,PtrAddress%A_Index%,Uint,4)
      i := A_Index
      Loop, 4
      {
         if Straddress%i%
            Straddress%i% := Straddress%i% "." ExtractInteger(address%i%,(A_Index-1 ),false,1)
         else
            Straddress%i% := ExtractInteger(address%i%,(A_Index-1 ),false,1)
      }
      Straddress0 = %i%
   }
   loop, %Straddress0% ; put them together and return them
   {
      _this := Straddress%A_Index%
      if _this <>
         IPs = %IPs%%_this%
      if A_Index = %Straddress0%
         break
      IPs = %IPs%`n
   }
   return IPs
} ;</10.01.000022>
;<10.01.000023>
GetAdaptersInfo() {																	            			;-- GetAdaptersAddresses function & IP_ADAPTER_ADDRESSES structure
	/*                              	DESCRIPTION

				Link: https://autohotkey.com/boards/viewtopic.php?t=18768
				Dependencies: none
	*/
	/*                              	EXAMPLE(s)

			OutPut := GetAdaptersInfo()
			PrintArr(OutPut)

	*/


    ; initial call to GetAdaptersInfo to get the necessary size
    if (DllCall("iphlpapi.dll\GetAdaptersInfo", "ptr", 0, "UIntP", size) = 111) ; ERROR_BUFFER_OVERFLOW
        if !(VarSetCapacity(buf, size, 0))  ; size ==>  1x = 704  |  2x = 1408  |  3x = 2112
            return "Memory allocation failed for IP_ADAPTER_INFO struct"

    ; second call to GetAdapters Addresses to get the actual data we want
    if (DllCall("iphlpapi.dll\GetAdaptersInfo", "ptr", &buf, "UIntP", size) != 0) ; NO_ERROR / ERROR_SUCCESS
        return "Call to GetAdaptersInfo failed with error: " A_LastError

    ; get some information from the data we received
    addr := &buf, IP_ADAPTER_INFO := {}
    while (addr)
    {
        IP_ADAPTER_INFO[A_Index, "ComboIndex"]          		:= NumGet(addr+0, o := A_PtrSize, "UInt")   , o += 4
        IP_ADAPTER_INFO[A_Index, "AdapterName"]         	:= StrGet(addr+0 + o, 260, "CP0")           , o += 260
        IP_ADAPTER_INFO[A_Index, "Description"]         		:= StrGet(addr+0 + o, 132, "CP0")           , o += 132
        IP_ADAPTER_INFO[A_Index, "AddressLength"]       		:= NumGet(addr+0, o, "UInt")                , o += 4
        loop % IP_ADAPTER_INFO[A_Index].AddressLength
									mac .= Format("{:02X}",                       NumGet(addr+0, o + A_Index - 1, "UChar")) "-"
        IP_ADAPTER_INFO[A_Index, "Address"]             			:= SubStr(mac, 1, -1), mac := ""            , o += 8
        IP_ADAPTER_INFO[A_Index, "Index"]               			:= NumGet(addr+0, o, "UInt")                , o += 4
        IP_ADAPTER_INFO[A_Index, "Type"]                			:= NumGet(addr+0, o, "UInt")                , o += 4
        IP_ADAPTER_INFO[A_Index, "DhcpEnabled"]         		:= NumGet(addr+0, o, "UInt")                , o += A_PtrSize
																					Ptr 	:= NumGet(addr+0, o, "UPtr")                , o += A_PtrSize
        IP_ADAPTER_INFO[A_Index, "CurrentIpAddress"]   	:= Ptr ? StrGet(Ptr + A_PtrSize, "CP0") : ""
        IP_ADAPTER_INFO[A_Index, "IpAddressList"]       		:= StrGet(addr + o + A_PtrSize, "CP0")
        IP_ADAPTER_INFO[A_Index, "IpMaskList"]          			:= StrGet(addr + o + A_PtrSize + 16, "CP0") , o += A_PtrSize + 32 + A_PtrSize
        IP_ADAPTER_INFO[A_Index, "GatewayList"]         		:= StrGet(addr + o + A_PtrSize, "CP0")      , o += A_PtrSize + 32 + A_PtrSize
        IP_ADAPTER_INFO[A_Index, "DhcpServer"]          		:= StrGet(addr + o + A_PtrSize, "CP0")      , o += A_PtrSize + 32 + A_PtrSize
        IP_ADAPTER_INFO[A_Index, "HaveWins"]            		:= NumGet(addr+0, o, "Int")                 , o += A_PtrSize
        IP_ADAPTER_INFO[A_Index, "PrimaryWinsServer"] 	:= StrGet(addr + o + A_PtrSize, "CP0")      , o += A_PtrSize + 32 + A_PtrSize
        IP_ADAPTER_INFO[A_Index, "SecondaryWinsServer"] := StrGet(addr + o + A_PtrSize, "CP0")      , o += A_PtrSize + 32 + A_PtrSize
        IP_ADAPTER_INFO[A_Index, "LeaseObtained"]       		:= DateAdd(NumGet(addr+0, o, "Int"))        , o += A_PtrSize
        IP_ADAPTER_INFO[A_Index, "LeaseExpires"]        		:= DateAdd(NumGet(addr+0, o, "Int"))
        addr := NumGet(addr+0, "UPtr")
    }

    ; output the data we received and free the buffer
    return IP_ADAPTER_INFO, VarSetCapacity(buf, 0), VarSetCapacity(addr, 0)
} ;</10.01.000023>
;<10.01.000024>
DNSQuery(AddrOrName, ByRef ResultArray := "", ByRef CNAME := "") {		;-- retrieve IP adresses or host/domain names from DNS

	/*    	DESCRIPTION of function DNSQuery()
			 ==================================================================================================================================
			 Function:
					Query DNS to get the IPv4 address(es) for the given host/domain name or vice versa.
			 Parameters:
					AddrOrName  -  host/domain name or IPv4 address (xxx.xxx.xxx.xxx).
					ResultArray -  optional array to retrieve multiple answers.
					CNAME       -  optional variable to retrieve the 'canonical name' (CNAME) returned from DNS for host/domain name queries.
			 Return values:
					On success: First returned address or name.
					On failure: an empty string, ErrorLevel is set to the DNS error code.
			 Link:
					https://autohotkey.com/boards/viewtopic.php?t=489
			 License:
					The Unlicense (for details see http://unlicense.org/).
			 MSDN:
					DnsQuery   -> msdn.microsoft.com/en-us/library/ms682016(v=vs.85).aspx
					DNS_RECORD -> msdn.microsoft.com/en-us/library/ms682082(v=vs.85).aspx
			 DNS record types:
					DNS_TYPE_A = 0x01, DNS_TYPE_CNAME = 0x05, DNS_TYPE_PTR = 0x0C
			 DNS record options:
					DNS_QUERY_STANDARD = 0, DNS_QUERY_USE_TCP_ONLY = 0x02, DNS_QUERY_BYPASS_CACHE = 0x08, DNS_QUERY_NO_HOSTS_FILE = 0x40
					DNS_QUERY_WIRE_ONLY = 0x0100
					DNS_FREE_TYPE:
					DnsFreeRecordList = 1
			 ==================================================================================================================================
	*/

	/*    	EXAMPLE(s)

			#NoEnv
			AddrOrName := "www.berlin.de"
			Addr := DNSQuery(AddrOrName, Results, Name)
			MsgBox, 0, %AddrOrName%, % "Result: " . Addr . "`nError: " . ErrorLevel
			Msg := ""
			For I, V In Results {
			   Msg .= V . "`r`n"
			}
			MsgBox, 0, Results, %Msg%
			MsgBox, 0, CNAME, %Name%
			Name := DNSQuery(Addr, Results)
			MsgBox, 0, %Addr%, % "Result: " . Name . "`nError: " . ErrorLevel
			Msg := ""
			For I, V In Results {
			   Msg .= V . "`r`n"
			}
			MsgBox, 0, Results, %Msg%
			ExitApp

	*/

   Static OffRR := (A_PtrSize * 2) + 16 ; offset of resource record (RR) within the DNS_RECORD structure
   HDLL := DllCall("LoadLibrary", "Str", "Dnsapi.dll", "UPtr")
   CNAME := ""
   Error := 0
   ResultArray := []
   If RegExMatch(AddrOrName, "^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$", IP) {
      RevIP := IP4 . "." . IP3 . "." . IP2 . "." . IP1 . ".IN-ADDR.ARPA"
      If !(Error := DllCall("Dnsapi.dll\DnsQuery_", "Str", RevIP, "Short", 0x0C, "UInt", 0, "Ptr", 0, "PtrP", PDNS, "Ptr", 0)) {
         REC_TYPE := NumGet(PDNS + 0, A_PtrSize * 2, "UShort")
         If (REC_TYPE = 0x0C) { ; DNS_TYPE_PTR
            PDR := PDNS
            While (PDR) {
               Name := StrGet(NumGet(PDR + 0, OffRR, "UPtr"))
               ResultArray.Push(Name)
               PDR := NumGet(PDR + 0, "UPtr")
            }
         }
         DllCall("Dnsapi.dll\DnsRecordListFree", "Ptr", PDNS, "Int", 1) ; DnsFreeRecordList
      }
   }
   Else {
      CNAME := AddrOrName
      Loop {
         If !(Error := DllCall("Dnsapi.dll\DnsQuery_", "Str", CNAME, "Short", 0x01, "UInt", 0, "Ptr", 0, "PtrP", PDNS, "Ptr", 0)) {
            REC_TYPE := NumGet(PDNS + 0, A_PtrSize * 2, "UShort")
            If (REC_TYPE = 0x05) { ; DNS_TYPE_CNAME
               CNAME := StrGet(NumGet(PDNS + OffRR, "UPtr"))
               DllCall("Dnsapi.dll\DnsRecordListFree", "Ptr", PDNS, "Int", 1) ; DnsFreeRecordList
               Continue
            }
            If (REC_TYPE = 0x01) { ; DNS_TYPE_A
               PDR := PDNS
               While (PDR) {
                  Addr := ""
                  Loop, 4
                     Addr .= NumGet(PDR + OffRR + (A_Index - 1), "UChar") . "."
                  ResultArray.Push(RTrim(Addr, "."))
                  PDR := NumGet(PDR + 0, "UPtr")
               }
               DllCall("Dnsapi.dll\DnsRecordListFree", "Ptr", PDNS, "Int", 1) ; DnsFreeRecordList
               Break
            }
         }
         Break
      }
   }
   DllCall("FreeLibrary", "Ptr", HDLL)
   ErrorLevel := Error
   Return ResultArray[1]
} ;</10.01.000024>
;<10.01.000025>
RestartNetwork(ConnectionName := "") {                                                   	;-- Restart "Local area connection" without admin privileges

	/*	DESCRIPTION OF FUNCTION: -- RestartNetwork --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Restart "Local area connection" without admin privileges
	Link              	:	https://gist.github.com/tmplinshi/431bc80dbbbf93715f4bd3fb704d8eec
	                          	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=65822
	Author         	:	tmplinshi
	Date             	:	June 29, 2019
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	If ConnectionName is omited, the adapter name that contains "Realtek PCIe" will be selected.
	Dependencies	:	none
	KeyWords    	:	Lan, network, COM, connection
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	RestartNetwork("Local area connection")
	*/

	oShell := ComObjCreate("Shell.Application")
	oShell.Open("::{7007ACC7-3202-11D1-AAD2-00805FC1270E}") ; Open Network Connections
	FolderName := oShell.Namespace(0x31).Title

	; Find "Network Connections" window
	Loop
	{
		Sleep, 200

		for oWin in oShell.Windows
		{
			if ( oWin.LocationName = FolderName )
			&& ( oWin.LocationURL = "" )
			&& ( InStr(oWin.FullName, "\Explorer.EXE") )
				Break, 2
		}
	}

	oFolder := oWin.Document.Folder

	for item in oFolder.Items
	{
		devName := oFolder.GetDetailsOf(item, 2)

		if (item.name = ConnectionName)
		|| (ConnectionName = "" && InStr(devName, "Realtek PCIe"))
		{
			if InStr(item.Verbs.Item(0).Name, "&B")
			{
				item.InvokeVerb("disable")
				Sleep, 1000
			}

			item.InvokeVerb("enable")
			break
		}
	}

	oWin.Quit
} ;</10.01.000025>
;<10.01.000026>
GetAllResponseHeaders(Url, RequestHeaders := ""                                    	;-- Returns a string that contains all response headers
, NO_AUTO_REDIRECT := false, NO_COOKIES := false) {

	/*	DESCRIPTION OF FUNCTION: --  --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Returns a string that contains all response headers
								The response headers contain information about the server and the retrieved content
								('Content-Length', 'Content-Type', ...). To get the value of a specific response header,
								use the getResponseHeader method.
	Link              	:	https://gist.github.com/tmplinshi/ccd11fae4953a27b9d04db6ef10bc3de
	Author         	:	tmplinshi
	Date             	:	23 Dec 2016
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	internet, html
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	static INTERNET_OPEN_TYPE_DIRECT := 1
	     , INTERNET_SERVICE_HTTP := 3
	     , HTTP_QUERY_RAW_HEADERS_CRLF := 22
	     , CP_UTF8 := 65001
	     , Default_UserAgent := "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"

	hModule := DllCall("LoadLibrary", "str", "wininet.dll", "ptr")

	if !hInternet := DllCall("wininet\InternetOpen", "ptr", &Default_UserAgent, "uint", INTERNET_OPEN_TYPE_DIRECT
		, "str", "", "str", "", "uint", 0)
		return
	; -----------------------------------------------------------------------------------
	if !InStr(Url, "://")
		Url := "http://" Trim(Url)

	regex := "(?P<protocol>\w+)://((?P<user>\w+):(?P<pwd>\w+)@)?(?P<host>[\w.]+)(:(?P<port>\d+))?(?P<path>.*)"
	RegExMatch(Url, regex, v_)

	if (v_protocol = "ftp") {
		throw, "ftp is not supported."
	}
	if (v_port = "") {
		v_port := (v_protocol = "https") ? 443 : 80
	}
	; -----------------------------------------------------------------------------------
	Internet_Flags := 0
	                | 0x400000   ; INTERNET_FLAG_KEEP_CONNECTION
	                | 0x80000000 ; INTERNET_FLAG_RELOAD
	                | 0x20000000 ; INTERNET_FLAG_NO_CACHE_WRITE
	if (v_protocol = "https") {
		Internet_Flags |= 0x1000  ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
		               | 0x2000   ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
		               | 0x800000 ; INTERNET_FLAG_SECURE ; Technically, this is redundant for https
	}
	if NO_AUTO_REDIRECT
		Internet_Flags |= 0x00200000 ; INTERNET_FLAG_NO_AUTO_REDIRECT
	if NO_COOKIES
		Internet_Flags |= 0x00080000 ; INTERNET_FLAG_NO_COOKIES
	; -----------------------------------------------------------------------------------
	hConnect := DllCall("wininet\InternetConnect", "ptr", hInternet, "ptr", &v_host, "uint", v_port
		, "ptr", &v_user, "ptr", &v_pwd, "uint", INTERNET_SERVICE_HTTP, "uint", Internet_Flags, "uint", 0, "ptr")

	hRequest := DllCall("wininet\HttpOpenRequest", "ptr", hConnect, "str", "HEAD", "ptr", &v_path
		, "str", "HTTP/1.1", "ptr", 0, "ptr", 0, "uint", Internet_Flags, "ptr", 0, "ptr")

	nRet := DllCall("wininet\HttpSendRequest", "ptr", hRequest, "ptr", &RequestHeaders, "int", -1
		, "ptr", 0, "uint", 0)

	Loop, 2 {
		DllCall("wininet\HttpQueryInfoA", "ptr", hRequest, "uint", HTTP_QUERY_RAW_HEADERS_CRLF
			, "ptr", &pBuffer, "uint*", bufferLen, "uint", 0)
		if (A_Index = 1)
			VarSetCapacity(pBuffer, bufferLen, 0)
	}
	; -----------------------------------------------------------------------------------
	output := StrGet(&pBuffer, "UTF-8")
	; -----------------------------------------------------------------------------------
	DllCall("wininet\InternetCloseHandle", "ptr", hRequest)
	DllCall("wininet\InternetCloseHandle", "ptr", hConnect)
	DllCall("wininet\InternetCloseHandle", "ptr", hInternet)
	DllCall("FreeLibrary", "Ptr", hModule)

	return output
} ;</10.01.000026>

}
;|   DownloadFile()                        	|   NewLinkMsg()                          	|   TimeGap()                                	|   GetSourceURL()                        	|
;|   DNS_QueryName()                 	|   GetHTMLFragment()                	|   ScrubFragmentIdents()	            	|   EnumClipFormats()                  	|
;|   GetClipFormatNames()           	|   GoogleTranslate()                    	|   getText()                                   	|   getHtmlById()                          	|
;|   getTextById()                           	|   getHtmlByTagName()              	|   getTextByTagName()               	|   DNS_QueryName()                  	|
;|   CreateGist()	                            	|   GetAllResponseHeaders()	        	|   NetStat()                                  	|   ExtractTableData()                   	|
;|   IsConnected()                          	|   HostToIp()                                	|   LocalIps()                                 	|   GetAdaptersInfo()                     	|
;|   DNSQuery()                            	|   RestartNetwork(25)                  	|   GetAllResponseHeaders(26)     	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Math/Converting (24) -                                                                                                                            	baseID: <11>
;<11.01.000001>
Min(x, y) {																						;-- returns the smaller of 2 numbers
  return x < y ? x : y
} ;</11.01.000001>
;<11.01.000002>
Max(x, y) {																						;-- determines the larger number
  return x > y ? x : y
} ;</11.01.000002>
;<11.01.000003>
Mean(List) {																						;-- returns Average values in comma delimited list

	;https://autohotkey.com/board/topic/4858-mean-median-mode-functions/

	Loop, Parse, List , `,
	{
		Total += %A_LoopField%
		D = %A_Index%
	}
	R := Total/D

	Return R
} ;</11.01.000003>
;<11.01.000004>
Median(List) {																					;-- returns Median in a set of numbers from a list

	;https://autohotkey.com/board/topic/4858-mean-median-mode-functions/
	;list must be comma delimited

	Sort, List, N D,  ; Sort numerically, use comma as delimiter.

	;Create Array
	StringSplit, Set, List, `,

	;Figure if odd or even
	R := Set0 / 2
	StringSplit, B, R, .
	StringLeft, C, B2, 1

	;Even
	If (C = 0) {
		pt1 := B1 + 1
		Med := (Set%B1% + Set%pt1%) / 2
	} Else {				;Odd
		Med := Ceil(R)
		Med := Set%Med%
	}

	Return Med
} ;</11.01.000004>
;<11.01.000005>
Mode(List) {																						;-- returns the mode from a list of numbers

	;https://autohotkey.com/board/topic/4858-mean-median-mode-functions/

	StringSplit, Cont, List, `,

	Loop, %Cont0% {

		i := A_Index
		C := Cont%i%
		If ModeArr%C% =
			ModeArr%C% = 1
		Else {
			Amt := ModeArr%C%
			ModeArr%C% := Amt + 1
		}
	}

	Loop %i%	{
		LMC = %CMC%
		CMC := ModeArr%A_Index%
		If CMC > %LMC%
			Mode = %A_Index%
	}

	Return Mode

} ;</11.01.000005>
;<11.01.000006>
Dec2Base( _Number, _Base = 16 ) {         										 ;-- Base to Decimal and
    Loop % _BaseLen := _Base<10 ? Ceil( ( 10/_Base ) * Strlen( _Number ) ) : Strlen( _Number )
        _D := Floor( _Number/( T := _Base**( _BaseLen-A_index ) ) ), _B .= !_D ? 0: ( _D>9 ? Chr( _D + 87 ) : _D ), _Number := _Number - _D * T
    return Ltrim( _B, "0" )
} ;</11.01.000006>
;<11.01.000007>
Base2Dec( _Number, _Base = 16 ) {           										;-- Decimal to Base conversion
    Loop, Parse, _Number
        _N += ( ( A_LoopField * 1 = "" ) ? Asc( A_LoopField ) - 87 : A_LoopField ) * _Base**( Strlen( _Number ) - A_index )
    return _N
} ;</11.01.000007>
;<11.01.000008>
HexToFloat(value) {																			;-- Hexadecimal to Float conversion
    Return, (1 - 2 * (value >> 31)) * (2 ** ((value >> 23 & 255) - 150)) * (0x800000 | value & 0x7FFFFF)
} ;</11.01.000008>
;<11.01.000009>
FloatToHex(value) {																			;-- Float to Hexadecimal conversion

   format := A_FormatInteger
   SetFormat, Integer, H
   result := DllCall("MulDiv", Float, value, Int, 1, Int, 1, UInt)
   SetFormat, Integer, %format%
   Return, result

} ;</11.01.000009>
;<11.01.000010>
CalculateDistance(x1, y1, x2, y2) {													;-- calculates the distance between two points in a 2D-Space
    Return, sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
} ;</11.01.000010>
;<11.01.000011>
IsInRange(value1, value2, range) {													;-- shows if a second variable is in range
    If ((value1 >= (value2 - range)) && (value1 <= (value2 + range)))
    {
        Return, True
    }
    Else
    {
        Return, False
    }
} ;</11.01.000011>
;<11.01.000012>
FormatFileSize(Bytes, Decimals = 1, 												;-- Formats a file size in bytes to a human-readable size string
Prefixes = "B,KB,MB,GB,TB,PB,EB,ZB,YB") {
	StringSplit, Prefix, Prefixes, `,
	Loop, Parse, Prefixes, `,
		if (Bytes < e := 1024 ** A_Index)
			return % Round(Bytes / (e / 1024), decimals) Prefix%A_Index%
} ;</11.01.000012>
;<11.01.000013>
Color_RGBtoHSV( r, g, b, Byref h, Byref s, Byref v ) {						;-- converts beetween color two color spaces: RGB -> HSV
	;https://autohotkey.com/board/topic/71858-solved-help-coming-up-with-color-definitions/#p478116
	;from http://www.cs.rit.edu/~ncs/color/t_convert.html
	;// r,g,b values are from 0 to 1
	;// h = [0,360], s = [0,1], v = [0,1]
	;//		if s == 0, then h = -1 (undefined)
	min := MIN( r, g, b )
	max := MAX( r, g, b )
	v := max 				; v
	delta := max - min
	if ( max != 0 )
		s := delta / max  	; s
	else {
		;// r = g = b = 0		// s = 0, v is undefined
		s := 0
		h := -1
		return
	}
	if ( r = max )
		h := ( g - b ) / delta ;		// between yellow & magenta
	else if ( g == max )
		h := 2 + ( b - r ) / delta ;	// between cyan & yellow
	else
		h := 4 + ( r - g ) / delta ;	// between magenta & cyan
	h *= 60 ;				// degrees
	if ( h < 0 )
		h += 360 ;
	return
} ;</11.01.000013>
;<11.01.000014>
Color_HSVtoRGB( h, s, v, ByRef r, ByRef g, ByRef b ) {						;-- converts beetween color two color spaces: HSV -> RGB

	if ( s = 0 ) {
		;// achromatic (grey)
		r := v, g := v, b := v ;
		return
	}
	h /= 60 ;			// sector 0 to 5
	i := floor( h ) ;
	f := h - i ;			// factorial part of h
	p := v * ( 1 - s ) ;
	q := v * ( 1 - s * f ) ;
	t = v * ( 1 - s * ( 1 - f ) ) ;
	if (i = 0) {
		r := v
		g := t
		b := p
		Return
	}
	if (i = 1) {
		r := q
		g := v
		b := p
		Return
	}
	if (i = 2) {
		r := p
		g := v
		b := t
		Return
	}
	if (i = 3) {
		r := p
		g := q
		b := v
		Return
	}
	if (i = 4) {
		r := t
		g := p
		b := v
		Return
	}
	;default
	r := v
	g := p
	b := q
	Return

} ;</11.01.000014>
;{ subfunction for Color_RGBtoHSV and Color_HSVtoRGB
MIN(in1="", in2="", in3="", in4="", in5="", in6="", in7="", in8="", in9="", in10="") {
	Loop, 10
		If in%A_Index% is number
		  list .= in%A_Index% . "`n"

	Sort, list, N
	StringSplit, item, list, `n, `r
  Return item1
}
MAX(in1="", in2="", in3="", in4="", in5="", in6="", in7="", in8="", in9="", in10="") {
	Loop, 10
		If in%A_Index% is number
		  list .= in%A_Index% . "`n"

	Sort, list, N R
	StringSplit, item, list, `n, `r
  Return item1
}
;}
;<11.01.000015>
JEE_HexToBinData(vHex, ByRef vSize:="") {										;-- hexadecimal to binary
	vChars := StrLen(vHex)
	;CRYPT_STRING_HEX := 0x4
	;CRYPT_STRING_HEXRAW := 0xC ;(not supported by Windows XP)
	DllCall("crypt32\CryptStringToBinary", Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,0, UIntP,vSize, Ptr,0, Ptr,0)
	VarSetCapacity(vData, vSize, 0)
	DllCall("crypt32\CryptStringToBinary", Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,&vData, UIntP,vSize, Ptr,0, Ptr,0)
	return &vData
} ;</11.01.000015>
;<11.01.000016>
JEE_BinDataToHex(vAddr, vSize) {													;-- binary to hexadecimal
	;CRYPT_STRING_HEX := 0x4 ;to return space/CRLF-separated text
	;CRYPT_STRING_HEXRAW := 0xC ;to return raw hex (not supported by Windows XP)
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Ptr,0, UIntP,vChars)
	VarSetCapacity(vHex, vChars*2, 0)
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Str,vHex, UIntP,vChars)
	vHex := StrReplace(vHex, "`r`n")
	vHex := StrReplace(vHex, " ")
	return vHex
} ;</11.01.000016>
;<11.01.000017>
JEE_BinDataToHex2(vAddr, vSize) {													;-- binary to hexadecimal2
	;CRYPT_STRING_HEXRAW := 0xC ;to return raw hex (not supported by Windows XP)
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0xC, Ptr,0, UIntP,vChars)
	VarSetCapacity(vHex, vChars*2, 0)
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0xC, Str,vHex, UIntP,vChars)
	return vHex
} ;</11.01.000017>
;<11.01.000018>
RadianToDegree(Radians, Centesimal := false) {								;-- convert radian (rad) to degree
	/*                              	DESCRIPTION

			Syntax: RadianToDegree ([radians], [centesimal?])
			Example: MsgBox % RadianToDegree(120) "`n" RadianToDegree(120, true) ;6875.493542 | 7639.437268

	*/

	if (Centesimal)
		return Radians*63.6619772368 ;200/pi | 200/3.14159265359 = 63.6619772368
	return Radians*57.2957795131 ;180/pi | 180/3.14159265359 = 57.2957795131
} ;</11.01.000018>
;<11.01.000019>
DegreeToRadian(Degrees, Centesimal := false) {							;-- convert degree to radian (rad)
	/*                              	DESCRIPTION

			Syntax: RadianToDegree ([degrees], [centesimal?])
			 EXAMPLE
			MsgBox % DegreeToRadian(6875.493542) "`n" DegreeToRadian(7639.437268, true) ;120 | 120

	*/

	if (Centesimal)
		return Degrees*0.01570796326 ;pi/200 | 3.14159265359/200 = 0.01570796326
	return Degrees*0.01745329251 ;pi/180 | 3.14159265359/180 = 0.01745329251
} ;</11.01.000019>
;<11.01.000020>
RGBToARGB(RGB, Transparent := -1) { 											;-- convert RGB to ARGB
	/*                              	DESCRIPTION

			ARGB (A = alpha channel, transparency). FF = solid color. 00 = Transparent
			convert RGB to ARGB.
			Syntax: RGBToARGB ([RGB], [0 ~ 255])
			Return: ARGB with the prefix 0x

			Notes:
			If an RGB color is specified, the default transparency is 0xFF (255).
			If you specify an ARGB color, the transparency by default is the same (does not modify it).
			the prefix 0x does not matter, you can specify an integer, in color and in transparency.
			The value of the transparency ranges from 0 (0x00) to 255 (0xFF), where 0 in total transparency and 255 a solid color.

			Example:
			 MsgBox% RGBToARGB ("0x8000FF") "," RGBToARGB ("8000FF")
			 . "`n "RGBToARGB (" 0xFF8000FF ")", "RGBToARGB (" FF8000FF ")
			 . "`n`n "RGBToARGB (" 0x8000FF ", 0)", "RGBToARGB (" 8000FF ", 0)
			 . "`n "RGBToARGB (" 0xFF8000FF ", 0)", "RGBToARGB (" FF8000FF ", 0)

	*/

	RGB := SubStr(RGB:=Hex(RGB, 6), 1, 2)="0x"?SubStr(RGB, 3):RGB, Transparent := Transparent=0?"00":Transparent
	return "0x" CharUpper(StrLen(RGB)=8?(Transparent=-1?RGB:Hex(Transparent, 2,, "") SubStr(RGB, 3))
	: ((Transparent=-1?"FF":Hex(Transparent, 2,, "")) Hex("0x" RGB, 6,, "")))
} ;</11.01.000020>
;<11.01.000021>
ARGBToRGB(ARGB) {																		;-- convert ARGB to RGB.
	/*                              	DESCRIPTION


			; Syntax: ARGBToRGB ([ARGB])
			; Return: RGB with the prefix 0x
			;Notes:
			If a RGB color is specified, it does not change it.
			If you specify an ARGB color, the transparency is removed.
			the prefix 0x does not matter, you can specify a whole number.
			;Example:
			; MsgBox% ARGBToRGB ("0x8000FF") "," ARGBToRGB ("8000FF")
			; . "`n "ARGBToRGB (" 0xFF8000FF ")", "ARGBToRGB (" FF8000FF ")

	*/

	return Hex(SubStr(SubStr(ARGB:=Hex(ARGB, 8), 1, 2)="0x"?SubStr(ARGB, 3):ARGB, -5), 6, true)
} ;</11.01.000021>
;<11.01.000022>
FormatByteSize(Bytes) {                                                                  	;-- give's back the given bytes in KB, MB, GB .... (for AHK_V1)

	/*    	DESCRIPTION of function FormatByteSize()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	give's back the given bytes in KB, MB, GB ....
			Link              	:	https://www.autohotkey.com/boards/viewtopic.php?p=18338#p18338
			Author         	:	HotKeyIt
			Date             	:	17.05.2014
			AHK-Version	:	AHK_V1
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	faster, keeps dot '.' as comma separator instead using locale (e.g. ',' in german)
			Dependencies	:	none
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

  static size:="bytes,KB,MB,GB,TB,PB,EB,ZB,YB"
  Loop,Parse,size,`,
    If (bytes>999)
      bytes:=bytes/1024
    else {
      bytes:=Trim(SubStr(bytes,1,4),".") " " A_LoopField
      break
    }
  return bytes
} ;</11.01.000022>
;<11.01.000023>
FormatByteSize(Bytes) {                                                              		;-- give's back the given bytes in KB, MB, GB ....(for AHK_V2)

	/*    	DESCRIPTION of function FormatByteSize()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:		/*    	DESCRIPTION of function FormatByteSize()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	give's back the given bytes in KB, MB, GB ....
			Link              	:	https://www.autohotkey.com/boards/viewtopic.php?p=18338#p18338
			Author         	:	HotKeyIt
			Date             	:	17.05.2014
			AHK-Version	:	AHK_V1
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:	faster, keeps dot '.' as comma separator instead using locale (e.g. ',' in german)
			Dependencies	:	none
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/

  static size:="bytes,KB,MB,GB,TB,PB,EB,ZB,YB"
  LoopParse,%size%,`,
    If bytes>999,bytes/=1024
    else if bytes:=RTrim(SubStr(bytes,1,4),".") " " A_LoopField,break
  return bytes
} ;</11.01.000023>
;<11.01.000024>
RGBEuclidianDistance( c1, c2 ) {                                                  	;-- find the distance between 2 colors

	/*	DESCRIPTION OF FUNCTION: -- RGBEuclidianDistance() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:
	Link              	:
	Author         	:	VxE
	Date             	:
	AHK-Version	:
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:	value range = [0, 441.67295593006372]
                            	that just means that any two colors will have a distance less than 442
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

   r1 := c1 >> 16
   g1 := c1 >> 8 & 255
   b1 := c1 & 255
   r2 := c2 >> 16
   g2 := c2 >> 8 & 255
   b2 := c2 & 255

return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
} ;</11.01.000024>


} ;end
;|   Min(01)                                   	|   Max(02)                                   	|   Mean(03)                                 	|   Median(04)                              	|
;|   Mode(05)                                 	|   Dec2Base(06)                           	|   Base2Dec(07)                           	|   HexToFloat(08)                        	|
;|   FloatToHex(09)                        	|   CalculateDistance(10)	            	|   IsInRange(11)                           	|   FormatFileSize(12)                   	|
;|   Color_RGBtoHSV(13)               	|   Color_HSVtoRGB(14)                	|   JEE_HexToBinData(15)             	|   JEE_BinDataToHex(16)             	|
;|   JEE_BinDataToHex2(17)          	|   RadianToDegree(18)                	|   DegreeToRadian(19)                	|   RGBToARGB(20)                      	|
;|   ARGBToRGB(21)                      	|   FormatByteSize_AHK1(22)       	|   FormatByteSize_AHK2(23)       	|   RGBEuclidianDistance(24)        	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Objects (8) -- handle objects --                                                                                                                 	baseID: <12>
;<12.01.000001>
ObjMerge(OrigObj, MergingObj, MergeBase=True) {                    	;-- merge two objects

    If !IsObject(OrigObj) || !IsObject(MergingObj)
        Return False
    For k, v in MergingObj
        ObjInsert(OrigObj, k, v)
    if MergeBase && IsObject(MergingObj.base) {
        If !IsObject(OrigObj.base)
            OrigObj.base := []
        For k, v in MergingObj.base
            ObjInsert(OrigObj.base, k, v)
    }
    Return True
} ;</12.01.000001>
;<12.01.000002>
evalRPN(s) {                                                                                     	;-- Parsing/RPN calculator algorithm

	/*											Example

			evalRPN("3 4 2 * 1 5 - 2 3 ^ ^ / +")

	*/

	stack := []
	out := "For RPN expression: '" s "'`r`n`r`nTOKEN`t`tACTION`t`t`tSTACK`r`n"
	Loop Parse, s
		If A_LoopField is number
			t .= A_LoopField
		else
		{
			If t
				stack.Insert(t)
				, out .= t "`tPush num onto top of stack`t" stackShow(stack) "`r`n"
				, t := ""
			If InStr("+-/*^", l := A_LoopField)
			{
				a := stack.Remove(), b := stack.Remove()
				stack.Insert(	 l = "+" ? b + a
						:l = "-" ? b - a
						:l = "*" ? b * a
						:l = "/" ? b / a
						:l = "^" ? b **a
						:0	)
				out .= l "`tApply op " l " to top of stack`t" stackShow(stack) "`r`n"
			}
		}
	r := stack.Remove()
	out .= "`r`n The final output value is: '" r "'"
	clipboard := out
	return r
} ;</12.01.000002>
;{ sub of evalRPN()
;<12.01.000003>
StackShow(stack){																			;--
	for each, value in stack
		out .= A_Space value
	return subStr(out, 2)
} ;</12.01.000003>
;}
;<12.01.000004>
ExploreObj(Obj, Depth=12, NewRow="`n"                                     	;-- print object function
, Equal="  =  ", Indent="`t", CurIndent="") {

	/*    	DESCRIPTION of function ExploreObj() ID: 12.01.00003
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Returns a string containing the formatted object keys and values (very nice for debugging!)
			Link              	:	https://autohotkey.com/board/topic/64366-function-explore-object/
										www.autohotkey.com/forum/topic69253.html
			Author         	:	Learning one / Lexikos
			Date	            	:
			AHK-Version	:	AHK-V1
			License         	:
			Parameter(s)	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	object, debug, output, print
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			;====== Testing area ======
			oKey3 := Object("Key`n`n3.1", "value `n`n3.1", "Key3.2", "value 3.2")
			oKey4 := Object("Key4.1", "value 4.1",  "Key4.2", Object("Key4.2.1", "value 4.2.1", "Key4.2.2", "value 4.2.2"), "Key4.3", "value 4.3")
			oKey5 := Object("Key5.1", "value 5.1", "Key5.2", "value 5.2", "Key5.3", "value 5.3")

			oRoot := Object()
			oRoot["Key`n`n1"] := "value 1 `n`nThe string to search for. Matching is not case sensitive unless StringCaseSense has been turned on."
			oRoot.Key2 := "value 2"
			oRoot.Key3 := oKey3
			oRoot.Key4 := oKey4
			oRoot.Key5 := oKey5

			MsgBox,, Exploring Root object, % ExploreObj(oRoot)
			MsgBox,, Exploring Root object - 1 level deep, % ExploreObj(oRoot,1)
			MsgBox,, Exploring Key4 object, % ExploreObj(oKey4)
			MsgBox,, Exploring oRoot.Key4["Key4.2"] object, % ExploreObj(oRoot.Key4["Key4.2"])

	*/

	static ShowChar := 60	; number of characters to show
	For k,v in Obj {
		StringReplace, k, k, `n,,all
		StringReplace, k, k, `r,,all
		k := (StrLen(k) > ShowChar) ? SubStr(k,1,ShowChar) " ..." : k
		if (IsObject(v))
		ToReturn .= CurIndent . k . NewRow . (depth>1 ? %A_ThisFunc%(v, Depth-1, NewRow, Equal, Indent, CurIndent . Indent) . NewRow : "")
		else {
			StringReplace, v, v, `n,,all
			StringReplace, v, v, `r,,all
			v := (StrLen(v) > ShowChar) ? SubStr(v,1,ShowChar) " ..." : v, ToReturn .= CurIndent . k . Equal . v . NewRow
		}
    }
	return RTrim(ToReturn, NewRow)
} ;</12.01.000004>
;<12.01.000005>
KeyValueObjectFromLists(keyList, valueList, delimiter:="`n"          	;-- merge two lists into one key-value object, useful for 2 two lists you retreave from WinGet
, IncludeKeys:="", KeyREx:="", IncludeValues:="", ValueREx:="") {

	/*    	DESCRIPTION of function KeyValueObjectFromLists() ID: 12.01.00004
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	merge two lists into one key-value object.
	                                 	The elements of the first list make up the key and the elements of the second list are the associated content.
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=59542
			Author         	:	Ixiko
			Date             	:	01.12.2018
			AHK-Version	:	AHK_L
			License         	:
			Parameter(s)	:	keyList     	-  	list of which you want to get the keys
	                                	valueList    	-  	list of which you want to get the values
	                                	delimiter    	-  	character that separates the elements of the list
										IncludeKeys	-	a comma delimited list of keys you want to include,
	                                                        	leave it blank to include all keys to the new object
	                                 	KeyREx        	-  	a RegExMatch string is sometimes needed if you want compare keyList and Includekeys
	                                 	IncludeValues and ValueREx - read above
			Return value	:
			Remark(s)    	:	if you assign a value to IncludesKeys and IncludesValues, the function returns only the key-value pairs
	                                	where both parameters fit
			Dependencies	:	List2Array() ID: 13.01.05.00010
			KeyWords    	:	array, object, list. merge list,
        	-------------------------------------------------------------------------------------------------------------------
	*/

	keyArr:= valueArr:= []
	merged:= Object()
	mustMatches:=0

	If !(IncludeKeys="")
			mustMatches+=1
	If !(IncludeValues="")
			mustMatches+=1

	keyArr:= List2Array(keyList, delimiter)
	valueArr:= List2Array(valueList, delimiter)

	Loop % keyArr.Count()
	{
				If (KeyREx="")
					mkey:= keyArr[A_Index]
				else
					RegExMatch(keyArr[A_Index], KeyREx, mkey)

				If (ValueREx="")
					mval:= valueArr[A_Index]
				else
					RegExMatch(valueArr[A_Index], ValueREx, mval)

				If mkey in %IncludeKeys%
					matched:= 1
				else
					matched:= 0

				If mval in %IncludeValues%
					matched += 1

				If (matched=mustMatches) {
						merged[(keyArr[A_Index])]:= valueArr[A_Index]
				}
	}

return merged
} ;</12.01.000005>
;<12.01.000006>
GetCallStack(Report := 0) {                                                                 	;-- retrieves the current callstack

		/*    	DESCRIPTION of function
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	retrieves the current callstack, Similar functions have been posted on the old forum several times. The function seems to be rather useful for "quick debugging"
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=1379
			Author         	:	just me
			Date             	:	11 Jan 2014, 06:25

			AHK-Version	:
			License         	:
			Syntax          	:
			Parameter(s)	:	The properties of the first object contain the currently executed line and file
			Return value	:	Returns an array of objects with the following keys:
	                                	Called	-  the name of the called function/label
	                                	Caller   -  the name of the function/label which called the function/label
	                                	Line    	-  the number of the line Called was called from
	                                	File    	-  the name of the file containing the line
			Remark(s)    	:	The parameter Report may be set to one of the following values:
	                                	0      	-  return the stack array silently
	                                	1      	-  additionally show the values by MsgBox
	                                	2      	-  additionally send the values to the debugger by OutputDebug
	                                	3      	-  use both of the report options
			Dependencies	:	none
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)

			#NoEnv
			Gui, Margin, 100, 50
			Gui, Add, Button, gShowCallstack, Show Callstack
			Gui, Show, , Test
			Return
			GuiClose:
			ExitApp
			ShowCallstack:
			   Gosub, Start
			Return
			Start:
			   Func1()
			Return
			Func1() {
			   Func2()
			}
			Func2() {
			   Func3()
			}
			Func3() {
			   GetCallStack(1)
			}

	*/

   Local Stack := [], StackIndex := 0, E, M
   While (E := Exception("", --StackIndex)).What <> StackIndex {
      Stack[A_Index] := {Called: E.What, Caller: "Auto-Exec/Event", Line: E.Line, File: E.File}
      If (A_Index > 1)
         Stack[A_Index - 1].Caller := E.What
   }
   If (Report & 1) { ; MsgBox
      M := ""
      For Each, E In Stack
         M .= E.Called . "  <<  called by " . E.Caller . " at line " . E.Line . " of " . E.File . "`r`n"
      MsgBox, 0, Callstack, % M
   }
   If (Report & 2) ; OutputDebug
      For Each, E In Stack
         OutputDebug, %  "`r`n" . E.Called . " called by " . E.Caller . " at line " . E.Line . " of " . E.File
   Return Stack
} ;</12.01.000006>
;<12.01.000007>
Traceback(actual:=false) {                                                                  	;-- get stack trace

		/*    	DESCRIPTION of function
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	simple function which can be used to inspect/retrieve a stack trace. It must be called from within a function.
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=6001
			Author         	:	Coco
			Date             	:	18 Jan 2015
			AHK-Version	:	AHK_L
			License         	:
			Syntax          	:	tb := Traceback( [ actual := false ] )
										If actual is true, the actual stack trace is returned which includes Traceback() itself
			Parameter(s)	:
			Return value	:	This function returns an array of objects representing a stack trace entry. Each object has the following fields:
                                    	offset 	- negative offset from the top of the call stack.
                                    	file   	- the script file (I'm not sure if this is equivalent to A_LineFile or if it's the file that contains the function, I suspect the former)
                                    	line     	- the line number at which the function is called
                                    	caller 	- function name
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	stack, trace
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			#Include Traceback.ahk

			f()
			return

			a() {
				b()
			}

			b() {
				c()
			}

			c() {
				out := "Stack trace:"
				for i, info in Traceback()
				{
					out .= Format("
					(LTrim Join`r`n
					`r`n
					Offset: {}
					File:   {}
					Line:   {}
					Caller: {}
					)", info.offset, info.file, info.line, info.caller)
				}
				ListVars
				WinWait ahk_id %A_ScriptHwnd%
				ControlSetText Edit1, %out%
				WinWaitClose
			}

			f() {
				a()
			}


	*/


	r := [], i := 0, n := actual ? 0 : A_AhkVersion<"2" ? 1 : 2
	Loop
	{
		e := Exception(".", offset := -(A_Index + n))
		if (e.What == offset)
			break
		r[++i] := { "file": e.file, "line": e.Line, "caller": e.What, "offset": offset + n }
	}
	return r
} ;</12.01.000007>
;<12.01.000008>
ObjGetNumOfKeys(ByRef Obj, KeyType := "") {                                	;-- gets the current number of key-value pairs stored in the passed AHK 'basic object'

	/*	DESCRIPTION OF FUNCTION: -- ObjGetNumOfKeys --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Gets the current number of key-value pairs stored in the passed AHK 'basic object'
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=36284
	Author         	:	just me
	Date             	:	25.08.2017
	AHK-Version	:	AHK_L
	License         	:	---
	Syntax          	:	---
	Parameter(s)	:	Obj                  	-  An AHK basic object.
			                	KeyType           	-  One of the following values:
				            	Empty/omitted  	-  return the total number of keys.
				            	I                          	-  return the number of integer keys.
				            	O                       	-  return the number of object keys.
				            	S                      	-  return the number of string keys.
	Return value	:	On success the function returns the number of the specified keys.
	                        	Otherwise (e.g. if the passed value isn't an AHK basic object) the function returns an empty string.
	Remark(s)    	:	Based on the current (2017-08-26) AHK object layout defined in script_object.h (all fields are pointer-sized):
		                    	vTbl pointer
		                    	RefCount
		                    	mFields                	-  Array of pointers to the object's keys.
		                    	mFieldCount        	-  Current number of key-value pairs.
		                    	mFieldCountMax  	-  Current capacity of the object as returned by Obj.GetCapacity().
		                    	mKeyOffsetObject  	-  Index of the first possible object key in mFields.
		                    					                	This is equal to the current number of integer keys.
		                    	mKeyOffsetString  	-  Index of the first possible string key in mFields.
		                    					                	The current number of object keys is: mKeyOffsetString - mKeyOffsetObject.
		                    					                	The current number of string keys is: mFieldCount - mKeyOffsetString.
	Dependencies	:	none
	KeyWords    	:	object,keys
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	#NoEnv
	; --------------------------------------------------------------------------------------------------------------------------------
	Obj1 := {1: 1, 8: 8, 16: 16}
	Obj2 := {Str1: "String1", Str2: String2, Str3: String3}
	Obj3 := {1: 1, 8: 8, 16: 16, Str1: "String1", Str2: String2, Str3: String3}
	Obj4 := New Dummy
	; --------------------------------------------------------------------------------------------------------------------------------
	GetNumOfKeys(Obj1)
	GetNumOfKeys(Obj2)
	GetNumOfKeys(Obj3)
	GetNumOfKeys(Obj4)
	; --------------------------------------------------------------------------------------------------------------------------------
	ExitApp
	*/

   Static TestObj := {1: "", {}: "", S: ""}
   Static TestCnt := ObjGetNumOfKeys(TestObj, "I") + ObjGetNumOfKeys(TestObj, "O") + ObjGetNumOfKeys(TestObj, "S")
   Static CheckFn := ObjGetNumOfKeys(TestObj, "*")
   If (KeyType = "*") {
      If (TestCnt <> 3)
         Throw Exception(A_ThisFunc . "()`nThe object layout has been changed!`nThis function won't work properly!")
      Return ""
   }
   If IsObject(Obj) && (NumGet(&Obj, "UPtr") = NumGet(&TestObj, "UPtr")) ; it's an AHK basic object
      Return (KeyType = "")  ? NumGet(&Obj + (A_PtrSize * 4), "UPtr")
           : (KeyType = "I") ? NumGet(&Obj + (A_PtrSize * 6), "UPtr")
           : (KeyType = "O") ? NumGet(&Obj + (A_PtrSize * 7), "UPtr") - NumGet(&Obj + (A_PtrSize * 6), "UPtr")
           : (KeyType = "S") ? NumGet(&Obj + (A_PtrSize * 4), "UPtr") - NumGet(&Obj + (A_PtrSize * 7), "UPtr")
           : ""
} ;</12.01.000008>

}
;|   ObjMerge(01)                          	|   evalRPN(02)                         	|   StackShow(03)                             	|   ExploreObj(04)                         	|
;|   KeyValueObjectFromLists(05)  	|   GetCallStack(06)                  	|   Traceback(07)                              	|   ObjGetNumOfKeys(08)            	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;String/Array/Text (56) -                                                                                                                             	baseID: <13>
;<Name>String/Array/Text</Name><Description></Description>

; -----------------------------------------------------------------  #Sort functions#  -------------------------------------------------------------------
{ ;<13.01> (4)
;<Name>array sort functions</Name><Description>functions to sort arrays</Description>
;<13.01.000001>
Sort2DArray(Byref TDArray, KeyName, Order=1) {                     	;-- a two dimensional TDArray

   ;TDArray : a two dimensional TDArray
   ;KeyName : the key name to be sorted
   ;Order: 1:Ascending 0:Descending

    For index2, obj2 in TDArray {
        For index, obj in TDArray {
            if (lastIndex = index)
                break
            if !(A_Index = 1) &&  ((Order=1) ? (TDArray[prevIndex][KeyName] > TDArray[index][KeyName]) : (TDArray[prevIndex][KeyName] < TDArray[index][KeyName])) {
               tmp := TDArray[index][KeyName]
               TDArray[index][KeyName] := TDArray[prevIndex][KeyName]
               TDArray[prevIndex][KeyName] := tmp
            }
            prevIndex := index
        }
        lastIndex := prevIndex
    }
} ;</13.01.000001>
;<13.01.000002>
SortArray(Array, Order="A") {															;-- ordered sort: Ascending, Descending, Reverse

    ;Order A: Ascending, D: Descending, R: Reverse
    MaxIndex := ObjMaxIndex(Array)
    If (Order = "R") {
        count := 0
        Loop, % MaxIndex
            ObjInsert(Array, ObjRemove(Array, MaxIndex - count++))
        Return
    }
    Partitions := "|" ObjMinIndex(Array) "," MaxIndex
    Loop {
        comma := InStr(this_partition := SubStr(Partitions, InStr(Partitions, "|", False, 0)+1), ",")
        spos := pivot := SubStr(this_partition, 1, comma-1) , epos := SubStr(this_partition, comma+1)
        if (Order = "A") {
            Loop, % epos - spos {
                if (Array[pivot] > Array[A_Index+spos])
                    ObjInsert(Array, pivot++, ObjRemove(Array, A_Index+spos))
            }
        } else {
            Loop, % epos - spos {
                if (Array[pivot] < Array[A_Index+spos])
                    ObjInsert(Array, pivot++, ObjRemove(Array, A_Index+spos))
            }
        }
        Partitions := SubStr(Partitions, 1, InStr(Partitions, "|", False, 0)-1)
        if (pivot - spos) > 1    ;if more than one elements
            Partitions .= "|" spos "," pivot-1        ;the left partition
        if (epos - pivot) > 1    ;if more than one elements
            Partitions .= "|" pivot+1 "," epos        ;the right partition
    } Until !Partitions
} ;</13.01.000002>
;<13.01.000003>
QuickSort(Arr, Ascend = True, M*) {												;-- Sort array using QuickSort algorithm

	;******************************************************************************
	;                          QuickSort
	; 		Sort array using QuickSort algorithm
	;		https://autohotkey.com/boards/viewtopic.php?t=17312
	;
	;    	ARR - Array to be sorted or Matrix to be sorted (By Column)
	;     	ASCEND is TRUE if sort is in ascending order
	;     	*M => VET1,VET2, - Optional arrays of same size to be sorted accordingly
	;        or NCOL - Column number in ARR to be sorted if ARR is a matrix
	;
	; Limitation: Don't check if arrays are sparse arrays.
	;             Assume dense arrays or matrices with integer indices starting from 1.
	;******************************************************************************

	/*		EXAMPLES

	;******************************************************************************************
	;                       PrintMat
	; Sample for print examples
	;*******************************************************************************************
	PrintMat(VetG, bG = 0, cG = 0) 	{
	Local StOut := "", k, v
	If IsObject(VetG[1])
		for k, v in VetG {
			for j, w in v
				StOut := StOut . w  . " - "
			StOut := StOut . "@r@n"
		}
	Else  {
	  for k, v in VetG
		StOut := StOut . v  . ","
	  StOut := StOut . "@r@n"
	  If (bG<> 0) {
		for k, v in bG
		 StOut := StOut . v  . ","
		StOut := StOut . "@r@n"
	  }
	  If (cG<>0) {
		for k, v in cG
		  StOut := StOut . v  . ","
	   }
	}
	MsgBox 0, Example, % StOut
	}

	;**** FIRST EXAMPLE ****

	#EscapeChar @   ;  Changes escape character from ' (default) to  @
	aG := [2, 3, 1, 5, 4]
	bG := ["Butterfly", "Cat","Animal", "Zebra", "Elephant"]
	cG := ["B","C", "A","Z","E"]
	VetG := QuickSort(aG,False,bG,cG)
	PrintMat(VetG,bG,cG)

	;**** SECOND EXAMPLE ****

	#EscapeChar @   ;  Changes escape character from ' (default) to  @
	MatG := [ [2, "Animal", "Z" ],  [3, "Elephant", "E" ],  [1, "Cat", "C" ] ,  [5, "Butterfly", "B" ],  [4, "Zebra", "A" ] ]
	MatG := QuickSort(MatG,True,2)
	PrintMat(MatG)

	*/

	Local I, V, Out, L,  Rasc, N, LI, Multi, ComprM, NCol, Ind

	if (Arr.Length() <= 1) ; Array with size <= 1 is already sorted
		return Arr

	If (Not Isobject(Arr))
		return "First parameter needs to be a array"

	LenM := M.Length()    ; Number of parameters after ASCEND
	NCol := 0               ; Assumes initially no matrix
	HasOtherArrays := ( LenM > 0 )   ; TRUE if has other arrays or column number

	Multi := False
	IF HasOtherArrays {
	   Multi := Not IsObject(M[1])  ; True if ARR is bidimensional
	   If (Multi) {
		 NCol := M[1]                 ; Column number of bidimensional array
		 HasOtherArrays :=  False

		 If NCol is Not Integer
			return "Third parameter needs to be a valid column number"
		 If (Not IsObject(Arr(1)))
			return "First parameter needs to be a multidimensional array"
		 If ( (NCol<=0) or (NCol > Arr[1].Length()) )
			return "Third parameter needs to be a valid column number"
	   }
	}

	If (Not Multi)  {
	   If (IsObject(Arr[1]))
		 return "If first parameter is a bidimensional array, it demands a column number"
	}


	LI := 0
	N := 0
	IF (HasOtherArrays)  {
	   Loop % LenM {    ; Scan aditional array parameters
		 Ind := A_INDEX
		 V := M[Ind]
		 If (IsObject(V[1]))
			return  (Ind+2) . "o. parameter needs to be a single array"
	   }

	   LI := 1   ; Assumes 1 as the array/matrix start
	   N := Arr.Clone()   ; N : Array with same size than Array to be sorted
	   L := Arr.Length()  ; L : Array Size

	   Loop % L
		   N[A_INDEX] := A_INDEX  ; Starts with index number of each element from array
	}


	 ; Sort ARR with ASCEND, N is array with elements positions and
	 ;  LI is 1 if has additional arrays to be sorted
	 ;  NCOL is column number to be sorted if ARR is a bidimensional array
	Out :=  QuickAux(Arr, Ascend, N, LI, NCol)

	; Scan additional arrays storing the original position in sorted array
	If (HasOtherArrays)  {
		Loop % ComprM {
		   V := M[A_Index]  ; Current aditional array
		   Rasc := V.Clone()
		   Loop % L     ; Put its elements in the sorted order based on position of sorted elements in the original array
			   V[A_INDEX] := Rasc[N[A_Index]]
		}
	}

	Return Out
} ;</000004>
QuickAux(Arr,Ascend, N, LI, NCol) {                                            	;-- subfunction of Quicksort
;=================================================================
;                       QuickAux
; Auxiliary recursive function to make a Quicksort in a array ou matrix
;    ARR - Array or Matrix to be sorted
;    ASCEND - TRUE if sort is ascending
;    N   - Array with original elements position
;    LI  - Position of array ARR in the array from parent recursion
;    NCOL - Column number in Matrix to be sorted. O in array case.
;===================================================================

Local Bef, Aft, Mid
Local Before, Middle, After
Local Pivot, kInd, vElem, LAr, Met
Local LB := 0, LM := 0, LM := 0

LAr := Arr.Length()

if (LAr <= 1)
	return Arr

IF (LI>0) {    ; Has Another Arrays
   Bef := [],  Aft := [], Mid := []
}

Before := [], Middle := [], After := []


Met := LAr // 2    ; Regarding speed, halfway is the Best pivot element for almost sorted array and matrices

If (NCol > 0)
   Pivot := Arr[Met,NCol]
else
   Pivot := Arr[Met]  ; PIVOT is Random  element in array

; Classify array elems in 3 groups: Greater than PIVOT, Lower Than PIVOT and equal
for kInd, vElem in Arr     {
	if (NCol > 0)
		Ch := vElem[NCol]
	else
		Ch := vElem

	if ( Ascend ? Ch < Pivot : Ch > Pivot )  {
			Before.Push(vElem)    ; Append vElem at BEFORE
			IF (LI>0)             ; if has another arrays
		       Bef.Push(N[kInd+LI-1])     ; Append index to original element at BEF
		} else if ( Ascend ? Ch > Pivot : Ch < Pivot ) {
		    After.Push(vElem)
  		    IF (LI>0)
               Aft.Push(N[kInd+LI-1])
		} else  {
			Middle.Push(vElem)
  			IF (LI>0)
   		       Mid.Push(N[kInd+LI-1])
  	    }
}

;  Put pieces of array with index to elements together in N
IF (LI>0) {
	LB := Bef.Length()
	LM := Mid.Length()
	LA := Aft.Length()

	Loop % LB
	  N[LI + A_INDEX - 1] := Bef[A_INDEX]

	Loop % LM
	  N[LI + LB +  A_INDEX - 1] := Mid[A_INDEX]

	Loop % LA
	  N[LI + LB + LM + A_INDEX - 1] := Aft[A_INDEX]
}

; Concat BEFORE, MIDDLE and AFTER Arrays
; BEFORE and AFTER arrays need to be sorted before
; N stores the array position to be sorted in the original array
return Cat(QuickAux(Before,Ascend,N,LI,NCol), Middle, QuickAux(After,Ascend,N,LI+LB+LM,NCol)) ; So Concat the sorted BEFORE, MIDDLE and sorted AFTER arrays
}
Cat(Vet*) {                                                                                    	;-- subfunction of Quicksort

	;*************************************************************
	;                       Cat
	; Concat 2 or more arrays or matrices by rows
	;**************************************************************

	Local VRes := [] , L, i, V
	For I , V in Vet {
		L := VRes.Length()+1
		If ( V.Length() > 0 )
			VRes.InsertAt(L,V*)
	}
	Return VRes
}
CatCol(Vet*) {                                                                              	;-- subfunction of Quicksort

	;***************************************************************************
	;                       CatCol
	; Concat 2 or more matrices by columns
	; Is a aditional function no used directly in QuickSort, but akin with Cat
	;*************************************************************************

	Local VRes := [] , L, I, V, VAux, NLins, NL, Aux, NC, NV, NCD

	NVets := Vet.Length()          ; Number of parameters
	NLins := Vet[1].Length()       ; Number of rows from matrix

	VRes := []

	Loop % NLins  {
		NL := A_INDEX      ; Current Row
		ColAcum := 0
		Loop % NVets  {
			NV := A_INDEX  ; Current Matrix
			NCols := Vet[NV,1].Length()
			Loop % NCols  {
				NC := A_INDEX  ; Current Column
				NCD := A_INDEX + ColAcum   ; Current Column in Destination
				Aux := Vet[NV,NL,NC]
				VRes[NL,NCD] := Aux
			}
			ColAcum := ColAcum + NCols
		}
	}
	Return VRes
} ;</13.01.000003>
;<13.01.000004>
sortArray( a, o := "A") {                                                                   	;-- sorts an array (another way)

		/*    	DESCRIPTION of function sortArray()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:
			Link              	:	https://sites.google.com/site/ahkref/custom-functions/sortarray
	                                	https://www.autohotkey.com/boards/viewtopic.php?t=60181
			Author         	:	IMEime
			Date             	:	20.12.2018
			AHK-Version	:	AHK_V1
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:	array
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	array, sort
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			myArray := ["kab9046 = Kevin"
			, "bba9485 = Blake"
			, "kft6512 = Kala"]

			myArray2 := []
			For Each, x In myArray
				myArray2.Push(RegExReplace(x, "(.*?)(\d+)(.*?)", "${2}____${1}____${3}"))
			sortArray(myArray2)

			myArray := []
			For Each, x In myArray2
			{
				myTemp := RegExReplace(x, "(\d+)____(.*?)____(.*?)", "${2}${1}${3}")
				myArray.Push(myTemp)
				myResult .= myTemp "`n"
			}
			MsgBox % myResult

	*/

    MaxIndex := ObjMaxIndex(a)
    If (o = "R")
	{
        count := 0
        Loop, % MaxIndex
            ObjInsert( a, ObjRemove( a, MaxIndex - count++))
        Return
    }
    Partitions := "|" ObjMinIndex( a) "," MaxIndex
    Loop
	{
        comma := InStr( this_partition := SubStr( Partitions, InStr( Partitions, "|", False, 0)+1), ",")
        spos := pivot := SubStr( this_partition, 1, comma-1)
		epos := SubStr( this_partition, comma+1)
        if (o = "A")
		{
            Loop, % epos - spos
                if (a[pivot] > a[A_Index+spos])
                    ObjInsert(a, pivot++, ObjRemove( a, A_Index+spos))
        }
		else
            Loop, % epos - spos
                if (a[pivot] < a[A_Index+spos])
                    ObjInsert(a, pivot++, ObjRemove( a, A_Index+spos))
        Partitions := SubStr( Partitions, 1, InStr( Partitions, "|", False, 0)-1)
        if (pivot - spos) > 1    						;if more than one elements
            Partitions .= "|" spos "," pivot-1      	;the left partition
        if (epos - pivot) > 1    						;if more than one elements
            Partitions .= "|" pivot+1 "," epos      	;the right partition
    } Until !Partitions
} ;</13.01.000004>



} ;</13.01.000004> funcID>

; ---------------------------------------------------------------  #encoding/decoding#  ---------------------------------------------------------------
{ ;<13.02> (9)
;<13.02.000001>
StringMD5( ByRef V, L = 0 ) {               											;-- String MD5 Hashing

    VarSetCapacity( MD5_CTX, 104, 0 ), DllCall( "advapi32\MD5Init", Str, MD5_CTX )
    DllCall( "advapi32\MD5Update", Str, MD5_CTX, Str, V, UInt, L ? L : VarSetCapacity( V ) )
    DllCall( "advapi32\MD5Final", Str, MD5_CTX )
    Loop % StrLen( Hex := "123456789ABCDEF0" )
        N := NumGet( MD5_CTX, 87+A_Index, "Char" ), MD5 .= SubStr( Hex, N>>4, 1 ) . SubStr( Hex, N&15, 1 )
return MD5
} ;</13.02.000001>
;<13.02.000002>
uriEncode(str) { 																				;-- a function to escape characters like & for use in URLs.

    f = %A_FormatInteger%
    SetFormat, Integer, Hex
    If RegExMatch(str, "^\w+:/{0,2}", pr)
        StringTrimLeft, str, str, StrLen(pr)
    StringReplace, str, str, `%, `%25, All
    Loop
        If RegExMatch(str, "i)[^\w\.~%/:]", char)
           StringReplace, str, str, %char%, % "%" . SubStr(Asc(char),3), All
        Else Break
    SetFormat, Integer, %f%
    Return, pr . str
} ;</13.02.000002>
;<13.02.000003>
Ansi2Unicode(ByRef sString, ByRef wString, CP = 0) {					;-- easy convertion from Ansi to Unicode, you can set prefered codepage
     nSize := DllCall("MultiByteToWideChar"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &sString
      , "int",  -1
      , "Uint", 0
      , "int",  0)

   VarSetCapacity(wString, nSize * 2)

   DllCall("MultiByteToWideChar"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &sString
      , "int",  -1
      , "Uint", &wString
      , "int",  nSize)
} ;</13.02.000003>
;<13.02.000004>
Unicode2Ansi(ByRef wString, ByRef sString, CP = 0) {					;-- easy convertion from Unicode to Ansi, you can set prefered codepage
     nSize := DllCall("WideCharToMultiByte"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &wString
      , "int",  -1
      , "Uint", 0
      , "int",  0
      , "Uint", 0
      , "Uint", 0)

   VarSetCapacity(sString, nSize)

   DllCall("WideCharToMultiByte"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &wString
      , "int",  -1
      , "str",  sString
      , "int",  nSize
      , "Uint", 0
      , "Uint", 0)
} ;</13.02.000004>
;<13.02.000005>
Ansi2Oem(sString) {																		;-- using Ansi2Unicode and Unicode2Ansi functions
	Ansi2Unicode(sString, wString, 0)
	Unicode2Ansi(wString, zString, 1)
	Return zString
} ;</13.02.000005>
;<13.02.000006>
Oem2Ansi(zString) {                                                                    	;-- using Ansi2Unicode and Unicode2Ansi functions
	Ansi2Unicode(zString, wString, 1)
	Unicode2Ansi(wString, sString, 0)
	Return sString
} ;</13.02.000006>
;<13.02.000007>
Ansi2UTF8(sString) {                                                                    	;-- using Ansi2Unicode and Unicode2Ansi functions
	Ansi2Unicode(sString, wString, 0)
	Unicode2Ansi(wString, zString, 65001)
	Return zString
} ;</13.02.000007>
;<13.02.000008>
UTF82Ansi(zString) {                                                                    	;-- using Ansi2Unicode and Unicode2Ansi functions
	Ansi2Unicode(zString, wString, 65001)
	Unicode2Ansi(wString, sString, 0)
	Return sString
} ;</13.02.000008>
;<13.02.000009>
CRC32(ByRef Buffer, Bytes=0, Start=-1) {	                            		;-- CRC32 function, uses MCode
   Static f
   If f =
      MCode(f,"558bec8b450c85c07e3a8b5508535689450c8b4510578a0a6a08425e8bf80fb6d9c1e"
. "f1833fb03c0f7c780ffffff740535b71dc10402c94e75e2ff4d0c75d75f5e5beb038b4510f7d05dc3")
   If Bytes <= 0
      Bytes := StrLen(Buffer)
   Return DllCall(&f, "uint",&Buffer, "uint",Bytes, "int",Start, "cdecl uint")
} ;</13.02.000009>

}

; ---------------------------------------------------------------------  #parsing#  ----------------------------------------------------------------------
{ ;<13.03> (7)
;<13.03.000001>
ParseJsonStrToArr(json_data) {														;-- Parse Json string to an array

  	/*                              	DESCRIPTION of Function ParseJsonStrToArr (v1.2.1)


				 Link:
				 Syntax: 							ParseJsonStrToArr(json_data)
				 Parameters:
				 Return Value:					return an array
				 Remarks:     					Each item in the array still is string type
				 Related:
				 Example:
														j := "[,,]"
														arr = ParseJsonStrToArr(j)

	*/

   arr := []
   pos :=1
   While pos:=RegExMatch(json_data,"((?:{)[\s\S][^{}]+(?:}))", j, pos+StrLen(j))
   {
	arr.Insert(j1)                      ; insert json string to array  arr=[{"id":"a1","subject":"s1"},{"id":"a2","subject":"s2"},{"id":"a3","subject":"s3"}]
   }
   return arr
} ;</13.03.000001>
;<13.03.000002>
parseJSON(txt) {																				;-- Parse Json string to an object

	out := {}
	Loop																				; Go until we say STOP
	{
		ind := A_index															; INDex number for whole array
		ele := strX(txt,"{",n,1, "}",1,1, n)									; Find next ELEment {"label":"value"}
		if (n > strlen(txt)) {
			break																	; STOP when we reach the end
		}
		sub := StrSplit(ele,",")												; Array of SUBelements for this ELEment
		Loop, % sub.MaxIndex()
		{
			StringSplit, key, % sub[A_Index] , : , `"					; Split each SUB into label (key1) and value (key2)
			out[ind,key1] := key2											; Add to the array
		}
	}
	return out

} ;</13.03.000002>
;<13.03.000003>
GetNestedTag(data,tag,occurrence="1") {										;--

	; AHK Forum Topic : http://www.autohotkey.com/forum/viewtopic.php?t=77653
   ; Documentation   : http://www.autohotkey.net/~hugov/functions/GetNestedTag.html

	 Start:=InStr(data,tag,false,1,occurrence)
	 RegExMatch(tag,"i)<([a-z]*)",basetag) ; get yer basetag1 here
	 Loop
		{
		 Until:=InStr(data, "</" basetag1 ">", false, Start, A_Index) + StrLen(basetag1) + 3
 		 Strng:=SubStr(data, Start, Until - Start)

		 StringReplace, strng, strng, <%basetag1%, <%basetag1%, UseErrorLevel ; start counting to make match
		 OpenCount:=ErrorLevel
		 StringReplace, strng, strng, </%basetag1%, </%basetag1%, UseErrorLevel
		 CloseCount:=ErrorLevel
		 If (OpenCount = CloseCount)
		 	Break

		 If (A_Index > 250) ; for safety so it won't get stuck in an endless loop,
		 	{                 ; it is unlikely to have over 250 nested tags
		 	 strng=
		 	 Break
		 	}
		}
	 If (StrLen(strng) < StrLen(tag)) ; something went wrong/can't find it
	 	strng=
	 Return strng
	} ;</13.03.000003>
;<13.03.000004>
GetHTMLbyID(HTMLSource, ID, Format=0) {									;-- uses COM

	;Format 0:Text 1:HTML 2:DOM
	ComError := ComObjError(false), `(oHTML := ComObjCreate("HtmlFile")).write(HTMLSource)
	if (Format = 2) {
		if (innerHTML := oHTML.getElementById(ID)["innerHTML"]) {
			`(oDOM := ComObjCreate("HtmlFile")).write(innerHTML)
			Return oDOM, ComObjError(ComError)
		} else
			Return "", ComObjError(ComError)
	} else
	Return (result := oHTML.getElementById(ID)[(Format ? "innerHTML" : "innerText")]) ? result : "", ComObjError(ComError)

} ;</13.03.000004>
;<13.03.000005>
GetHTMLbyTag(HTMLSource, Tag, Occurrence=1, Format=0) {	;-- uses COM

	;Format 0:Text 1:HTML 2:DOM
	ComError := ComObjError(false), `(oHTML := ComObjCreate("HtmlFile")).write(HTMLSource)
	if (Format = 2) {
		if (innerHTML := oHTML.getElementsByTagName(Tag)[Occurrence-1]["innerHTML"]) {
			`(oDOM := ComObjCreate("HtmlFile")).write(innerHTML)
			Return oDOM, ComObjError(ComError)
		} else
			Return "", ComObjError(ComError)
	}
	return (result := oHTML.getElementsByTagName(Tag)[Occurrence-1][(Format ? "innerHTML" : "innerText")]) ? result : "", ComObjError(ComError)

} ;</13.03.000005>
;<13.03.000006>
GetXmlElement(xml, pathToElement) {											;-- RegEx function

   Loop, parse, pathToElement, .,
   {
      elementName:=A_LoopField
      regex=<%elementName%>(.*)</%elementName%>

      RegExMatch(xml, regex, xml)
      ;TODO switch to use xml1, instead of parsing stuff out
      ;errord("nolog", xml1)
      xml := StringTrimLeft(xml, strlen(elementName)+2)
      xml := StringTrimRight(xml, strlen(elementName)+3)
   }

   return xml

} ;</13.03.000006>
;<13.03.000007>
sXMLget( xml, node, attr = "" ) {														;-- simple solution to get information out of xml and html

	;  by infogulch - simple solution get information out of xml and html
	;  supports getting the values from a nested nodes; does NOT support decendant/ancestor or sibling
	;  for something more than a little complex, try Titan's xpath: http://www.autohotkey.com/forum/topic17549.html

	RegExMatch( xml
      , (attr ? ("<" node "\b[^>]*\b" attr "=""(?<match>[^""]*)""[^>]*>") : ("<" node "\b[^>/]*>(?<match>(?<tag>(?:[^<]*(?:<(\w+)\b[^>]*>(?&tag)</\3>)*)*))</" node ">"))
      , retval )
   return retvalMatch

} ;</13.03.000007>

}

; ----------------------------------------------------------------  #String handling#  ------------------------------------------------------------------
{ ;<13.04> (18)
;<13.04.000001>
cleanlines(ByRef txt) {																		;-- removes all empty lines

	Loop, Parse, txt, `n, `r
	{
		i := A_LoopField
		if !(i){
			continue
		}
		newtxt .= i "`n"
	}
	return newtxt
} ;</13.04.000001>
;<13.04.000002>
cleancolon(txt) {																				;-- what for? removes on ':' at beginning of a string

	if substr(txt,1,1)=":" {
		txt:=substr(txt,2)
		txt = %txt%
	}
	return txt

} ;</13.04.000002>
;<13.04.000003>
cleanspace(ByRef txt) {																	;-- removes all Space chars

	StringReplace txt,txt,`n`n,%A_Space%, All
	StringReplace txt,txt,%A_Space%.%A_Space%,.%A_Space%, All
	loop
	{
		StringReplace txt,txt,%A_Space%%A_Space%,%A_Space%, UseErrorLevel
		if ErrorLevel = 0
			break
	}
	return txt
} ;</13.04.000003>
;<13.04.000004>
SplitLine(str, Byref key, ByRef val) {                                              	;-- split string to key and value

	If (p := InStr(str, "=")) {
		key := Trim(SubStr(str, 1, p - 1))
		val := Trim(SubStr(str, p + 1))
		Return True
	}
	Return False
} ;</13.04.000004>
;<13.04.000005>
EnsureEndsWith(string, char) {  														;-- Ensure that the string given ends with a given char

   if ( StringRight(string, strlen(char)) <> char )
      string .= char

   return string
} ;</13.04.000005>
;<13.04.000006>
EnsureStartsWith(string, char) { 														;-- Ensure that the string given starts with a given char
   if ( StringLeft(string, strlen(char)) <> char )
      string := char . string

   return string
} ;</13.04.000006>
;<13.04.000007>
StrPutVar(string, ByRef var, encoding) {    										;-- Convert the data to some Enc, like UTF-8, UTF-16, CP1200 and so on
   { ;-------------------------------------------------------------------------------
    ;
    ; Function: StrPutVar
    ; Description:
    ;		Convert the data to some Enc, like UTF-8, UTF-16, CP1200 and so on
    ; Syntax: StrPutVar(Str, ByRef Var [, Enc = ""])
    ; Parameters:
    ;		Str - String
    ;		Var - The name of the variable
    ;		Enc - Encoding
    ; Return Value:
    ;		String in a particular encoding
    ; Example:
    ;		None
    ;
    ;-------------------------------------------------------------------------------
    }


    VarSetCapacity( var, StrPut(string, encoding)
        * ((encoding="cp1252"||encoding="utf-16") ? 2 : 1) )
    return StrPut(string, &var, encoding)
} ;</13.04.000007>
;<13.04.000008>
RegExSplit(ByRef psText, psRegExPattern, piStartPos:=1) {				;-- split a String by a regular expressin pattern and you will receive an array as a result

	;https://autohotkey.com/board/topic/123708-useful-functions-collection/ - ObiWanKenobi
	;Parameters for RegExSplit:
	;psText                      the text you want to split
	;psRegExPattern      the Regular Expression you want to use for splitting
	;piStartPos               start at this posiiton in psText (optional parameter)
	;function ExtractSE() is a helper-function to extract a string at a specific start and end position.

	aRet := []
	if (psText != "") 	{

		iStartPos := piStartPos
		while (iPos := RegExMatch(psText, "P)" . psRegExPattern, match, iStartPos)) {

			sFound := ExtractSE(psText, iStartPos, iPos-1)
			aRet.Push(sFound)
			iStartPos := iPos + match
		}
        sFound := ExtractSE(psText, iStartPos)
        aRet.Push(sFound)
	}
	return aRet
} ;</13.04.000008>
;<13.04.000009>
ExtractSE(ByRef psText, piPosStart, piPosEnd:="") {                      	;-- subfunction of RegExSplit
	if (psText != "")
	{
		piPosEnd := piPosEnd != "" ? piPosEnd : StrLen(psText)
		return SubStr(psText, piPosStart, piPosEnd-(piPosStart-1))
	}
} ;</13.04.000009>
;<13.04.000010>
StringM( _String, _Option, _Param1 = "", _Param2 = "" ) {          	 ;--  String manipulation with many options is using RegExReplace  (bloat, drop, Flip, Only, Pattern, Repeat, Replace, Scramble, Split)

    if ( _Option = "Bloat" )
        _NewString := RegExReplace( _String, "(.)", _Param1 . "$1" . ( ( _Param2 ) ? _Param2 : _Param1) )
    else if ( _Option = "Drop" )
        _NewString := RegExReplace( _String, "i )[" . _Param1 . "]" )
    else if ( _Option = "Flip" )
        Loop, Parse, _String
            _NewString := A_LoopField . _NewString
    else if ( _Option = "Only" )
        _NewString := RegExReplace( _String, "i )[^" . _Param1 . "]" )
    else if ( _Option = "Pattern" ) {
        _Unique := RegExReplace( _String, "(.)", "$1" . Chr(10) )
        Sort, _Unique, % "U Z D" . Chr(10)
        _Unique := RegExReplace( _Unique, Chr(10) )
        Loop, Parse, _Unique
        {
            StringReplace, _String, _String, % A_LoopField,, UseErrorLevel
            _NewString .= A_LoopField . ErrorLevel
        }
    }
    else if ( _Option = "Repeat" )
        Loop, % _Param1
            _NewString := _NewString . _String
    else if ( _Option = "Replace" )
        _NewString := RegExReplace( _String, "i )" . _Param1, _Param2 )
    else if ( _Option = "Scramble" ) {
        _NewString := RegExReplace( _String, "(.)", "$1" . Chr(10) )
        Sort, _NewString, % "Random Z D" . Chr(10)
        _NewString := RegExReplace( _NewString, Chr(10) )
    }
    else if ( _Option = "Split" ) {
        Loop % Ceil( StrLen( _String ) / _Param1 )
            _NewString := _NewString . SubStr( _String, ( A_Index * _Param1 ) - _Param1 + 1, _Param1 ) . ( ( _Param2 ) ? _Param2 : " " )
        StringTrimRight, _NewString, _NewString, 1
    }
    return _NewString

} ;</13.04.000010>
;<13.04.000011>
StrCount(Haystack,Needle) {															;-- a very handy function to count a needle in a Haystack

	; https://github.com/joedf/AEI.ahk/blob/master/AEI.ahk
	StringReplace, Haystack, Haystack, %Needle%, %Needle%, UseErrorLevel
	return ErrorLevel
} ;</13.04.000011>
;<13.04.000012>
SuperInstr(Hay, Needles, return_min=true, Case=false,               	;-- Returns min/max position for a | separated values of Needle(s)
Startpoint=1, Occurrence=1)	{

	; Source: https://github.com/aviaryan/autohotkey-scripts/blob/master/Others/Ahk%20Coding%20Assistant.ahk

	/*			DESCRIPTION
			SuperInstr()
				Returns min/max position for a | separated values of Needle(s)

				return_min = true  ; return minimum position
				return_min = false ; return maximum position
	*/

	pos := return_min*Strlen(Hay)
	if return_min
	{
		loop, parse, Needles,|
			if ( pos > (var := Instr(Hay, A_LoopField, Case, startpoint, Occurrence)) )
				pos := ( var = 0 ? pos : var )
	}
	else
	{
		loop, parse, Needles,|
			if ( (var := Instr(Hay, A_LoopField, Case, startpoint, Occurrence)) > pos )
				pos := var
	}
	return pos
} ;</13.04.000012>
;<13.04.000013>
LineDelete(V, L, R := "", O := "", ByRef M := "") {                            	;-- deletes a specific line or a range of lines from a variable containing one or more lines of text. No use of any loop!

	/*    	DESCRIPTION of function
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	deletes a specific line or a range of lines from a variable containing one or more lines of text. No use of any loop!
										OutputVar := LineDelete(InVar, line nr [, Range, Options := "B", DumpVar]) ;Parameters inside [] are optional
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=46520
			Author         	:	Cuadrix
			Date             	:
			AHK-Version	:	AHK_L (tested works well!)
			License         	:
			Parameter(s)	:	(var)         	V	-	The variable whose lines will be deleted.
			                        	(line nr)    	L	-	The line which will be deleted.
			                        	(range)	    	R	-	If this parameter is set, Pos will act as the first line and Range as the last line. All lines in-between and
																		including Pos and Range will be deleted.
			                        	(options)    	O	-	If Range has been set, using "B" in Options will make the operation prevent Pos and Range from being
																		deleted, and only delete what's in-between them.
			                        	(dumpVar) 	M	-	Specify a variable in which to store the deleted lines from the operation.
			Return value	:	This function returns a version of InVar whose contents have been altered by the operation to 	OutputVar.
			                           	If no alterations are needed, InVar is returned unaltered.
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	string,lists
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)

			Var =
			(
			One
			Two
			Three
			Four
			Five
			)
			Output := LineDelete(Var, 2) ; Deletes line 2.
			MsgBox, % Output ; Returns variable's contents without line 2.

	*/


	T := StrSplit(V, "`n").MaxIndex()

	if (L > 0 && L <= T && (O = "" || O = "B"))
	{
		V := StrReplace(V, "`r`n", "`n"), S := "`n" V "`n"
		P := (O = "B") ? InStr(S, "`n",,, L + 1)
		   : InStr(S, "`n",,, L)
		M	:= (R <> "" && R > 0 && O = "" ) 	? SubStr(S, P + 1, InStr(S, "`n",, P, 2 + (R - L)) - P - 1)
			: 	(R <> "" && R < 0 && O = "" )  	? SubStr(S, P + 1, InStr(S, "`n",, P, 3 + (R - L + T)) - P - 1)
			: 	(R <> "" && R > 0 && O = "B")	? SubStr(S, P + 1, InStr(S, "`n",, P, R - L) - P - 1)
			: 	(R <> "" && R < 0 && O = "B")	? SubStr(S, P + 1, InStr(S, "`n",, P, 1 + (R - L + T)) - P - 1)
			: 	SubStr(S, P + 1, InStr(S, "`n",, P, 2) - P - 1)
		X := SubStr(S, 1, P - 1) . SubStr(S, P + StrLen(M) + 1), X := SubStr(X, 2, -1)
	}
	Else if (L < 0 && L >= -T && (O = "" || O = "B"))
	{
		V := StrReplace(V, "`r`n", "`n"), S := "`n" V "`n"
		P := (R <> "" && R < 0 && O = "" ) 	? InStr(S, "`n",,, R + T + 1)
		   : 	(R <> "" && R > 0 && O = "" )  	? InStr(S, "`n",,, R)
		   : 	(R <> "" && R < 0 && O = "B")	? InStr(S, "`n",,, R + T + 2)
		   : 	(R <> "" && R > 0 && O = "B")	? InStr(S, "`n",,, R + 1)
		   : 	InStr(S, "`n",,, L + T + 1)
		M := (R <> "" && R < 0 && O = "" ) 	? SubStr(S, P + 1, InStr(S, "`n",, P, 2 + (L - R)) - P - 1)
		   : 	(R <> "" && R > 0 && O = "" )  	? SubStr(S, P + 1, InStr(S, "`n",, P, 3 + (T - R + L)) - P - 1)
		   : 	(R <> "" && R < 0 && O = "B")	? SubStr(S, P + 1, InStr(S, "`n",, P, (L - R)) - P - 1)
		   : 	(R <> "" && R > 0 && O = "B")	? SubStr(S, P + 1, InStr(S, "`n",, P, 1 + (T - R + L)) - P - 1)
		   : SubStr(S, P + 1, InStr(S, "`n",, P, 2) - P - 1)
		X := SubStr(S, 1, P - 1) . SubStr(S, P + StrLen(M) + 1), X := SubStr(X, 2, -1)
	}

Return X
} ;</13.04.000013>
;<13.04.000014>
GetWordsNumbered(string, conditions) {										;-- gives back an array of words from a string, you can specify the position of the words you want to keep

	/*                              	DESCRIPTION

			by Ixiko 2018 - i know there's a better way, but I needed a function quickly

			Parameters:
			string:						the string to split in words
			conditions:				it's not the best name for this parameter, conditions must be a comma separated list of numbers like : "1,2,5,6"

	*/

	;this lines are not mine, they remove some chars i didn't need and they remove repeated space chars to one
	new:= RegExReplace(string, "(\s+| +(?= )|\s+$)", A_Space)
	new:= RegExReplace(new, "(,+)", A_Space)
	word:= StrSplit(new, A_Space)

	Loop, % word.MaxIndex()
	{
		If A_Index not in %conditions%
				word[A_Index]:= " "
	}

	Loop, % word.MaxIndex()
	{
		If (word[A_Index] = " ")
				word.Delete(A_Index)
	}

return word
} ;</13.04.000014>
;<13.04.000015>
AddTrailingBackslash(ptext) {															;-- adds a backslash to the beginning of a string if there is none

	if (SubStr(ptext, 0, 1) <> "\")
		return, ptext . "\"
	return, ptext

} ;</13.04.000015>
;<13.04.000016>
CheckQuotes(Path) {																		;--

   if (InStr(Path, A_Space, false) <> 0)
   {
      Path = "%Path%"
   }
   return, Path
} ;</13.04.000016>
;<13.04.000017>
ReplaceForbiddenChars(S_IN, ReplaceByStr = "") {							;-- hopefully working, not tested function, it uses RegExReplace

   Replace_RegEx := "im)[\/:*?""<>|]*"

   S_OUT := RegExReplace(S_IN, Replace_RegEx, "")
   if (S_OUT = 0)
      return, S_IN
   if (ErrorLevel = 0) and (S_OUT <> "")
      return, S_OUT

} ;</13.04.000017>
;<13.04.000018>
WrapText(Text, LineLength) {                                                        	;-- basic function to wrap a text-string to a given length

	/*    	DESCRIPTION of function WrapText() 13.04.00018
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	basic function to wrap a text-string to a given length
			Link              	:	https://rosettacode.org/wiki/Word_wrap#AutoHotkey
			Author         	:
			Date             	:
			AHK-Version	:	AHK_V1
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	string, text, string manipulation
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			MsgBox, % "72`n" WrapText(Clipboard, 72) "`n`n80`n" WrapText(Clipboard, 80)
			return

	*/

	StringReplace, Text, Text, `r`n, %A_Space%, All
	while (p := RegExMatch(Text, "(.{1," LineLength "})(\s|\R+|$)", Match, p ? p + StrLen(Match) : 1))
		Result .= Match1 ((Match2 = A_Space || Match2 = A_Tab) ? "`n" : Match2)
	return, Result
} ;</13.04.000018>

}

; ----------------------------------------------------------------------  #others#  ----------------------------------------------------------------------
{ ;<13.05> (18)

;<13.05.000001>
ExtractFuncTOuserAHK(data) {                                                     	;-- extract user function and helps to write it to userAhk.api

	; https://autohotkey.com/board/topic/78781-extract-function-declarations-from-ahk-lib-to-scite4ahk/

	/*	                                        	DESCRIPTION

			 The script extracts AHK function declarations from the clipboard and opens
			 user.ahk.api file where you can paste the function declarations.
			 Example usage:
			 - open an AHK library file you've downloaded,
			 - copy all code from within the file to the clipboard,
			 - run the script (parse clipboard contents, open user.ahk.api file)
			 - paste function declarations to user.ahk.api file
			 - restart SciTE.
			 Notes:
			 - modify the path variables below if needed
			 - good practice: rescan library catalog every time this script gets updated
				(vide script 1.0.0 skipped function declarations that had comments at
				the end)

			 TODO:
				- enable/disable sorting option?
				- if @ found in string, pick other sign
				- import constants
				- check if any of fn names are AHK built-in function names - if yes, warn
					user (see my GetTypeInfo.ahk)
				- option to skip comments in file
				- GUI window?

			 Version 1.0.4 (20120402)

			 Changes since version 1.0.3 (20120402)
				- regular expressions upgraded thanks to rvcv32's Regex Sandbox

			 Changes since version 1.0.2 (20120402)
				- remove duplicate entries
				- inform user if duplicate function names found (dup fn names, but not fn
					params / comments)
				- bug: ? changed to  - comment sign has to be present if text after
					trailing { (or '(')

			 Changes since version 1.0.1 (20120401)
				- look for `n if `r`n not found in clipboard
				- display a warning if both `n and `r`n not found in clipboard
				- small tweaking of the script

			 Changes since version 1.0.0 (20120327)
				- there can be comment sign and comments behind { sign. Updated RegEx
					pattern to handle that. Comment text is added to tooltip.

	*/


		editor_path := A_ProgramFiles "\Autohotkey\SciTE\SciTE.exe"
		API_path := A_MyDocuments "\Autohotkey\SciTE\user.ahk.api"

		; extract function declarations from clipboard, update clipboard contents
		data := clipboard
		output := ""
		StringReplace, data, data, `r`n, @, All
		if (ErrorLevel) { ; if `r`n missing in the string
			StringReplace, data, data, `n, @, All
			if (ErrorLevel) { ; if both `r`n and `n missing in the string
				MsgBox, 4132, % "Single line in clipboard, Did you copy a single line"
					. "of text to the clipboard?"
				IfMsgBox, No
				{
					MsgBox, 4112, Error, % "End of line character could not be "
						. "determined. Exiting."
					ExitApp
				}
			}
		}

		Loop, Parse, data, @
		{
			; if fn declaration line found, modify line and save line in output
			if (RegExMatch(A_LoopField, "^[a-zA-Z0-9_]* *\([^\)]*\) *\{? *$") )
										; no comments after {
										; this statement will cover most cases
				output .= RegExReplace(A_LoopField, "^([a-zA-Z0-9_]*) *(\([^\)]*\)) *\{? *$", "$1 $2") . "`r`n"
					; add a space between fn name and left bracket so SciTE parser
					; 	would work properly. I.e. fun (), not fun()
					; skip the trailing space and { if they are present
			else if (RegExMatch(A_LoopField, "^[a-zA-Z0-9_]* *\([^\)]*\) *\{? +;.*$") )
										; comments after {
				output .= RegExReplace(A_LoopField, "^([a-zA-Z0-9_]*) *(\([^\)]*\)) *\{? +; *(.*)$", "$1 $2 \n$3") . "`r`n"
		}

		; Sort the output
		Sort, output, U ; remove duplicates, case insinsitive for [a-zA-Z]

		; Inform user if duplicate function names found
		StringReplace, output, output, `r`n, @, All
		oldLine := ""
		Loop, Parse, output, @
		{
			line := A_LoopField
			line1 := "", oldline1 := ""
			StringSplit, line, line, `(
			StringSplit, oldLine, oldLine, `(
			if (line1 = oldLine1) { ; case insensitive
				MsgBox, 64, % "Duplicate function names found., Duplicate function"
					. " names found. User attention required."
				break
			}
			oldLine := line
		}
		StringReplace, output, output, @, `r`n, All

		clipboard := output

		; open *.api file and exit
		Run, "%editor_path%" "%API_path%"
		ToolTip, Done
		Sleep 1500
		ToolTip

return
} ;</13.05.000001>
;<13.05.000002>
PdfToText(PdfPath) {																		;-- copies a selected PDF file to memory - it needs xpdf - pdftotext.exe

	;  This function copies a selected PDF file to memory.  This function was written by kon at AHK forums
	;  and is origionally published in the AHK forums as post 23 in the following thread:
	;  https://autohotkey.com/boards/viewtopic.php?f=5&t=15880&sid=d554d6a38f58672776ff4e272b317308
	;  please note:  the word " -table" below was origionally " -nopgprk"
	;  kon -- if you ever see this THANK YOU

    static XpdfPath := """" A_ScriptDir "\pdftotext.exe"""
    objShell := ComObjCreate("WScript.Shell")

    ;--------- Building CmdString (look in the .txt docs incuded with xpdf):
    ; From the xpdf docs in [ScriptDir]\xpdfbin-win-3.04\doc\pdftotext.txt:
    ;   SYNOPSIS
    ;       pdftotext [options] [PDF-file [text-file]]
    ;   ...
    ;       If text-file is '-', the text is sent to stdout.
    ; Options (Example option. Look in the xpdf docs for more):
    ;   -nopgbrk    Don't insert page breaks (form feed characters)  between  pages.
    ;---------
    CmdString := XpdfPath " -table """ PdfPath """ -"
    objExec := objShell.Exec(CmdString)
    while, !objExec.StdOut.AtEndOfStream ; Wait for the program to finish
        strStdOut := objExec.StdOut.ReadAll()
    return strStdOut
} ;</13.05.000002>
;<13.05.000003>
PdfPageCounter(PathToPdfFile){                                                		;-- counts pages of a pdffile (works with 95% of pdf files)

	;https://autohotkey.com/board/topic/90560-pdf-page-counter/
    F:=FileOpen(PathToPdfFile,"r"), FSize:=F.Length, FContents:=F.Read(FSize), F.Close()
    while pos := RegExMatch(FContents, "is)<<[^>]*(/Count[^>]*/Kids|/Kids[^>]*/Count)[^>]*>>", m, (pos?pos:1)+StrLen(m))
	{
		if InStr(m, "Parent")
			continue
		PageCountLine := m
	}
    if !(PageCount := RegExReplace(PageCountLine, "is).*/Count\D*(\d+).*", "$1")) > 0
        while pos  := RegExMatch(FContents, "i)Type\s*/Page[^s/]", m, (pos?pos:1) +StrLen(m))
            PageCount++
    return, PageCount
} ;</13.05.000003>
;<13.05.000004>
PasteWithIndent(clp, ind="Tab", x=1) {											;-- paste string to an editor with your prefered indent key

	;use Tab or Space for example , x how many times you want to have an indent, clp = can contains many lines (lines must liminated through `n)
	ind:= "`{" . ind . " " . x . "`}"

	Loop, Parse, clp, `n
		{
			Send, {Shift Down}{HOME}{Shift Up}
			Send, {Del}
			StringReplace, t, A_LoopField, `n`r, , All
			Send, %ind%%t%				; {ENTER}
		}

return
}  ;</13.05.000004>
;<13.05.000005>
Ask_and_SetbackFocus(AskTitle, AskText) {				    		 			;-- by opening a msgbox you lost focus and caret pos in any editor - this func will restore the previous positions of the caret

	/*                              	DESCRIPTION

			************************************* a function to assist writing of code *************************************

			this function can be used to open a user prompt after entering a hotstring. It saves the the name of the
			active control and after closing the prompt it will give the focus back.

			this function is only tested with SciTE. The Scintilla1 window is losing it's focus when you open a MsgBox.
			This function will restore the focus.

			In SciTE it's not necessary to call a Mouse- or ControlClick command at the old position of caret. It's only
			need to use ControlFocus. Maybe this won't work with other editors, i leave some untested code here.

			OPTIONS:                   	AskTitle and AskText are strings for MsgBox title and text only
			DEPENDANCYS:          	you need GetFocusedControl(Option := "") function
			                                	https://autohotkey.com/boards/viewtopic.php?f=6&t=23987 from V for Vendetta

			****************************************************************************************************************
																												        	coded by Ixiko 2018 (in dirty mode)
	*/

	CoordMode, Caret, Window
	CoordMode, Mouse, Window
	;xcaret:= A_CaretX, ycaret:= A_CaretY
	active_WId:=WinExist("A")
	active_CId:= GetFocusedControl("Hwnd")
	;user input - change this line to what you like
	MsgBox, 4, %AskTitle%, %AskText%
	BlockInput, On
		WinActivate, ahk_id %active_WId%
			WinWaitActive, ahk_id %active_WId%, 4
	ControlFocus, , ahk_id %active_CId%
		;this part can be used, but with SciTE it's only needed to set the focus back to the editor window
		;Pause
		;DllCall("SetCursorPos", int, xcaret, int, ycaret)
		;SetControlDelay -1
		;ControlClick,, ahk_id %active_WId%,, Left, 1, x%xcaret% y%ycaret%
		;Click, %xcaret%, %ycaret%
	BlockInput, Off
	IfMsgBox, Yes
		return 1
	IfMsgBox, No
		return 0

}  ;</13.05.000005>
;<13.05.000006>
CleanLine(Target) {																			;-- Return a line with leading and trailing spaces removed, and tabs converted to spaces

	/*                              	DESCRIPTION of Func: CleanLine

			 Return a line with leading and trailing spaces removed, and tabs converted to spaces. This is mostly useful
			 for command-line parsing when the command-line is coming from an unknown source.  It makes subsequent
			 parsing of the string using searches and regular expressions simpler, without much danger of removing things
			 you're likely to need.

			 Parameters:		Target   - ByRef Target String to clean

			 Returns:   			String minus leading and trailing spaces, and all tabs converted to a single space.

	*/

   Work := RegexReplace(Target, "\t"  , " ")
   Work := RegexReplace(Work  , "^\s+", "")
   Work := RegexReplace(Work  , "\s+$", "")

   return Work
}  ;</13.05.000006>
;<13.05.000007>
StrTrim(Target) {																				;-- Remove all leading and trailing whitespace including tabs, spaces, CR and LF

	/*                              	DESCRIPTION

			 Func: StrTrim
			 Remove all leading and trailing whitespace including tabs, spaces, CR and LF.  This is slightl less
			 agressive than <CleanLine>.

			 Parameters:
			  Target   - Target String to clean

			 Returns:
			  String minus leading and trailing whitespace.


	*/


   return RegexReplace(RegexReplace(Target, "^\s+", ""), "\s+$", "")
}  ;</13.05.000007>
;<13.05.000008>
StrDiff(str1, str2, maxOffset:=5) {													;-- SIFT3 : Super Fast and Accurate string distance algorithm

	/*                              	DESCRIPTION

			By Toralf:
			Forum thread: http://www.autohotkey.com/forum/topic59407.html
			Download: https://gist.github.com/grey-code/5286786

			Basic idea for SIFT3 code by Siderite Zackwehdex
			http://siderite.blogspot.com/2007/04/super-fast-and-accurate-string-distance.html

			Took idea to normalize it to longest string from Brad Wood
			http://www.bradwood.com/string_compare/

			Own work:
			    - when character only differ in case, LSC is a 0.8 match for this character
			    - modified code for speed, might lead to different results compared to original code
			    - optimized for speed (30% faster then original SIFT3 and 13.3 times faster than basic Levenshtein distance)

			Dependencies. None

	*/

	/*                              	EXAMPLE(s)

			MsgBox % StrDiff( "A H K", "A H Kn" )
			MsgBox % StrDiff( "A H K", "A H K" )
			MsgBox % StrDiff( "A H K", "A h K" )
			MsgBox % StrDiff( "AHK", "" )
			MsgBox % StrDiff( "He", "Ben" )
			MsgBox % StrDiff( "Toralf", "ToRalf" )
			MsgBox % StrDiff( "Toralf", "esromneb" )
			MsgBox % StrDiff( "Toralf", "RalfLaDuce" )

	*/


	if (str1 = str2)
		return (str1 == str2 ? 0/1 : 0.2/StrLen(str1))
	if (str1 = "" || str2 = "")
		return (str1 = str2 ? 0/1 : 1/1)
	StringSplit, n, str1
	StringSplit, m, str2
	ni := 1, mi := 1, lcs := 0
	while ((ni <= n0) && (mi <= m0)) {
		if (n%ni% == m%mi%)
			lcs += 1
		else if (n%ni% = m%mi%)
			lcs += 0.8
		else {
			Loop, % maxOffset {
				oi := ni + A_Index, pi := mi + A_Index
				if ((n%oi% = m%mi%) && (oi <= n0)) {
					ni := oi, lcs += (n%oi% == m%mi% ? 1 : 0.8)
					break
				}
				if ((n%ni% = m%pi%) && (pi <= m0)) {
					mi := pi, lcs += (n%ni% == m%pi% ? 1 : 0.8)
					break
				}
			}
		}
		ni += 1
		mi += 1
	}
	return ((n0 + m0)/2 - lcs) / (n0 > m0 ? n0 : m0)
}  ;</13.05.000008>
;<13.05.000009>
PrintArr(Arr, Option := "w800 h200", GuiNum := 90) {					;-- show values of an array in a listview gui for debugging
    for index, obj in Arr {
        if (A_Index = 1) {
            for k, v in obj {
                Columns .= k "|"
                cnt++
            }
            Gui, %GuiNum%: Margin, 5, 5
            Gui, %GuiNum%: Add, ListView, %Option%, % Columns
        }
        RowNum := A_Index
        Gui, %GuiNum%: default
        LV_Add("")
        for k, v in obj {
            LV_GetText(Header, 0, A_Index)
            if (k <> Header) {
                FoundHeader := False
                loop % LV_GetCount("Column") {
                    LV_GetText(Header, 0, A_Index)
                    if (k <> Header)
                        continue
                    else {
                        FoundHeader := A_Index
                        break
                    }
                }
                if !(FoundHeader) {
                    LV_InsertCol(cnt + 1, "", k)
                    cnt++
                    ColNum := "Col" cnt
                } else
                    ColNum := "Col" FoundHeader
            } else
                ColNum := "Col" A_Index
            LV_Modify(RowNum, ColNum, (IsObject(v) ? "Object()" : v))
        }
    }
    loop % LV_GetCount("Column")
        LV_ModifyCol(A_Index, "AutoHdr")
    Gui, %GuiNum%: Show,, Array
} ;</13.05.000009>
;<13.05.000010>
List2Array(list, delimiter) {								               					;-- function uses StrSplit () to return an array
return StrSplit(list, delimiter)
}  ;</13.05.000010>
;<13.05.000011>
Array_Gui(Array, Parent="") {                                                        	;-- shows your array as an interactive TreeView

		/*    	DESCRIPTION of function Array_Gui()
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	show your array as an interactive TreeView
			Link              	:	https://autohotkey.com/boards/viewtopic.php?f=6&t=35124&p=162012#p162012
			Author         	:	GeekDude
			Date             	:	28 Jul 2017, 09:43
			AHK-Version	:	AHK-V1, AHK_L
			License         	:
			Syntax          	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	none
			KeyWords    	:	array, gui, debug, treeview
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			Array_Gui({"Apples":["Red", "Crunchy", "Lumpy"], "Oranges":["Orange", "Squishy", "Spherical"]})

	*/

	if !Parent
	{
		Gui, +HwndDefault
		Gui, New, +HwndGuiArray +LabelGuiArray +Resize
		Gui, Margin, 5, 5
		Gui, Add, TreeView, w300 h200

		Item := TV_Add("Array", 0, "+Expand")
		Array_Gui(Array, Item)

		Gui, Show,, GuiArray
		Gui, %Default%:Default

		WinWait, ahk_id%GuiArray%
		WinWaitClose, ahk_id%GuiArray%
		return
	}

	For Key, Value in Array
	{
		Item := TV_Add(Key, Parent)
		if (IsObject(Value))
			Array_Gui(Value, Item)
		else
			TV_Add(Value, Item)
	}
	return

	GuiArrayClose:
	Gui, Destroy
	return

	GuiArraySize:
	GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10
	return
} ;</13.05.000011>
;<13.05.000012>
RandomString(length, special := false) {                                     	;-- builds a string with random char of specified length
	;from Columbus.ahk
	Loop % length
		str .= (r := Random(1, special ? 4 : 3)) = 1
	? Random(0, 9) : r = 2
	? Chr(Random(65, 90)) : r = 3
	? Chr(Random(97, 122)) : SubStr("-_?!&:", r := Random(1, 6), 1)
	return % str
} ;</13.05.000012>
;<13.05.000013>
PrintStr(Str,FontName:="Arial",FontSize:=10,FontOpts:="") {        	;-- Prints the passed string on the default printer

	/*	DESCRIPTION OF FUNCTION: -- PrintStr --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Prints the passed string on the default printer
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?p=78205#p78205
	Author         	:	justme, *Lexikos
	Date             	:	29.03.2016
	AHK-Version	:	AHK_L
	License         	:	-
	Syntax          	:	-
	Parameter(s)	:	Str            	-  string to print
                            	FontName 	-  name of the font to be used for printing like the FontName parameter of the 'Gui, Font' command
												    	Default: Arial
                               	FontSize 		-  size of the font in points
                               			             	Default: 10
                               	FontOpts 	-  other font options like the Options parameter of the 'Gui, Font' command
                               			            	Default: s10
	Return value	:	On success: True
								On failure: False
								Errorlevel contains one of the following values:
                        			 1 - the specified font is not available
                        			 2 - error when calling the PrintDlg API function
                        			 3 - couldn't retrieve a valid DC for the printer
                        			 4 - an error occured while trying to print
	Remark(s)    	:	Based on the code published by Lexikos at autohotkey.com/board/topic/20468-detecting-printer-printing-text/page-2#entry146062
	Dependencies	:	none
	KeyWords    	:	Gui, Edit, Print,
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	#NoEnv
	SetBatchLines -1
	Lorem =
	(Join
	Lorem ipsum dolor sit amet consectetuer nulla vitae et felis nonummy. Tempor quis volutpat risus consectetuer Phasellus et quam
	 congue nec est. Volutpat Sed Vestibulum ridiculus montes tincidunt ac Pellentesque tempor leo Duis. Amet wisi at pretium et
	 faucibus semper at Curabitur pretium at. Et Morbi Nullam tincidunt condimentum at nunc egestas Maecenas leo et. Dolor eros montes
	 In Morbi dignissim consequat lacinia amet ut Duis. Et leo eros.
	`r`n`r`n
	Turpis volutpat sodales feugiat odio quis id netus facilisis ac a. Cursus congue dolor urna urna pellentesque tellus nascetur
	 facilisis Sed laoreet. Sem lacus porta id wisi consectetuer id Donec elit at.
	`r`n`r`n
	Cursus vel non feugiat at Aenean interdum nec tellus Ut Donec. Tortor Aliquam sit dui Vivamus nec dui dapibus metus amet feugiat.
	 Ac ridiculus Donec ipsum et et Curabitur leo mollis sagittis vitae. Facilisis Nam nec tellus velit tincidunt dapibus ac adipiscing.
	`r`n`r`n
	Penatibus In netus tristique egestas tincidunt risus risus malesuada convallis tellus. Facilisi Sed Maecenas ultrices sem auctor
	 netus scelerisque accumsan ac egestas. Neque vel elit a enim euismod ac vitae tincidunt porttitor laoreet. Interdum urna nibh at
	 nunc aliquet Fusce hac semper lacinia elit. Tellus tortor Ut sapien interdum orci vel enim sed Nam arcu. Nam id justo mauris nunc
	 Donec justo id pede Lorem lacinia. Eget parturient turpis Donec consequat tempus lobortis tortor id Suspendisse Nam. Justo amet.
	)
	EditText := Lorem
	Loop, 3
	   EditText .= "`r`n`r`n" . Lorem
	; ----------------------------------------------------------------------------------------------------------------------------------
	Gui, Margin, 10, 10
	Gui, Font, s10, Arial
	Gui, Add, Edit, xm ym w600 r20 hwndHED, %EditText%
	Gui, Add, Button, gPrint vBtnPrint Default, Print
	GuiControl, Focus, BtnPrint
	Gui, Show, , Print Edit
	Return
	; ----------------------------------------------------------------------------------------------------------------------------------
	GuiClose:
	GuiEscape:
	ExitApp
	; ----------------------------------------------------------------------------------------------------------------------------------
	Print:
	ControlGetText, Str, , ahk_id %HED% ; it's important to use ControlGetText if you read the text from an Edit control
	If (Str) {
	   If !PrintStr(Str)
		  MsgBox, 0, PrintStr, An error occurred!`nErrorLevel = %ErrorLevel%
	}
	Return

	*/

   Static DISize := A_PtrSize * 5 ; size of DOCINFO structure
   Static DPSize := 20 ; size of DRAWTEXTPARAMS structure
   Static LFSize := A_IsUnicode ? 60 : 92 ; size of LOGFONT structure
   Static PDSize := A_PtrSize = 8 ? (A_PtrSize * 13) + 16 : 66 ; size of PRINTDLG structure
   Static Margins := 20 ; left, top, right, and bottom margins in millimeters
   Static DocName := "PrintStr" ; document name
   ; Get a HFONT handle and the LOGFONT structure for the passed font (lazy method)
   Gui, PrintStrGUI: Font, %FontOpts% q2 s%FontSize%, %FontName%
   Gui, PrintStrGUI: Add, Text, hwndHTX, Dummy!
   HFONT := DllCall("SendMessage", "Ptr", HTX, "UInt", 0x0031, "Ptr", 0, "ptr", 0, "UPtr") ; WM_GETFONT
   Gui, PrintStrGUI: Destroy
   VarSetCapacity(LOGFONT, LFSize, 0) ; LOGFONT
   DllCall("GetObject", "Ptr", HFONT, "Int", LFSize, "Ptr", &LOGFONT)
   If (FontName <> StrGet(&LOGFONT + 28))
      Return (ErrorLevel := 1) & 0
   ; Get a device context of the default printer
   VarSetCapacity(PRINTDLG, PDSize, 0) ; PRINTDLG
   NumPut(PDSize, PRINTDLG, 0, "UInt")
   NumPut(0x0100 | 0x0400, PRINTDLG, A_PtrSize * 5, "UInt")
   If !(DllCall("Comdlg32.dll\PrintDlg", "Ptr", &PRINTDLG, "Int"))
      Return (ErrorLevel := 2) & 0
   DllCall("GlobalFree", "Ptr", NumGet(PRINTDLG, A_PtrSize * 2, "UPtr"))
   DllCall("GlobalFree", "Ptr", NumGet(PRINTDLG, A_PtrSize * 3, "UPtr"))
   If !(HDC := NumGet(PRINTDLG, A_PtrSize * 4, "UPtr"))
      Return (ErrorLevel := 3) & 0
   ; Get the device specific values
   DPIX := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x58)     ; LOGPIXELSX (horizontal resolution)
   , DPIY := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x5A)   ; LOGPIXELSY (vertical resolution)
   , PageW := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x08)  ; HORZRES (width of the printable area)
   , PageH := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x0A)  ; VERTRES (height of the printable area)
   , PhysW := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x6E)  ; PHYSICALWIDTH (physical width in device units)
   , PhysH := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x6F)  ; PHYSICALHEIGHT (physical height in device units)
   , OffsL := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x70)  ; PHYSICALOFFSETX (physical printable area x margin)
   , OffsT := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x71)  ; PHYSICALOFFSETY (physical printable area y margin)
   , OffsR := PhysW - PageW - OffsL                              ; physical printable area right offset
   , OffsB := PhysH - PageH - OffsT                              ; physical printable area bottom offset
   , HorzM := Round((DPIX / 25.4) * Margins)                     ; horizontal margins (~ 20 mm)
   , VertM := Round((DPIY / 25.4) * Margins)                     ; vertical margins (~ 20 mm)
   ; Set the printing rectangle
   RectL := HorzM - OffsL ; left
   , RectT := VertM - OffsT ; top
   , RectR := PageW - HorzM + OffsR ; right
   , RectB := PageH - VertM + OffsB ; bottom
   ; Scale the font height according to the vertical resolution of the printer
   FontH := NumGet(LOGFONT, 0, "Int") ; lfHeight
   , NumPut(Round(-FontSize * DPIY / 72), LOGFONT, 0, "Int")
   , NumPut(0, LOGFONT, 4, "Int") ; lfWidth
   , HFONT := DllCall("CreateFontIndirect", "Ptr", &LOGFONT, "UPtr")
   ; Select the scaled font
   DllCall("SelectObject", "Ptr", HDC, "Ptr", HFONT)
   ; Prepare for printing
   VarSetCapacity(DOCINFO, DISize, 0) ; DOCINFO
   , NumPut(DISize, DOCINFO, "UInt")
   , NumPut(&DocName, DOCINFO, A_PtrSize, "UPtr")
   VarSetCapacity(DTPARAMS, DPSize, 0) ; DRAWTEXTPARAMS
   , NumPut(DPSize, DTPARAMS, "UInt")
   VarSetCapacity(RECT, 16, 0)
   , NumPut(RectL, RECT, 0, "Int")
   , NumPut(RectT, RECT, 4, "Int")
   , NumPut(RectR, RECT, 8, "Int")
   , NumPut(RectB, RECT, 12, "Int")
   RC := 0
   ; Print
   If DllCall("StartDoc", "Ptr", HDC, "Ptr", &DOCINFO, "UInt") {
      Loop {
         Len := StrLen(Str)
         If DllCall("StartPage", "Ptr", HDC, "Int") {
            RC := DllCall("DrawTextEx", "Ptr", HDC, "Ptr", &Str, "Int", Len, "Ptr", &RECT, "UInt", 0x2250, "Ptr", &DTPARAMS, "Int")
            DllCall("EndPage", "Ptr", HDC, "Int")
         }
         If (RC) {
            LD := NumGet(DTPARAMS, 16, "UInt") ; uiLengthDrawn
            Str := LD < Len ? SubStr(Str, LD + 1) : ""
         }
      } Until (RC = 0) || (Str = "")
      DllCall("EndDoc", "Ptr", HDC)
   }
   DllCall("DeleteDC", "Ptr", HDC)
   If (HFONT)
      DllCall("DeleteObject", "Ptr", HFONT)
   Return (RC ? 1 : (ErrorLevel := 4) & 0)
} ;</13.05.000013>
;<13.05.000014>
NumStr(Value, Width, Dec, PadB4:="") {                                     	;-- Use to format a float or to pad leading characters (any character!) to a numeric string

	/*	DESCRIPTION OF FUNCTION: -- NumStr() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Use NumStr() to format a float . You may also use NumStr() to pad leading characters (any character!) to a numeric string
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	string (formated)
	Remark(s)    	:	--
	Dependencies	:	SPACE(13.05.000016)
	KeyWords    	:	string,formatting,leading characters,numeric
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Number=21.3263
	NumStr(Number,10,2,"_") returns "_____21.33"
	NumStr(Number,10,0,"0") returns "0000000021"
	NumStr(Number,10,2) returns "21.33" (Note: 21.33 is leaded by 5 spaces which I am not able to reproduce)
	FileAppend, % "ItemCode" NumStr(Number,5,0,0) , Temp.txt outputs "ItemCode00021" to temp.txt
	*/

  AFF := A_FormatFloat
  SetFormat, Float, 0.%Dec%
  Value += 0.00
  Loop
       If (StrLen(Value) < Width AND PadB4!="")
          Value := PadB4 Value
       else
          Break
  SetFormat, Float, %AFF%

Return Value
} ;</13.05.000014>
;<13.05.000015>
SetWidth(Str, Width, AlignText) {                                                	;-- increases a string's length by adding spaces to it and aligns it Left/Center/Right

	/*	DESCRIPTION OF FUNCTION: -- SetWidth() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	increases a string's length by adding spaces to it and aligns it Left/Center/Right
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	AlignText = 0(left), 1(center), 2(right)
	Return value	:	string (formated)
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	string,formatting
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	If (AlignText!=0 and AlignText!=1 and AlignText!=2)
			AlignText:=0

	if AlignText = 0
	{
			RetStr	:= Str . Space(Width)
			RetStr	:= SubStr(RetStr, 1, Width)
	 }
	else If AlignText = 1
	{
			Spaces	:= Width - StrLen(Str)
			RetStr	:= Space(Round(Spaces/2)) . Str . Space(Spaces- Round(Spaces/2))
	}
	else if AlignText = 2
	{
			RetStr	:= Space(Width) . Str
			RetStr	:= SubStr(RetStr, -Width)
	}

Return RetStr
} ;</13.05.000015>
;<13.05.000016>
Replicate( Chr=" ", X:=1 ) {                                                           	;-- replicates one char x-times

	/*	DESCRIPTION OF FUNCTION: -- Replicate() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	replicates one char x-times
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	string,formatting
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

Return VarSetCapacity( V, VarSetCapacity(V,VarSetCapacity(V,64)>>32)+X, Asc(Chr) ) ? V :
} ;</13.05.000016>
;<13.05.000017>
Space(Width) {                                                                              	;-- generates a string containing only spaces

	/*	DESCRIPTION OF FUNCTION: -- Space() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	generates a string containing only spaces
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	width is number of Space chars
	Return value	:	string
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	string,formatting
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/

	Loop, % Width
		Space.= Chr(32)
Return Space
} ;</13.05.000017>
;<13.05.000018>
SoundExC(Wrd="") {	;-- phonetic algorithm for indexing names by sound

	/*	DESCRIPTION OF FUNCTION: -- SoundExC() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Soundex is a phonetic algorithm for indexing names by sound, as pronounced in English.
								The goal is for names with the same pronunciation to be encoded to the same
								representation so that they can be matched despite minor differences in spelling.
								Soundex is the most widely known of all phonetic algorithms and is often used
								(incorrectly) as a synonym for "phonetic algorithm". Improvements to Soundex are the
								basis for many modern phonetic algorithms.

								The Algorithm as an Outline
								* Capitalize all letters in the word and drop all punctuation marks. Pad the word with
								   rightmost blanks as needed during each procedure step.
								* Retain the first letter of the word.
								* Change all occurrence of the following letters to '0' (zero):
								    'A', E', 'I', 'O', 'U', 'H', 'W', 'Y'.
								* Change letters from the following sets into the digit given:
								    1 = 'B', 'F', 'P', 'V'
								    2 = 'C', 'G', 'J', 'K', 'Q', 'S', 'X', 'Z'
								    3 = 'D','T'
								    4 = 'L'
								    5 = 'M','N'
								    6 = 'R'
								* Remove all pairs of digits which occur beside each other from the string that resulted
								    after step (4).
								* Remove all zeros from the string that results from step 5.0 (placed there in step 3)
								* Pad the string that resulted from step (6) with trailing zeros and return only the first
								    four positions, which will be of the form <uppercase letter> <digit> <digit> <digit>.
									The algorithm presented above is slightly improved over the originally patented
									algorithm. The original Soundex algorithm of 1918 starts to fail when the number of
									words in the database gets to be large. For example, the diversity of names in a large
									database with many foreign spellings starts to put more and more phonetically unlike
									names into the same code.

								* The slightly improved algorithm presented here differs from the original in step three,
								    where the vowel sounds are replaced with zeros ('0'), and in step (6.0) where those
									zeros are removed. The original algorithm eliminated the vowels completely in step
									3.0, before duplicate adjacent digits are removed.

								* This improved version will produce SoundEx codes with duplicate digits in them;
								   for example, "HERMAN" will code to "H06505" which will then reduce to "H655" in the
								   last step. In the original version, "HERMAN" would code to "H655" which will then
								   reduce to "H65" and finally to "H650" in the last step.
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-8
	Author         	:	SKAN (SoundEx Classic Version)
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	Leading spaces, if any, should be trimmed out before passing it to SoundExC()
	Dependencies	:	none
	KeyWords    	:	natural language processing, fuzzy search
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	words=crazy|crazie|craezie|crazi|crasie|cracie|crecie|crazee|crezie|crraazziiee
	Loop, Parse, words, |
		List .= A_LoopField "`t=  " SoundExC( A_LoopField ) "`n"
	MsgBox, % List
	*/

	Static A=0, B=1, C=2, D=3, E=0, F=1, G=2, H=0, I=0, J=2, K=2, L=4, M=5
	Static N=5, O=0, P=1, Q=2, R=6, S=2, T=3, U=0, V=1, W=0, X=2, Y=0, Z=2

	Wrd:= Format("{:U}", Wrd)
	Pre:= SubStr(Wrd, 1, 1)
	Prv:= %Pre%
	Word:= SubStr(Wrd, 2)

	Loop, Parse, Word
		If (Asc(A_LoopField) > 64 && Asc(A_LoopField) < 91)
			Word:= StrReplace(Word, A_LoopField, % %A_LoopField%)
		Else
			Word:= StrReplace(Word, A_LoopField)

	Loop, Parse, Word
		SE .= A_LoopField = Prv ? "" : Prv:=A_LoopField

	 SE:= StrReplace(SE, 0,, All)

Return Pre . SubStr(SE "000", 1, 3)
} ;</13.05.000018>
}

}
; -----------------------------------------------------------------  #Sort functions#  -------------------------------------------------------------------
;|   Sort2DArray(01)                      	|   SortArray()                                	|   QuickSort()                               	|   sortArray(4)                              	|
;|
; ---------------------------------------------------------------  #encoding/decoding#  ---------------------------------------------------------------
;|   uriEncode()                              	|   Ansi2Unicode()                         	|   Unicode2Ansi()                         	|   Ansi2Oem()                              	|
;|   Oem2Ansi()                             	|   Ansi2UTF8()                             	|   UTF82Ansi()                             	|   StringMD5()					             	|
;|   CRC32(9)                                 	|
; ---------------------------------------------------------------------  #parsing#  ----------------------------------------------------------------------
;|   ParseJsonStrToArr()	                	|    parseJSON()                            	|   GetNestedTag()                        	|   GetHTMLbyID()                        	|
;|   GetHTMLbyTag()                     	|   GetXmlElement()                      	|   sXMLget()                                 	|
; --------------------------------------------------------------  #String / lists handling#  --------------------------------------------------------------
;|   cleanlines(1)                            	|   cleancolon(2)                            	|   cleanspace(3)                            	|   SplitLine(4)                                  	|
;|   EnsureEndsWith(5)                  	|   EnsureStartsWith(6)                  	|   StrPutVar(7)                            		|
;|   RegExSplit(8)                           	|   StringM(10)                              	|   StrCount(11)                            	|   SuperInstr(12)                          	|
;|   LineDelete(13)                         	|   GetWordsNumbered(14)            	|   AddTrailingBackslash(15)		    	|   CheckQuotes(16)                     	|
;|   ReplaceForbiddenChars(17)    	|   WrapText(18)                             	|
; ----------------------------------------------------------------------  #others#  ----------------------------------------------------------------------
;|   ExtractFuncTOuserAHK(1)          	|   PdfToText(2)                             	|   PdfPageCounter(3)                  	|   PasteWithIndent(4)                  	|
;|   Ask_and_SetbackFocus(5)           	|   CleanLine(6)                             	|   StrTrim(7)                                	|   StrDiff(8)                                  	|
;|   PrintArr(9)                                 	|   List2Array(10)                           	|   Array_Gui(11)                          	|   RandomString(12)                    	|
;|   PrintStr(13)                               	|   NumStr(14)                               	|   SetWidth(15)                            	|   Replicate(16)                            	|
;|   Space(17)                                 	|   SoundExC(18)                           	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Keys/Hotkeys/Hotstring (11) -                                                                                                                  	baseID: <14>
;<14.01.000001>
DelaySend(Key, Interval=200, SendMethod="Send") {                       	;-- Send keystrokes delayed

	/*
	Sends keystrokes with a specified delay. It will be useful for an application which does not accept key presses sent too quickly.
	Remarks
	It remembers the sent count and completes them all.
	Requirements
	AutoHotkey_L v1.1.01 or later.  Tested on: Windows 7 64bit, AutoHotkey 32bit Unicode 1.1.05.01.
	*/

	static KeyStack := []
    KeyStack[Key] := IsObject(KeyStack[Key]) ? KeyStack[Key] : {base: {LastTickCount: 0}}
    ObjInsert( KeyStack[Key], { Key: Key, Interval: Interval, SendMethod: SendMethod })
    Gosub, Label_DelaySend
    Return

    Label_DelaySend:
        For Key in KeyStack {
            if !(MinIndex := KeyStack[Key].MinIndex())
                Continue
            Span := A_TickCount - KeyStack[Key].LastTickCount
            if (Span < KeyStack[Key][MinIndex].Interval)    ;loaded too early
                SetTimer,, % -1 * (KeyStack[Key][KeyStack[Key].MinIndex()].Interval - Span)     ;[v1.1.01+]
            else {
                SendMethod := KeyStack[Key][MinIndex].SendMethod
                SendingKey := KeyStack[Key][MinIndex].Key
                if (SendMethod = "SendInput")
                    SendInput, % SendingKey
                Else if (SendMethod = "SendPlay")
                    SendPlay, % SendingKey
                Else if (SendMethod = "SendRaw")
                    SendRaw, % SendingKey
                Else if (SendMethod = "SendEvent")
                    SendEvent, % SendingKey
                Else
                    Send, % SendingKey

                ObjRemove(KeyStack[Key], MinIndex)    ;decrement other elements
                if KeyStack[Key].MinIndex() ;if there is a next queue
                    SetTimer,, % -1 * KeyStack[Key][KeyStack[Key].MinIndex()].Interval        ;[v1.1.01+]
                KeyStack[Key].base.LastTickCount := A_TickCount
            }
        }
    Return
} ;</14.01.000001>
;<14.01.000002>
SetLayout(layout, winid) {																;-- set a keyboard layout
    Result := (DllCall("LoadKeyboardLayout", "Str", layout, "UInt", "257"))
    DllCall("SendMessage", "UInt", winid, "UInt", "80", "UInt", "1", "UInt", Result)
} ;</14.01.000002>
;<14.01.000003>
GetAllInputChars() {                                                        					;-- Returns a string with input characters

    Loop 256
        ChrStr .= Chr( a_index ) " "

    ChrStr .= "{down} {up} {right} {left} "

    Return ChrStr
} ;</14.01.000003>
;<14.01.000004>
ReleaseModifiers(Beep = 1, CheckIfUserPerformingAction = 0,    ;-- helps to solve the Hotkey stuck problem
AdditionalKeys = ""	, timeout := "") {

	/*						Description

				To have maximum reliability you really need to loop through all of the modifier and only proceed with the actions once none of them are down.
				It checks the modifiers keys and if one is down it will continually re-check them every 5ms  - when they are all released it will then wait 35ms and
				recheck them again (this second re-check is only required for this game) - if none are down it will return otherwise it keeps going (unless a 'timeout' period was specified).

				Also as pointed out some people have had success sending modifer up keystrokes like  {LWin up} -
				but I think this is hit and miss for many. Some find using Senevent or Send blind is required to 'unstick' the key.

	*/

	; https://autohotkey.com/board/topic/94091-sometimes-modifyer-keys-always-down/
	 ;timout in ms
	GLOBAL HotkeysZergBurrow
	startTime := A_Tickcount

	startReleaseModifiers:
	count := 0
	firstRun++
	while getkeystate("Ctrl", "P") || getkeystate("Alt", "P")
	|| getkeystate("Shift", "P") || getkeystate("LWin", "P") || getkeystate("RWin", "P")
	||  AdditionalKeys && (ExtraKeysDown := isaKeyPhysicallyDown(AdditionalKeys))  ; ExtraKeysDown should actually return the actual key
	|| (isPerformingAction := CheckIfUserPerformingAction && isUserPerformingAction()) ; have this function last as it can take the longest if lots of units selected
	{
		count++
		if (timeout && A_Tickcount - startTime >= timeout)
			return 1 ; was taking too long
		if (count = 1 && Beep) && !isPerformingAction && !ExtraKeysDown && firstRun = 1	;wont beep if casting or burrow AKA 'extra key' is down
				nothing=	   ;placeholder i dont want to play songs right now                            			;~ SoundPlay, %A_Temp%\ModifierDown.wav
		if ExtraKeysDown
			LastExtraKeyHeldDown := ExtraKeysDown ; as ExtraKeysDown will get blanked in the loop preventing detection in the below if
		else LastExtraKeyHeldDown := ""
		sleep, 5
	}
	if count
	{
		if (LastExtraKeyHeldDown = HotkeysZergBurrow)
			sleep 10 ;as burrow can 'buffer' within sc2
		else sleep, 5	;give time for sc2 to update keystate - it can be a slower than AHK (or it buffers)!
		Goto, startReleaseModifiers
	}
	return
} ;</14.01.000004>
;<14.01.000005>
isaKeyPhysicallyDown(Keys) {                                                        	;-- belongs to ReleaseModifiers() function

  if isobject(Keys)
  {
    for Index, Key in Keys
      if getkeystate(Key, "P")
        return key
  }
  else if getkeystate(Keys, "P")
  	return Keys ;keys!
  return 0
} ;</14.01.000005>
;<14.01.000006>
GetText(ByRef MyText = "") {                                                       	;-- copies the selected text to a variable while preserving the clipboard.(Ctrl+C method)

   SavedClip := ClipboardAll
   Clipboard =
   Send ^c
   ClipWait 0.5
   If ERRORLEVEL
   {
      Clipboard := SavedClip
      MyText =
      Return
   }
   MyText := Clipboard
   Clipboard := SavedClip
   Return MyText
} ;</14.01.000006>
;<14.01.000007>
PutText(MyText) {                                       	                                	;-- Pastes text from a variable while preserving the clipboard. (Ctrl+v method)

   SavedClip := ClipboardAll
   Clipboard =              ; For better compatability
   Sleep 20                 ; with Clipboard History
   Clipboard := MyText
   Send ^v
   Sleep 100
   Clipboard := SavedClip
   Return
} ;</14.01.000007>
;<14.01.000008>
Hotkeys(ByRef Hotkeys) {                                                        		;-- a handy function to show all used hotkeys in script

	/*                              	DESCRIPTION

			Link: https://autohotkey.com/boards/viewtopic.php?t=33437

	*/

	/*                              	EXAMPLE(s)

			F1:: ; Gui Hotkeys
			Gui, Add, ListView, h700 w500, HOTKEY|COMMENT
			LV_ModifyCol(1, 125)
			LV_ModifyCol(2, 375)
			for Index, Element in Hotkeys(Hotkeys)
			    LV_Add("",Element.Hotkey, Element.Comment)
			    If (Toggle := oggle)
			     Gui, Show, x0 y0
			    else
			     Gui, Destroy
			return

	*/


if (A_ComputerName = "Computer") {
    FileRead, Script, %A_ScriptFullPath%
}
If (A_ComputerName = "Laptop") {
    FileRead, Script, %A_ScriptFullPath%
}
    Script :=  RegExReplace(Script, "ms`a)^\s*/\*.*?^\s*\*/\s*|^\s*\(.*?^\s*\)\s*")
    Hotkeys := {}
    Loop, Parse, Script, `n, `r
        if RegExMatch(A_LoopField,"^\s*(.*):`:.*`;\s*(.*)",Match)
        {
            if !RegExMatch(Match1,"(Shift|Alt|Ctrl|Win)")
            {
                StringReplace, Match1, Match1, +, Shift+
                StringReplace, Match1, Match1, <^>!, AltGr+
                StringReplace, Match1, Match1, <, Left, All
                StringReplace, Match1, Match1, >, Right, All
                StringReplace, Match1, Match1, !, Alt+
                StringReplace, Match1, Match1, ^, Ctrl+
                StringReplace, Match1, Match1, #, Win+
            }
            Hotkeys.Push({"Hotkey":Match1, "Comment":Match2})
        }
    return Hotkeys
} ;</14.01.000008>
;<14.01.000009>
BlockKeyboard(block=-1) {                                                         	;-- block keyboard, and unblock it through usage of keyboard

	;Thanks to Lexikos
	 ; -1, true or false.

	static hHook = 0, cb = 0
	if !cb ; register callback once only.
		cb := RegisterCallback("BlockKeyboardProc","Fast")
	if (block = -1) ; toggle
		block := (hHook=0)
	if ( (hHook!=0) = (block!=0) ) ; already (un)blocked, no action necessary.
		return
	if (block)
		{
		hHook := DllCall("SetWindowsHookEx"
		, "int", 13 ; WH_KEYBOARD_LL
		, "uint", cb ; lpfn (callback)
		, "uint", 0 ; hMod (NULL)
		, "uint", 0) ; dwThreadId (all threads)
		}
	else
		{
		DllCall("UnhookWindowsHookEx", "uint", hHook)
		hHook = 0
		}
	}
BlockKeyboardProc(nCode, wParam, lParam) {

	static count=1, Keys:=["r","F12","LCtrl",".","CapsLock"]   ;password, some keys don't work, beware!
	if (NumGet(lParam+8) & 0x80)
		{
		if (NumGet(lParam+4)=GetKeyHex(Keys[count]))
			count++
		else
			count=1
		If (count=Keys.MaxIndex()+1)
			BlockKeyboard(false)
		}
	return 1
}
GetKeyHex(Key) {

	OldFormat:=A_FormatInteger
	SetFormat, Integer, H
	Ans:=GetKeySC(Key) + 0
	SetFormat, Integer, % OldFormat
	return Ans
} ;</14.01.000009>
;<14.01.000010>
RapidHotkey(keystroke, times="2", delay=0.2, IsLabel=0) {          	;-- Using this function you can send keystrokes or launch a Label by pressing a key several times.

	;https://autohotkey.com/board/topic/35566-rapidhotkey/

	/*    DESCRIPTION OF FUNCTION: -- RapidHotkey --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Using this function you can send keystrokes or launch a Label by pressing a key several times.
	Link              	:	https://autohotkey.com/board/topic/35566-rapidhotkey/
	Author         	:	HotkeyIt
	Date             	:	02.06.2010
	AHK-Version	:	AHK_L
	License         	:	?
	Syntax          	:	Key::RapidHotkey("keystrokes" ;Enter keystrokes here. E.g.: "^o"
                            				   , times          ;optional. The number of times the key must be pressed to execute.  E.g.: 3
                            				   , delay          ;optional. How quick the key must be pressed to execute. E.g.: 0.2
                            				   , IsLabel)        ;optional. specify 1 to indicate that parameter 1 is a label.
                            	E.g.
                            	~o::RapidHotkey("^o") open file dialog if o pressed twice

                            	To specify several actions , use " as separator and leave times parameter empty.
                            	If press times parameter is omitted, first action would be triggered on 2 presses.

                            	~e::RapidHotkey("#r""#e""#f")  #r if pressed twice, #e 3 times and so on
                            	You can specify also one (can be also 1) or separated value for times
                            	~s::RapidHotkey("^s""{F12}""^+s", 5) so pressing 5 times = ^s, 6 times = {F12} and so on
                            	You can also specify separated times value
                            	$x::RapidHotkey("x""#r""#e", "1""5""3")
                            	use same separator for delay and islabel parameter
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:	Morse()
	KeyWords    	:	hotkey, typing
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

		~+::RapidHotkey("Plus")
		~h::RapidHotkey("{Raw}Hello World!", 3) ;Press h 3 times rapidly to send Hello World!
		~o::RapidHotkey("^o", 4, 0.2) ;be careful, if you use this hotkey, above will not work properly
		~Esc::RapidHotkey("exit", 4, 0.2, 1) ;Press Esc 4 times rapidly to exit this script
		~LControl::RapidHotkey("!{TAB}",2) ;Press LControl rapidly twice to AltTab
		~RControl::RapidHotkey("+!{TAB}",2) ;Press RControl rapidly twice to ShiftAltTab
		~LShift::RapidHotkey("^{TAB}", 2) ;Switch back in internal windows
		~RShift::RapidHotkey("^+{TAB}", 2) ;Switch between internal windows
		~e::RapidHotkey("#e""#r",3) ;Run Windows Explorer
		~^!7::RapidHotkey("{{}{}}{Left}", 2)

		~a::RapidHotkey("test", 2, 0.3, 1) ;You Can also specify a Label to be launched
		test:
		MsgBox, Test
		Return

		Exit:
		ExitApp

		~LButton & RButton::RapidHotkey("Menu1""Menu2""Menu3",1,0.3,1)
		Menu1:
		Menu2:
		Menu3:
		MsgBox % A_ThisLabel
		Return

	*/

	Pattern := Morse(delay*1000)
	If (StrLen(Pattern) < 2 and Chr(Asc(times)) != "1")
		Return
	If (times = "" and InStr(keystroke, """"))
	{
		Loop, Parse, keystroke,""
			If (StrLen(Pattern) = A_Index+1)
				continue := A_Index, times := StrLen(Pattern)
	}
	Else if (RegExMatch(times, "^\d+$") and InStr(keystroke, """"))
	{
		Loop, Parse, keystroke,""
			If (StrLen(Pattern) = A_Index+times-1)
				times := StrLen(Pattern), continue := A_Index
	}
	Else if InStr(times, """")
	{
		Loop, Parse, times,""
			If (StrLen(Pattern) = A_LoopField)
				continue := A_Index, times := A_LoopField
	}
	Else if (times = "")
		continue := 1, times := 2
	Else if (times = StrLen(Pattern))
		continue = 1
	If !continue
		Return
	Loop, Parse, keystroke,""
		If (continue = A_Index)
			keystr := A_LoopField
	Loop, Parse, IsLabel,""
		If (continue = A_Index)
			IsLabel := A_LoopField
	hotkey := RegExReplace(A_ThisHotkey, "[\*\~\$\#\+\!\^]")
	IfInString, hotkey, %A_Space%
		StringTrimLeft, hotkey,hotkey,% InStr(hotkey,A_Space,1,0)
	backspace := "{BS " times "}"
	keywait = Ctrl|Alt|Shift|LWin|RWin
	Loop, Parse, keywait, |
		KeyWait, %A_LoopField%
	If ((!IsLabel or (IsLabel and IsLabel(keystr))) and InStr(A_ThisHotkey, "~") and !RegExMatch(A_ThisHotkey
	, "i)\^[^\!\d]|![^\d]|#|Control|Ctrl|LCtrl|RCtrl|Shift|RShift|LShift|RWin|LWin|Alt|LAlt|RAlt|Escape|BackSpace|F\d\d?|"
	. "Insert|Esc|Escape|BS|Delete|Home|End|PgDn|PgUp|Up|Down|Left|Right|ScrollLock|CapsLock|NumLock|AppsKey|"
	. "PrintScreen|CtrlDown|Pause|Break|Help|Sleep|Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|"
	. "Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|Volume_Down|Volume_Up|MButton|RButton|LButton|"
	. "Media_Next|Media_Prev|Media_Stop|Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2"))
		Send % backspace
	If (WinExist("AHK_class #32768") and hotkey = "RButton")
		WinClose, AHK_class #32768
	If !IsLabel
		Send % keystr
	else if IsLabel(keystr)
		Gosub, %keystr%
	Return
}
Morse(timeout = 400) { ;by Laszo -> http://www.autohotkey.com/forum/viewtopic.php?t=16951 (Modified to return: KeyWait %key%, T%tout%)
   tout := timeout/1000
   key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
   IfInString, key, %A_Space%
		StringTrimLeft, key, key,% InStr(key,A_Space,1,0)
	If Key in Shift,Win,Ctrl,Alt
		key1:="{L" key "}{R" key "}"
   Loop {
      t := A_TickCount
      KeyWait %key%, T%tout%
		Pattern .= A_TickCount-t > timeout
		If(ErrorLevel)
			Return Pattern
    If key in Capslock,LButton,RButton,MButton,ScrollLock,CapsLock,NumLock
      KeyWait,%key%,T%tout% D
    else if Asc(A_ThisHotkey)=36
		KeyWait,%key%,T%tout% D
    else
      Input,pressed,T%tout% L1 V,{%key%}%key1%
	If (ErrorLevel="Timeout" or ErrorLevel=1)
		Return Pattern
	else if (ErrorLevel="Max")
		Return
   }
} ;</14.01.000010>
;<14.01.000011>
hk(keyboard:=0, mouse:=0, message:="", timeout:=3, displayonce:=0) {                 	;-- Disable all keyboard buttons

	/*	DESCRIPTION OF FUNCTION: - hk()- Disable all keyboard buttons --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	So I tweaked the function and added an option (displayonce=) to display the message only
                            	once or more and also the possiblity to disable the right mouse button only (mouse=2). :dance:
                            	everything works fine now the only thing is that the code need to be cleaned up :?
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=33925
	Author         	:	SpeedMaster
	Date             	:	06 Jul 2017, 18:19
	AHK-Version	:	AHK_L
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:
	KeyWords    	:	keyboard, mouse, hook, hotkey, hotstring
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
		!F1::hk(1,1,"Keyboard keys and mouse buttons disabled!`nPress Alt+F2 to enable")   ; Disable all keyboard keys and mouse buttons
		!F2::hk(0,0,"Keyboard keys and mouse buttons restored!")         ; Enable all keyboard keys and mouse buttons
		!F3::hk(1,0,"Keyboard keys disabled!`nPress Alt+F2 to enable")   ; Disable all keyboard keys (but not mouse buttons)
		!F4::hk(0,1,"Mouse buttons disabled!`nPress Alt+F2 to enable")   ; Disable all mouse buttons (but not keyboard keys)
		!F5::hk(1,2,"Keyboard keys and Right Mouse button disabled!`nPress Alt+F2 to enable")   ; Disable all keyboard keys and right mouse button only
		!F6::hk(0,2,"Right Mouse button disabled!`nPress Alt+F2 to enable",3,1)   ; Disable right mouse button only and show message only once
	*/


   static AllKeys, z, d
   z:=message
   d:=displayonce
      For k,v in AllKeys {
           Hotkey, *%v%, Block_Input, off         ; initialisation
      }
   if !AllKeys {
      s := "||NumpadEnter|Home|End|PgUp|PgDn|Left|Right|Up|Down|Del|Ins|"
      Loop, 254
         k := GetKeyName(Format("VK{:0X}", A_Index))
       , s .= InStr(s, "|" k "|") ? "" : k "|"
      For k,v in {Control:"Ctrl",Escape:"Esc"}
         AllKeys := StrReplace(s, k, v)
      AllKeys := StrSplit(Trim(AllKeys, "|"), "|")
   }
   ;------------------
   if (mouse!=2)  ; if mouse=1 disable right and left mouse buttons  if mouse=0 don't disable mouse buttons
    {
        For k,v in AllKeys {
           IsMouseButton := Instr(v, "Wheel") || Instr(v, "Button")
           Hotkey, *%v%, Block_Input, % (keyboard && !IsMouseButton) || (mouse && IsMouseButton) ? "On" : "Off"
        }
    }
   if (mouse=2)   ;disable right mouse button (but not left mouse)
    {
     ExcludeKeys:="LButton"
      For k,v in AllKeys {
           IsMouseButton := Instr(v, "Wheel") || Instr(v, "Button")
           if v not in %ExcludeKeys%
           Hotkey, *%v%, Block_Input, % (keyboard && !IsMouseButton) || (mouse && IsMouseButton) ? "On" : "Off"
        }
    }
   if d
    {
   if (z != "") {
      Progress, B1 ZH0, %z%
      SetTimer, TimeoutTimer, % -timeout*1000
   }
   else
      Progress, Off
     }
   Block_Input:
   if (d!=1)
    {
   if (z != "") {
      Progress, B1 ZH0, %z%
      SetTimer, TimeoutTimer, % -timeout*1000
   }
   else
      Progress, Off
     }
   Return
   TimeoutTimer:
   Progress, Off
   Return
} ;</14.01.000011>

}
;|   DelaySend(01)                           	|   SetLayout(02)	                           	|   GetAllInputChars(03)                 	|   ReleaseModifiers(04)                  	|
;|   isaKeyPhysicallyDown(05)        	|   GetText(06)                                 	|   PutText(07)                               	|   Hotkeys(08)                               	|
;|   BlockKeyboard(09)                     	|   RapidHotkey(10)                         	|   hk(11)                                       	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;ToolTips (6) -                                                                                                                                             	baseID: <15>
;<15.01.000001>
ShowTrayBalloon(TipTitle = "", TipText = "", ShowTime = 5000, TipType = 1) {					;--

   global cfg

   if (not cfg.ShowBalloons)
      return, 0
   gosub, RemoveTrayTip
   if (TipText <> "")
   {
      Title := (TipTitle <> "") ? TipTitle : ProgramName
      TrayTip, %Title%, %TipText%, 10, %TipType%+16
      SetTimer, RemoveTrayTip, %ShowTime%
   }
   else
   {
      gosub, RemoveTrayTip
      return, 0
   }
   return, 0

   RemoveTrayTip:
      SetTimer, RemoveTrayTip, Off
      TrayTip
   return
} ;</15.01.000001>
;<15.01.000002>
ColoredTooltip(sTooltipTxt,seconds=5,bg=0xFFFFE7,fg=0x0,x=-1,y=-1) {                            ;-- show a tooltip for a given time with a custom color in rgb format (fore and background is supported). This function shows how to obtain the hWnd of the tooltip.
	/*                              	DESCRIPTION

			OriginalName: ColoredToolTip by derRaphael
			Origin: https://autohotkey.com/board/topic/31548-function-stooltip-colored-standard-tooltip-with-timeout/
			this version is not tested by me on Win7 and above

	*/

	/*                              	EXAMPLE(s)

			sTooltip("Tooltip with custom Colors",5,0xffff00,0x00ff00)

	*/


	; (w) derRaphael / zLib Style released / v 0.3
	if (Seconds+0=0)
		Seconds = 5
	StartTime := EndTime := A_Now
	EnvAdd,EndTime,Seconds,Seconds

	fg := ((fg&255)<<16)+(((fg>>8)&255)<<8)+(fg>>16) ; rgb -> bgr
	bg := ((bg&255)<<16)+(((bg>>8)&255)<<8)+(bg>>16) ; rgb -> bgr

	tooltip,% (ttID:="TooltipColor " A_TickCount)
	tThWnd1:=WinExist(ttID ahk_class tooltips_class32)
	; remove border
	; WinSet,Style,-0x800000,ahk_id %tThWnd1%
	SendMessage, 0x413, bg,0,, ahk_id %tThWnd1%   ; 0x413 is TTM_SETTIPBKCOLOR
	SendMessage, 0x414, fg,0,, ahk_id %tThWnd1%   ; 0x414 is TTM_SETTIPTEXTCOLOR
	; according to http://msdn.microsoft.com/en-us/library/bb760411(VS.85).aspx
	; there is no limitation on vista for this.
	Loop,
	{
		if (EndTime=A_Now)
			Break
		else
			if (x<0) || (y<0)
				ToolTip, %sTooltipTxt%
			else
				ToolTip, %sTooltipTxt%, %x%, %y%
		sleep, 50
	}
	ToolTip
} ;</15.01.000002>
 ;<15.01.000003>
AddToolTip(_CtrlHwnd, _TipText, _Modify = 0) {                                                        			;-- very easy to use function to add a tooltip to a control

	/*                              	DESCRIPTION

			 Adds Multi-line ToolTips to any Gui Control
			 AHK basic, AHK ANSI, Unicode x86/x64 compatible

			 Thanks Superfraggle & Art: http://www.autohotkey.com/forum/viewtopic.php?p=188241
			 Heavily modified by Rseding91 3/4/2014:
			 Version: 1.0
			   * Fixed 64 bit support
			   * Fixed multiple GUI support
			   * Changed the _Modify parameter
					   * blank/0/false:                                	Create/update the tool tip.
					   * -1:                                           		Delete the tool tip.
					   * any other value:                             Update an existing tool tip - same as blank/0/false
                                                        						but skips unnecessary work if the tool tip already
                                                        						exists - silently fails if it doesn't exist.
			   * Added clean-up methods:
					   * AddToolTip(YourGuiHwnd, "Destroy", -1):       		Cleans up and erases the cached tool tip data created
                                                                                    					for that GUI. Meant to be used in conjunction with
                                                                                    					GUI, Destroy.
					   * AddToolTip(YourGuiHwnd, "Remove All", -1):	   	Removes all tool tips from every control in the GUI.
                                                                                    					Has the same effect as "Destroy" but first removes
                                                                                    					every tool tip from every control. This is only used
                                                                                    					when you want to remove every tool tip but not destroy
                                                                                    					the entire GUI afterwords.
					   * NOTE: Neither of the above are required if
                            	your script is closing.

			 - 'Text' and 'Picture' Controls requires a g-label to be defined.
			 - 'ComboBox' = Drop-Down button + Edit (Get hWnd of the 'Edit'   control using "ControlGet" command).
			 - 'ListView' = ListView + Header       (Get hWnd of the 'Header' control using "ControlGet" command).

	*/
	/*                              	EXAMPLE(s)

			gui, Add, Button, w180 HwndButton1Hwnd, Button 1
			Gui, Add, Button, w180 HwndButton2Hwnd, Button 2
			Gui, Add, Radio, HwndRadio1Hwnd, Radio 1
			Gui, Add, Radio, HwndRadio2Hwnd, Radio 2

			AddToolTip(Button1Hwnd, "Tool tip for button #1.")
			AddToolTip(Button2Hwnd, "Tool tip #2.")
			AddToolTip(Radio1Hwnd, "Radio 1.")
			AddToolTip(Radio2Hwnd, "Radio 2 with a`nmulti-line tool tip.")
			Gui, Show, w200
			Return

			; This closes the script when the GUI is closed.
			GuiClose:
			GuiEscape:
				Exitapp
			Return

*/

	Static TTHwnds, GuiHwnds, Ptr
	, LastGuiHwnd
	, LastTTHwnd
	, TTM_DELTOOLA := 1029
	, TTM_DELTOOLW := 1075
	, TTM_ADDTOOLA := 1028
	, TTM_ADDTOOLW := 1074
	, TTM_UPDATETIPTEXTA := 1036
	, TTM_UPDATETIPTEXTW := 1081
	, TTM_SETMAXTIPWIDTH := 1048
	, WS_POPUP := 0x80000000
	, BS_AUTOCHECKBOX = 0x3
	, CW_USEDEFAULT := 0x80000000

	Ptr := A_PtrSize ? "Ptr" : "UInt"

	/*                              	NOTE

			     This is used to remove all tool tips from a given GUI and to clean up references used
				 This can be used if you want to remove every tool tip but not destroy the GUI
				 When a GUI is destroyed all Windows tool tip related data is cleaned up.
				 The cached Hwnd's in this function will be removed automatically if the caching code
				 ever matches them to a new GUI that doesn't actually own the Hwnd's.
				 It's still possible that a new GUI could have the same Hwnd as a previously destroyed GUI
				 If such an event occurred I have no idea what would happen. Either the tool tip
				 To avoid that issue, do either of the following:
				       * Don't destroy a GUI once created
				 NOTE: You do not need to do the above if you're exiting the script Windows will clean up
				  all tool tip related data and the cached Hwnd's in this function are lost when the script
				  exits anyway.AtEOF
	*/

	If (_TipText = "Destroy" Or _TipText = "Remove All" And _Modify = -1)
	{
		; Check if the GuiHwnd exists in the cache list of GuiHwnds
		; If it doesn't exist, no tool tips can exist for the GUI.
		;
		; If it does exist, find the cached TTHwnd for removal.
		Loop, Parse, GuiHwnds, |
			If (A_LoopField = _CtrlHwnd)
			{
				TTHwnd := A_Index
				, TTExists := True
				Loop, Parse, TTHwnds, |
					If (A_Index = TTHwnd)
						TTHwnd := A_LoopField
			}

		If (TTExists)
		{
			If (_TipText = "Remove All")
			{
				WinGet, ChildHwnds, ControlListHwnd, ahk_id %_CtrlHwnd%

				Loop, Parse, ChildHwnds, `n
					AddToolTip(A_LoopField, "", _Modify) ;Deletes the individual tooltip for a given control if it has one

				DllCall("DestroyWindow", Ptr, TTHwnd)
			}

			GuiHwnd := _CtrlHwnd
			; This sub removes 'GuiHwnd' and 'TTHwnd' from the cached list of Hwnds
			GoSub, RemoveCachedHwnd
		}

		Return
	}

	If (!GuiHwnd := DllCall("GetParent", Ptr, _CtrlHwnd, Ptr))
		Return "Invalid control Hwnd: """ _CtrlHwnd """. No parent GUI Hwnd found for control."

	; If this GUI is the same one as the potential previous one
	; else look through the list of previous GUIs this function
	; has operated on and find the existing TTHwnd if one exists.
	If (GuiHwnd = LastGuiHwnd)
		TTHwnd := LastTTHwnd
	Else
	{
		Loop, Parse, GuiHwnds, |
			If (A_LoopField = GuiHwnd)
			{
				TTHwnd := A_Index
				Loop, Parse, TTHwnds, |
					If (A_Index = TTHwnd)
						TTHwnd := A_LoopField
			}
	}

	; If the TTHwnd isn't owned by the controls parent it's not the correct window handle
	If (TTHwnd And GuiHwnd != DllCall("GetParent", Ptr, TTHwnd, Ptr))
	{
		GoSub, RemoveCachedHwnd
		TTHwnd := ""
	}

	; Create a new tooltip window for the control's GUI - only one needs to exist per GUI.
	; The TTHwnd's are cached for re-use in any subsequent calls to this function.
	If (!TTHwnd)
	{
		TTHwnd := DllCall("CreateWindowEx"
						, "UInt", 0                             ;dwExStyle
						, "Str", "TOOLTIPS_CLASS32"             ;lpClassName
						, "UInt", 0                             ;lpWindowName
						, "UInt", WS_POPUP | BS_AUTOCHECKBOX    ;dwStyle
						, "UInt", CW_USEDEFAULT                 ;x
						, "UInt", 0                             ;y
						, "UInt", 0                             ;nWidth
						, "UInt", 0                             ;nHeight
						, "UInt", GuiHwnd                       ;hWndParent
						, "UInt", 0                             ;hMenu
						, "UInt", 0                             ;hInstance
						, "UInt", 0)                            ;lpParam

		; TTM_SETWINDOWTHEME
		DllCall("uxtheme\SetWindowTheme"
					, Ptr, TTHwnd
					, Ptr, 0
					, Ptr, 0)

		; Record the TTHwnd and GuiHwnd for re-use in any subsequent calls.
		TTHwnds .= (TTHwnds ? "|" : "") TTHwnd
		, GuiHwnds .= (GuiHwnds ? "|" : "") GuiHwnd
	}

	; Record the last-used GUIHwnd and TTHwnd for re-use in any immediate future calls.
	LastGuiHwnd := GuiHwnd
	, LastTTHwnd := TTHwnd


	/*
		*TOOLINFO STRUCT*

		UINT        cbSize
		UINT        uFlags
		HWND        hwnd
		UINT_PTR    uId
		RECT        rect
		HINSTANCE   hinst
		LPTSTR      lpszText
		#if (_WIN32_IE >= 0x0300)
			LPARAM    lParam;
		#endif
		#if (_WIN32_WINNT >= Ox0501)
			void      *lpReserved;
		#endif
	*/

	, TInfoSize := 4 + 4 + ((A_PtrSize ? A_PtrSize : 4) * 2) + (4 * 4) + ((A_PtrSize ? A_PtrSize : 4) * 4)
	, Offset := 0
	, Varsetcapacity(TInfo, TInfoSize, 0)
	, Numput(TInfoSize, TInfo, Offset, "UInt"), Offset += 4                         ; cbSize
	, Numput(1 | 16, TInfo, Offset, "UInt"), Offset += 4                            ; uFlags
	, Numput(GuiHwnd, TInfo, Offset, Ptr), Offset += A_PtrSize ? A_PtrSize : 4      ; hwnd
	, Numput(_CtrlHwnd, TInfo, Offset, Ptr), Offset += A_PtrSize ? A_PtrSize : 4    ; UINT_PTR
	, Offset += 16                                                                  ; RECT (not a pointer but the entire RECT)
	, Offset += A_PtrSize ? A_PtrSize : 4                                           ; hinst
	, Numput(&_TipText, TInfo, Offset, Ptr)                                         ; lpszText


	; The _Modify flag can be used to skip unnecessary removal and creation if
	; the caller follows usage properly but it won't hurt if used incorrectly.
	If (!_Modify Or _Modify = -1)
	{
		If (_Modify = -1)
		{
			; Removes a tool tip if it exists - silently fails if anything goes wrong.
			DllCall("SendMessage"
					, Ptr, TTHwnd
					, "UInt", A_IsUnicode ? TTM_DELTOOLW : TTM_DELTOOLA
					, Ptr, 0
					, Ptr, &TInfo)

			Return
		}

		; Adds a tool tip and assigns it to a control.
		DllCall("SendMessage"
				, Ptr, TTHwnd
				, "UInt", A_IsUnicode ? TTM_ADDTOOLW : TTM_ADDTOOLA
				, Ptr, 0
				, Ptr, &TInfo)

		; Sets the preferred wrap-around width for the tool tip.
		 DllCall("SendMessage"
				, Ptr, TTHwnd
				, "UInt", TTM_SETMAXTIPWIDTH
				, Ptr, 0
				, Ptr, A_ScreenWidth)
	}

	; Sets the text of a tool tip - silently fails if anything goes wrong.
	DllCall("SendMessage"
		, Ptr, TTHwnd
		, "UInt", A_IsUnicode ? TTM_UPDATETIPTEXTW : TTM_UPDATETIPTEXTA
		, Ptr, 0
		, Ptr, &TInfo)

	Return


	RemoveCachedHwnd:
		Loop, Parse, GuiHwnds, |
			NewGuiHwnds .= (A_LoopField = GuiHwnd ? "" : ((NewGuiHwnds = "" ? "" : "|") A_LoopField))

		Loop, Parse, TTHwnds, |
			NewTTHwnds .= (A_LoopField = TTHwnd ? "" : ((NewTTHwnds = "" ? "" : "|") A_LoopField))

		GuiHwnds := NewGuiHwnds
		, TTHwnds := NewTTHwnds
		, LastGuiHwnd := ""
		, LastTTHwnd := ""
	Return
} ;</15.01.000003>
 ;<15.01.000004>
AddToolTip(ID="",TEXT="",TITLE="",OPTIONS="") {                                                        	;-- add ToolTips to controls - Advanced ToolTip features + Unicode
	/*					DESCRIPTION
ToolTip() by HotKeyIt http://www.autohotkey.com/forum/viewtopic.php?t=40165

Syntax: ToolTip(Number,Text,Title,Options)

Return Value: ToolTip returns hWnd of the ToolTip

|         Options can include any of following parameters separated by space
| Option   |      Meaning
| A      		|   Aim ConrolId or ClassNN (Button1, Edit2, ListBox1, SysListView321...)
|         		|   - using this, ToolTip will be shown when you point mouse on a control
|         		|   - D (delay) can be used to change how long ToolTip is shown
|         		|   - W (wait) can wait for specified seconds before ToolTip will be shown
|         		|   - Some controls like Static require a subroutine to have a ToolTip!!!
| B + F   	|   Specify here the color for ToolTip in 6-digit hexadecimal RGB code
|        		|   - B = Background color, F = Foreground color (text color)
|        		|   - this can be 0x00FF00 or 00FF00 or Blue, Lime, Black, White...
| C     		|   Close button for ToolTip/BalloonTip. See ToolTip actions how to use it
| D     		|   Delay. This option will determine how long ToolTip should be shown.30 sec. is maximum
|        		|   - this option is also available when assigning the ToolTip to a control.
| E      		|   Edges for ToolTip, Use this to set margin of ToolTip window (space between text and border)
|        		|   - Supply Etop.left.bottom.right in pixels, for example: E10.0.10.5
| G     		|   Execute one or more internal Labels of ToolTip function only.
|        		|   For example:
|        		|   - Track the position only, use ToolTip(1,"","","Xcaret Ycaret gTTM_TRACKPOSITION")
|        		|      - When X+Y are empty (= display near mouse position) you can use TTM_UPDATE
|        		|   - Update text only, use ToolTip(1,"text","","G1"). Note specify L1 if links are used.
|        		|   - Update title only, use ToolTip(1,"","Title","G1")
|        		|   - Hide ToolTip, use ToolTip(1,"","","gTTM_POP")
|        		|      - To show ToolTip again use ToolTip(1,"","","gTTM_TRACKPOSITION.TTM_TRACKACTIVATE")
|        		|   - Update background color + text color, specify . between gLabels to execute several:
|        		|      - ToolTip(1,"","","BBlue FWhite gTTM_SETTIPBKCOLOR.TTM_SETTIPTEXTCOLOR")
|        		|   - Following labels can be used: TTM_SETTITLEA + TTM_SETTITLEW (title+I), TTM_POPUP, TTM_POP
|        		|     TTM_SETTIPBKCOLOR (B), TTM_SETTIPTEXTCOLOR (F), TTM_TRACKPOSITION (N+X+Y),
|        		|     TTM_SETMAXTIPWIDTH (R), TTM_SETMARGIN (E), TT_SETTOOLINFO (text+A+P+N+X+Y+S+L)
|        		|     TTM_SETWINDOWTHEME (Q)
| H     		|   Hide ToolTip after a link is clicked.See L option
| I     		|   Icon 1-3, e.g. I1. If this option is missing no Icon will be used (same as I0)
|       		|   - 1 = Info, 2 = Warning, 3 = Error, > 3 is meant to be a hIcon (handle to an Icon)
|       		|   Use Included MI_ExtractIcon and GetAssociatedIcon functions to get hIcon
| J     		|   Justify ToolTip to center of control
| L     		|   Links for ToolTips. See ToolTip actions how Links for ToolTip work.
| M   		|   Mouse click-trough. So a click will be forwarded to the window underneath ToolTip
| N    		|   Do NOT activate ToolTip (N1), To activate (show) call ToolTip(1,"","","gTTM_TRACKACTIVATE")
| O    		|   Oval ToolTip (BalloonTip). Specify O1 to use a BalloonTip instead of ToolTip.
| P    		|   Parent window hWnd or GUI number. This will assign a ToolTip to a window.
|       		|   - Reqiered to assign ToolTip to controls and actions.
| Q    		|   Quench Style/Theme. Use this to disable Theme of ToolTip.
|       		|   Using this option you can have for example colored ToolTips in Vista.
| R    		|   Restrict width. This will restrict the width of the ToolTip.
|       		|   So if Text is to long it will be shown in several lines
| S    		|   Show at coordinates regardless of position. Specify S1 to use that feature
|       		|   - normally it is fed automaticaly to show on screen
| T    		|   Transparency. This option will apply Transparency to a ToolTip.
|       		|   - this option is not available to ToolTips assigned to a control.
| V    		|   Visible: even when the parent window is not active, a control-ToolTip will be shown
| W   		|   Wait time in seconds (max 30) before ToolTip pops up when pointing on one of controls.
| X + Y   	|   Coordinates where ToolTip should be displayed, e.g. X100 Y200
|         		|   - leave empty to display ToolTip near mouse
|         		|   - you can specify Xcaret Ycaret to display at caret coordinates
|
|          		To destroy a ToolTip use ToolTip(Number), to destroy all ToolTip()
|
|               ToolTip Actions (NOTE, OPTION P MUST BE PRESENT TO USE THAT FEATURE)
|      			Assigning an action to a ToolTip to works using OnMessage(0x4e,"Function") - WM_NOTIFY
|      			Parameter/option P must be present so ToolTip will forward messages to script
|      			All you need to do inside this OnMessage function is to include:
|         		- If wParam=0
|            	ToolTip("",lParam[,Label])
|
|  			    Additionally you need to have one or more of following labels in your script
|  			    - ToolTip: when clicking a link
|  			    - ToolTipClose: when closing ToolTip
|  			       - You can also have a diferent label for one or all ToolTips
|  			       - Therefore enter the number of ToolTip in front of the label
|  			          - e.g. 99ToolTip: or 1ToolTipClose:
|
|  			    - Those labels names can be customized as well
|  			       - e.g. ToolTip("",lParam,"MyTip") will use MyTip: and MyTipClose:
|  			       - you can enter the number of ToolTip in front of that label as well.
|
|  			    - Links have following syntax:
|  			       - <a>Link</a> or <a link>LinkName</a>
|  			       - When a Link is clicked, ToolTip() will jump to the label
|  			          - Variable ErrorLevel will contain clicked link
|
|  			       - So when only LinkName is given, e.g. <a>AutoHotkey</a> Errorlevel will be AutoHotkey
|  			       - When using Link is given as well, e.g. <a http://www.autohotkey.com>AutoHotkey</a>
|  			          - Errorlevel will be set to http://www.autohotkey.com
|
|  			    Please note some options like Close Button and Links will require Win2000++ (+version 6.0 of comctl32.dll)
|  			      AutoHotKey Version 1.0.48++ is required due to "assume static mode"
|  			      If you use 1 ToolTip for several controls, the only difference between those can be the text.
|  			         - Other options, like Title, color and so on, will be valid globally
*/
	/*                              	EXAMPLE(s)

			OnMessage(0x4e,"WM_NOTIFY") ;Will make LinkClick and ToolTipClose possible
			OnMessage(0x404,"AHK_NotifyTrayIcon") ;Will pop up the ToolTip when you click on Tray Icon
			OnExit, ExitApp
			NoEnv
			SingleInstance Force

			Restart:
			ToolTip(99,"Please click a link:`n`n"
			. "<a>My Favorite Websites</a>`n`n"
			. "<a>ToolTip Examples</a>`n`n"
			. "<a notepad.exe >Notepad</a>`n"
			. "<a explorer.exe >Explorer</a>`n"
			. "<a calc.exe >Calcu`lator</a>`n"
			. "`n<A>Hide ToolTip</a>n - To show this ToolTip again click onto Tray Icon"
			. "`n<a>ExitApp</a>`n"
			, "Welcome to ToolTip Control"
			, "L1 H1 O1 C1 T220 BLime FBlue I" . GetAssociatedIcon(A_ProgramFiles . "\Internet Explorer\iexplore.exe")
			. " P99 X" A_ScreenWidth . " Y" . A_ScreenHeight)

			My_Favorite_Websites:
			ToolTip(98,"<a http://www.autohotkey.com >AutoHotKEY>/a> - <a http://de.autohotkey.com>DE</a>"
			. " - <a http://autohotkey.free.fr/docs/>FR</a> - <a http://www.autohotkey.it/>IT</a>"
			. " - <a http://www.script-coding.info/AutoHotkeyTranslation.html>RU</a>"
			. " - <a http://lukewarm.s101.xrea.com/>JP</a>"
			. " - <a http://lukewarm.s101.xrea.com/>GR</a>"
			. " - <a http://www.autohotkey.com/docs/Tutorial-Portuguese.html>PT</a>"
			. " - <a http://cafe.naver.com/AutoHotKèy>KR</a>"
			. " - <a http://forum.ahkbbs.cn/bbs.php>CN</a>"
			. "`n<a http://www.google.com>Google</a> - <a http://www.maps.google.com>Maps</a>`n"
			. "<a http://social.msdn.microsoft.com/Search/en-US/?Refinement=86&Query=>MSDN</a>`n"
			, "My Websites"
			, "L1 O1 C1 BSilver FBlue I" . GetAssociatedIcon(A_ProgramFiles . "\Internet Explorer\iexplore.exe")
			. " P99")

			ToolTip_Examples:
			ToolTip(97, "<a>Message Box ToolTip</a>n"
			. "<a>Change ToolTip</a>`n"
			. "<a>ToolTip Loop
*/

static
local option,a,b,c,d,e,f,g,h,i,k,l,m,n,o,p,q,r,s,t,v,w,x,y,xc,yc,xw,yw,RECT,_DetectHiddenWindows,OnMessage
If !Init
Gosub, TTM_INIT
OnMessage:=OnMessage(0x4e,"") ,_DetectHiddenWindows:=A_DetectHiddenWindows
DetectHiddenWindows, On
If !ID
{
If text
If text is Xdigit
GoTo, TTN_LINKCLICK
Loop, Parse, hWndArray, % Chr(2) ;Destroy all ToolTip Windows
{
If WinExist("ahk_id " . A_LoopField)
DllCall("DestroyWindow","Uint",A_LoopField)
hWndArray%A_LoopField%=
}
hWndArray=
Loop, Parse, idArray, % Chr(2) ;Destroy all ToolTip Structures
{
TT_ID:=A_LoopField
If TT_ALL_%TT_ID%
Gosub, TT_DESTROY
}
idArray=
Goto, TT_EXITFUNC
}

TT_ID:=ID
TT_HWND:=TT_HWND_%TT_ID%

;___________________  Load Options Variables and Structures ___________________

If (options) {
Loop,Parse,options,%A_Space%
If (option:= SubStr(A_LoopField,1,1))
%option%:= SubStr(A_LoopField,2)
}
If (G) {
If (Title!="") {
                        Gosub, TTM_SETTITLE
Gosub, TTM_UPDATE
}
If (Text!="") {
If (A!="")
ID:=A
If (InStr(text,"<a") and L){
TOOLTEXT_%TT_ID%:=text
text:=RegExReplace(text,"<a\K[^<]*?>",">")
} else
TOOLTEXT_%TT_ID%:=
NumPut(&text,TOOLINFO_%ID%,36)
Gosub, TTM_UPDATETIPTEXT
}
Loop, Parse,G,.
If IsLabel(A_LoopField)
Gosub, %A_LoopField%
Sleep,10
    Goto, TT_EXITFUNC
}
;__________________________  Save TOOLINFO Structures _________________________

If P {
If (p<100 and !WinExist("ahk_id " p)){
Gui,%p%:+LastFound
P:=WinExist()
}
If !InStr(TT_ALL_%TT_ID%,Chr(2) . Abs(P) . Chr(2))
TT_ALL_%TT_ID%  .= Chr(2) . Abs(P) . Chr(2)
}
If !InStr(TT_ALL_%TT_ID%,Chr(2) . ID . Chr(2))
TT_ALL_%TT_ID%  .= Chr(2) . ID . Chr(2)
If H
TT_HIDE_%TT_ID%:=1
;__________________________  Create ToolTip Window  __________________________

If (!TT_HWND and text) {
TT_HWND := DllCall("CreateWindowEx", "Uint", 0x8, "str", "tooltips_class32", "str", "", "Uint", 0x02 + (v ? 0x1 : 0) + (l ? 0x100 : 0) + (C ? 0x80 : 0)+(O ? 0x40 : 0), "int", 0x80000000, "int", 0x80000000, "int", 0x80000000, "int", 0x80000000, "Uint", P ? P : 0, "Uint", 0, "Uint", 0, "Uint", 0)
TT_HWND_%TT_ID%:=TT_HWND
hWndArray .=(hWndArray ? Chr(2) : "") . TT_HWND
idArray .=(idArray ? Chr(2) : "") . TT_ID
Gosub, TTM_SETMAXTIPWIDTH
DllCall("SendMessage", "Uint", TT_HWND, "Uint", 0x403, "Uint", 2, "Uint", (D ? D*1000 : -1)) ;TTDT_AUTOPOP
DllCall("SendMessage", "Uint", TT_HWND, "Uint", 0x403, "Uint", 3, "Uint", (W ? W*1000 : -1)) ;TTDT_INITIAL
DllCall("SendMessage", "Uint", TT_HWND, "Uint", 0x403, "Uint", 1, "Uint", (W ? W*1000 : -1)) ;TTDT_RESHOW
} else if (!text and !options){
DllCall("DestroyWindow","Uint",TT_HWND)
Gosub, TT_DESTROY
GoTo, TT_EXITFUNC
}

;______________________  Create TOOLINFO Structure  ______________________

Gosub, TT_SETTOOLINFO

If (Q!="")
Gosub, TTM_SETWINDOWTHEME
If (E!="")
Gosub, TTM_SETMARGIN
If (F!="")
Gosub, TTM_SETTIPTEXTCOLOR
If (B!="")
Gosub, TTM_SETTIPBKCOLOR
If (title!="")
Gosub, TTM_SETTITLE

If (!A) {
Gosub, TTM_UPDATETIPTEXT
Gosub, TTM_UPDATE
If D {
A_Timer := A_TickCount, D *= 1000
Gosub, TTM_TRACKPOSITION
Gosub, TTM_TRACKACTIVATE
Loop
{
Gosub, TTM_TRACKPOSITION
If (A_TickCount - A_Timer > D)
Break
}
Gosub, TT_DESTROY
DllCall("DestroyWindow","Uint",TT_HWND)
TT_HWND_%TT_ID%=
} else {
Gosub, TTM_TRACKPOSITION
Gosub, TTM_TRACKACTIVATE
If T
WinSet,Transparent,%T%,ahk_id %TT_HWND%
If M
WinSet,ExStyle,^0x20,ahk_id %TT_HWND%
}
}

;________  Return HWND of ToolTip  ________

Gosub, TT_EXITFUNC
Return TT_HWND

;________________________  Internal Labels  ________________________

TT_EXITFUNC:
If OnMessage
OnMessage(0x4e,OnMessage)
DetectHiddenWindows, %_DetectHiddenWindows%
Return
TTM_POP:  ;Hide ToolTip
TTM_POPUP:  ;Causes the ToolTip to display at the coordinates of the last mouse message.
TTM_UPDATE: ;Forces the current tool to be redrawn.
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", 0)
Return
TTM_TRACKACTIVATE: ;Activates or deactivates a tracking ToolTip.
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", (N ? 0 : 1), "Uint", &TOOLINFO_%ID%)
Return
TTM_UPDATETIPTEXT:
TTM_GETBUBBLESIZE:
TTM_ADDTOOL:
TTM_DELTOOL:
TTM_SETTOOLINFO:
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", &TOOLINFO_%ID%)
Return
TTM_SETTITLE:
title := (StrLen(title) < 96) ? title : (Chr(133) SubStr(title, -97))
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", I, "Uint", &Title)
Return
TTM_SETWINDOWTHEME:
If Q
DllCall("uxtheme\SetWindowTheme", "Uint", TT_HWND, "Uint", 0, "UintP", 0)
else
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", &K)
Return
TTM_SETMAXTIPWIDTH:
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", R ? R : A_ScreenWidth)
Return
TTM_TRACKPOSITION:
VarSetCapacity(xc, 20, 0), xc := Chr(20)
DllCall("GetCursorInfo", "Uint", &xc)
yc := NumGet(xc,16), xc := NumGet(xc,12)
SysGet,xl,76
SysGet,xr,78
SysGet,yl,77
SysGet,yr,79
xc+=15,yc+=15
If (x="caret" or y="caret") {
WinGetPos,xw,yw,,,A
If x=caret
{
xc:=xw+A_CaretX +1
xc:=(xl>xc ? xl : (xr<xc ? xr : xc))
}
If (y="caret"){
yc:=yw+A_CaretY+15
yc:=(yl>yc ? yl : (yr<yc ? yr : yc))
}
} else if (x="TrayIcon" or y="TrayIcon"){
Process, Exist
PID:=ErrorLevel
hWndTray:=WinExist("ahk_class Shell_TrayWnd")
ControlGet,hWndToolBar,Hwnd,,ToolbarWindow321,ahk_id %hWndTray%
RemoteBuf_Open(TrayH,hWndToolBar,20)
DataH:=NumGet(TrayH,0)
SendMessage, 0x418,0,0,,ahk_id %hWndToolBar%
Loop % ErrorLevel
{
SendMessage,0x417,A_Index-1,RemoteBuf_Get(TrayH),,ahk_id %hWndToolBar%
RemoteBuf_Read(TrayH,lpData,20)
VarSetCapacity(dwExtraData,8)
pwData:=NumGet(lpData,12)
DllCall( "ReadProcessMemory", "uint", DataH, "uint", pwData, "uint", &dwExtraData, "uint", 8, "uint", 0 )
BWID:=NumGet(dwExtraData,0)
WinGet,BWPID,PID, ahk_id %BWID%
If (BWPID!=PID and BWPID!=#__MAIN_PID_)
continue
SendMessage, 0x41d,A_Index-1,RemoteBuf_Get(TrayH),,ahk_id %hWndToolBar%
RemoteBuf_Read(TrayH,rcPosition,20)
If (NumGet(lpData,8)>7){
ControlGetPos,xc,yc,xw,yw,Button2,ahk_id %hWndTray%
xc+=xw/2, yc+=yw/4
} else {
ControlGetPos,xc,yc,,,ToolbarWindow321,ahk_id %hWndTray%
halfsize:=NumGet(rcPosition,12)/2
xc+=NumGet(rcPosition,0)+ halfsize
yc+=NumGet(rcPosition,4)+ (halfsize/2)
}
WinGetPos,xw,yw,,,ahk_id %hWndTray%
xc+=xw,yc+=yw
break
}
RemoteBuf_close(TrayH)
}
If xc not between %xl% and %xr%
xc=xc<xl ? xl : xr
If yc not between %yl% and %yr%
yc=yc<yl ? yl : yr
If (!x and !y)
Gosub, TTM_UPDATE
else if !WinActive("ahk_id " . TT_HWND)
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", (x<9999999 ? x : xc & 0xFFFF)|(y<9999999 ? y : yc & 0xFFFF)<<16)
Return
TTM_SETTIPBKCOLOR:
If B is alpha
If (%b%)
B:=%b%
B := (StrLen(B) < 8 ? "0x" : "") . B
B := ((B&255)<<16)+(((B>>8)&255)<<8)+(B>>16) ; rgb -> bgr
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", B, "Uint", 0)
Return
TTM_SETTIPTEXTCOLOR:
If F is alpha
If (%F%)
F:=%f%
F := (StrLen(F) < 8 ? "0x" : "") . F
F := ((F&255)<<16)+(((F>>8)&255)<<8)+(F>>16) ; rgb -> bgr
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint",F & 0xFFFFFF, "Uint", 0)
Return
TTM_SETMARGIN:
VarSetCapacity(RECT,16)
Loop,Parse,E,.
NumPut(A_LoopField,RECT,(A_Index-1)*4)
DllCall("SendMessage", "Uint", TT_HWND, "Uint", %A_ThisLabel%, "Uint", 0, "Uint", &RECT)
Return
TT_SETTOOLINFO:
If A {
If A is not Xdigit
ControlGet,A,Hwnd,,%A%,ahk_id %P%
ID :=Abs(A)
If !InStr(TT_ALL_%TT_ID%,Chr(2) . ID . Chr(2))
TT_ALL_%TT_ID%  .= Chr(2) . ID . Chr(2) . ID+Abs(P) . Chr(2)
If !TOOLINFO_%ID%
VarSetCapacity(TOOLINFO_%ID%, 40, 0),TOOLINFO_%ID%:=Chr(40)
else
Gosub, TTM_DELTOOL
Numput((N ? 0 : 1)|(J ? 2 : 0)|(L ? 0x1000 : 0)|16,TOOLINFO_%ID%,4),Numput(P,TOOLINFO_%ID%,8),Numput(ID,TOOLINFO_%ID%,12)
If (text!="")
NumPut(&text,TOOLINFO_%ID%,36)
Gosub, TTM_ADDTOOL
      ID :=ID+Abs(P)
If !TOOLINFO_%ID%
{
VarSetCapacity(TOOLINFO_%ID%, 40, 0),TOOLINFO_%ID%:=Chr(40)
Numput(0|16,TOOLINFO_%ID%,4), Numput(P,TOOLINFO_%ID%,8), Numput(P,TOOLINFO_%ID%,12)
}
Gosub, TTM_ADDTOOL
ID :=Abs(A)
} else {
If !TOOLINFO_%ID%
VarSetCapacity(TOOLINFO_%ID%, 40, 0),TOOLINFO_%ID%:=Chr(40)
If (text!=""){
If InStr(text,"<a"){
TOOLTEXT_%ID%:=text
text:=RegExReplace(text,"<a\K[^<]*?>",">")
} else
TOOLTEXT_%ID%:=
NumPut(&text,TOOLINFO_%ID%,36)
}
      NumPut((J ? 2 : 0)|(!(x . y) ? 0 : 0x20)|(S ? 0x80 : 0)|(L ? 0x1000 : 0),TOOLINFO_%ID%,4), Numput(P,TOOLINFO_%ID%,8), Numput(P,TOOLINFO_%ID%,12)
Gosub, TTM_ADDTOOL
}
    TOOLLINK%ID%:=L
  Return
TTN_LINKCLICK:
Loop 4
m += *(text + 8 + A_Index-1) << 8*(A_Index-1)
If !(TTN_FIRST-2=m or TTN_FIRST-3=m or TTN_FIRST-1=m)
Return, OnMessage ? OnMessage(0x4e,OnMessage) : 0
Loop 4
p += *(text + 0 + A_Index-1) << 8*(A_Index-1)
If (TTN_FIRST-3=m)
Loop 4
option += *(text + 16 + A_Index-1) << 8*(A_Index-1)
Loop,Parse,hWndArray,% Chr(2)
If (p=A_LoopField and i:=A_Index)
break
Loop,Parse,idArray,% Chr(2)
{
If (i=A_Index){
If (TTN_FIRST-1=m){
Loop 4
ErrorLevel += *(text + 4 + A_Index-1) << 8*(A_Index-1)
Return A_LoopField, OnMessage ? OnMessage(0x4e,OnMessage) : 0
}
text:=TOOLTEXT_%A_LoopField%
If (TTN_FIRST-2=m){
If Title
{
If IsLabel(A_LoopField . title . "Close")
Gosub % A_LoopField . title . "Close"
else If IsLabel(title . "Close")
Gosub % title . "Close"
} else {
If IsLabel(A_LoopField . A_ThisFunc . "Close")
Gosub % A_LoopField . A_ThisFunc . "Close"
else If IsLabel(A_ThisFunc . "Close")
Gosub % A_ThisFunc . "Close"
}
} else If (InStr(TOOLTEXT_%A_LoopField%,"<a")){
Loop % option+1
StringTrimLeft,text,text,% InStr(text,"<a")+1
If TT_HIDE_%A_LoopField%
%A_ThisFunc%(A_LoopField,"","","gTTM_POP")
If ((a:=A_AutoTrim)="Off")
AutoTrim, On
ErrorLevel:=SubStr(text,1,InStr(text,">")-1)
StringTrimLeft,text,text,% InStr(text,">")
text:=SubStr(text,1,InStr(text,"</a>")-1)
If !ErrorLevel
ErrorLevel:=text
ErrorLevel=%ErrorLevel%
AutoTrim, %a%
If Title
{
If IsFunc(f:=(A_LoopField . title))
%f%(ErrorLevel)
else if IsLabel(A_LoopField . title)
Gosub % A_LoopField . title
else if IsFunc(title)
%title%(ErrorLevel)
else If IsLabel(title)
Gosub, %title%
} else {
if IsFunc(f:=(A_LoopField . A_ThisFunc))
%f%(ErrorLevel)
else If IsLabel(A_LoopField . A_ThisFunc)
Gosub % A_LoopField . A_ThisFunc
else If IsLabel(A_ThisFunc)
Gosub % A_ThisFunc
}
}
break
}
}
DetectHiddenWindows, %_DetectHiddenWindows%
Return OnMessage ? OnMessage(0x4e,OnMessage) : 0
TT_DESTROY:
Loop, Parse, TT_ALL_%TT_ID%,% Chr(2)
If A_LoopField
{
ID:=A_LoopField
Gosub, TTM_DELTOOL
TOOLINFO_%A_LoopField%:="", TT_HWND_%A_LoopField%:="", TOOLTEXT_%A_LoopField%:="", TT_HIDE_%A_LoopField%:="",TOOLLINK%A_LoopField%:=""
}
TT_ALL_%TT_ID%=
Return

TTM_INIT:
Init:=1
; Messages
TTM_ACTIVATE := 0x400 + 1, TTM_ADDTOOL := A_IsUnicode ? 0x432 : 0x404, TTM_DELTOOL := A_IsUnicode ? 0x433 : 0x405
,TTM_POP := 0x41c, TTM_POPUP := 0x422, TTM_UPDATETIPTEXT := 0x400 + (A_IsUnicode ? 57 : 12)
,TTM_UPDATE := 0x400 + 29, TTM_SETTOOLINFO := 0x409, TTM_SETTITLE := 0x400 + (A_IsUnicode ? 33 : 32)
,TTN_FIRST := 0xfffffdf8, TTM_TRACKACTIVATE := 0x400 + 17, TTM_TRACKPOSITION := 0x400 + 18
,TTM_SETMARGIN:=0x41a, TTM_SETWINDOWTHEME:=0x200b, TTM_SETMAXTIPWIDTH:=0x418,TTM_GETBUBBLESIZE:=0x41e
,TTM_SETTIPBKCOLOR:=0x413, TTM_SETTIPTEXTCOLOR:=0x414
;Colors
,Black:=0x000000, Green:=0x008000,Silver:=0xC0C0C0
,Lime:=0x00FF00, Gray:=0x808080, Olive:=0x808000
,White:=0xFFFFFF, Yellow:=0xFFFF00, Maroon:=0x800000
,Navy:=0x000080, Red:=0xFF0000, Blue:=0x0000FF
,Purple:=0x800080, Teal:=0x008080, Fuchsia:=0xFF00FF
   ,Aqua:=0x00FFFF
Return
} ;</15.01.000004>
 ;{ sub
MI_ExtractIcon(Filename, IconNumber, IconSize) {
If A_OSVersion in WIN_VISTA,WIN_2003,WIN_XP,WIN_2000
{
 DllCall("PrivateExtractIcons", "Str", Filename, "Int", IconNumber-1, "Int", IconSize, "Int", IconSize, "UInt*", hIcon, "UInt*", 0, "UInt", 1, "UInt", 0, "Int")
If !ErrorLevel
Return hIcon
}
If DllCall("shell32.dll\ExtractIconExA", "Str", Filename, "Int", IconNumber-1, "UInt*", hIcon, "UInt*", hIcon_Small, "UInt", 1)
{
SysGet, SmallIconSize, 49

If (IconSize <= SmallIconSize) {
DllCall("DeStroyIcon", "UInt", hIcon)
hIcon := hIcon_Small
}
 Else
DllCall("DeStroyIcon", "UInt", hIcon_Small)

If (hIcon && IconSize)
hIcon := DllCall("CopyImage", "UInt", hIcon, "UInt", 1, "Int", IconSize, "Int", IconSize, "UInt", 4|8)
}
Return, hIcon ? hIcon : 0
}
GetAssociatedIcon(File) {
   static
   sfi_size:=352
   local Ext,Fileto,FileIcon,FileIcon#
   If !File
      Loop, Parse, #_hIcons, |
         If A_LoopField
            DllCall("DestroyIcon",UInt,A_LoopField)
   If not sfi
      VarSetCapacity(sfi, sfi_size)
   SplitPath, File,,, Ext
If !Ext
Return
   else if Ext in EXE,ICO,ANI,CUR,LNK
   {
      If ext=LNK
      {
         FileGetShortcut,%File%,Fileto,,,,FileIcon,FileIcon#
         File:=!FileIcon ? FileTo : FileIcon
      }
      SplitPath, File,,, Ext
      hIcon%Ext%:=MI_ExtractIcon(file,FileIcon# ? FileIcon# : 1,32)
   } else If (!hIcon%Ext% or !InStr(hIcons,"|" . hIcon%Ext% . "|")){
      If DllCall("Shell32\SHGetFileInfoA", "str", File, "uint", 0, "str", sfi, "uint", sfi_size, "uint", 0x101){
         Loop 4
            hIcon%Ext% += *(&sfi + A_Index-1) << 8*(A_Index-1)
      }
      hIcons .= "|" . hIcon%Ext% . "|"
   }
   return hIcon%Ext%
}
;}  ;</15.01.000004>
;<15.01.000005>
AddToolTip(con,text,Modify = 0) {                                                                                    	;-- just a simple add on to allow tooltips to be added to controls without having to monitor the wm_mousemove messages
	/*                              	EXAMPLE(s)

			Gui,Add,Button,hwndbutton1 Gbut1,Test Button 1
			AddTooltip(button1,"Press me to change my tooltip")
			Gui,show,,Test Gui
			Return

			But1:
			AddTooltip(button1,"Wasn't that easy `;)",1)
			REturn

			GuiClose:
			Guiescape:
			Exitapp

	*/

 Static TThwnd,GuiHwnd
  If (!TThwnd){
    Gui,+LastFound
    GuiHwnd:=WinExist()
    TThwnd:=CreateTooltipControl(GuiHwnd)
	Varsetcapacity(TInfo,44,0)
	Numput(44,TInfo)
	Numput(1|16,TInfo,4)
	Numput(GuiHwnd,TInfo,8)
	Numput(GuiHwnd,TInfo,12)
	;Numput(&text,TInfo,36)
	Detecthiddenwindows,on
	Sendmessage,1028,0,&TInfo,,ahk_id %TThwnd%
    SendMessage,1048,0,300,,ahk_id %TThwnd%
  }
  Varsetcapacity(TInfo,44,0)
  Numput(44,TInfo)
  Numput(1|16,TInfo,4)
  Numput(GuiHwnd,TInfo,8)
  Numput(con,TInfo,12)
  Numput(&text,TInfo,36)
  Detecthiddenwindows,on
  If (Modify){
    SendMessage,1036,0,&TInfo,,ahk_id %TThwnd%
  }
  Else {
    Sendmessage,1028,0,&TInfo,,ahk_id %TThwnd%
    SendMessage,1048,0,300,,ahk_id %TThwnd%
  }


} ;</15.01.000005>
;{ sub
CreateTooltipControl(hwind) {

  Ret:=DllCall("CreateWindowEx"
          ,"Uint",0
          ,"Str","TOOLTIPS_CLASS32"
          ,"Uint",0
          ,"Uint",2147483648 | 3
          ,"Uint",-2147483648
          ,"Uint",-2147483648
          ,"Uint",-2147483648
          ,"Uint",-2147483648
          ,"Uint",hwind
          ,"Uint",0
          ,"Uint",0
          ,"Uint",0)

  Return Ret
}
;} ;</15.01.000005>
;<15.01.000006>
AddToolTip(hControl,p_Text) {                                                                                    		;-- this is a function from jballi -

		/*                              	DESCRIPTION

			 Function: AddToolTip

			 Description:

			   Add/Update tooltips to GUI controls.

			 Parameters:

			   hControl - Handle to a GUI control.

			   p_Text - Tooltip text.

			 Returns:

			   Handle to the tooltip control.

			 Remarks:

			 * This function accomplishes this task by creating a single Tooltip control
			   and then creates, updates, or delete tools which are/were attached to the
			   individual GUI controls.

			 * This function returns the handle to the Tooltip control so that, if desired,
			   additional actions can be performed on the Tooltip control outside of this
			   function.  Once created, this function reuses the same Tooltip control.
			   If the tooltip control is destroyed outside of this function, subsequent
			   calls to this function will fail.  If desired, the tooltip control can be
			   destroyed just before the script ends.

			 Credit and History:

			 * Original author: Superfraggle
			   Post: <http://www.autohotkey.com/board/topic/27670-add-tooltips-to-controls/>

			 * Updated to support Unicode: art
			   Post: <http://www.autohotkey.com/board/topic/27670-add-tooltips-to-controls/page-2ntry431059>

			 * Additional: jballi
			   Bug fixes.  Added support for x64.  Removed Modify parameter.  Added
			   additional functionality, documentation, and constants.

	*/

	Static hTT

          ;-- Misc. constants
          ,CW_USEDEFAULT:=0x80000000
          ,HWND_DESKTOP :=0
          ,WS_EX_TOPMOST:=0x8

          ;-- Tooltip styles
          ,TTS_ALWAYSTIP:=0x1
                ;-- Indicates that the ToolTip control appears when the cursor
                ;   is on a tool, even if the ToolTip control's owner window is
                ;   inactive. Without this style, the ToolTip appears only when
                ;   the tool's owner window is active.

          ,TTS_NOPREFIX:=0x2
                ;-- Prevents the system from stripping ampersand characters from
                ;   a string or terminating a string at a tab character. Without
                ;   this style, the system automatically strips ampersand
                ;   characters and terminates a string at the first tab
                ;   character. This allows an application to use the same string
                ;   as both a menu item and as text in a ToolTip control.

          ;-- TOOLINFO uFlags
          ,TTF_IDISHWND:=0x1
                ;-- Indicates that the uId member is the window handle to the
                ;   tool.  If this flag is not set, uId is the identifier of the
                ;   tool.

          ,TTF_SUBCLASS:=0x10
                ;-- Indicates that the ToolTip control should subclass the
                ;   window for the tool in order to intercept messages, such
                ;   as WM_MOUSEMOVE. If you do not set this flag, you must use
                ;   the TTM_RELAYEVENT message to forward messages to the
                ;   ToolTip control.  For a list of messages that a ToolTip
                ;   control processes, see TTM_RELAYEVENT.

          ;-- Messages
          ,TTM_ADDTOOLA      :=0x404                    ;-- WM_USER + 4
          ,TTM_ADDTOOLW      :=0x432                    ;-- WM_USER + 50
          ,TTM_DELTOOLA      :=0x405                    ;-- WM_USER + 5
          ,TTM_DELTOOLW      :=0x433                    ;-- WM_USER + 51
          ,TTM_GETTOOLINFOA  :=0x408                    ;-- WM_USER + 8
          ,TTM_GETTOOLINFOW  :=0x435                    ;-- WM_USER + 53
          ,TTM_SETMAXTIPWIDTH:=0x418                    ;-- WM_USER + 24
          ,TTM_UPDATETIPTEXTA:=0x40C                    ;-- WM_USER + 12
          ,TTM_UPDATETIPTEXTW:=0x439                    ;-- WM_USER + 57

    ;-- Workarounds for AutoHotkey Basic and x64
    PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"
    PtrSize:=A_PtrSize ? A_PtrSize:4

    ;-- Save/Set DetectHiddenWindows
    l_DetectHiddenWindows:=A_DetectHiddenWindows
    DetectHiddenWindows On

    ;-- Tooltip control exists?
    if not hTT
        {
        ;-- Create Tooltip window
        hTT:=DllCall("CreateWindowEx"
            ,"UInt",WS_EX_TOPMOST                       ;-- dwExStyle
            ,"Str","TOOLTIPS_CLASS32"                   ;-- lpClassName
            ,"UInt",0                                   ;-- lpWindowName
            ,"UInt",TTS_ALWAYSTIP|TTS_NOPREFIX          ;-- dwStyle
            ,"UInt",CW_USEDEFAULT                       ;-- x
            ,"UInt",CW_USEDEFAULT                       ;-- y
            ,"UInt",CW_USEDEFAULT                       ;-- nWidth
            ,"UInt",CW_USEDEFAULT                       ;-- nHeight
            ,"UInt",HWND_DESKTOP                        ;-- hWndParent
            ,"UInt",0                                   ;-- hMenu
            ,"UInt",0                                   ;-- hInstance
            ,"UInt",0                                   ;-- lpParam
            ,PtrType)                                   ;-- Return type

        ;-- Disable visual style
        DllCall("uxtheme\SetWindowTheme",PtrType,hTT,PtrType,0,"UIntP",0)

        ;-- Set the maximum width for the tooltip window
        ;   Note: This message makes multi-line tooltips possible
        SendMessage TTM_SETMAXTIPWIDTH,0,A_ScreenWidth,,ahk_id %hTT%
        }

    ;-- Create/Populate TOOLINFO structure
    uFlags:=TTF_IDISHWND|TTF_SUBCLASS
    cbSize:=VarSetCapacity(TOOLINFO,8+(PtrSize*2)+16+(PtrSize*3),0)
    NumPut(cbSize,      TOOLINFO,0,"UInt")              ;-- cbSize
    NumPut(uFlags,      TOOLINFO,4,"UInt")              ;-- uFlags
    NumPut(HWND_DESKTOP,TOOLINFO,8,PtrType)             ;-- hwnd
    NumPut(hControl,    TOOLINFO,8+PtrSize,PtrType)     ;-- uId

    VarSetCapacity(l_Text,4096,0)
    NumPut(&l_Text,     TOOLINFO,8+(PtrSize*2)+16+PtrSize,PtrType)
        ;-- lpszText

    ;-- Check to see if tool has already been registered for the control
    SendMessage
        ,A_IsUnicode ? TTM_GETTOOLINFOW:TTM_GETTOOLINFOA
        ,0
        ,&TOOLINFO
        ,,ahk_id %hTT%

    RegisteredTool:=ErrorLevel

    ;-- Update TOOLTIP structure
    NumPut(&p_Text,TOOLINFO,8+(PtrSize*2)+16+PtrSize,PtrType)
        ;-- lpszText

    ;-- Add, Update, or Delete tool
    if RegisteredTool
        {
        if StrLen(p_Text)
            SendMessage
                ,A_IsUnicode ? TTM_UPDATETIPTEXTW:TTM_UPDATETIPTEXTA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%
         else
            SendMessage
                ,A_IsUnicode ? TTM_DELTOOLW:TTM_DELTOOLA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%
        }
    else
        if StrLen(p_Text)
            SendMessage
                ,A_IsUnicode ? TTM_ADDTOOLW:TTM_ADDTOOLA
                ,0
                ,&TOOLINFO
                ,,ahk_id %hTT%

    ;-- Restore DetectHiddenWindows
    DetectHiddenWindows %l_DetectHiddenWindows%

    ;-- Return the handle to the tooltip control
    Return hTT
    }


}  ;</15.01.000006>
;|   ShowTrayBalloon(01)                 	|   ColoredTooltip(02)                      	|   AddToolTip(03-06) x 4                	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;System functions/Binary handling (64) -  	                                                                                                	baseID: <16>
;<16.01.000001>
CreateNamedPipe(Name, OpenMode=3, PipeMode=0, MaxInstances=255) {          	;-- creates an instance of a named pipe and returns a handle for subsequent pipe operations
    return DllCall("CreateNamedPipe","str","\\.\pipe\" Name,"uint",OpenMode
        ,"uint",PipeMode,"uint",MaxInstances,"uint",0,"uint",0,"uint",0,"uint",0)
} ;</16.01.000001>
;<16.01.000002>
RestoreCursors() {                                                                                                        	;-- for normal cursor at GUI
   SPI_SETCURSORS := 0x57
   DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
} ;</16.01.000002>
;<16.01.000003>
SetSystemCursor( Cursor = "", cx = 0, cy = 0 ) {                                                          	;-- enables an application to customize the system cursors by using a file or by using the system cursor

	BlankCursor := 0, SystemCursor := 0, FileCursor := 0
	SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS
        ,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE
        ,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL
        ,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP
	If Cursor =
	{
        VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
        BlankCursor = 1
	}
	Else If SubStr( Cursor,1,4 ) = "IDC_"
	{
        Loop, Parse, SystemCursors, `,
        {
        	CursorName := SubStr( A_Loopfield, 6, 15 )
        	CursorID := SubStr( A_Loopfield, 1, 5 )
        	SystemCursor = 1
        	If ( CursorName = Cursor )
        	{
                CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
                Break
        	}
        }
        If CursorHandle =
        {
        	Msgbox,, SetCursor, Error: Invalid cursor name
        	CursorHandle = Error
        }
	}
	Else If FileExist( Cursor )
	{
        SplitPath, Cursor,,, Ext
        If Ext = ico
        	uType := 0x1
        Else If Ext in cur,ani
        	uType := 0x2
        Else
        {
        	Msgbox,, SetCursor, Error: Invalid file type
        	CursorHandle = Error
        }
        FileCursor = 1
	}
	Else
	{
        Msgbox,, SetCursor, Error: Invalid file path or cursor name
        CursorHandle = Error
	}
	If CursorHandle != Error
	{
        Loop, Parse, SystemCursors, `,
        {
        	If BlankCursor = 1
        	{
                Type = BlankCursor
                %Type%%A_Index% := DllCall( "CreateCursor", Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
                CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
                DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
        	}
        	Else If SystemCursor = 1
        	{
                Type = SystemCursor
                CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
                %Type%%A_Index% := DllCall( "CopyImage"
                	, Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )
                CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
                DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
        	}
        	Else If FileCursor = 1
        	{
                Type = FileCursor
                %Type%%A_Index% := DllCall( "LoadImageA"
                	, UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
                DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )
        	}
        }
	}
} ;</16.01.000003>
;<16.01.000004>
SystemCursor(OnOff=1) {                                                                                            	;-- hiding mouse cursor

	; Borrowed from Laszlo's post @ http://www.autohotkey.com/board/topic/5727-hiding-the-mouse-cursor/
	; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others

    static AndMask, XorMask, $, h_cursor
        ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13                                      	; system cursors
        , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13                                   	; blank cursors
        , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13                                    	; handles of default cursors
    if (OnOff = "Init" or OnOff = "I" or $ = "") {                                            	; init when requested or at first call

        	$ = h                                                                                                	; active default cursors
        	VarSetCapacity( h_cursor,4444, 1 )
        	VarSetCapacity( AndMask, 32*4, 0xFF )
        	VarSetCapacity( XorMask, 32*4, 0 )
        	system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
        	StringSplit c, system_cursors, `,
        	Loop %c0%
        	{
                h_cursor   := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
                h%A_Index% := DllCall( "CopyImage",  "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
                b%A_Index% := DllCall("CreateCursor","uint",0, "int",0, "int",0
                	, "int",32, "int",32, "uint",&AndMask, "uint",&XorMask )
        	}
    }

    if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
        $ = b                                                                  	; use blank cursors
    else
        $ = h                                                                  	; use the saved cursors

    Loop %c0%
    {
        h_cursor := DllCall( "CopyImage", "uint",%$%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
        DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
    }

} ;</16.01.000004>
;<16.01.000005>
ToggleSystemCursor( p_id, p_hide=false ) {                                                                	;-- choose a cursor from system cursor list

	/*                	DESCRIPTION

	from Library of Lateralus138's window functions, objects, and classes for AutoHotkey
	Email: faithnomoread@yahoo.com for help, suggestions, or possible collaboration.
	OCR_NORMAL         	IDC_ARROW            	32512	1
	OCR_IBEAM            		IDC_IBEAM              	32513	2
	OCR_WAIT              		IDC_WAIT                	32514	3
	OCR_CROSS             	IDC_CROSS              	32515	4
	OCR_UP                  		IDC_UPARROW       	32516	5
	OCR_SIZENWSE       	IDC_SIZENWSE        	32642	6
	OCR_SIZENESW       	IDC_SIZENESW        	32643	7
	OCR_SIZEWE           	IDC_SIZEWE             	32644	8
	OCR_SIZENS           		IDC_SIZENS             	32645	9
	OCR_SIZEALL          		IDC_SIZEALL            	32646	10
	OCR_NO                  	IDC_NO                   	32648	11
	OCR_HAND             	IDC_HAND              	32649	12
	OCR_APPSTARTING	IDC_APPSTARTING  	32650	13
	*/

	static	system_cursor_list

	if system_cursor_list=
		system_cursor_list = |1:32512|2:32513|3:32514|4:32515|5:32516|6:32642|7:32643|8:32644|9:32645|10:32646|11:32648|12:32649|13:32650|

	ix := InStr( system_cursor_list, "|" p_id )
	ix := InStr( system_cursor_list, ":", false, ix )+1

	StringMid, id, system_cursor_list, ix, 5

	ix_b := ix+6
	ix_e := InStr( system_cursor_list, "|", false, ix )-1

	SysGet, cursor_w, 13
	SysGet, cursor_h, 14

	if ( cursor_w != 32 or cursor_h != 32 )
	{
        MsgBox, System parameters not supported!
        return
	}

	if ( p_hide )
	{
        if ( ix_b < ix_e )
        	return

        h_cursor := DllCall( "LoadCursor", "uint", 0, "uint", id )

        h_cursor := DllCall( "CopyImage", "uint", h_cursor, "uint", 2, "int", 0, "int", 0, "uint", 0 )

        StringReplace, system_cursor_list, system_cursor_list, |%p_id%:%id%, |%p_id%:%id%`,%h_cursor%

        VarSetCapacity( AndMask, 32*4, 0xFF )
        VarSetCapacity( XorMask, 32*4, 0 )

        h_cursor := DllCall( "CreateCursor"
                                , "uint", 0
                                , "int", 0
                                , "int", 0
                                , "int", cursor_w
                                , "int", cursor_h
                                , "uint", &AndMask
                                , "uint", &XorMask )
	}
	else
	{
        if ( ix_b > ix_e )
        	return

        StringMid, h_cursor, system_cursor_list, ix_b, ix_e-ix_b+1

        StringReplace, system_cursor_list, system_cursor_list, |%p_id%:%id%`,%h_cursor%, |%p_id%:%id%
	}

	result := DllCall( "SetSystemCursor", "uint", h_cursor, "uint", id )
} ;</16.01.000005>
;<16.01.000006>
SetTimerF( Function, Period=0, ParmObject=0, Priority=0 ) {                                    	;-- Starts a timer that can call functions and object methods

 Static current,tmrs:=Object() ;current will hold timer that is currently running
 If IsFunc( Function ) || IsObject( Function ){
    if IsObject(tmr:=tmrs[Function]) ;destroy timer before creating a new one
       ret := DllCall( "KillTimer", UInt,0, UInt, tmr.tmr)
       , DllCall("GlobalFree", UInt, tmr.CBA)
       , tmrs.Remove(Function)
    if (Period = 0 || Period ? "off")
       return ret ;Return as we want to turn off timer
    ; create object that will hold information for timer, it will be passed trough A_EventInfo when Timer is launched
    tmr:=tmrs[Function]:=Object("func",Function,"Period",Period="on" ? 250 : Period,"Priority",Priority
                        ,"OneTime",(Period<0),"params",IsObject(ParmObject)?ParmObject:Object()
                        ,"Tick",A_TickCount)
    tmr.CBA := RegisterCallback(A_ThisFunc,"F",4,&tmr)
    return !!(tmr.tmr  := DllCall("SetTimer", UInt,0, UInt,0, UInt
                        , (Period && Period!="On") ? Abs(Period) : (Period := 250)
                        , UInt,tmr.CBA)) ;Create Timer and return true if a timer was created
            , tmr.Tick:=A_TickCount
 }
 tmr := Object(A_EventInfo) ;A_Event holds object which contains timer information
 if IsObject(tmr) {
    DllCall("KillTimer", UInt,0, UInt,tmr.tmr) ;deactivate timer so it does not run again while we are processing the function
    If (!tmr.active && tmr.Priority<(current.priority ? current.priority : 0)) ;Timer with higher priority is already current so return
       Return (tmr.tmr:=DllCall("SetTimer", UInt,0, UInt,0, UInt, 100, UInt,tmr.CBA)) ;call timer again asap
    current:=tmr
    tmr.tick:=ErrorLevel :=Priority ;update tick to launch function on time
    func := tmr.func.(tmr.params*) ;call function
    current= ;reset timer
    if (tmr.OneTime) ;One time timer, deactivate and delete it
       return DllCall("GlobalFree", UInt,tmr.CBA)
             ,tmrs.Remove(tmr.func)
    tmr.tmr:= DllCall("SetTimer", UInt,0, UInt,0, UInt ;reset timer
            ,((A_TickCount-tmr.Tick) > tmr.Period) ? 0 : (tmr.Period-(A_TickCount-tmr.Tick)), UInt,tmr.CBA)
 }
} ;</16.01.000006>
;<16.01.000007>
GlobalVarsScript(var="",size=102400,ByRef object=0) {                                              	;--

  global
  static globalVarsScript
  If (var="")
    Return globalVarsScript
  else if !size {
    If !InStr(globalVarsScript,var ":= CriticalObject(" CriticalObject(object,1) "," CriticalObject(object,2) ")`n"){
      If !CriticalObject(object,1)
        object:=CriticalObject(object)
      globalVarsScript .= var ":= CriticalObject(" CriticalObject(object,1) "," CriticalObject(object,2) ")`n"
    }
  } else {
    Loop,Parse,Var,|
    If !InStr(globalVarsScript,"Alias(" A_LoopField "," GetVar(%A_LoopField%) ")`n"){
      %A_LoopField%:=""
      If size
        VarSetCapacity(%A_LoopField%,size)
      globalVarsScript:=globalVarsScript . "Alias(" A_LoopField "," GetVar(%A_LoopField%) ")`n"
    }
  }
  Return globalVarsScript
} ;</16.01.000007>
;<16.01.000008>
patternScan(pattern, haystackAddress, haystackSize) {                                              	;-- scan for a pattern in memory

	/*                              	DESCRIPTION

        	 Parameters

                         pattern
                                	A string of two digit numbers representing the hex value of each byte of the pattern. The '0x' hex-prefix is not required
                                	?? Represents a wildcard byte (can be any value)
                                	All of the digit groups must be 2 characters long i.e 05, 0F, and ??, NOT 5, F or ?
                                	Spaces, tabs, and 0x hex-prefixes are optional

                         haystackAddress
                                	The memory address of the binary haystack eg &haystack

                         haystackAddress
                                	The byte length of the binary haystack

                         Return values
                          0  	Not Found
                         -1 	An odd number of characters were passed via pattern
                                Ensure you use two digits to represent each byte i.e. 05, 0F and ??, and not 5, F or ?
                         -2   	No valid bytes in the needle/pattern
                         int 	The offset from haystackAddress of the start of the found pattern

	*/


        StringReplace, pattern, pattern, 0x,, All
        StringReplace, pattern, pattern, %A_Space%,, All
        StringReplace, pattern, pattern, %A_Tab%,, All
        pattern := RTrim(pattern, "?")                ; can pass patterns beginning with ?? ?? - but why not just start the pattern with the first known byte
        loopCount := bufferSize := StrLen(pattern) / 2
        if Mod(StrLen(pattern), 2)
        	return -1
        VarSetCapacity(binaryNeedle, bufferSize)
        aOffsets := [], startGap := 0
        loop, % loopCount
        {
        	hexChar := SubStr(pattern, 1 + 2 * (A_Index - 1), 2)
        	if (hexChar != "??") && (prevChar = "??" || A_Index = 1)
                binNeedleStartOffset := A_index - 1
        	else if (hexChar = "??" && prevChar != "??" && A_Index != 1)
        	{

                aOffsets.Insert({ "binNeedleStartOffset": binNeedleStartOffset
                                , "binNeedleSize": A_Index - 1 - binNeedleStartOffset
                                , "binNeedleGap": !aOffsets.MaxIndex() ? 0 : binNeedleStartOffset - startGap + 1}) ; equals number of wildcard bytes between two sub needles
                startGap := A_index
        	}

        	if (A_Index = loopCount) ; last char cant be ??
                aOffsets.Insert({ "binNeedleStartOffset": binNeedleStartOffset
                                , "binNeedleSize": A_Index - binNeedleStartOffset
                                , "binNeedleGap": !aOffsets.MaxIndex() ? 0 : binNeedleStartOffset - startGap + 1})
        	prevChar := hexChar
        	if (hexChar != "??")
        	{
                numput("0x" . hexChar, binaryNeedle, A_index - 1, "UChar")
                realNeedleSize++
        	}
        }
        if !realNeedleSize
        	return -2 ; no valid bytes in the needle

        haystackOffset := 0
        aOffset := aOffsets[arrayIndex := 1]
        loop
        {
        	if (-1 != foundOffset := scanInBuf(haystackAddress, &binaryNeedle + aOffset.binNeedleStartOffset, haystackSize, aOffset.binNeedleSize, haystackOffset))
        	{
                ; either the first subneedle was found, or the current subneedle is the correct distance from the previous subneedle
                ; The scanInBuf returned 'foundOffset' is relative to haystackAddr regardless of haystackOffset
                if (arrayIndex = 1 || foundOffset = haystackOffset)
                {
                	if (arrayIndex = 1)
                	{
                        currentStartOffstet := aOffset.binNeedleSize + foundOffset ; save the offset of the match for the first part of the needle - if remainder of needle doesn't match,  resume search from here
                        tmpfoundAddress := foundOffset
                	}
                	if (arrayIndex = aOffsets.MaxIndex())
                        return foundAddress := tmpfoundAddress - aOffsets[1].binNeedleStartOffset  ;+ haystackAddress ; deduct the first needles starting offset - in case user passed a pattern beginning with ?? eg "?? ?? 00 55"
                	prevNeedleSize := aOffset.binNeedleSize
                	aOffset := aOffsets[++arrayIndex]
                	haystackOffset := foundOffset + prevNeedleSize + aOffset.binNeedleGap   ; move the start of the haystack ready for the next needle - accounting for previous needle size and any gap/wildcard-bytes between the two needles
                	continue
                }
                ; else the offset of the found subneedle was not the correct distance from the end of the previous subneedle
        	}
        	if (arrayIndex = 1) ; couldn't find the first part of the needle
                return 0
        	; the subsequent subneedle couldn't be found.
        	; So resume search from the address immediately next to where the first subneedle was found
        	aOffset := aOffsets[arrayIndex := 1]
        	haystackOffset := currentStartOffstet
        }

} ;</16.01.000008>
;<16.01.000009>
scanInBuf(haystackAddr, needleAddr, haystackSize, needleSize, StartOffset = 0)     {	;-- scan for a pattern in memory buffer
        ;Doesn't WORK with AHK 64 BIT, only works with AHK 32 bit
	/*                              	DESCRIPTION

        	;taken from:
                ;http://www.autohotkey.com/board/topic/23627-machine-code-binary-buffer-searching-regardless-of-null/
                ; -1 not found else returns offset address (starting at 0)
                ; The returned offset is relative to the haystackAddr regardless of StartOffset
                	static fun

	*/


        ; AHK32Bit a_PtrSize = 4 | AHK64Bit - 8 bytes
        if (a_PtrSize = 8)
          return -1

        ifequal, fun,
        {
          h =
          (  LTrim join
             5589E583EC0C53515256579C8B5D1483FB000F8EC20000008B4D108B451829C129D9410F8E
             B10000008B7D0801C78B750C31C0FCAC4B742A4B742D4B74364B74144B753F93AD93F2AE0F
             858B000000391F75F4EB754EADF2AE757F3947FF75F7EB68F2AE7574EB628A26F2AE756C38
             2775F8EB569366AD93F2AE755E66391F75F7EB474E43AD8975FC89DAC1EB02895DF483E203
             8955F887DF87D187FB87CAF2AE75373947FF75F789FB89CA83C7038B75FC8B4DF485C97404
             F3A775DE8B4DF885C97404F3A675D389DF4F89F82B45089D5F5E5A595BC9C2140031C0F7D0
             EBF0
          )
          varSetCapacity(fun, strLen(h)//2)
          loop % strLen(h)//2
             numPut("0x" . subStr(h, 2*a_index-1, 2), fun, a_index-1, "char")
        }

        return DllCall(&fun, "uInt", haystackAddr, "uInt", needleAddr
                      , "uInt", haystackSize, "uInt", needleSize, "uInt", StartOffset)
} ;</16.01.000009>
;<16.01.000010>
hexToBinaryBuffer(hexString, byRef buffer) {                                                              	;--

	StringReplace, hexString, hexString, 0x,, All
	StringReplace, hexString, hexString, %A_Space%,, All
	StringReplace, hexString, hexString, %A_Tab%,, All
	if !length := strLen(hexString)
	{
        msgbox nothing was passed to hexToBinaryBuffer
        return 0
	}
	if mod(length, 2)
	{
        msgbox Odd Number of characters passed to hexToBinaryBuffer`nEnsure two digits are used for each byte e.g. 0E
        return 0
	}
	byteCount := length/ 2
	VarSetCapacity(buffer, byteCount)
	loop, % byteCount
        numput("0x" . substr(hexString, 1 + (A_index - 1) * 2, 2), buffer, A_index - 1, "UChar")
	return byteCount

} ;</16.01.000010>
;<16.01.000011>
RegRead64(sRootKey, sKeyName, sValueName = "", DataMaxSize=1024) {              	;-- Provides RegRead64() function that do not redirect to Wow6432Node on 64-bit machines (for ansi- and unicode)

	; _reg64.ahk ver 0.1 by tomte
	; Script for AutoHotkey   ( http://www.autohotkey.com/ )
	;
	; Provides RegRead64() and RegWrite64() functions that do not redirect to Wow6432Node on 64-bit machines
	; RegRead64() and RegWrite64() takes the same parameters as regular AHK RegRead and RegWrite commands, plus one optional DataMaxSize param for RegRead64()
	;
	; RegRead64() can handle the same types of values as AHK RegRead:
	; REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD, and REG_BINARY
	; (values are returned in same fashion as with RegRead - REG_BINARY as hex string, REG_MULTI_SZ split with linefeed etc.)
	;
	; RegWrite64() can handle REG_SZ, REG_EXPAND_SZ and REG_DWORD only
	;
	; Usage:
	; myvalue := RegRead64("HKEY_LOCAL_MACHINE", "SOFTWARE\SomeCompany\Product\Subkey", "valuename")
	; RegWrite64("REG_SZ", "HKEY_LOCAL_MACHINE", "SOFTWARE\SomeCompany\Product\Subkey", "valuename", "mystring")
	; If the value name is blank/omitted the subkey's default value is used, if the value is omitted with RegWrite64() a blank/zero value is written
	;

	HKEY_CLASSES_ROOT   := 0x80000000   ; http://msdn.microsoft.com/en-us/library/aa393286.aspx
    HKEY_CURRENT_USER   := 0x80000001
    HKEY_LOCAL_MACHINE  := 0x80000002
    HKEY_USERS          := 0x80000003
    HKEY_CURRENT_CONFIG := 0x80000005
    HKEY_DYN_DATA       := 0x80000006
    HKCR := HKEY_CLASSES_ROOT
    HKCU := HKEY_CURRENT_USER
    HKLM := HKEY_LOCAL_MACHINE
    HKU  := HKEY_USERS
    HKCC := HKEY_CURRENT_CONFIG

    REG_NONE                := 0    ; http://msdn.microsoft.com/en-us/library/ms724884.aspx
    REG_SZ                  := 1
    REG_EXPAND_SZ           := 2
    REG_BINARY              := 3
    REG_DWORD               := 4
    REG_DWORD_BIG_ENDIAN    := 5
    REG_LINK                := 6
    REG_MULTI_SZ            := 7
    REG_RESOURCE_LIST       := 8

    KEY_QUERY_VALUE := 0x0001   ; http://msdn.microsoft.com/en-us/library/ms724878.aspx
    KEY_WOW64_64KEY := 0x0100   ; http://msdn.microsoft.com/en-gb/library/aa384129.aspx (do not redirect to Wow6432Node on 64-bit machines)
    KEY_SET_VALUE   := 0x0002
    KEY_WRITE       := 0x20006
    ENC := A_IsUnicode?"W":"A"
    hKey := "", sValueType := ""

    myhKey := %sRootKey%        ; pick out value (0x8000000x) from list of HKEY_xx vars
    IfEqual,myhKey,, {      ; Error - Invalid root key
        ErrorLevel := 3
        return ""
    }
    RegAccessRight := KEY_QUERY_VALUE + KEY_WOW64_64KEY
    ;VarSetCapacity(sValueType, 4)
    DllCall("Advapi32.dll\RegOpenKeyEx" ENC, "uint", myhKey, "str", sKeyName, "uint", 0, "uint", RegAccessRight, "uint*", hKey)    ; open key
    DllCall("Advapi32.dll\RegQueryValueEx" ENC, "uint", hKey, "str", sValueName, "uint", 0, "uint*", sValueType, "uint", 0, "uint", 0)     ; get value type
    If (sValueType == REG_SZ or sValueType == REG_EXPAND_SZ) {
        VarSetCapacity(sValue, vValueSize:=DataMaxSize)
        DllCall("Advapi32.dll\RegQueryValueEx" ENC, "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sValue, "uint*", vValueSize) ; get string or string-exp
    } Else If (sValueType == REG_DWORD) {
        VarSetCapacity(sValue, vValueSize:=4)
        DllCall("Advapi32.dll\RegQueryValueEx" ENC, "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "uint*", sValue, "uint*", vValueSize)   ; get dword
    } Else If (sValueType == REG_MULTI_SZ) {
        VarSetCapacity(sTmp, vValueSize:=DataMaxSize)
        DllCall("Advapi32.dll\RegQueryValueEx" ENC, "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sTmp, "uint*", vValueSize)   ; get string-mult
        sValue := ExtractData(&sTmp) "`n"
        Loop {
            If (errorLevel+2 >= &sTmp + vValueSize)
                Break
            sValue := sValue ExtractData( errorLevel+1 ) "`n"
        }
    } Else If (sValueType == REG_BINARY) {
        VarSetCapacity(sTmp, vValueSize:=DataMaxSize)
        DllCall("Advapi32.dll\RegQueryValueEx" ENC, "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sTmp, "uint*", vValueSize)   ; get binary
        sValue := ""
        SetFormat, integer, h
        Loop %vValueSize% {
            hex := SubStr(Asc(SubStr(sTmp,A_Index,1)),3)
            StringUpper, hex, hex
            sValue := sValue hex
        }
        SetFormat, integer, d
    } Else {                ; value does not exist or unsupported value type
        DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
        ErrorLevel := 1
        return ""
    }
    DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
    return sValue
} ;</16.01.000011>
;<16.01.000012>
RegWrite64(sValueType, sRootKey, sKeyName, sValueName = "", sValue = "") {      	;-- RegWrite64() function that do not redirect to Wow6432Node on 64-bit machines

	HKEY_CLASSES_ROOT         	:= 0x80000000                        	; http://msdn.microsoft.com/en-us/library/aa393286.aspx
	HKEY_CURRENT_USER        	:= 0x80000001
	HKEY_LOCAL_MACHINE      	:= 0x80000002
	HKEY_USERS                        	:= 0x80000003
	HKEY_CURRENT_CONFIG    	:= 0x80000005
	HKEY_DYN_DATA                	:= 0x80000006
	HKCR                                   	:= HKEY_CLASSES_ROOT
	HKCU                                   	:= HKEY_CURRENT_USER
	HKLM                                  	:= HKEY_LOCAL_MACHINE
	HKU	                                    	:= HKEY_USERS
	HKCC                                   	:= HKEY_CURRENT_CONFIG

	REG_NONE                          	:= 0                                          	; http://msdn.microsoft.com/en-us/library/ms724884.aspx
	REG_SZ                                	:= 1
	REG_EXPAND_SZ                		:= 2
	REG_BINARY                        	:= 3
	REG_DWORD                       	:= 4
	REG_DWORD_BIG_ENDIAN		:= 5
	REG_LINK                            	:= 6
	REG_MULTI_SZ                    	:= 7
	REG_RESOURCE_LIST          	:= 8

	KEY_QUERY_VALUE             	:= 0x0001                                	; http://msdn.microsoft.com/en-us/library/ms724878.aspx
	KEY_WOW64_64KEY            	:= 0x0100                                	; http://msdn.microsoft.com/en-gb/library/aa384129.aspx (do not redirect to Wow6432Node on 64-bit machines)
	KEY_SET_VALUE                   	:= 0x0002
	KEY_WRITE                          	:= 0x20006

	myhKey := %sRootKey%                                                         	; pick out value (0x8000000x) from list of HKEY_xx vars
	myValueType := %sValueType%                                            		; pick out value (0-8) from list of REG_SZ,REG_DWORD etc. types
	IfEqual,myhKey,, {                                                                    	; Error - Invalid root key
		ErrorLevel := 3
		return ErrorLevel
	}
	IfEqual,myValueType,, {                                                           	; Error - Invalid value type
		ErrorLevel := 2
		return ErrorLevel
	}

	RegAccessRight := KEY_QUERY_VALUE + KEY_WOW64_64KEY + KEY_WRITE

	DllCall("Advapi32.dll\RegCreateKeyExA", "uint", myhKey, "str", sKeyName, "uint", 0, "uint", 0, "uint", 0, "uint", RegAccessRight, "uint", 0, "uint*", hKey)	; open/create key
	If (myValueType == REG_SZ or myValueType == REG_EXPAND_SZ) {
		vValueSize := StrLen(sValue) + 1
		DllCall("Advapi32.dll\RegSetValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", myValueType, "str", sValue, "uint", vValueSize)	; write string
	} Else If (myValueType == REG_DWORD) {
		vValueSize := 4
		DllCall("Advapi32.dll\RegSetValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", myValueType, "uint*", sValue, "uint", vValueSize)	; write dword
	} Else {		; REG_MULTI_SZ, REG_BINARY, or other unsupported value type
		ErrorLevel := 2
	}
	DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
	return ErrorLevel
}
{ ;sub
ExtractData(pointer) {

	; Thanks Chris, Lexikos and SKAN
	; http://www.autohotkey.com/forum/topic37710-15.html
	; http://www.autohotkey.com/forum/viewtopic.php?p=235522
	 ; http://www.autohotkey.com/forum/viewtopic.php?p=91578#91578 SKAN

	Loop {
			errorLevel := ( pointer+(A_Index-1) )
			Asc := *( errorLevel )
			IfEqual, Asc, 0, Break ; Break if NULL Character
			String := String . Chr(Asc)
		}
	Return String
}
}  ;</16.01.000012>
;<16.01.000013>
KillProcess(proc) {                                                                                                        	;-- uses DllCalls to end a process

	; https://autohotkey.com/board/topic/119052-check-if-a-process-exists-if-it-does-kill-it/page-2

    static SYNCHRONIZE                 := 0x00100000
    static STANDARD_RIGHTS_REQUIRED    := 0x000F0000
    static OSVERSION                   := (A_OSVersion = "WIN_XP" ? 0xFFF : 0xFFFF)
    static PROCESS_ALL_ACCESS          := STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | OSVERSION

    local tPtr := pPtr := nTTL := 0, PList := ""
    if !(DllCall("wtsapi32.dll\WTSEnumerateProcesses", "Ptr", 0, "Int", 0, "Int", 1, "PtrP", pPtr, "PtrP", nTTL))
        return "", DllCall("kernel32.dll\SetLastError", "UInt", -1)

    tPtr := pPtr
    loop % (nTTL)
    {
        if (InStr(PList := StrGet(NumGet(tPtr + 8)), proc))
        {
            PID := NumGet(tPtr + 4, "UInt")
            if !(hProcess := DllCall("kernel32.dll\OpenProcess", "UInt", PROCESS_ALL_ACCESS, "UInt", FALSE, "UInt", PID, "Ptr"))
                return DllCall("kernel32.dll\GetLastError")
            if !(DllCall("kernel32.dll\TerminateProcess", "Ptr", hProcess, "UInt", 0))
                return DllCall("kernel32.dll\GetLastError")
            if !(DllCall("kernel32.dll\CloseHandle", "Ptr", hProcess))
                return DllCall("kernel32.dll\GetLastError")
        }
        tPtr += (A_PtrSize = 4 ? 16 : 24)
    }
    DllCall("wtsapi32.dll\WTSFreeMemory", "Ptr", pPtr)

    return "", DllCall("kernel32.dll\SetLastError", "UInt", nTTL)
} ;</16.01.000013>
;<16.01.000014>
LoadScriptResource(ByRef Data, Name, Type = 10) {                                                 	;-- loads a resource into memory (e.g. picture, scripts..)

	;https://autohotkey.com/board/topic/77519-load-and-display-imagespng-jpg-with-loadscriptresource/

	/*	 example script demonstrates showing an icon image from the resource. It requires sample.ico with the size 64x64 in the script folder.

		#NoEnv
		SetWorkingDir %A_ScriptDir%

		if A_IsCompiled {
			If size := LoadScriptResource(buf,".\sample.ico")
                hIcon := HIconFromBuffer(buf, 64, 64)
			else MsgBox Resource could not be loaded!
		} else {
			FileRead, buf, *c %A_ScriptDir%\sample.ico
			hIcon := HIconFromBuffer(buf, 64, 64)
		}

		Gui, Margin, 20, 20
		Gui, Add, Picture, w64 h64 0x3 hWndPic1      	;0x3 = SS_ICon
		SendMessage, STM_SETICON := 0x0170, hIcon, 0,, ahk_id %Pic1%
		Gui, Show

		Return
		GuiClose:
		   Gui, Destroy
		   hIcon := hIcon := ""
		   ExitApp
		Return


	*/

	; originally posted by Lexikos, modified by HotKeyIt
	; http://www.autohotkey.com/forum/post-516086.html#516086

    lib := DllCall("GetModuleHandle", "ptr", 0, "ptr")
    res := DllCall("FindResource", "ptr", lib, "str", Name, "ptr", Type, "ptr")
    DataSize := DllCall("SizeofResource", "ptr", lib, "ptr", res, "uint")
    hresdata := DllCall("LoadResource", "ptr", lib, "ptr", res, "ptr")
    VarSetCapacity(Data, DataSize)
    DllCall("RtlMoveMemory", "PTR", &Data, "PTR", DllCall("LockResource", "ptr", hresdata, "ptr"), "UInt", DataSize)
    return DataSize
} ;</16.01.000014>
;<16.01.000015>
HIconFromBuffer(ByRef Buffer, width, height) {                                                           	;-- Function provides a HICON handle e.g. from a resource previously loaded into memory (LoadScriptResource)

	;Ptr := Ptr ? "Ptr" : "Uint"	; For AutoHotkey Basic Users
	hIcon := DllCall( "CreateIconFromResourceEx"
        , UInt, &Buffer+22
        , UInt, NumGet(Buffer,14)
        , Int,1
        , UInt, 0x30000
        , Int, width
        , Int, height
        , UInt, 0
        , Ptr)
	return hIcon
} ;</16.01.000015>
;<16.01.000016>
hBMPFromPNGBuffer(ByRef Buffer, width, height) {                                                   	;-- Function provides a hBitmap handle e.g. from a resource previously loaded into memory (LoadScriptResource)

	;modified SKAN's code ; http://www.autohotkey.com/forum/post-147052.html#147052

	; for AutoHotkey Basic users
	; Ptr := A_PtrSize ? "Ptr" : "Uint" , PtrP := A_PtrSize ? "PtrP" : "UIntP"

	nSize := StrLen(Buffer) * 2 ;// 2 ; <-- I don't understand why it has to be multiplied by 2
	hData := DllCall("GlobalAlloc", UInt, 2, UInt, nSize, Ptr)
	pData := DllCall("GlobalLock", Ptr, hData , Ptr)
	DllCall( "RtlMoveMemory", Ptr, pData, Ptr,&Buffer, UInt,nSize )
	DllCall( "GlobalUnlock", Ptr, hData )
	DllCall( "ole32\CreateStreamOnHGlobal", Ptr, hData, Int, True, PtrP, pStream )
	DllCall( "LoadLibrary", Str,"gdiplus" )
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall( "gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, UInt,0 )
	DllCall( "gdiplus\GdipCreateBitmapFromStream", Ptr, pStream, PtrP, pBitmap )
	DllCall( "gdiplus\GdipCreateHBITMAPFromBitmap", Ptr,pBitmap, PtrP, hBitmap, UInt,0)

	hNewBitMap := DllCall("CopyImage"
          , Ptr, hBitmap
          , UInt, 0
          , Int, width
          , Int, height
          , UInt, 0x00000008      ;LR_COPYDELETEORG
          , Ptr)

	DllCall( "gdiplus\GdipDisposeImage", Ptr, pBitmap )
	DllCall( "gdiplus\GdiplusShutdown", Ptr, pToken )
	DllCall( NumGet(NumGet(1*pStream)+8), Ptr, pStream )

	Return hNewBitMap
} ;</16.01.000016>
;<16.01.000017>
SaveSetColours(set := False, liteSet := True) {                                                	            	;-- Sys colours saving adapted from an approach found in Bertrand Deo's code

	; https://gist.github.com/qwerty12/110b6e68faa60a0145198722c8b8c291
	; The rest is from Michael Maltsev: https://github.com/RaMMicHaeL/Windows-10-Color-Control
	static DWMCOLORIZATIONPARAMS, IMMERSIVE_COLOR_PREFERENCE
           ,DwmGetColorizationParameters := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleW", "WStr", "dwmapi.dll", "Ptr"), "Ptr", 127, "Ptr")
           ,DwmSetColorizationParameters := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleW", "WStr", "dwmapi.dll", "Ptr"), "Ptr", 131, "Ptr")
           ,GetUserColorPreference := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleW", "WStr", "uxtheme.dll", "Ptr"), "AStr", "GetUserColorPreference", "Ptr")
           ,SetUserColorPreference := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleW", "WStr", "uxtheme.dll", "Ptr"), "Ptr", 122, "Ptr")
           ,WM_SYSCOLORCHANGE := 0x0015, sys_colours, sav_colours, colourCount := 31, GetSysColor := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleW", "WStr", "user32.dll", "Ptr"), "AStr", "GetSysColor", "Ptr")
	if (!set) {
        if (!VarSetCapacity(DWMCOLORIZATIONPARAMS)) {
        	VarSetCapacity(sys_colours, 4 * colourCount)
        	,VarSetCapacity(sav_colours, 4 * colourCount)
        	VarSetCapacity(DWMCOLORIZATIONPARAMS, 28)
        	,VarSetCapacity(IMMERSIVE_COLOR_PREFERENCE, 8)
        	Loop % colourCount
                NumPut(A_Index - 1, sys_colours, 4 * (A_Index - 1))
        }
        Loop % colourCount
        	NumPut(DllCall(GetSysColor, "Int", A_Index - 1, "UInt"), sav_colours, 4 * (A_Index - 1), "UInt")
        DllCall(DwmGetColorizationParameters, "Ptr", &DWMCOLORIZATIONPARAMS)
        DllCall(GetUserColorPreference, "Ptr", &IMMERSIVE_COLOR_PREFERENCE, "Int", False)
	} else {
        if (!liteSet)
        	DllCall("SetSysColors", "int", colourCount, "Ptr", &sys_colours, "Ptr", &sav_colours)
        if (VarSetCapacity(DWMCOLORIZATIONPARAMS)) {
        	if (!liteSet)
                DllCall(DwmSetColorizationParameters, "Ptr", &DWMCOLORIZATIONPARAMS, "UInt", 0)
        	DllCall(SetUserColorPreference, "Ptr", &IMMERSIVE_COLOR_PREFERENCE, "Int", True)
        }
	}
} ;</16.01.000017>
;<16.01.000018>
ChangeMacAdress() {                                                                                                  	;-- change MacAdress, it makes changes to the registry!

        ; http://ahkscript.org/germans/forums/viewtopic.php?t=8423 from ILAN12346
        ; Caution: Really only change if you know what a MAC address is or what you are doing.
        ; I do not assume any liability for any damages!

        Rootkey := "HKEY_LOCAL_MACHINE"
        ValueName := "DriverDesc"
        loop
        {
          Subkey := "SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\" . num := "00" . (A_Index < 10  ? "0" . A_Index : A_Index)
          RegRead, name, % Rootkey, % Subkey, % ValueName
          if name
        	nwa .= name . "***" . num . (A_Index = 1 ? "||" : "|")
          Else
        	break
        }
        gui, Font, s10
        Gui, Add, Edit, x10 y40 w260 h20 +Center vmac,
        Gui, Add, DropDownList, x10 y10 w260 h20 r10 vselect gselect, % RegExReplace(nwa, "\*\*\*", _
                                        	  . "                                                   *")
        Gui, Add, Button, x280 y10 w60 h50 gset , Set Mac
        Gui, Show, x270 y230 h70 w350, MAC
        ValueName := "NetworkAddress"
        Return

        select:
          gui, submit, NoHide
          Subkey := "SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\" . substr(select,instr(select, "*")+1)
          RegRead, macaddr, % Rootkey, % Subkey, % ValueName
          GuiControl,, mac, % macaddr
        Return

        set:
          gui, submit, NoHide
          link := "SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\" . substr(select,instr(select, "*")+1)
          RegRead, macaddr, % Rootkey, % Subkey, % ValueName
          newmac := RegExReplace(RegExReplace(mac, "-", ""), " ","")
          StringLower, newmac, newmac
          maccheck := "0x" . newmac
          if (strlen(newmac)=12 && (maccheck+1)) || !strlen(newmac)
        	RegWrite, REG_SZ, % RootKey, % SubKey , % ValueName, % newmac
          Else
        	MsgBox,16, Error, Incorrect MAC address
        	MsgBox, 48,Successful, New MAC Address Acquired
        	MsgBox, 36,Reconnect?,The network adapter needs to be reconnected. `n`n reconnect now?
        	 IfMsgBox, Yes
        	  Run, "ipconfig.exe" -renew,,Hide
        Return

        GuiClose:
          ExitApp

} ;</16.01.000018>
;<16.01.000019>
ListAHKStats(Section="ListVars") {                                                                              	;-- Select desired section: ListLines, ListVars, ListHotkeys, KeyHistory

	; Based on the "ListVars" feature of Lexikos
	; http://www.autohotkey.com/forum/post-165430.html#165430
	; extensions MEC: http://ahkscript.org/germans/forums/viewtopic.php?t=8080
	; Select desired section: ListLines, ListVars, ListHotkeys, KeyHistory
	; Passed data KeyHistory cleaned up with explanatory text

    static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
    if !hwndEdit
    {
        dhw := A_DetectHiddenWindows
        DetectHiddenWindows, On
        Process, Exist
        ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
        DetectHiddenWindows, %dhw%

        astr := A_IsUnicode ? "astr":"str"
        ptr := A_PtrSize=8 ? "ptr":"uint"
        hmod := DllCall("GetModuleHandle", "str", "user32.dll")
        pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
        pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
        DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
        DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
        bkpSFW := NumGet(pSFW+0, 0, "int64")
        bkpSW := NumGet(pSW+0, 0, "int64")
    }

    if (A_PtrSize=8) {
        NumPut(0x0000C300000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0000C300000001B8, pSW+0, 0, "int64")   ; return TRUE
    } else {
        NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
    }

      ;added by MEC:
      ;Section: "ListLines","ListVars","ListHotkeys","KeyHistory"
      If (Section="ListLines")
         ListLines
      Else
         If (Section="ListVars")
            ListVars
         Else
            If (Section="ListHotkeys")
               ListHotkeys
            Else
               KeyHistory

    NumPut(bkpSFW, pSFW+0, 0, "int64")
    NumPut(bkpSW, pSW+0, 0, "int64")

    ControlGetText, text,, ahk_id %hwndEdit%

      ;---MEC: Text explanations cut out and out with them
      If (Section="KeyHistory") {
         pos:=InStr(text, "NOTE:" ,"", 200)
         text1:=SubStr(text, 1, pos-1)
         pos:=InStr(text, "#IfWinActive/Exist" ,"", pos)
         text:=SubStr(text, pos +23)
         text:=text1 . text
         }
    return text
} ;</16.01.000019>
;<16.01.000020>
MouseExtras(HoldSub, HoldTime="200", DoubleSub=""                                           	;-- Allows to use subroutines for Holding and Double Clicking a Mouse Button.
, DClickTime="0.2", Button="") {

	; Author: Pulover [Rodolfo U. Batista]
	; rodolfoub@gmail.com

	/*        Description
		- Allows to use subroutines for Holding and Double Clicking a Mouse Button.
		- Keeps One-Click and Drag functions.
		- Works with combinations, i.e. LButton & RButton.

		Usage:
		Assign the function to the Mouse Hotkey and input the Labels to
		trigger with GoSub and wait times in the parameters:

		MouseExtras("HoldSub", "DoubleSub", "HoldTime", "DClickTime", "Button")
		  HoldSub: Button Hold Label.
		  HoldTime: Wait Time to Hold Button (miliseconds - optional).
		  DoubleSub: Double Click Label.
		  DClickTime: Wait Time for Double Click (seconds - optional).
		  Button: Choose a different Button (optional - may be useful for combinations).

		- If you don't want to use a certain function put "" in the label.
		- I recommend using the "*" prefix to allow them to work with modifiers.
		- Note: Althought it's designed for MouseButtons it will work with Keyboard as well.
	*/

    If Button =
		Button := A_ThisHotkey
	Button := LTrim(Button, "~*$")
	If InStr(Button, "&")
		Button := RegExReplace(Button, "^.*&( +)?")
	MouseGetPos, xpos
	Loop
	{
		MouseGetPos, xposn
		If (A_TimeSinceThisHotkey > HoldTime)
		{
			If IsLabel(HoldSub)
                GoSub, %HoldSub%
			Else
			{
                Send {%Button% Down}
                KeyWait, %Button%
                Send {%Button% Up}
			}
			return
		}
		Else
		If (xpos <> xposn)
		{
			Send {%Button% Down}
			KeyWait, %Button%
			Send {%Button% Up}
			return
		}
		Else
		If !GetKeyState(Button, "P")
		{
			If !IsLabel(DoubleSub)
			{
                Send {%Button%}
                return
			}
			KeyWait, %Button%, D T%DClickTime%
			If ErrorLevel
                Send {%Button%}
			Else
			{
                If IsLabel(DoubleSub)
                	GoSub, %DoubleSub%
                Else
                	Send {%Button%}
			}
			return
		}
	}
} ;</16.01.000020>
;<16.01.000021>
TimedFunction( _Label, _Params = 0, _Period = 250 ) {                                              	;-- SetTimer functionality for functions

    /*
    MIT License
    Copyright (c) 2017 Gene Alyson Fortunado Torcende
    */

    static _List := []
    if IsFunc( _Label ) {
        if _List.HasKey( _Label ) {
            _Func := _List[_Label]
            _Timer := _Func.TID
            if ( _Period = "Off" ) {
                SetTimer, % _Timer, OFF
                _List.Remove( _Label )
                return
            }
            else
                return _List[ _Label ]
        }
        _Timer := Func( _Label ).Bind( _Params* )
        SetTimer, % _Timer, % _Period
        return _List[_Label] := { Function: _Label, Parameters: _Params, Period: _Period, TID: _Timer }
    }

} ;</16.01.000021>
;<16.01.000022>
ListGlobalVars() {                                                                                                         	;-- ListGlobalVars() neither shows nor activates the AutoHotkey main window, it returns a string

	; Written by Lexikos - see: http://www.autohotkey.com/board/topic/20925-listvars/#entry156570
	/*		examples
		Loop {
			tick := A_TickCount
			ToolTip % ListGlobalVars()
		}
	*/

    static hwndEdit, pSFW, pSW, bkpSFW, bkpSW

    if !hwndEdit
    {
        dhw := A_DetectHiddenWindows
        DetectHiddenWindows, On
        Process, Exist
        ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
        DetectHiddenWindows, %dhw%

        astr := A_IsUnicode ? "astr":"str"
        ptr := A_PtrSize=8 ? "ptr":"uint"
        hmod := DllCall("GetModuleHandle", "str", "user32.dll")
        pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
        pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
        DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
        DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
        bkpSFW := NumGet(pSFW+0, 0, "int64")
        bkpSW := NumGet(pSW+0, 0, "int64")
    }

    if (A_PtrSize=8) {
        NumPut(0x0000C300000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0000C300000001B8, pSW+0, 0, "int64")   ; return TRUE
    } else {
        NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
    }

    ListVars

    NumPut(bkpSFW, pSFW+0, 0, "int64")
    NumPut(bkpSW, pSW+0, 0, "int64")

    ControlGetText, text,, ahk_id %hwndEdit%

    RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
    return text
} ;</16.01.000022>
;<16.01.000023>
TaskList(delim:="|", getArray:=0, sort:=0) {		                                                            	;-- list all running tasks (no use of COM)

		;https://github.com/Lateralus138/Task-Lister

		d := delim
		s := 4096
		Process, Exist
		h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
		DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
		VarSetCapacity(ti, 16, 0)
		NumPut(1, ti, 0, "UInt")
		DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
		NumPut(luid, ti, 4, "Int64")
		NumPut(2, ti, 12, "UInt")
		r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
		DllCall("CloseHandle", "Ptr", t)
		DllCall("CloseHandle", "Ptr", h)
		hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")
		s := VarSetCapacity(a, s)
		c := 0
		DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
		Loop, % r // 4
		{
		   id := NumGet(a, A_Index * 4, "UInt")
		   h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
		   if !h
			  continue
		   VarSetCapacity(n, s, 0)
		   e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
		   if !e
			  if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
                {
                	 SplitPath, n, n
                }
		   DllCall("CloseHandle", "Ptr", h)
		   if (n && e)
			  l .= n . d, c++
		}
		DllCall("FreeLibrary", "Ptr", hModule)
		l:=SubStr(l,1,StrLen(l)-1) " " ndir
		If getArray
			{
                proc:=!proc?Object():""
                Loop, Parse, l, |
                	proc.Push(A_LoopField)
			}
		If sort
			Sort, l, D%delim%
		Return getArray?proc:l
} ;</16.01.000023>
;<16.01.000024>
MouseDpi(mode_speed:=0) {                                                                                      	;-- Change the current dpi setting of the mouse

	; https://github.com/Lateralus138/OnTheFlyDpi/blob/master/ontheflydpi_funcs.ahk
	DllCall("SystemParametersInfo","UInt",0x70,"UInt",0,"UIntP",_current_,"UInt",0)
	If mode_speed Is Not Number
		{
			If (InStr(mode_speed,"reset") And (_current_!=10)){
                DllCall("SystemParametersInfo","UInt",0x71,"UInt",0,"UInt",10,"UInt",0)
                DllCall("SystemParametersInfo","UInt",0x70,"UInt",0,"UIntP",_current_,"UInt",0)
			}
			Return _current_
		}
	mode_speed	:=(mode_speed!=0 And mode_speed>20)?20
                :(mode_speed!=0 And mode_speed<0)?1
                :mode_speed
	If (mode_speed!=0 And (_current_!=mode_speed))
		DllCall("SystemParametersInfo","UInt",0x71,"UInt",0,"UInt",mode_speed,"UInt",0)
	Return !mode_speed?_current_:mode_speed
} ;</16.01.000024>
;<16.01.000025>
SendToAHK(String, WinString) {                                                                                  	;-- Sends strings by using a hidden gui between AHK scripts

	/*                              	EXAMPLE(s) will be found in ReceiveFromAHK() function
	*/

	/*                              	DESCRIPTION

		a function by DJAnonimo: posted on https://autohotkey.com/boards/viewtopic.php?f=6&t=45965
		with a bit modification by Ixiko

		added 'WinString' option to handle different windows
		you have to paste a string like WinString:="MyGuiWinTitle" or WinString:="ahk_exe MyAHKScript"
		you can paste also WinString:="ahk_id " . MyGuiHwnd

	*/

	Prev_DetectHiddenWindows := A_DetectHiddenWindows
	DetectHiddenWindows On
	StringLen := StrLen(String)
	Loop, %StringLen%
	{
	AscNum := Asc(SubStr(String, A_Index, 1))
	if (A_Index = StringLen)
		LastChar := 1
	PostMessage, 0x5555, AscNum, LastChar,,%WinString%
	}
	DetectHiddenWindows %Prev_DetectHiddenWindows%
} ;</16.01.000025>
;<16.01.000026>
ReceiveFromAHK(wParam, lParam, Msg) {                                                                  	;-- Receiving strings from SendToAHK

	/*                              	EXAMPLE(s)

			gui, new,, AHK
			OnMessage(0x5555, "ReceiveFromAHK")
			SetTimer, MyTimer, 100


			MyTimer:
                if receivedVar
                Received_String := receivedVar, receivedVar := ""
                Msgbox "%Received_String%"

			return

	*/

	global tempVar
	global receivedVar
		if (Msg = 0x5555)
			{
			tempVar .= Chr(wParam)
			if lParam
                receivedVar := tempVar, tempVar := ""
			}

} ;</16.01.000026>
;<16.01.000027>
GetUIntByAddress(_addr, _offset = 0) {                                                                       	;-- get UInt direct from memory. I found this functions only within one script
	/*                              	DESCRIPTION

			Origin: https://autohotkey.com/board/topic/15950-treeview-with-tooltip-tvn-getinfotip-notification/

	*/
	local result
	Loop 4
	{
		result += *(_addr + _offset + A_Index-1) << 8*(A_Index-1)
	}
	Return result
} ;</16.01.000027>
;<16.01.000028>
SetUIntByAddress(_addr, _integer, _offset = 0) {                                                	        	;-- write UInt direct to memory
	/*                              	DESCRIPTION

			Origin: https://autohotkey.com/board/topic/15950-treeview-with-tooltip-tvn-getinfotip-notification/

	*/
	Loop 4
	{
		DllCall("RtlFillMemory"
                , "UInt", _addr + _offset + A_Index-1
                , "UInt", 1
                , "UChar", (_integer >> 8*(A_Index-1)) & 0xFF)
	}
} ;</16.01.000028>
;<16.01.000029>
SetRestrictedDacl() {                                                                                                    	;-- run this in your script to hide it from Task Manager

	/*                              	DESCRIPTION

			Link: https://autohotkey.com/boards/viewtopic.php?t=43235
			By:	qwerty12

			Description: Paste the following functions in somewhere and call SetRestrictedDacl() on startup of your script.
			It's not foolproof: an admin can always kill the process (even without the explicit PROCESS_ALL_ACCESS granted to it) and given that the owner of the process is you,
			if a person knows how to re-add the process's missing rights back to its object, then there's nothing stopping them from doing so.

			(Note: under default UAC settings, when Task Manager is launched it will automatically be elevated if your account is part of the Administrators group.)

	*/

	ret := False

	hCurProc := DllCall("GetCurrentProcess", "Ptr")
	if (!DllCall("advapi32\OpenProcessToken", "Ptr", hCurProc, "UInt", TOKEN_QUERY := 0x0008, "Ptr*", hToken))
		return ret

	if (!_GetTokenInformation(hToken, TokenUser := 1, 0, 0, dwLengthNeeded))
		if (A_LastError == 122 && VarSetCapacity(TOKEN_USER, dwLengthNeeded)) ; ERROR_INSUFFICIENT_BUFFER
			if (_GetTokenInformation(hToken, TokenUser, &TOKEN_USER, dwLengthNeeded, dwLengthNeeded)) {
                SECURITY_MAX_SID_SIZE := 68
                SIDs := {"WinWorldSid": "1", "WinLocalSystemSid": "22", "WinBuiltinAdministratorsSid": "26"}
                for k, v in SIDs {
                	SIDs.SetCapacity(k, (cbSid := SECURITY_MAX_SID_SIZE))
                	if (!DllCall("advapi32\CreateWellKnownSid", "UInt", v+0, "Ptr", 0, "Ptr", SIDs.GetAddress(k), "UInt*", cbSid)) {
                		DllCall("CloseHandle", "Ptr", hToken)
                		return ret
                	}
                }

                EA := [{ "grfAccessPermissions": PROCESS_ALL_ACCESS := (STANDARD_RIGHTS_REQUIRED := 0x000F0000) | (SYNCHRONIZE := 0x00100000) | 0xFFFF ; 0xFFF for XP and 2000
                		,"grfAccessMode":        GRANT_ACCESS := 1
                		,"grfInheritance":       NO_INHERITANCE := 0
                		,"TrusteeForm":          TRUSTEE_IS_SID := 0
                		,"TrusteeType":          TRUSTEE_IS_WELL_KNOWN_GROUP := 5
                		,"ptstrName":            SIDs.GetAddress("WinLocalSystemSid")}
                	  ,{ "grfAccessPermissions": PROCESS_ALL_ACCESS
                		,"grfAccessMode":        GRANT_ACCESS
                		,"grfInheritance":       NO_INHERITANCE
                		,"TrusteeForm":          TRUSTEE_IS_SID
                		,"TrusteeType":          TRUSTEE_IS_WELL_KNOWN_GROUP
                		,"ptstrName":            SIDs.GetAddress("WinBuiltinAdministratorsSid")}
                	  ,{ "grfAccessPermissions": PROCESS_QUERY_LIMITED_INFORMATION := 0x1000 | PROCESS_CREATE_PROCESS := 0x0080
                		,"grfAccessMode":        GRANT_ACCESS
                		,"grfInheritance":       NO_INHERITANCE
                		,"TrusteeForm":          TRUSTEE_IS_SID
                		,"TrusteeType":          TRUSTEE_IS_USER := 1
                		,"ptstrName":            NumGet(TOKEN_USER,, "Ptr")} ; user script is running under
                	  ,{ "grfAccessPermissions": PROCESS_ALL_ACCESS
                		,"grfAccessMode":        DENY_ACCESS := 3
                		,"grfInheritance":       NO_INHERITANCE
                		,"TrusteeForm":          TRUSTEE_IS_SID
                		,"TrusteeType":          TRUSTEE_IS_WELL_KNOWN_GROUP
                		,"ptstrName":            SIDs.GetAddress("WinWorldSid")}]

                padding := A_PtrSize == 8 ? 4 : 0
                cbEXPLICIT_ACCESS_W := (4 * 3) + padding + (A_PtrSize + (4 * 3) + padding + A_PtrSize)
                VarSetCapacity(EXPLICIT_ACCESS_W, cbEXPLICIT_ACCESS_W * EA.MaxIndex(), 0)
                for i, v in EA {
                	thisEA := cbEXPLICIT_ACCESS_W * (i - 1)
                	NumPut(v.grfAccessPermissions, EXPLICIT_ACCESS_W, thisEA, "UInt")
                	NumPut(v.grfAccessMode, EXPLICIT_ACCESS_W, thisEA + 4, "UInt")
                	NumPut(v.grfInheritance, EXPLICIT_ACCESS_W, thisEA + (4 * 2), "UInt")
                	NumPut(v.TrusteeForm, EXPLICIT_ACCESS_W, thisEA + ((4 * 3) + padding + A_PtrSize + 4), "UInt")
                	NumPut(v.TrusteeType, EXPLICIT_ACCESS_W, thisEA + ((4 * 3) + padding + A_PtrSize + (4 * 2)), "UInt")
                	NumPut(v.ptstrName, EXPLICIT_ACCESS_W, thisEA + ((4 * 3) + padding + A_PtrSize + (4 * 3) + padding), "Ptr")
                }

                if (!DllCall("advapi32\SetEntriesInAcl", "UInt", EA.MaxIndex(), "Ptr", &EXPLICIT_ACCESS_W, "Ptr", 0, "Ptr*", pNewDacl)) {
                	ret := !DllCall("Advapi32\SetSecurityInfo", "Ptr", hCurProc, "UInt", SE_KERNEL_OBJECT := 6, "UInt", DACL_SECURITY_INFORMATION := 0x00000004, "Ptr", 0, "Ptr", 0, "Ptr", pNewDacl, "Ptr", 0)
                	DllCall("LocalFree", "Ptr", pNewDacl, "Ptr")
                }
			}

	DllCall("CloseHandle", "Ptr", hToken)
	return ret
} ;</16.01.000029>
;{ sub
_GetTokenInformation(TokenHandle, TokenInformationClass, ByRef TokenInformation, TokenInformationLength, ByRef ReturnLength, _tokenInfoType := "Ptr") {
	return DllCall("advapi32\GetTokenInformation", "Ptr", TokenHandle, "UInt", TokenInformationClass, _tokenInfoType, TokenInformation, "UInt", TokenInformationLength, "UInt*", ReturnLength)
}
;} ;</16.01.000029>
;<16.01.000030>
getActiveProcessName() {                                                                                           	;-- this function finds the process to the 'ForegroundWindow'
	;by Lexikos  https://autohotkey.com/boards/viewtopic.php?p=73137#p73137
	handle := DllCall("GetForegroundWindow", "Ptr")
	DllCall("GetWindowThreadProcessId", "Int", handle, "int*", pid)
	global true_pid := pid
	callback := RegisterCallback("enumChildCallback", "Fast")
	DllCall("EnumChildWindows", "Int", handle, "ptr", callback, "int", pid)
	handle := DllCall("OpenProcess", "Int", 0x0400, "Int", 0, "Int", true_pid)
	length := 259 ;max path length in windows
	VarSetCapacity(name, length)
	DllCall("QueryFullProcessImageName", "Int", handle, "Int", 0, "Ptr", &name, "int*", length)
	SplitPath, name, pname
	return pname
} ;</16.01.000030>
;<16.01.000031>
enumChildCallback(hwnd, pid) {                                                                                 	;-- i think this retreave's the child process ID for a known gui hwnd and the main process ID
	DllCall("GetWindowThreadProcessId", "Int", hwnd, "int*", child_pid)
	if (child_pid != pid)
		global true_pid := child_pid
	return 1
} ;</16.01.000031>
;<16.01.000032>
GetDllBase(DllName, PID = 0) {                                                                                   	;--
    TH32CS_SNAPMODULE := 0x00000008
    INVALID_HANDLE_VALUE = -1
    VarSetCapacity(me32, 548, 0)
    NumPut(548, me32)
    snapMod := DllCall("CreateToolhelp32Snapshot", "Uint", TH32CS_SNAPMODULE
                                                 , "Uint", PID)
    If (snapMod = INVALID_HANDLE_VALUE) {
        Return 0
    }
    If (DllCall("Module32First", "Uint", snapMod, "Uint", &me32)){
        while(DllCall("Module32Next", "Uint", snapMod, "UInt", &me32)) {
            If !DllCall("lstrcmpi", "Str", DllName, "UInt", &me32 + 32) {
                DllCall("CloseHandle", "UInt", snapMod)
                Return NumGet(&me32 + 20)
            }
        }
    }
    DllCall("CloseHandle", "Uint", snapMod)
    Return 0
} ;</16.01.000032>
;<16.01.000033>
getProcBaseFromModules(process) {                                                                          	;--

/*
	http://stackoverflow.com/questions/14467229/get-base-address-of-process
	Open the process using OpenProcess -- if successful, the value returned is a handle to the process, which is just an opaque token used by the kernel to identify a kernel object. Its exact integer value (0x5c in your case) has no meaning to userspace programs, other than to distinguish it from other handles and invalid handles.
	Call GetProcessImageFileName to get the name of the main executable module of the process.
	Use EnumProcessModules to enumerate the list of all modules in the target process.
	For each module, call GetModuleFileNameEx to get the filename, and compare it with the executable's filename.
	When you've found the executable's module, call GetModuleInformation to get the raw entry point of the executable.
*/


	_MODULEINFO := "
                	(
                	  LPVOID lpBaseOfDll;
                	  DWORD  SizeOfImage;
                	  LPVOID EntryPoint;
                  	)"
	Process, Exist, %process%
	if ErrorLevel                 			; PROCESS_QUERY_INFORMATION + PROCESS_VM_READ
		hProc := DllCall("OpenProcess", "uint", 0x0400 | 0x0010 , "int", 0, "uint", ErrorLevel)
	if !hProc
		return -2
	VarSetCapacity(mainExeNameBuffer, 2048 * (A_IsUnicode ? 2 : 1))
	DllCall("psapi\GetModuleFileNameEx", "uint", hProc, "Uint", 0
                , "Ptr", &mainExeNameBuffer, "Uint", 2048 / (A_IsUnicode ? 2 : 1))
	mainExeName := StrGet(&mainExeNameBuffer)
	; mainExeName = main executable module of the process
	size := VarSetCapacity(lphModule, 4)
	loop
	{
		DllCall("psapi\EnumProcessModules", "uint", hProc, "Ptr", &lphModule
                , "Uint", size, "Uint*", reqSize)
		if ErrorLevel
			return -3, DllCall("CloseHandle","uint",hProc)
		else if (size >= reqSize)
			break
		else
			size := VarSetCapacity(lphModule, reqSize)
	}
	VarSetCapacity(lpFilename, 2048 * (A_IsUnicode ? 2 : 1))
	loop % reqSize / A_PtrSize ; sizeof(HMODULE) - enumerate the array of HMODULEs
	{
		DllCall("psapi\GetModuleFileNameEx", "uint", hProc, "Uint", numget(lphModule, (A_index - 1) * 4)
                , "Ptr", &lpFilename, "Uint", 2048 / (A_IsUnicode ? 2 : 1))
		if (mainExeName = StrGet(&lpFilename))
		{
			moduleInfo := struct(_MODULEINFO)
			DllCall("psapi\GetModuleInformation", "uint", hProc, "Uint", numget(lphModule, (A_index - 1) * 4)
                , "Ptr", moduleInfo[], "Uint", SizeOf(moduleInfo))
			;return moduleInfo.SizeOfImage, DllCall("CloseHandle","uint",hProc)
			return moduleInfo.lpBaseOfDll, DllCall("CloseHandle","uint",hProc)
		}
	}
	return -1, DllCall("CloseHandle","uint",hProc) ; not found
} ;</16.01.000033>
;<16.01.000034>
InjectDll(pid,dllpath)  {                                                                                                 	;-- injects a dll to a running process (ahkdll??)

    FileGetSize, size, %dllpath%
    file := FileOpen(dllpath, "r")
    file.RawRead(dllFile, size)

    pHandle := DllCall("OpenProcess", "UInt", 0x1F0FFF, "Int", false, "UInt", pid)

    pLibRemote := DllCall("VirtualAllocEx", "Uint", pHandle, "Uint", 0, "Uint", size, "Uint", 0x1000, "Uint", 4)

    VarSetCapacity(result,4)
    DllCall("WriteProcessMemory","Uint",pHandle,"Uint",pLibRemote,"Uint",&dllFile,"Uint",size,"Uint",&result)

    LoadLibraryAdd := DllCall("GetProcAddress", "Uint", DllCall("GetModuleHandle", "str", "kernel32.dll"),"AStr", "LoadLibraryA")

    hThrd := DllCall("CreateRemoteThread", "Uint", pHandle, "Uint", 0, "Uint", 0, "Uint", LoadLibraryAdd, "Uint", pLibRemote, "Uint", 0, "Uint", 0)

    DllCall("VirtualFreeEx","Uint",hProcess,"Uint",pLibRemote,"Uint",0,"Uint",32768)

    DllCall("CloseHandle", "Uint", hThrd)
    DllCall("CloseHandle", "Uint", pHandle)
    Return True

} ;</16.01.000034>
;<16.01.000035>
getProcessBaseAddress(WindowTitle, MatchMode=3)	{                                            	;-- gives a pointer to the base address of a process for further memory reading

	;-- https://autohotkey.com/boards/viewtopic.php?t=9016
	;--WindowTitle can be anything ahk_exe ahk_class etc
	mode :=  A_TitleMatchMode
	SetTitleMatchMode, %MatchMode%	;mode 3 is an exact match
	WinGet, hWnd, ID, %WindowTitle%
	; AHK32Bit A_PtrSize = 4 | AHK64Bit - 8 bytes
	BaseAddress := DllCall(A_PtrSize = 4
		? "GetWindowLong"
		: "GetWindowLongPtr", "Uint", hWnd, "Uint", -6)
	SetTitleMatchMode, %mode%	; In case executed in autoexec

	return BaseAddress
} ;</16.01.000035>
;<16.01.000036>
LoadFile(path, exe:="", exception_level:=-1) {                                                             	;-- Loads a script file as a child process and returns an object

	/*		DESCRIPTION

    LoadFile(Path [, EXE])

        Loads a script file as a child process and returns an object
        which can be used to call functions or get/set global vars.

    Path:
          The path of the script.
    EXE:
          The path of the AutoHotkey executable (defaults to A_AhkPath).

    Requirements:
      - AutoHotkey v1.1.17+    http://ahkscript.org/download/
      - ObjRegisterActive      http://goo.gl/wZsFLP
      - CreateGUID             http://goo.gl/obfmDc

    Version: 1.0
*/

    ObjRegisterActive(client := {}, guid := CreateGUID())
    code =
    (LTrim
    LoadFile.Serve("%guid%")
    #include %A_LineFile%
    #include %path%
    )
    try {
        exe := """" (exe="" ? A_AhkPath : exe) """"
        exec := ComObjCreate("WScript.Shell").Exec(exe " /ErrorStdOut *")
        exec.StdIn.Write(code)
        exec.StdIn.Close()
        while exec.Status = 0 && !client._proxy
            Sleep 10
        if exec.Status != 0 {
            err := exec.StdErr.ReadAll()
            ex := Exception("Failed to load file", exception_level)
            if RegExMatch(err, "Os)(.*?) \((\d+)\) : ==> (.*?)(?:\s*Specifically: (.*?))?\R?$", m)
                ex.Message .= "`n`nReason:`t" m[3] "`nLine text:`t" m[4] "`nFile:`t" m[1] "`nLine:`t" m[2]
            throw ex
        }
    }
    finally
        ObjRegisterActive(client, "")
    return client._proxy
}
{ ;sub LoadFile_class
class LoadFile {
    Serve(guid) {
        try {
            client := ComObjActive(guid)
            client._proxy := new this.Proxy
            client := ""
        }
        catch ex {
            stderr := FileOpen("**", "w")
            stderr.Write(format("{} ({}) : ==> {}`n     Specifically: {}"
                , ex.File, ex.Line, ex.Message, ex.Extra))
            stderr.Close()  ; Flush write buffer.
            ExitApp
        }
        ; Rather than sleeping in a loop, make the script persistent
        ; and then return so that the #included file is auto-executed.
        Hotkey IfWinActive, %guid%
        Hotkey vk07, #Persistent, Off
        #Persistent:
    }
    class Proxy {
        __call(name, args*) {
            if (name != "G")
                return %name%(args*)
        }
        G[name] { ; x.G[name] because x[name] via COM invokes __call.
            get {
                global
                return ( %name% )
            }
            set {
                global
                return ( %name% := value )
            }
        }
        __delete() {
            ExitApp
        }
    }
}
}  ;</16.01.000036>
;<16.01.000037>
ReadProcessMemory(hProcess, BaseAddress, Buffer, Bytes := 0                                	;-- reads data from a memory area in a given process.
, ByRef NumberOfBytesRead := "", ReturnType := "UInt") {

		/*                              	DESCRIPTION

			The entire area to be read must be accessible or the operation will fail
			Syntax:                 ReadProcessMemory ([hProcess], [BaseAddress], [data (out)], [size, in bytes], [NumberOfBytesRead (in_out)], [ReturnType])
			Parameters:			BaseAddress: a pointer to the base address in the specific process to read
			Data:                 	A pointer to a buffer that receives the contents of the address space of the specified process.
			Size:                 	the number of bytes that is read from the specified processNumberOfBytesRead: receives the number of bytes transferred in the specified bufferReturnType: type of value to return. defect = UInt

	*/


	BaseAddress := IsObject(BaseAddress)?BaseAddress:["UInt", BaseAddress], Error := ErrorLevel
	if IsByRef(NumberOfBytesRead)
		VarSetCapacity(NumberOfBytesRead, NumberOfBytesRead?NumberOfBytesRead:16, 0)
	Result := DllCall("Kernel32.dll\ReadProcessMemory", "Ptr", hProcess, BaseAddress[1], BaseAddress[2], "Ptr", Buffer, "UPtr"
	, Bytes>0?Bytes:VarSetCapacity(Buffer), "UPtrP", IsByRef(NumberOfBytesRead)?&NumberOfBytesRead:0, ReturnType)
	if IsByRef(NumberOfBytesRead)
		NumberOfBytesRead := NumGet(NumberOfBytesRead, 0, "UPtrP")
	return Result, ErrorLevel := Error
} ;</16.01.000037>
;<16.01.000038>
WriteProcessMemory(hProcess, BaseAddress                                                            	;-- writes data to a memory area in a specified process. the entire area to be written must be accessible or the operation will fail
, Buffer, Bytes := 0, ByRef NumberOfBytesWritten := "") {

	/*                              	DESCRIPTION

			Syntax: WriteProcessMemory( [hProcess], [BaseAddress], [Buffer], [Size], [NumberOfBytesWritten] )

	*/

	BaseAddress := IsObject(BaseAddress)?BaseAddress:["UInt", BaseAddress], Error := ErrorLevel
	if IsByRef(NumberOfBytesWritten)
		VarSetCapacity(NumberOfBytesWritten, 16, 0)
	Result :=  DllCall("Kernel32.dll\WriteProcessMemory", "Ptr", hProcess, BaseAddress[1], BaseAddress[2], "Ptr", Buffer, "UPtr"
	, Bytes>0?Bytes:VarSetCapacity(Buffer), "UPtrP", IsByRef(NumberOfBytesWritten)?&NumberOfBytesWritten:0, "UInt")
	if IsByRef(NumberOfBytesWritten)
		NumberOfBytesWritten := NumGet(NumberOfBytesWritten, 0, "UPtrP")
	return Result, ErrorLevel := Error
} ;</16.01.000038>
;<16.01.000039>
CopyMemory(ByRef Destination, Source, Bytes) {                                                       	;-- Copy a block of memory from one place to another
	/*                              	DESCRIPTION

			Syntax: CopyMemory[ [destination], [source], [bytes] )

	*/

	DllCall("msvcrt.dll\memcpy_s", "Ptr", Destination, "UInt", Bytes, "Ptr", Source, "UInt", Bytes)
} ;</16.01.000039>
;<16.01.000040>
MoveMemory(ByRef Destination, Source, Bytes) {                                                      	;-- moves a block memory from one place to another
   	 /*                              	DESCRIPTION
 			Syntax: MoveMemory [[target], [source], [bytes])
	*/

	DllCall("msvcrt.dll\memmove_s", "Ptr", Destination, "UInt", Bytes, "Ptr", Source, "UInt", Bytes)
}  ;</16.01.000040>
 ;<16.01.000041>
FillMemory(ByRef Destination, Bytes, Fill) {                                                                  	;-- fills a block of memory with the specified value
	;Syntax: FillMemory ([destination], [bytes], [value])
	DllCall("ntdll.dll\RtlFillMemory", "Ptr", Destination, "UInt", Bytes, "UChar", Fill)
}  ;</16.01.000041> ;https://msdn.microsoft.com/en-us/library/windows/hardware/ff561870(v=vs.85).aspx
;<16.01.000042>
ZeroMemory(ByRef Destination, Bytes) {                                                                    	;-- fills a memory block with zeros
	DllCall("ntdll.dll\RtlZeroMemory", "Ptr", Destination, "UInt", Bytes)
}  ;</16.01.000042> ;https://msdn.microsoft.com/en-us/library/windows/hardware/ff563610(v=vs.85).aspx
;<16.01.000043>
CompareMemory(Source1, Source2, Size := 0) {                                                         	;-- compare two memory blocks

	/*                              	DESCRIPTION

			Syntax: 	CompareMemory ([mem1], [mem2], [total size, in bytes])
			Return:		1 	= mem1> mem2
                			0 	= mem1 = mem2
                			-1	= mem1 <mem2
	*/

	if !(Size)
		Size1 := VarSetCapacity(Source1), Size2 := VarSetCapacity(Source2), Size := Size1<Size2?Size1:Size2
		, Result := DllCall("msvcrt.dll\memcmp", "UPtr", &Source1, "UPtr", &Source2, "UInt", Size, "CDecl Int")
	else Result := DllCall("msvcrt.dll\memcmp", "UPtr", Source1, "UPtr", Source2, "UInt", Size, "CDecl Int")
	return Result>0?1:Result<0?-1:0, ErrorLevel := ((Result+0)="")
} ;</16.01.000043>
 ;<16.01.000044>
VirtualAlloc(ByRef hProcess := 0, ByRef Address := 0                                                  	;-- changes the state of a region of memory within the virtual address space of a specified process. the memory is assigned to zero.AtEOF
, ByRef Bytes := 0, AllocationType := 0x00001000, Protect := 0x04, Preferred := 0) {

	/*                              	DESCRIPTION

			Syntax: VirtualAlloc ([hProcess], [address], [size], [type], [protection], [NUMA])
			hProcess (optional): HANDLE a process, if it is not used, use the current process.
			Address (optional): start address of the assign Region
			Size: size of the region, in bytes
			Type: type of memory allocation
			MEM_COMMIT (default) = 0x00001000
			MEM_RESERVE = 0x00002000
			MEM_RESET = 0x00080000
			MEM_RESET_UNDO = 0x1000000
			-------------------------------------------------- -------
			MEM_LARGE_PAGES = 0x20000000
			MEM_PHYSICAL = 0x00400000
			MEM_TOP_DOWN = 0x00100000
			Protection: Memory protection for the region of pages that will be assigned
			PAGE_EXECUTE = 0x10
			PAGE_EXECUTE_READ = 0x20
			PAGE_EXECUTE_READWRITE = 0x40
			PAGE_EXECUTE_WRITECOPY = 0x80
			PAGE_NOACCESS = 0x01
			PAGE_READONLY = 0x02
			PAGE_READWRITE (default) = 0x04
			PAGE_WRITECOPY = 0x08
			PAGE_TARGETS_INVALID = 0x40000000
			PAGE_TARGETS_NO_UPDATE = 0x40000000
			-------------------------------------------------- -------
			PAGE_GUARD = 0x100
			PAGE_NOCACHE = 0x200
			PAGE_WRITECOMBINE = 0x400
			NUMA (optional): NUMA node, where the physical memory must reside.

	*/

	if !(hProcess) ;VirtualAlloc
		return DllCall("Kernel32.dll\VirtualAlloc", "UInt", Address, "UPtr", Bytes, "UInt", AllocationType, "UInt", Protect, "UInt")
	if !(Preferred) ;VirtualAllocEx + hProcess | else VirtualAllocExNuma + NUMA
		return DllCall("Kernel32.dll\VirtualAllocEx", "Ptr", hProcess, "UInt", Address, "UPtr", Bytes, "UInt", AllocationType, "UInt", Protect, "UInt")
	return DllCall("Kernel32.dll\VirtualAllocExNuma", "Ptr", hProcess, "UInt", Address, "UPtr", Bytes, "UInt", AllocationType, "UInt", Protect, "UInt", Preferred, "UInt")
}  ;</16.01.000044> ;https://msdn.microsoft.com/en-us/library/windows/desktop/aa366891(v=vs.85).aspx
;<16.01.000045>
VirtualFree(hProcess := 0, Address := 0, Bytes := 0, AllocationType := 0x8000) {       	;-- release a region of pages within the virtual address space of the specified process
	/*                              	DESCRIPTION
			Syntax: VirtualFree( [hProcess], [direccion], [tamaño, en bytes], [tipo] )
			Types:
			MEM_DECOMMIT = 0x4000
			MEM_RELEASE (default) = 0x8000
	*/

	Error := ErrorLevel
	if !(hProcess) ;VirtualFree | else VirtualFreeEx + hProcess
		return DllCall("Kernel32.dll\VirtualFree", "UInt", Address, "UPtr", Bytes, "UInt", AllocationType, "UInt"), ErrorLevel := Error
	return DllCall("Kernel32.dll\VirtualFreeEx", "Ptr", hProcess, "UInt", Address, "UPtr", Bytes, "UInt", AllocationType, "UInt"), ErrorLevel := Error
} ;</16.01.000045>
 ;<16.01.000046>
ReduceMem() {                                                                                                            	;-- reduces usage of memory from calling script

	/*                              	DESCRIPTION

			Link:                 	https://autohotkey.com/board/topic/56984-new-process-notifier/
			 Function from: 	New Process Notifier
			 Language:       	English
			 Platform:       		Windows XP or later

                                		Copyright (C) 2010 sbc <http://sites.google.com/site/littlescripting/>
                                		Licence: GNU GENERAL PUBLIC LICENSE. Please reffer to this page for more information. http://www.gnu.org/licenses/gpl.html

	*/


    pid := DllCall("GetCurrentProcessId")
    h := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "Int", pid)
    DllCall("SetProcessWorkingSetSize", "UInt", h, "Int", -1, "Int", -1)
    DllCall("CloseHandle", "Int", h)
} ;</16.01.000046>
;<16.01.000047>
GlobalLock(hMem) {                                                                                                    	;-- memory management functions
	return DllCall("Kernel32.dll\GlobalLock", "Ptr", hMem, "Ptr")
} GlobalAlloc(Bytes, Flags := 0x0002) {
	return DllCall("Kernel32.dll\GlobalAlloc", "UInt", Flags, "UInt", Bytes, "Ptr")
} GlobalReAlloc(hMem, Bytes, Flags := 0x0002) {
	return DllCall("Kernel32.dll\GlobalReAlloc", "Ptr", hMem, "UInt", Bytes, "UInt", Flags, "Ptr")
} GlobalUnlock(hMem) {
	return DllCall("Kernel32.dll\GlobalUnlock", "Ptr", hMem, "UInt")
} GlobalFree(hMem) {
	return DllCall("Kernel32.dll\GlobalFree", "Ptr", hMem, "Ptr")
} GlobalSize(hMem) {
	return DllCall("Kernel32.dll\GlobalSize", "Ptr", hMem, "UInt")
} GlobalDiscard(hMem) {
	return DllCall("Kernel32.dll\GlobalDiscard", "Ptr", hMem, "Ptr")
} GlobalFlags(hMem) {
	return DllCall("Kernel32.dll\GlobalFlags", "Ptr", hMem, "UInt")
} ;</16.01.000047>
;<16.01.000048>
LocalFree(hMem*) {                                                                                                     	;-- free a locked memory object
	Error := ErrorLevel, Ok := 0
	for k, v in hMem
		Ok += !DllCall("Kernel32.dll\LocalFree", "Ptr", v, "Ptr")
	return Ok=hMem.MaxIndex(), ErrorLevel := Error
} ;</16.01.000048>
;<16.01.000049>
CreateStreamOnHGlobal(hGlobal, DeleteOnRelease := true) {                                   	;-- creates a stream object that uses an HGLOBAL memory handle to store the stream contents. This object is the OLE-provided implementation of the IStream interface.
	DllCall("ole32.dll\CreateStreamOnHGlobal", "Ptr", hGlobal, "Int", !!DeleteOnRelease, "PtrP", IStream)
	return IStream
} ;</16.01.000049>
;<16.01.000050>
CoTaskMemFree(ByRef hMem) {                                                                                 	;-- releases a memory block from a previously assigned task through a call to the CoTaskMemAlloc () or CoTaskMemAlloc () function.
	Error := ErrorLevel
	, Ok := DllCall("Ole32.dll\CoTaskMemFree", "UPtr", hMem)
	return !!Ok, VarSetCapacity(hMem, 0), ErrorLevel := Error
} ;</16.01.000050> ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms680722(v=vs.85).aspx
;<16.01.000051>
CoTaskMemAlloc(Bytes) {                                                                                            	;-- assign a working memory block
	/*                              	DESCRIPTION
                Syntax: CoTaskMemAlloc ([memory block size, in bytes])
			Return: hMem
	*/

	return DllCall("Ole32.dll\CoTaskMemAlloc", "UPtr", Bytes, "UPtr")
} ;</16.01.000051> ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms692727(v=vs.85).aspx
;<16.01.000052>
CoTaskMemRealloc(hMem, Bytes) {                                                                            	;-- change the size of a previously assigned block of working memory
	/*                              	DESCRIPTION

			.Syntax: CoTaskMemRealloc ([hMem], [new size for the memory block, in bytes])

	*/

	return DllCall("Ole32.dll\CoTaskMemRealloc", "Ptr", hMem, "UPtr", Bytes, "Ptr")
} ;</16.01.000052> ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms687280(v=vs.85).aspx
;<16.01.000053>
VarAdjustCapacity(ByRef Var) {                                                                                   	;-- adjusts the capacity of a variable to its content
	/*                              	DESCRIPTION

			Example:
			VarSetCapacity (OutputVar, 104857600, 0) attaches 100 MB to OutputVar
			OutputVar: = "123456789" assigns a string of characters to OutputVar
			MsgBox % "Contenido: " OutputVar "`nCapacidad: "
			VarSetCapacity(OutputVar) shows the content and current capacity of OutputVar, in bytes.
			VarAdjustCapacity (OutputVar) by applying the adjustment.
			MsgBox % "Contenido: " OutputVar "`nCapacidad: " VarSetCapacity(OutputVar) returns to show the current content and capacity of OutputVar, in bytes.

	*/

	return Capacity := VarSetCapacity(Var, -1)
	, OutputVar := Var, VarSetCapacity(Var, 0)
	, VarSetCapacity(Var, Capacity), Var := OutputVar
} ;</16.01.000053>
;<16.01.000054>
DllListExports( DLL, Hdr := 0 ) {                                                                                   	;-- List of Function exports of a DLL

	/*                              	DESCRIPTION

			By SKAN,  http://goo.gl/DsMqa6 ,  CD:26/Aug/2010 | MD:14/Sep/2014
			llListExports() - List of Function exports of a DLL  |  http://ahkscript.org/boards/viewtopic.php?t=4563
			Author: Suresh Kumar A N ( arian.suresh@gmail.com )
			_________________________________________________________________________________________________________
	*/



Local LOADED_IMAGE, nSize := VarSetCapacity( LOADED_IMAGE, 84, 0 ), pMappedAddress, pFileHeader
    , pIMGDIR_EN_EXP, IMAGE_DIRECTORY_ENTRY_EXPORT := 0, RVA, VA, LIST := ""
    , hModule := DllCall( "LoadLibrary", "Str","ImageHlp.dll", "Ptr" )

  If ! DllCall( "ImageHlp\MapAndLoad", "AStr",DLL, "Int",0, "Ptr",&LOADED_IMAGE, "Int",True, "Int",True )
    Return

  pMappedAddress := NumGet( LOADED_IMAGE, ( A_PtrSize = 4 ) ?  8 : 16 )
  pFileHeader    := NumGet( LOADED_IMAGE, ( A_PtrSize = 4 ) ? 12 : 24 )

  pIMGDIR_EN_EXP := DllCall( "ImageHlp\ImageDirectoryEntryToData", "Ptr",pMappedAddress
                           , "Int",False, "UShort",IMAGE_DIRECTORY_ENTRY_EXPORT, "PtrP",nSize, "Ptr" )

  VA  := DllCall( "ImageHlp\ImageRvaToVa", "Ptr",pFileHeader, "Ptr",pMappedAddress, "UInt"
, RVA := NumGet( pIMGDIR_EN_EXP + 12 ), "Ptr",0, "Ptr" )

  If ( VA ) {
     VarSetCapacity( LIST, nSize, 0 )
     Loop % NumGet( pIMGDIR_EN_EXP + 24, "UInt" ) + 1
        LIST .= StrGet( Va + StrLen( LIST ), "" ) "`n"
             ,  ( Hdr = 0 and A_Index = 1 and ( Va := Va + StrLen( LIST ) ) ? LIST := "" : "" )
  }

  DllCall( "ImageHlp\UnMapAndLoad", "Ptr",&LOADED_IMAGE ),   DllCall( "FreeLibrary", "Ptr",hModule )

Return RTrim( List, "`n" )
} ;</16.01.000054>
;<16.01.000055>
RtlUlongByteSwap64(num){                                                                                        	;-- routine reverses the ordering of the four bytes in a 32-bit unsigned integer value (AHK v2)
	/*                              	DESCRIPTION

			; Url:
                ;	- https://msdn.microsoft.com/en-us/library/windows/hardware/ff562886(v=vs.85).aspx (RtlUlongByteSwap routine)
                ;	- https://msdn.microsoft.com/en-us/library/e8cxb8tk.aspx (_swab function)
                ; For example, if the Source parameter value is 0x12345678, the routine returns 0x78563412.
                ; works on both 32 and 64 bit.

	*/
	/*                              	EXAMPLE(s)

			; Tested only on these examples,
			msgbox(format("0x", RtlUlongByteSwap64(0x12345678)))
			msgbox(format("0x", RtlUlongByteSwap64(0x78563412)))

	*/

	static dest, i := varsetcapacity(dest,4)
	DllCall("MSVCRT.dll\_swab", "ptr", &num, "ptr", &dest+2, "int", 2, "cdecl")
	,DllCall("MSVCRT.dll\_swab", "ptr", &num+2, "ptr", &dest, "int", 2, "cdecl")
	return numget(dest,"uint")
} ;</16.01.000055>
;<16.01.000056>
RtlUlongByteSwap64(num) {                                                                                       	;-- routine reverses the ordering of the four bytes in a 32-bit unsigned integer value (AHK v1)
	/*                              	DESCRIPTION

                Link: https://autohotkey.com/boards/viewtopic.php?f=5&t=39002
                	- https://msdn.microsoft.com/en-us/library/windows/hardware/ff562886(v=vs.85).aspx (RtlUlongByteSwap routine)
                	- https://msdn.microsoft.com/en-us/library/e8cxb8tk.aspx (_swab function)
                A ULONG value to convert to a byte-swapped version
                For example, if the Source parameter value is 0x12345678, the routine returns 0x78563412.
                works on both 32 and 64 bit.
                v1 version

	*/
	/*                              	EXAMPLE(s)

			; Tested only on these examples,
			msgbox % format("0x", RtlUlongByteSwap64(0x12345678))
			msgbox % format("0x", RtlUlongByteSwap64(0x78563412))

	*/

	static dest, src
	static i := varsetcapacity(dest,4) + varsetcapacity(src,4)
	numput(num,src,"uint")
	,DllCall("MSVCRT.dll\_swab", "ptr", &src, "ptr", &dest+2, "int", 2, "cdecl")
	,DllCall("MSVCRT.dll\_swab", "ptr", &src+2, "ptr", &dest, "int", 2, "cdecl")
	return numget(dest,"uint")
} ;</16.01.000056>
;<16.01.000057>
PIDfromAnyID( anyID="" ) {                                                                                        	;-- for easy retreaving of process ID's (PID)

 	/*    	DESCRIPTION of function PIDfromAnyID() ID: 16.01.000056
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	for easy retreaving of process ID's
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=3533
			Author         	:	SKAN
			Date	            	:	10-May-2014
			AHK-Version	:
			License         	:
			Parameter(s)	:	thread ID, process name
			Return value	:	PID
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:	process, process id, PID,
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			MsgBox % PIDfromAnyID()                                     	; Own PID
			MsgBox % PIDfromAnyID( "winlogon.exe" )            	; process name
			MsgBox % PIDfromAnyID( 4 )                                  	; validating raw PID

			MsgBox % PIDfromAnyID( "MyScript.ahk" )            	; PID of a running script
			MsgBox % PIDfromAnyID( "MyScript.ahk ahk_class AutoHotkey" )  ; precise than above
			MsgBox % PIDfromAnyID( "Torrent" )                     	; part of window title

			MsgBox % PIDfromAnyID( A_ScripthWnd )             	; Own PID

			MouseGetPos,,, OutputVarWin
			MsgBox % PIDfromAnyID( OutputVarWin )            	; PID of Window under mouse

	*/

  Process, Exist, %anyID%
  If (ErrorLevel), Return ErrorLevel					;IfGreater, ErrorLevel, 0, Return ErrorLevel   	;<-comment line is the original: it uses an old syntax, not recommend for newer scripts

  DetectHiddenWindows, % SubStr( ( ADHW := A_DetectHiddenWindows ) . "On", -1 )
  SetTitleMatchMode,   % SubStr( ( ATMM := A_TitleMatchMode )   . "RegEx", -4 )

  WinGet, PID, PID, ahk_id %anyID%
  If (!PID)                                                        	;IfEqual, PID,, WinGet, PID, PID, %anyID% 	;<-comment line is the original: it uses an old syntax, not recommend for newer scripts
		WinGet, PID, PID, %anyID%

  DetectHiddenWindows, %ADHW%
  SetTitleMatchMode, %ATMM%

Return PID ? PID : 0
} ;</16.01.000057>
;<16.01.000058>
processPriority(PID) {                                                                                                   	;-- retrieves the priority of a process via PID
	return dllCall("GetPriorityClass","UInt",dllCall("OpenProcess","Uint",0x400,"Int",0,"UInt",PID)),dllCall("CloseHandle","Uint",hProc)
} ;</16.01.000058>
;<16.01.000059>
GetProcessMemoryInfo(PID,Units:="M") {                                                                  	;-- get informations about memory consumption of a process
	size := (A_PtrSize=8 ? 80 : 44)
	VarSetCapacity(mem,size,0)
	memory := 0
	hProcess := DllCall("OpenProcess", UInt,0x400|0x0010,Int,0,Ptr,PID, Ptr)
	if (hProcess){
		if (DllCall("psapi.dll\GetProcessMemoryInfo", Ptr, hProcess, Ptr, &mem, UInt,size))
			memory := Round(NumGet(mem, (A_PtrSize=8 ? 16 : 12), "Ptr"))
		DllCall("CloseHandle", Ptr, hProcess)

		if(Units == "raw"){
				return % memory
		}else	if(Units == "Cust"){
			memory := Round(memory/1024)
			if(memory<40000){
				RegExMatch(memory,"(\d+)(\d{3})$", out)
				memory:=out1 "," out2
				return % memory " KB"
			}else{
				memory := Round(memory/1024)
				return % memory " MB"
			}
		}else	if(Units == "B"){
					memory := memory  " B"
		}else if(Units == "K"){
					memory := Round(memory/1024)  " KB"
		}else if(Units == "M"){
					memory := Round(memory / 1024 / 1024)	 " MB"
		}
		return % memory
	}
} ;</16.01.000059>
;<16.01.000060>
SetTimerEx(period, func, params*) {                                                                            	;-- Similar to SetTimer, but calls a function, optionally with one or more parameters

	/*    	DESCRIPTION of function SetTimerEx() ID:
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	Similar to SetTimer, but calls a function, optionally with one or more parameters
			Link              	:	https://autohotkey.com/boards/viewtopic.php?t=1948
			Author         	:	Lexikos
			Date	            	:	05-Feb-2014
			AHK-Version	:	work with v2 (and v1.1)
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:	Timer_Stop()
			KeyWords    	:	Timer, Function-Replacement
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    	EXAMPLE(s)

			t1 := SetTimerEx(1000, "SoundTimer", "*-1")
			Sleep, 500
			t2 := SetTimerEx(1000, "SoundTimer", "*16")
			SoundTimer(param) {
				SoundPlay % param
				ToolTip % param
			}

			~Esc::  ; Press Esc to
			t1.stop()  ; stop the timer,
			Sleep 3000  ; wait 3 seconds,
			ExitApp  ; then exit.

	*/


    static s_timers, s_next_tick, s_timer, s_index, s_max_index

    if !s_timers  ; Init timers array and ensure script is #persistent.
        s_timers := Object(), n:="OnMessage",%n%(0)

    if (func = "!") ; Internal use.
    {
        ; This is a workaround for the timer-tick sub not being able to see itself
        ; in v2 (since it is local to the function, which is not running).
        SetTimer timer-tick, % period
        return
    }

    if !IsFunc(func)
        return

    ; Create a timer.
    timer           := {base: {stop: "Timer_Stop"}}
    timer.run_once  := period < 0
    timer.period    := period := Abs(period)
    timer.next_run  := next_run := A_TickCount + period
    timer.func      := func
    timer.params    := params

    ; If the timer is not set to run before next_run, set it:
    if (!s_next_tick || s_next_tick > next_run)
    {
        s_next_tick := next_run
        SetTimer timer-tick, % -period
    }

    return s_timers.Insert(timer) ? timer : 0

timer-tick:
    s_next_tick := "X" ; greater than any number
    s_index := 1
    While s_timer := s_timers[s_index]
    {
        if (s_timer.next_run <= A_TickCount)
        {
            if s_timer.next_run  ; Timer has not been disabled.
            {
                ; Update next run time before calling func in case it takes a while.
                s_timer.next_run := s_timer.run_once ? "" : A_TickCount + s_timer.period
                ; Call function.
                static s_f
                s_f := s_timer.func, %s_f%(s_timer.params*)
            }
            if !s_timer.next_run  ; Timer was run-once (disabled above) or previously disabled.
            {
                ; Remove both our references to this timer:
                s_timers._Remove(s_index)
                s_timer := ""
                ; Continue without incrementing s_index.
                continue
            }
        }
        ; Determine when the next timer should fire.
        if (s_next_tick > s_timer.next_run)
            s_next_tick := s_timer.next_run
        s_index += 1
    }
    s_timer := ""
    ; Set main timer for next sub-timer which should be fired, if any.
    if (s_next_tick != "X")
        SetTimerEx(s_next_tick > A_TickCount ? A_TickCount-s_next_tick : -1, "!")
    return
} ;</16.01.000060>
;{ sub
Timer_Stop(timer) {
    timer.next_run := 0
}
;} ;</16.01.00060>
;<16.01.000061>
DisableFadeEffect() {                                                                                                   	;-- disabling fade effect on gui animations
	; SPI_GETCLIENTAREAANIMATION = 0x1042
	/*	DESCRIPTION OF FUNCTION: -- DisableFadeEffect --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Disabling fade effect on gui animations
	Link              	:	https://gist.github.com/tmplinshi/70a8f7879d94b20a42a9d94ca12c1a82
	                         	https://www.autohotkey.com/boards/viewtopic.php?t=27743
	Author         	:	tmplinshi
	Date             	:	February 04, 2017
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	gui
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------

	*/
	DllCall("SystemParametersInfo", "UInt", 0x1042, "UInt", 0, "UInt*", isEnabled, "UInt", 0)

	if isEnabled {
		; SPI_SETCLIENTAREAANIMATION = 0x1043
		DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 0, "UInt", 0)
		Progress, 10:P100 Hide
		Progress, 10:Off
		DllCall("SystemParametersInfo", "UInt", 0x1043, "UInt", 0, "UInt", 1, "UInt", 0)
	}
} ;</16.01.000061>
;<16.01.000062>
GetPriority(process="") {                                                                                             	;-- ascertains the priority level for an existing process

	/*	DESCRIPTION OF FUNCTION: -- GetPriority() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	ascertains the priority level for an existing process and returns one of the
                            	following strings (see return value)
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-3
	Author         	:	SKAN
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	GetPriority(processName)
	Parameter(s)	:	width is number of Space chars
	Return value	:	string containing one of these
                            	"Low"
                            	"BelowNormal"
                            	"Normal"
                            	"AboveNormal"
                            	"High"
                            	"RealtimeNote"
	Remark(s)    	:	If no parameter is passed, the script's own priority level is retrieved.
	Dependencies	:	none
	KeyWords    	:	process,priority
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Run, calc.exe
	WinWait, Calculator
	Process, Exist, calc.exe
	PID := ErrorLevel

	Process, Priority, %PID%, Low
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Process, Priority, %PID%, BelowNormal
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Process, Priority, %PID%, AboveNormal
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Process, Priority, %PID%, High
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Process, Priority, %PID%, Realtime
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Process, Priority, %PID%, Normal
	MsgBox, 64, Process Priority [CALC.EXE], % GetPriority("calc.exe")

	Return
	*/

	 Process, Exist, %process%
	 PID := ErrorLevel
	 IfLessOrEqual, PID, 0, Return, "Error!"

	 hProcess := DllCall("OpenProcess", Int,1024, Int,0, Int,PID)
	 Priority := DllCall("GetPriorityClass", Int,hProcess)
	 DllCall("CloseHandle", Int,hProcess)

	 IfEqual, Priority, 64   		, Return, "Low"
	 IfEqual, Priority, 16384	, Return, "BelowNormal"
	 IfEqual, Priority, 32   		, Return, "Normal"
	 IfEqual, Priority, 32768	, Return, "AboveNormal"
	 IfEqual, Priority, 128  		, Return, "High"
	 IfEqual, Priority, 256  		, Return, "Realtime"
Return ""
} ;</16.01.000062>
;<16.01.000063>
ProcessCreationTime(PID) {                                                                                         	;-- ascertains the creation time for an existing process and returns a time string

	/*	DESCRIPTION OF FUNCTION: -- ProcessCreationTime() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	ascertains the creation time for an existing process and returns a time string
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-3
	Author         	:	SKAN
	Date             	:	04-Nov-2009
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	ProcessCreationTime( ProcessID )
	Parameter(s)	:	--
	Return value	:	string in YYYYMMDD24MISS format
	Remark(s)    	:	* If an invalid PID or a null is passed, the function returns a standard timestamp in
                            	   UTC : 16010101000000 i.e., Zero hour on 1st January 1601. But, for me it will be
								   16010101053000 as my timezone is UTC+ 5hr 30m
								* Does not return correctly for Windows Explorer instances. It will be creation time of
								   explorer.exe
								* Ask-for-Help Topic : Window (or process) creation time? - evl, Micha, shimanov ( Thanks! )
								   https://autohotkey.com/board/topic/6647-window-or-process-creation-time/
								* Ask-for-Help Post : VBS_ProcessCreationTime() - Skan ( Slow and ugly :evil: )
								   http://www.autohotkey.com/forum/viewtopic.php?p=96929#96929
								* MSDN Reference :
                                    	GetProcessTimes() :
     									    - http://msdn2.microsoft.com/en-us/library/ms683223.aspx
                                    	FileTimeToLocalFileTime , FILETIME Structure :
										    - http://msdn2.microsoft.com/en-us/library/ms724277.aspx
											- http://msdn2.microsoft.com/en-us/library/ms724284.aspx
                                    	FileTimeToSystemTime , SYSTEMTIME Structure :
                                            - http://msdn2.microsoft.com/en-us/library/ms724280.aspx
											- http://msdn2.microsoft.com/en-us/library/ms724950.aspx
                                    	OpenProcess() :
										    - https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/openprocess.asp
                                    	CloseHandle() :
										    - https://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/closehandle.asp
                                    	Process Security and Access Rights :
										    - https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/process_security_and_access_rights.asp
	Dependencies	:	none
	KeyWords    	:	string,formatting
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	Winget, PM_PID, PID, ahk_class Progman
	cTime := ProcessCreationTime( PM_PID )
	MsgBox, 0, ProcessCreationTime(), % cTime
	FormatTime, cTime, % cTime
	MsgBox, 0, Program Manager created on , % cTime
	Return
	*/

	 hPr := DllCall( "OpenProcess", UInt,1040, Int,0, Int,PID )
	 DllCall( "GetProcessTimes", UInt,hPr, Int64P,UTC, Int,0, Int,0, Int,0 )
	 DllCall( "CloseHandle", Int,hPr)
	 DllCall( "FileTimeToLocalFileTime", Int64P,UTC, Int64P,Local ), AT := 1601
	 AT += % Local//10000000, S
Return AT
} ;</16.01.000063>
;<16.01.000064>
ProcessOwner(PID) {                                                                                                     	;-- returns the Owner for a given Process ID

	/*	DESCRIPTION OF FUNCTION: -- ProcessOwner() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Returns the Owner for a given Process ID. To make it fully functional, one needs to call SetDebugPrivilege() prior to ProcessOwner()
	Link              	:	https://autohotkey.com/board/topic/7984-ahk-functions-incache-cache-list-of-recent-items/page-8
                            	http://www.autohotkey.com/forum/viewtopic.php?p=232199#232199
	Author         	:	SKAN
                            	Sincere thanks to Sean, for pointing out the method and for providing half the code
                                	- http://www.autohotkey.com/forum/viewtopic.php?p=232247#232247
                                	- http://www.autohotkey.com/forum/viewtopic.php?t=18438
								Nibu Thomas : How to get name of owner of a process?
                                	 - https://nibuthomas.wordpress.com/2008/01/08/how-to-get-name-of-owner-of-a-process/
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	ProcessOwner(ProcessID)
	Parameter(s)	:	--
	Return value	:	string with name of the owner
	Reference     	:	* CodeProject: How To Get Process Owner ID and Current User SID
                                	- http://www.codeproject.com/KB/cs/processownersid.aspx
								* MSDN: GetTokenInformation(),  LookupAccountSid()
									- https://msdn.microsoft.com/en-us/library/aa446671%28VS.85%29.aspx
									- https://msdn.microsoft.com/en-us/library/aa379166%28VS.85%29.aspx
	Remark(s)    	:
	Dependencies	:	none
	KeyWords    	:	string,formatting
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	; SetDebugPrivilege() ; www.autohotkey.com/forum/viewtopic.php?p=232199#232199
	Process Exist, svchost.exe
	PID := ErrorLevel
	MsgBox, % ProcessOwner( PID )
	*/


	 ; PROCESS_QUERY_INFORMATION=0x400, TOKEN_READ:=0x20008, TokenUser:=0x1
	 hProcess := DllCall( "OpenProcess", UInt,0x400,Int,0,UInt,PID )
	 DllCall( "Advapi32.dll\OpenProcessToken", UInt,hProcess, UInt,0x20008, UIntP,Tok )
	 DllCall( "Advapi32.dll\GetTokenInformation", UInt,Tok, UInt,0x1, Int,0, Int,0, UIntP,RL )
	 VarSetCapacity( TI,RL,0 )
	 DllCall( "Advapi32.dll\GetTokenInformation"
			  , UInt,Tok, UInt,0x1, UInt,&TI, Int,RL, UIntP,RL ),           pSid := NumGet(TI)
	 DllCall( "CloseHandle", UInt,hProcess ), DllCall( "CloseHandle", UInt,Tok )
	 ; following code taken from www.autohotkey.com/forum/viewtopic.php?p=116487 - Author Sean
	 DllCall( "Advapi32\LookupAccountSidA"
			 , Str,"", UInt,pSid, UInt,0, UIntP,nSizeNM, UInt,0, UIntP,nSizeRD, UIntP,eUser )
	 VarSetCapacity( sName,nSizeNM,0 ), VarSetCapacity( sRDmn,nSizeRD,0 )
	 DllCall( "Advapi32\LookupAccountSidA"
		, Str,"", UInt,pSid, Str,sName, UIntP,nSizeNM, Str,sRDmn, UIntP,nSizeRD, UIntP,eUser )
	 DllCall( "LocalFree", UInt,pSid )
Return sName
} ;</16.01.000064>
;<16.01.000065>
ProcessPriority(PID:="", PS:="") {                                                                                  	;-- Useful inside a library function to save/set/reset script's Process priority

	/*	 DESCRIPTION OF FUNCTION: -- ProcessPriority() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Useful inside a library function to save/set/reset script's Process priority
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=68471&sid=a9e2447ccaf812e44e8c29ba845fb263
	Author         	:	By SKAN on D2A1 @ bit.ly/2mIlZRy
	Date             	:	01.10.2019
	AHK-Version	:	AHK_L
	License         	:	-
	Syntax          	:	-
	Parameter(s)	:	-
	Return value	:	string
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	System,runtime,process
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	OldPP := ProcessPriority("","High")
	; Do things
	ProcessPriority("",OldPP)
	*/

	Local hProc, PG:=0, PROCESS_QUERY_INFORMATION:=0x0400
	  Process, Exist, %PID%
	  If ! ( Errorlevel := ! (PID:=ErrorLevel) )
		{
			hProc := DllCall("OpenProcess", "UInt",PROCESS_QUERY_INFORMATION, "UInt",0, "Ptr",PID, "Ptr")
			PG := DllCall("GetPriorityClass", "Ptr",hProc, "UInt")
			DllCall("CloseHandle", "Ptr",hProc)

			If InStr("|Low|BelowNormal|Normal|AboveNormal|High|Realtime|", "|" . PS . "|")
			  {
				Process, Priority, %PID%, %PS%
				ErrorLevel := ! (ErrorLevel=PID)
			  }
		}

Return {0x40:"Low",0x4000:"BelowNormal",0x20:"Normal",0x8000:"AboveNormal",0x80:"High",0x100:"Realtime"}[PG]
} ;</16.01.000065>
;<16.01.000066>
PIDfromAnyID( anyID="" ) {                                                                                        	;-- get PID from any ID

	/*	DESCRIPTION OF FUNCTION: -- PIDfromAnyID() --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Get PID from any ID
	Link              	:	http://ahkscript.org/boards/viewtopic.php?p=17974#p17974
	Author         	:	SKAN
	Date             	:	10-MAy-2014
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	ProcessID
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	process,system
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	MsgBox % PIDfromAnyID()                                                             	; Own PID
	MsgBox % PIDfromAnyID( "winlogon.exe" )                                       ; process name
	MsgBox % PIDfromAnyID( 4 )                                                         	; validating raw PID

	MsgBox % PIDfromAnyID( "MyScript.ahk" )                                    	; PID of a running script
	MsgBox % PIDfromAnyID( "MyScript.ahk ahk_class AutoHotkey" )  	; precise than above
	MsgBox % PIDfromAnyID( "Torrent" )                                             	; part of window title

	MsgBox % PIDfromAnyID( A_ScripthWnd )                                    	; Own PID

	MouseGetPos,,, OutputVarWin
	MsgBox % PIDfromAnyID( OutputVarWin )                                    	; PID of Window under mouse
	*/

	  Process, Exist, %anyID%
	  IfGreater, ErrorLevel, 0, Return ErrorLevel
	  DetectHiddenWindows, % SubStr( ( ADHW := A_DetectHiddenWindows ) . "On", -1 )
	  SetTitleMatchMode,   % SubStr( ( ATMM := A_TitleMatchMode )   . "RegEx", -4 )
	  WinGet, PID, PID, ahk_id %anyID%
	  IfEqual, PID,, WinGet, PID, PID, %anyID%
	  DetectHiddenWindows, %ADHW%
	  SetTitleMatchMode, %ATMM%

Return PID ? PID : 0
} ;</16.01.000066>

}
;|   CreateNamedPipe(01)             	|   RestoreCursors(02)                   	|   SetSystemCursor(03)                	|   SystemCursor(04)                     	|
;|   ToggleSystemCursor(05)         	|   SetTimerF(06)                          	|   IGlobalVarsScript(07)               	|   patternScan(08)                       	|
;|   scanInBuf()                              	|   hexToBinaryBuffer()	                	|   GetDllBase()                             	|   getProcBaseFromModules()      	|
;|   RegRead64()                            	|   RegWrite64()                            	|   LoadScriptResource()                	|
;|   HIconFromBuffer()                   	|   hBMPFromPNGBuffer()            	|   SaveSetColours()                      	|   ChangeMacAdress()                 	|
;|   ListAHKStats()                         	|   MouseExtras()                          	|   TimedFunction()                       	|   ListGlobalVars()                       	|
;|   TaskList()                                 	|   MouseDpi()                              	|   SendToAHK()                            	|   ReceiveFromAHK()                   	|
;|   GetUIntByAddress()                 	|   SetUIntByAddress()                   	|   SetRestrictedDacl()                    	|   getActiveProcessName()          	|
;|   enumChildCallback()               	|   GetDllBase()                             	|   getProcBaseFromModules()      	|   InjectDll()                                 	|
;|   getProcessBaseAddress()         	|   LoadFile()                                 	|   ReadProcessMemory()              	|   WriteProcessMemory()             	|
;|   CopyMemory()                        	|   MoveMemory()                         	|   FillMemory()                             	|   ZeroMemory()                          	|
;|   CompareMemory()                  	|   VirtualAlloc()                            	|   VirtualFree()                             	|   ReduceMem()                           	|
;|   GlobalLock()                            	|   LocalFree()                               	|   CreateStreamOnHGlobal()       	|   CoTaskMemFree()                    	|
;|   CoTaskMemRealloc()               	|   VarAdjustCapacity()                 	|   DllListExports()                         	|   RtlUlongByteSwap64() x2         	|
;|   PIDfromAnyID(56)                   	|   processPriority(57)                   	|   GetProcessMemoryInfo(58)      	|   SetTimerEx(59)                         	|
;|   DisableFadeEffect(61)              	|   GetPriority(62)                         	|   ProcessCreationTime(63)         	|   ProcessOwner(64)                    	|
;|   ProcessPriority(65)                   	|   PIDfromAnyID(66)                    	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;System/User/hardware (8) -- retreaving informations about system, user, hardware --                           	baseID: <17>
;<17.01.000001>
UserAccountsEnum(Options := "") {                                                                        	;-- list all users with information

	/*                              	DESCRIPTION

			; list all users with information
			; Syntax: UserAccountsEnum ([options])
			; Parameters:
			; Options: specify the search conditions
			; Syntax: [space] WHERE [that] = '[equal to]' [AND | OR ...]
			;Example:
			; for k, v in UserAccountsEnum ()
			; MsgBox% k "#` n "v.Domain" \ "v.Name
			 ;https://msdn.microsoft.com/en-us/library/windows/desktop/aa394507(v=vs.85).aspx

	*/

	List := []
	for this in ComObjGet("winmgmts:\\.\root\CIMV2").ExecQuery("SELECT * FROM Win32_UserAccount" Options) {
		Info := {}
		Loop, Parse, % "AccountType|Caption|Description|Disabled|Domain|FullName|InstallDate|LocalAccount"
		. "|Lockout|Name|PasswordChangeable|PasswordExpires|PasswordRequired|SID|SIDType|Status", |
			Info[A_LoopField] := this[A_LoopField]
		List.Push(Info)
	} return List
} ;</17.01.000001>
;<17.01.000002>
GetCurrentUserInfo() {                                                                                             	;-- obtains information from the current user

	/*                              	DESCRIPTION

			; obtains information from the current user
			; Example: MsgBox% "Domain \ User:" GetCurrentUserInfo (). Domain "\" GetCurrentUserInfo (). Name "`nSID: "GetCurrentUserInfo (). SID
			;Notes:
			Another way to get the SID, is using cmd.
			Link: http://www.windows-commandline.com/get-sid-of-user/
			; Example: wmic useraccount where (name = '% username%' and domain = '% userdomain%') get sid

	*/


	static CurrentUserInfo
	if !(CurrentUserInfo)
		if !(CurrentUserInfo:=UserAccountsEnum(" WHERE Name = '" A_UserName "' AND Domain = '" A_UserDomain() "'")[1])
			CurrentUserInfo := UserAccountsEnum(" WHERE Name = '" A_UserName "'")[1]
	return CurrentUserInfo
} ;</17.01.000002>
;<17.01.000003>
GetHandleInformation(Handle, ByRef Flags := "") {                                                	;-- obtain certain properties of a HANDLE

	/*                              	DESCRIPTION

			; https: //msdn.microsoft.com/en-us/library/windows/desktop/ms724329 (v = vs.85) .aspx
			; obtain certain properties of a HANDLE
			; Syntax: GetHandleInformation ([HANDLE], [flags])
			; Parameters:
			; Flags: can be one of the following values.
			; 0x00000000
			; 0x00000001 = HANDLE_FLAG_INHERIT
			; 0x00000002 = HANDLE_FLAG_PROTECT_FROM_CLOSE
			; Return: 0 | 1
			; ErrorLevel:
			; 1 = OK
			; 6 = the HANDLE is invalid
			; [another] = see https://msdn.microsoft.com/en-us/library/ms681382(v=vs.85).aspx

	*/


	Ok := DllCall("Kernel32.dll\GetHandleInformation", "Ptr", Handle, "UIntP", Flags)
	return !!Ok, ErrorLevel := Ok?false:A_LastError
}  ;</17.01.000003>
;<17.01.000004>
SetHandleInformation(Handle, Flags := 0x00000000) {                                          	;-- establishes the properties of a HANDLE

	/*                              	DESCRIPTION

			; establishes the properties of a HANDLE
			; Syntax: SetHandleInformation ([HANDLE], [flags])
			; Return / ErrorLevel / Parameters: see GetHandleInformation ()

	*/


	Ok := DllCall("Kernel32.dll\SetHandleInformation", "Ptr", Handle, "UInt", Flags, "UInt", Flags)
	return !!Ok, ErrorLevel := Ok?false:A_LastError
} ;</17.01.000004>
;<17.01.000005>
 GetPhysicallyInstalledSystemMemory() {                                                               	;-- recovers the amount of RAM in physically installed KB from the SMBIOS (System Management BIOS) firmware tables, WIN_V SP1+
	/*                              	DESCRIPTION

			Example: MsgBox % Round(GetPhysicallyInstalledSystemMemory()/1024, 1) " MB"
			Note: to recover only RAM, use GlobalMemoryStatus (). TotalPhys

	*/
	DllCall("Kernel32.dll\GetPhysicallyInstalledSystemMemory", "Int64P", TotalMemoryInKilobytes)
	return TotalMemoryInKilobytes
} ;</17.01.000005>
;<17.01.000006>
GlobalMemoryStatus() {                                                                                          	;-- retrieves information about the current use of physical and virtual memory of the system
	/*                              	EXAMPLE(s)
			MsgBox % (l:=GlobalMemoryStatus()) "Load: " l.Load " %`nRAM: " Round(l.TotalPhys/(1024**2), 1) " MB"
	*/

	VarSetCapacity(MEMORYSTATUSEX, 64, 0), NumPut(64, MEMORYSTATUSEX, "UInt")
	r := DllCall("Kernel32.dll\GlobalMemoryStatusEx", "Ptr", &MEMORYSTATUSEX)
	return !r?false:{Load: NumGet(MEMORYSTATUSEX, 4, "UInt") ;número entre 0 y 100 que especifica el porcentaje aproximado de la memoria física que está en uso
	, TotalPhys: NumGet(MEMORYSTATUSEX, 8, "UInt64") ;cantidad de memoria física real, en bytes
	, AvailPhys: NumGet(MEMORYSTATUSEX, 16, "UInt64") ;cantidad de memoria física disponible actualmente, en bytes
	, TotalPageFile: NumGet(MEMORYSTATUSEX, 24, "UInt64") ;límite de memoria comprometida actual para el sistema o el proceso actual, en bytes
	, AvailPageFile: NumGet(MEMORYSTATUSEX, 32, "UInt64") ;cantidad máxima de memoria que el proceso actual puede usar, en bytes.
	, TotalVirtual: NumGet(MEMORYSTATUSEX, 40, "UInt64") ;espacio de direcciones virtuales del proceso de llamada, en bytes
	, AvailVirtual: NumGet(MEMORYSTATUSEX, 48, "UInt64")} ;espacio disponible de direcciones virtuales del proceso de llamada, en bytes
} ;</17.01.000006> ;https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx
;<17.01.000007>
GetSystemFileCacheSize(ByRef MinimumFileCacheSize := ""	                                	;-- retrieves the current size limits for the working set of the system cache
, ByRef MaximumFileCacheSize := "", ByRef Flags := "") {
	/*                              	DESCRIPTION

			Syntax: GetSystemFileCacheSize ([min, in bytes], [max, in bytes], [FILE_CACHE_MAX_HARD_ENABLE = 1
			Example: MsgBox % GetSystemFileCacheSize(Min, Max, Flags) "`nMin: " Round(Min/(1024**2), 1) " MB" "`nMax: " Round(Max/(1024**2), 1) " MB" "`nFlags: " Flags
			Link:  https://msdn.microsoft.com/en-us/library/windows/desktop/aa965224(v=vs.85).aspx
	*/

	return DllCall("Kernel32.dll\GetSystemFileCacheSize", "Int64P", MinimumFileCacheSize, "Int64P", MaximumFileCacheSize, "UIntP", Flags)
} ;</17.01.000007>
;<17.01.000008>
Is64bitProcess(pid) {                                                                                                	;-- check if a process is running in 64bit

	;function from Toolbar.ahk - Scite4AHK
	if !A_Is64bitOS
		return 0

	proc := DllCall("OpenProcess", "uint", 0x0400, "uint", 0, "uint", pid, "ptr")
	DllCall("IsWow64Process", "ptr", proc, "uint*", retval)
	DllCall("CloseHandle", "ptr", proc)
	return retval ? 0 : 1
} ;</17.01.000008>
;<17.01.000009>
getSessionId() {                                                                                                       	;-- this functions finds out ID of current session

    ProcessId := DllCall("GetCurrentProcessId", "UInt")
    if ErrorLevel {
        OutputDebug, Error getting current process id: %ErrorLevel%
        return
    }
    OutputDebug, Current Process Id: %ProcessId%

    DllCall("ProcessIdToSessionId", "UInt", ProcessId, "UInt*", SessionId)
    if ErrorLevel {
        OutputDebug, Error getting session id: %ErrorLevel%
        return
    }
    OutputDebug, Current Session Id: %SessionId%
    return SessionId
} ;</17.01.000009>

}
;|   UserAccountsEnum(1)             	|   GetCurrentUserInfo(2)              	|   GetHandleInformation(3)         	|   SetHandleInformation(4)         	|
;|   GetPhysicallyInstalledSystemMemory(5)                                         	|   GlobalMemoryStatus(6)           	|   GetSystemFileCacheSize(7)      	|
;|   Is64bitProcess(8)                     	|   getSessionId(9)                         	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;UIAutomation (5)  -                                                                                                                                  	baseID: <18>
;<18.01.000001>
CreatePropertyCondition(propertyId, ByRef var, type :="Variant") {                                   	;-- I hope this one works
		If (A_PtrSize=8) {
			if (type!="Variant")
			UIA_Variant(var,type,var)
			return UIA_Hr(DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId, "ptr",&var, "ptr*",out))? new UIA_PropertyCondition(out):
		} else {
			if (type<>8)
				return UIA_Hr(DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId, "int64",type, "int64", var, "ptr*",out))? new UIA_PropertyCondition(out):
			else
			{
				vart:=DllCall("oleaut32\SysAllocString", "wstr",var,"ptr")
				return UIA_Hr(DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId, "int64",type, "ptr", vart, "ptr", 0, "ptr*",out))? new UIA_PropertyCondition(out):
			}
		}
} ;</18.01.000001>
;<18.01.000002>
CreatePropertyCondition(propertyId, ByRef var, type := "Variant") {                                  	;-- I hope this one is better
        ; CREDITS: Elgin, http://ahkscript.org/boards/viewtopic.php?f=5&t=6979&p=43985#p43985
        ; Parameters:
        ;   propertyId  - An ID number of the property to check.
        ;   var         - The value to check for.  Can be a variant, number, or string.
        ;   type        - The data type.  Can be the string "Variant", or one of standard
        ;                 variant type such as VT_I4, VT_BSTR, etc.
        local out:="", hr, bstr
        If (A_PtrSize = 8)
        {
            if (type!="Variant")
                UIA_Variant(var,type,var)
            hr := DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId, "ptr",&var, "ptr*",out)
            if (type!="Variant")
                UIA_VariantClear(&var)
            return UIA_Hr(hr)? new UIA_PropertyCondition(out):
        }
        else ; 32-bit.
        {
            if (type <> 8)
                return UIA_Hr(DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId
                            , "int64",type, "int64",var, "ptr*",out))? new UIA_PropertyCondition(out):
            else ; It's type is VT_BSTR.
            {
                bstr := DllCall("oleaut32\SysAllocString", "wstr",var, "ptr")
                hr := DllCall(this.__Vt(23), "ptr",this.__Value, "int",propertyId
                            , "int64",type, "ptr",bstr, "ptr",0, "ptr*",out)
                DllCall("oleaut32\SysFreeString", "ptr", bstr)
                return UIA_Hr(hr)? new UIA_PropertyCondition(out):
            }
        }
} ;</18.01.000002>
;<18.01.000003>
CreatePropertyConditionEx(propertyId, ByRef var, type := "Variant", flags := 0x1) {          	;--
        ; PropertyConditionFlags_IgnoreCase = 0x1
        local out:="", hr, bstr

        If (A_PtrSize = 8) {
            if (type!="Variant")
                UIA_Variant(var,type,var)
            hr := DllCall(this.__vt(24), "ptr",this.__Value, "int",propertyId
                        , "ptr",&var, "uint",flags, "ptr*",out)
            if (type!="Variant")
                UIA_VariantClear(&var)
            return UIA_Hr(hr)? new UIA_PropertyCondition(out):
        }
        else ; 32-bit.
        {
            if (type <> 8)
                return UIA_Hr(DllCall(this.__vt(24), "ptr",this.__Value, "int",propertyId
                            , "int64",type, "int64",var
                            , "uint",flags, "ptr*",out))? new UIA_PropertyCondition(out):
            else ; It's type is VT_BSTR.
            {
                bstr := DllCall("oleaut32\SysAllocString", "wstr",var, "ptr")
                hr := DllCall(this.__vt(24), "ptr",this.__Value, "int",propertyId
                            , "int64",type, "ptr",bstr, "ptr",0, "uint",flags, "ptr*",out)
                DllCall("oleaut32\SysFreeString", "ptr", bstr)
                return UIA_Hr(hr)? new UIA_PropertyCondition(out):
            }
        }
} ;</18.01.000003>
;<18.01.000004>
UIAgetControlNameByHwnd(_, controlHwnd) {		                                                            	;--

	UIAutomation := ComObjCreate("{ff48dba4-60ef-4201-aa87-54103eef594e}", "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
	DllCall(NumGet(NumGet(UIAutomation+0)+6*A_PtrSize), "Ptr", UIAutomation, "Ptr", controlHwnd, "Ptr*", IUIAutomationElement)
	DllCall(NumGet(NumGet(IUIAutomationElement+0)+29*A_PtrSize), "Ptr", IUIAutomationElement, "Ptr*", automationId)
	ret := StrGet(automationId,, "UTF-16")
	DllCall("oleaut32\SysFreeString", "Ptr", automationId)
	ObjRelease(IUIAutomationElement)
	ObjRelease(UIAutomation)
	return ret
} ;</18.01.000004>
;<18.01.000005>
MouseGetText(x := "", y := "", Encoding := "UTF-16") {                                                      	;-- get the text in the specified coordinates, function uses Microsoft UIA

	/*                              	DESCRIPTION

			; get the text in the specified coordinates
			; Syntax: MouseGetText ([x], [y])

	*/

	/*                              	EXAMPLE(s)

			;for k, v in MouseGetText()
				;	MsgBox % k ": " v
				;ExitApp

	*/


	static uia
	if (x="") || (y="")
		CursorGetPos(_x, _y), x := x=""?_x:x, y := y=""?_y:y
	if !(uia) ;https://msdn.microsoft.com/en-us/library/windows/desktop/ff384838%28v=vs.85%29.aspx
		uia := ComObjCreate("{ff48dba4-60ef-4201-aa87-54103eef594e}", "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
	Item := {}, DllCall(_vt(uia,7),"Ptr",uia,"int64",x|y<<32,"Ptr*",element)
	if !(element)
		return "", ErrorLevel := true
	DllCall(_vt(element,23),"Ptr",element,"Ptr*",name),DllCall(_vt(element,10),"Ptr",element,"UInt",30045,"Ptr",_variant(var))
	,DllCall(_vt(element,10),"Ptr",element,"uint",30092,"Ptr",_variant(lname)), DllCall(_vt(element,10),"Ptr",element,"uint",30093,"Ptr",_variant(lval))
	,a:=StrGet(name,"utf-16"),b:=StrGet(NumGet(val,8,"Ptr"),Encoding),c:=StrGet(NumGet(lname,8,"Ptr"),Encoding)
	,d:=StrGet(NumGet(lval,8,"Ptr"),Encoding),a?Item.Push(a):0,b&&_vas(Item,b)?Item.Push(b):0,c&&_vas(Item,c)?Item.Push(c):0
	,d&&_vas(Item,d)?Item.Push(d):0,DllCall(_vt(element,21),"Ptr",element,"Uint*",type)
	if (type=50004)
		e:=MouseGetText_ElementWhole(uia,element),e&&_vas(item,e)?item.Push(e):false
	return Item, ObjRelease(element), ErrorLevel := false
} MouseGetText_ElementWhole(uia, element) {
	static init := 1, trueCondition, walker
	if (init)
		init:=DllCall(_vt(uia,21),"ptr",uia,"ptr*",trueCondition),init+=DllCall(_vt(uia,14),"ptr",uia,"ptr*",walker)
	DllCall(_vt(uia,5),"ptr",uia,"ptr*",root), DllCall(_vt(uia,3),"ptr",uia,"ptr",element,"ptr",root,"int*",same), ObjRelease(root)
	if (same)
		return
	hr:=DllCall(_vt(walker,3),"ptr",walker,"ptr",element,"ptr*",parent)
	if !(e:="") && !(parent)
		return
	DllCall(_vt(parent,6),"ptr",parent,"uint",2,"ptr",trueCondition,"ptr*",array), DllCall(_vt(array,3),"ptr",array,"int*",length)
	Loop % (length)
		DllCall(_vt(array,4),"ptr",array,"int",A_Index-1,"ptr*",newElement), DllCall(_vt(newElement,23),"ptr",newElement,"ptr*",name)
		, e.=StrGet(name,"utf-16"), ObjRelease(newElement)
	return e, ObjRelease(array), ObjRelease(parent)
} _vas(obj,ByRef txt) {
	for k,v in obj
		if (v=txt)
			return false
	return true
}_variant(ByRef var,type:=0,val:=0) {
	return (VarSetCapacity(var,8+2*A_PtrSize)+NumPut(type,var,0,"short")+NumPut(val,var,8,"ptr"))*0+&var
}_vt(p,n) {
	return NumGet(NumGet(p+0,"ptr")+n*A_PtrSize,"ptr")
} ;</18.01.000005> ;http://www.autohotkey.com/board/topic/94619-ahk-l-screen-reader-a-tool-to-get-text-anywhere/

}
;|   CreatePropertyCondition(01)   	|   CreatePropertyCondition(02)   	|   CreatePropertyConditionEx(03)	|   getControlNameByHwnd(04)   	|
;|   MouseGetText(05)                   	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;ACC (MSAA) (8) -                                                                                                                                      	baseID: <19>
;<19.01.000001>
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {		;--

	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			      , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
} ;</19.01.000001>
;<19.01.000002>
Acc_Error(p="") {		;--
   static setting:=0
   return p=""?setting:setting:=p
} ;</19.01.000002>
;<19.01.000003>
Acc_ChildrenByRole(Acc, Role) {		;--
   if ComObjType(Acc,"Name")!="IAccessible"
      ErrorLevel := "Invalid IAccessible Object"
   else {
      Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
      if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
         Loop %cChildren% {
            i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
            if NumGet(varChildren,i-8)=9
               AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
            else
               Acc_Role(Acc, child)=Role?Children.Insert(child):
         }
         return Children.MaxIndex()?Children:, ErrorLevel:=0
      } else
         ErrorLevel := "AccessibleChildren DllCall Failed"
   }
   if Acc_Error()
      throw Exception(ErrorLevel,-1)
}
VARIANTstruct() { ;working?
	DllCall("LoadLibrary",str,"oleacc", ptr)

	VarSetCapacity(Point, 8, 0)
	DllCall("GetCursorPos", ptr, &Point)

	DllCall("oleacc\AccessibleObjectFromPoint", "int64", NumGet(Point, 0, "int64"), ptrp, pAccessible, ptr, &varChild)

	; get vtable for IAccessible
	vtAccessible :=  NumGet(pAccessible+0, "ptr")

	; call get_accName() through the vtable
	hr := DllCall(NumGet(vtAccessible+0, 10*A_PtrSize, "ptr"), ptr, pAccessible,"int64", 3, "int64", 0,"int64", 0 ptrp, pvariant)
	; variant's type is VT_I4 = 3
	; variant's value is CHILDID_SELF = 0

	; get_accName returns the following hresult error with 64 bit ahk
	hr_facility := (0x07FF0000 & hr) >>16	; shows facility = 7 "win32"
	hr_code := 0x0000ffff & hr		; code 1780 "RPC_X_NULL_REF_POINTER"

} ;</19.01.000003>
;<19.01.000004>
listAccChildProperty(hwnd){	;--

	COM_AccInit()
	If	pacc :=	COM_AccessibleObjectFromWindow(hWnd)
	{
		;~ VarSetCapacity(l,4),VarSetCapacity(t,4),VarSetCapacity(w,4),VarSetCapacity(h,4)
		;~ COM_Invoke(pacc,"accLocation",l,t,w,h,0)
		;~ a:=COM_Invoke(pacc,"accParent")

		sResult	:="[Window]`n"
			. "Name:`t`t"		COM_Invoke(pacc,"accName",0) "`n"
			. "Value:`t`t"		COM_Invoke(pacc,"accValue",0) "`n"
			. "Description:`t"	COM_Invoke(pacc,"accDescription",0) "`n"
			. COM_Invoke(pacc,"accDefaultAction",0) "`n"
			. COM_Invoke(pacc,"accHelp",0) "`n"
			. COM_Invoke(pacc,"accKeyboardShortcut",0) "`n"
			. COM_Invoke(pacc,"accRole",0) "`n"
			. COM_Invoke(pacc,"accState",0) "`n"


		Loop, %	COM_AccessibleChildren(pacc, COM_Invoke(pacc,"accChildCount"), varChildren)
			If	NumGet(varChildren,16*(A_Index-1),"Ushort")=3 && idChild:=NumGet(varChildren,16*A_Index-8)
				sResult	.="[" A_Index "]`n"
					. "Name:`t`t"		COM_Invoke(pacc,"accName",idChild) "`n"
					. "Value:`t`t"		COM_Invoke(pacc,"accValue",idChild) "`n"
					. "Description:`t"	COM_Invoke(pacc,"accDescription",idChild) "`n"
					. COM_Invoke(pacc,"accParent",idChild) "`n"

			Else If	paccChild:=NumGet(varChildren,16*A_Index-8) {
				sResult	.="[" A_Index "]`n"
					. "Name:`t`t"		COM_Invoke(paccChild,"accName",0) "`n"
					. "Value:`t`t"		COM_Invoke(paccChild,"accValue",0) "`n"
					. "Description:`t"	COM_Invoke(paccChild,"accDescription",0) "`n"
				if a_index=3
				{
					numput(1,var,"UInt")
					COM_Invoke(pacc,"accSelect",1,paccChild)
				}
				 COM_Release(paccChild)
			}
		COM_Release(pacc)
	}
	COM_AccTerm()

	return sResult
} ;</19.01.000004>
;<19.01.000005>
GetInfoUnderCursor() {                                                                                                	;-- retreavies ACC-Child under cursor
	Acc := Acc_ObjectFromPoint(child)
	if !value := Acc.accValue(child)
		value := Acc.accName(child)
	accPath := GetAccPath(acc, hwnd).path
	return {text: value, path: accPath, hwnd: hwnd}
} ;</19.01.000005>
;<19.01.000006>
GetAccPath(Acc, byref hwnd="") {                                                                               	;-- get the Acc path from (child) handle
	hwnd := Acc_WindowFromObject(Acc)
	WinObj := Acc_ObjectFromWindow(hwnd)
	WinObjPos := Acc_Location(WinObj).pos
	while Acc_WindowFromObject(Parent:=Acc_Parent(Acc)) = hwnd {
		t2 := GetEnumIndex(Acc) "." t2
		if Acc_Location(Parent).pos = WinObjPos
			return {AccObj:Parent, Path:SubStr(t2,1,-1)}
		Acc := Parent
	}
	while Acc_WindowFromObject(Parent:=Acc_Parent(WinObj)) = hwnd
		t1.="P.", WinObj:=Parent
	return {AccObj:Acc, Path:t1 SubStr(t2,1,-1)}
} ;</19.01.000006>
;<19.01.000007>
GetEnumIndex(Acc, ChildId=0) {                                                                                  	;-- for Acc child object
	if Not ChildId {
		ChildPos := Acc_Location(Acc).pos
		For Each, child in Acc_Children(Acc_Parent(Acc))
			if IsObject(child) and Acc_Location(child).pos=ChildPos
				return A_Index
	}
	else {
		ChildPos := Acc_Location(Acc,ChildId).pos
		For Each, child in Acc_Children(Acc)
			if Not IsObject(child) and Acc_Location(Acc,child).pos=ChildPos
				return A_Index
	}
} ;</19.01.000007>
;<19.01.000008>
GetElementByName(AccObj, name) {                                                                          	;-- search for one element by name
if (AccObj.accName(0) = name)
	return AccObj
for k, v in Acc_Children(AccObj)
	if IsObject(obj := GetElementByName(v, name))
		return obj
} ;</19.01.000008>

}
;|   Acc_Get(01)	                            	|   Acc_Error(02)                           	|   Acc_ChildrenByRole(03)           	|   listAccChildProperty(04)           	|
;|   GetInfoUnderCursor(05)          	|   GetAccPath(06)                        	|   GetEnumIndex(07)                   	|   GetElementByName(8)             	|
;|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Internet Explorer/Chrome/FireFox/HTML (11)  -                                                                                       	baseID: <20>
 ;<20.01.000001>
IEGet(name:="") {																							    			;-- AutoHotkey_L
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter
   Name := (Name="New Tab - Windows Internet Explorer")? "about:Tabs":RegExReplace(Name, " - (Windows|Microsoft) Internet Explorer")
   for WB in ComObjCreate("Shell.Application").Windows
      if WB.LocationName=Name and InStr(WB.FullName, "iexplore.exe")
         return WB
} ;</20.01.000001>
;<20.01.000002>
IEGet(name:="") {																							     			;-- AutoHotkey_Basic
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter
   Name := (Name="New Tab - Windows Internet Explorer") ? "about:Tabs":RegExReplace(Name, " - (Windows|Microsoft) Internet Explorer")
   oShell := COM_CreateObject("Shell.Application") ; Contains reference to all explorer windows
   Loop, % COM_Invoke(oShell, "Windows.Count") {
      if pwb := COM_Invoke(oShell, "Windows", A_Index-1)
         if COM_Invoke(pwb, "LocationName")=name and InStr(COM_Invoke(pwb, "FullName"), "iexplore.exe")
            Break
      COM_Release(pwb), pwb := ""
   }
   COM_Release(oShell)
   return, pwb
} ;</20.01.000002>
;<20.01.000003>
WBGet(WinTitle="ahk_class IEFrame", Svr#=1) { 														;-- AHK_L: based on ComObjQuery docs
	static	msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
	,	IID := "{0002DF05-0000-0000-C000-000000000046}" ; IID_IWebBrowserApp
;	,	IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IHTMLWindow2
	SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
	if (ErrorLevel != "FAIL") {
		lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		}
	}
} ;</20.01.000003>
;<20.01.000004>
WBGet(WinTitle="ahk_class IEFrame", Svr#=1) { 														;-- AHK_Basic: based on Sean's GetWebBrowser function
	static msg, IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IWebBrowserApp
	if Not msg
		msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
	SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
	if (ErrorLevel != "FAIL") {
		lResult:=ErrorLevel, GUID:=COM_GUID4String(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
		DllCall("oleacc\ObjectFromLresult", "Uint",lResult, "Uint",GUID, "int",0, "UintP",pdoc)
		return COM_QueryService(pdoc,IID,IID), COM_Release(pdoc)
	}
} ;</20.01.000004>
;<20.01.000005>
wb := WBGet()				;inner HTML
MsgBox % wb.document.documentElement.innerHTML
WBGet(WinTitle="ahk_class IEFrame", Svr#=1) { 														;-- based on ComObjQuery docs
   static   msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
         ,  IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IWebBrowserApp
   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
   if (ErrorLevel != "FAIL") {
      lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
      if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
         DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
         return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
      }
   }
} ;</20.01.000005>
; Firefox
SetTitleMatchMode 2
MsgBox % Acc_Get("Value", "4.20.2.4.2", 0, "Firefox")
MsgBox % Acc_Get("Value", "application1.property_page1.tool_bar2.combo_box1.editable_text1", 0, "Firefox")
 ;</20.01.000005>
 ;<20.01.000006>
IE_TabActivateByName(TabName, WinTitle="") {														;-- activate a TAB by name in InternetExplorer

	/*                              	DESCRIPTION

			Link: https://autohotkey.com/boards/viewtopic.php?f=9&t=542

	*/


	ControlGet, hTabUI , hWnd,, DirectUIHWND5, % WinTitle=""? "ahk_class IEFrame":WinTitle
	Tabs := Acc_ObjectFromWindow(hTabUI).accChild(1) ; access "Tabs" control
	Loop, % Tabs.accChildCount
		if (Tabs.accChild(A_Index).accName(0) = TabName)
			return, Tabs.accChild(A_Index).accDoDefaultAction(0)
} ;</20.01.000006>
;<20.01.000007>
IE_TabActivateByHandle(hwnd, tabName) {																;-- activates a tab by hwnd in InternetExplorer

	/*                              	DESCRIPTION

			Link: http://www.autohotkey.com/forum/topic37651.html&p=231093

	*/

   ControlGet, hTabUI , hWnd,, DirectUIHWND1, ahk_id %hwnd%
   Acc := Acc_ObjectFromWindow(hTabUI) ;// access "Tabs" control
   If (Acc.accChildCount > 1) ;// more than 1 tab
      tabs := Acc.accChild(3) ;// access just "IE document tabs"
   While (tabs.accChildCount >= A_Index) {
      tab := tabs.accChild(A_Index)
      If (tab.accName(0) = tabName)  ;// test vs. "tabName"
         return tab.accDoDefaultAction(0) ;// invoke tab
   }
} ;</20.01.000007>
;<20.01.000008>
IE_TabWinID(tabName) {																								;-- find the HWND of an IE window with a given tab name

	/*                              	DESCRIPTION

			Link: https://autohotkey.com/board/topic/52685-winactivate-on-a-specific-ie-browser-tab

	*/


   WinGet, winList, List, ahk_class IEFrame
   While, winList%A_Index% {
      n:=A_Index, ErrorLevel:=0
      While, !ErrorLevel {
         ControlGetText, tabText, TabWindowClass%A_Index%, % "ahk_id" winList%n%
         if InStr(tabText, tabName)
            return, winList%n%
      }
   }
} ;</20.01.000008>
;<20.01.000009>
ReadProxy(ProxySettingsRegRoot="HKEY_CURRENT_USER") {                                 	;-- reads the proxy settings from the windows registry
    static ProxySettingsIEKey:="Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    RegRead ProxyEnable, %ProxySettingsRegRoot%, %ProxySettingsIEKey%, ProxyEnable
    If ProxyEnable
	RegRead ProxyServer, %ProxySettingsRegRoot%, %ProxySettingsIEKey%, ProxyServer
    return ProxyServer
} ;</20.01.000009>
;<20.01.000010>
IE_getURL(t) {    																											 ;-- using shell.application
	If	psh	:=	COM_CreateObject("Shell.Application") {
		If	psw	:=	COM_Invoke(psh,	"Windows") {
			Loop, %	COM_Invoke(psw,	"Count")
				If	url	:=	(InStr(COM_Invoke(psw,"Item[" A_Index-1 "].LocationName"),t) && InStr(COM_Invoke(psw,"Item[" A_Index-1 "].FullName"), "iexplore.exe")) ? COM_Invoke(psw,"Item[" A_Index-1 "].LocationURL") :
					Break
			COM_Release(psw)
		}
		COM_Release(psh)
	}
	Return	url
} ;</20.01.000010>
;<20.01.000011>
ACCTabActivate(hwnd, tabName) { 																			;-- activate a Tab in IE - function uses acc.ahk library

	; https://autohotkey.com/boards/viewtopic.php?f=9&t=542
   ControlGet, hTabUI , hWnd,, DirectUIHWND5, ahk_id %hwnd%
   Acc := Acc_ObjectFromWindow(hTabUI) ;// access "Tabs" control
   msgbox % Acc.accChildCount
   If (Acc.accChildCount > 1) ;// more than 1 tab
      tabs := Acc.accChild(3) ;// access just "IE document tabs"
   While (tabs.accChildCount >= A_Index) {
      tab := tabs.accChild(A_Index)
      If (tab.accName(0) = tabName)  ;// test vs. "tabName"
         return tab.accDoDefaultAction(0) ;// invoke tab
   }
} ;</20.01.000011>
;<20.01.000012>
TabActivate(TabName, WinTitle="") {																			;-- a different approach to activate a Tab in IE - function uses acc.ahk library
	ControlGet, hTabUI , hWnd,, DirectUIHWND5, % WinTitle=""? "ahk_class IEFrame":WinTitle
	Tabs := Acc_ObjectFromWindow(hTabUI).accChild(1) ; access "Tabs" control
	Loop, % Tabs.accChildCount
		if (Tabs.accChild(A_Index).accName(0) = TabName)
			return, Tabs.accChild(A_Index).accDoDefaultAction(0)
} ;</20.01.000012>


}
;|   IEGet(01)                                    	|   WBGet(02)                                  	|   IE_TabActivateByName(03)         	|   IE_TabActivateByHandle(04)       	|
;|   IE_TabWinID(05)                        	|   ReadProxy(06)                            	|   IE_getURL(07)                             	|   ACCTabActivate(08)                    	|
;|   TabActivate(09)                          	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Variables (8)  -                                                                                                                                          	baseID: <21>
;<21.01.000001>
ComVar(Type:=0xC) { 																								;-- Creates an object which can be used to pass a value ByRef.

    ;   ComVar: Creates an object which can be used to pass a value ByRef.
    ;   ComVar[] retrieves the value.
    ;   ComVar[] := Val sets the value.
    ;   ComVar.ref retrieves a ByRef object for passing to a COM function.

    static base := { __Get: "ComVarGet", __Set: "ComVarSet" }
    ; Create an array of 1 VARIANT.  This method allows built-in code to take
    ; care of all conversions between VARIANT and AutoHotkey internal types.
    arr := ComObjArray(Type, 1)
    ; Retrieve a pointer to the VARIANT.
    arr_data := NumGet(ComObjValue(arr)+8+A_PtrSize)
    ; Store the array and an object which can be used to pass the VARIANT ByRef.
    return { ref: ComObject(0x4000|Type, arr_data), _: arr, base: base }
} ;</21.01.000001>
;<21.01.000002>
ComVarGet(cv, p*) { 																								;-- Called when script accesses an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]
        return cv._[0]
} ;</21.01.000002>
;<21.01.000003>
ComVarSet(cv, v, p*) { 																							;-- Called when script sets an unknown field.
    if p.MaxIndex() = "" ; No name/parameters, i.e. cv[]:=v
        return cv._[0] := v
} ;</21.01.000003>
;<21.01.000004>
GetScriptVARs() {																										;-- returns a key, value array with all script variables (e.g. for debugging purposes)

		; http://www.autohotkey.com/board/topic/20925-listvars/#entry156570

	global
	static hEdit, pSFW, pSW, bkpSFW, bkpSW
	local dhw, AStr, Ptr, hmod, text, v, i := 0, vars := []

	if !hEdit {
		dhw := A_DetectHiddenWindows
		DetectHiddenWindows, On
		ControlGet, hEdit, Hwnd,, Edit1, % "ahk_id " A_ScriptHwnd
		DetectHiddenWindows, % dhw

		AStr := A_IsUnicode ? "AStr" : "Str"
		Ptr := A_PtrSize=8 ? "Ptr" : "UInt"
		hmod := DllCall("GetModuleHandle", "Str", "user32.dll")
		pSFW := DllCall("GetProcAddress", Ptr, hmod, AStr, "SetForegroundWindow")
		pSW := DllCall("GetProcAddress", Ptr, hmod, AStr, "ShowWindow")
		DllCall("VirtualProtect", Ptr, pSFW, Ptr, 8, "UInt", 0x40, "UInt*", 0)
		DllCall("VirtualProtect", Ptr, pSW, Ptr, 8, "UInt", 0x40, "UInt*", 0)
		bkpSFW := NumGet(pSFW+0, 0, "int64")
		bkpSW := NumGet(pSW+0, 0, "int64")
	}

	if (A_PtrSize=8) {
        NumPut(0x0000C300000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0000C300000001B8, pSW+0, 0, "int64")   ; return TRUE
    } else {
        NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
    }

    ListVars

    NumPut(bkpSFW, pSFW+0, 0, "int64")
    NumPut(bkpSW, pSW+0, 0, "int64")

    ControlGetText, text,, % "ahk_id " hEdit

    RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
    Loop, Parse, text, `n, `r
    {
    	if (A_LoopField~="^\d+\[") || (A_LoopField = "")
    		continue
		v := SubStr(A_LoopField, 1, InStr(A_LoopField, "[")-1)
    	vars[i+=1] := {name: v, value:%v%}
    }
    return vars
} ;</21.01.000004>
;<21.01.000005>
Valueof(VarinStr) {																									;-- Super Variables processor by Avi Aryan, overcomes the limitation of a single level ( return %var% ) in nesting variables

	; https://github.com/aviaryan/autohotkey-scripts/blob/master/Functions/ValueOf.ahk
	; dependings: none

	/*			DESCRIPTION
	Super Variables processor by Avi Aryan
	Overcomes the limitation of a single level ( return %var% ) in nesting variables
	The function can nest as many levels as you want
	Run the Example to get going
	Updated 10/4/14
*/

	/*			EXAMPLE -------------------------------------------
		variable := "some_value"
		msgbox % valueof("%variable%")
		some_value := "Some_another_value"
		some_another_value := "a_unique_value"
		a_unique_value := "A magical value. Ha Ha Ha Ha"
		msgbox,% "%%%%variable%%%% (4 times)`t" ValueOf("%%%%variable%%%%")

		works with objects Too

		obj := {}
		obj["key"] := "value"
		msgbox % valueOf("%obj.key%")
		msgbox % valueOf("%some_%obj.key%%")        ==== value of some_value
		return
*/

global
local Midpoint, emVar, $j, $n
	loop,
	{
		StringReplace, VarinStr, VarinStr,`%,`%, UseErrorLevel
		Midpoint := ErrorLevel / 2
		if Midpoint = 0
			return ( emvar := VarinStr )
		emVar := Substr(VarinStr, Instr(VarinStr, "%", 0, 1, Midpoint)+1, Instr(VarinStr, "%", 0, 1, Midpoint+1)-Instr(VarinStr, "%", 0, 1, Midpoint)-1)

		if Instr(emVar, ".")
		{
			loop, parse, emVar,`.
				$j%A_index% := Trim(A_LoopField) , $n := A_index-1
			if $n=1
				emVar := %$j1%[$j2]
			if $n=2
				emVar := %$j1%[$j2][$j3]
		}
		else emVar := %emVar%

		VarinStr := Substr(VarinStr, 1, Instr(VarinStr, "%", 0, 1, Midpoint)-1) emVar Substr(VarinStr, Instr(VarinStr, "%", 0, 1, Midpoint+1)+1)
	}
} ;</21.01.000005>
;<21.01.000006>
type(v) {																													;-- Object version: Returns the type of a value: "Integer", "String", "Float" or "Object"

	/*                              	DESCRIPTION

			By:					Lexikos
			Link: 				https://autohotkey.com/boards/viewtopic.php?f=6&t=2306
			Description: 	Object version - depends on current float format including a decimal point.
	*/
	/*                              	EXAMPLE(s)

			MsgBox % type("")     ; String
			MsgBox % type(1)      ; Integer
			MsgBox % type(1/1)    ; Float
			MsgBox % type("1")    ; String
			MsgBox % type(2**42)  ; Integer

	*/


    if IsObject(v)
        return "Object"
    return v="" || [v].GetCapacity(1) ? "String" : InStr(v,".") ? "Float" : "Integer"
} ;</21.01.000006>
;<21.01.000007>
type(ByRef v) {																											;-- COM version: Returns the type of a value: "Integer", "String", "Float" or "Object"

	/*                              	DESCRIPTION

			By:					Lexikos
			Link: 				https://autohotkey.com/boards/viewtopic.php?f=6&t=2306
			Description:		COM version - reports the wrong type for integers outside 32-bit range.

	*/


	if IsObject(v)
		return "Object"
	a := ComObjArray(0xC, 1)
	a[0] := v
	DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(a), "ptr*", ap)
	type := NumGet(ap+0, "ushort")
	DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(a))
	return type=3?"Integer" : type=8?"String" : type=5?"Float" : type
} ;</21.01.000007>
;<21.01.000008>
A_DefaultGui() {																										;-- a nice function to have a possibility to get the number of the default gui

	/*                              	DESCRIPTION

			Link: https://autohotkey.com/board/topic/24532-function-a-defaultgui/
			Description: You don't have the way to get the current default gui in AHK. This functions fills that hole.

	*/
	/*                              	EXAMPLE(s)

			Gui,13: Default
				msgbox % A_DefaultGui()

	*/


	if A_Gui !=
		return A_GUI

	Gui, +LastFound
	m := DllCall( "RegisterWindowMessage", Str, "GETDEFGUI")
	OnMessage(m, "A_DefaultGui")
	res := DllCall("SendMessageW", "uint",  WinExist(), "uint", m, "uint", 0, "uint", 0)		;use A for Ansi and W for Unicode
	OnMessage(m, "")
	return res
} ;</21.01.000008>

} ;</21.01.000008>
;|   ComVar()                                	|   ComVarGet()                            	|   ComVarSet()                            	|   GetScriptVARs()                        	|
;|   Valueof()                                 	|   type() x 2                                  	|   A_DefaultGui()                         	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Other languages/MCode (2)  -                                                                                                                  	baseID: <22>
;<22.01.000001>
MCode_Bin2Hex(addr, len, ByRef hex) { 							;-- By Lexikos, http://goo.gl/LjP9Zq
	Static fun
	If (fun = "") {
		If Not A_IsUnicode
			h =
			( LTrim Join
				8B54240C85D2568B7424087E3A53578B7C24148A07478AC8C0E90480F9090F97C3F6
				DB80E30702D980C330240F881E463C090F97C1F6D980E10702C880C130880E464A75
				CE5F5BC606005EC3
			)
		Else
			h =
			( LTrim Join
				8B44240C8B4C240485C07E53568B74240C578BF88A168AC2C0E804463C090FB6C076
				066683C037EB046683C03066890180E20F83C10280FA09760C0FB6D26683C2376689
				11EB0A0FB6C26683C03066890183C1024F75BD33D25F6689115EC333C0668901C3
			)
		VarSetCapacity(fun, n := StrLen(h)//2)
		Loop % n
			NumPut("0x" . SubStr(h, 2 * A_Index - 1, 2), fun, A_Index - 1, "Char")
	}
	hex := ""
	VarSetCapacity(hex, A_IsUnicode ? 4 * len + 2 : 2 * len + 1)
	DllCall(&fun, "uint", &hex, "uint", addr, "uint", len, "cdecl")
	VarSetCapacity(hex, -1) ;update StrLen
} ;</22.01.000001>
;<22.01.000002>
gcd(a, b) {                                                                    	;-- MCode GCD - Find the greatest common divisor (GCD) of two numbers

	/*	DESCRIPTION OF FUNCTION: -- gcd --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	MCode GCD - Find the greatest common divisor (GCD) of two numbers using the euclidean algorithm.
								I had been meaning to make an MCode version. guest3456's comment finally gave me the motivation.
								This runs in about 37% of the time it takes the function above, so it is much faster.
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=3514&start=20
	Author         	:	kon
	Date             	:	Aug. 18., 2014
	AHK-Version	:	v1
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:	non
	KeyWords    	:	Math
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	MsgBox, % gcd(18, 48)

	*/

	static gcd, x := MCode(gcd, "5589E583E4F083EC10E800000000EB1C8B450C8944240C8B450889C2C1FA1FF77D0C89550C8B44240C894508837D0C000F95C084C075D98B4508C9C3")
	return dllcall(&gcd, "Int",a, "Int",b)
} ;</22.01.000002>

}
;|                                              	|                                                   	|                                                       	|                                                    	|
;|   MCode_Bin2Hex()                	|   gcd(2)                                      	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ;Other (10) -- various not categorized functions --																						baseID: <23>
;<23.01.000001>
GetCommState(ComPort) {																							;-- this function retrieves the configuration settings of a given serial port

	/*                              	DESCRIPTION

			this function retrieves the configuration settings of a given serial port.
			Having hardly any C\C experience it took me some time to find out that there is a bitmask in the DCB (Device Configuration Block) structure.

			Using BuildCommDCB and SetCommState functions it should also be possible to configure a serial port.
			Data can be written to a serial port using one of the binary writing functions on this forum.
			I appologize for the script not beeing commented at all, also I am not sure if I did everything right. Comments and suggestions are welcome.

			Regards, 	olfen

			Dependencies:				DecToBin()
												ExtractInteger()

	*/

	/*                              	EXAMPLE(s)

			msgbox, % GetCommState(4)
			listvars
			pause

	*/



global
local h, cs, ch, port, DCB, Str, Uint

port=com%comport%
h := DllCall("CreateFile","Str", port,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
If (h = -1 or h = 0 or ErrorLevel != 0)
return, -1
VarSetCapacity(DCB, 28, 0)
cs := DllCall("GetCommState", Uint, h, str, DCB)
If (cs = 0 or ErrorLevel != 0)
return, -2

;DCB_DCBlength:=ExtractInteger(DCB, 0, true, 4)
DCB_BaudRate:=ExtractInteger(DCB, 4, true, 4)

DCB_fBitMask:=ExtractInteger(DCB, 8, true, 4)
DCB_fBitMaskDec:=DCB_fBitMask
DCB_fBitMask:=DecToBin(DCB_fBitMask)

StringLeft, DCB_fAbortOnError, DCB_fBitMask, 1
StringMid, DCB_fRtsControl, DCB_fBitMask, 2, 2
StringMid, DCB_fNull, DCB_fBitMask, 4, 1
StringMid, DCB_fErrorChar, DCB_fBitMask, 5, 1
StringMid, DCB_fInX, DCB_fBitMask, 6, 1
StringMid, DCB_fOutX, DCB_fBitMask, 7, 1
StringMid, DCB_fTXContinueOnXoff, DCB_fBitMask, 8, 1
StringMid, DCB_fDsrSensitivity, DCB_fBitMask, 9, 1
StringMid, DCB_fDtrControl, DCB_fBitMask, 10, 2
StringMid, DCB_fOutxDsrFlow, DCB_fBitMask, 12, 1
StringMid, DCB_fOutxCtsFlow, DCB_fBitMask, 13, 1
StringMid, DCB_fParity, DCB_fBitMask, 14, 1
StringRight, DCB_fBinary, DCB_fBitMask, 1

IfEqual, DCB_fDtrControl, 00, SetEnv, DCB_fDtrControl, DTR_CONTROL_DISABLE
IfEqual, DCB_fDtrControl, 01, SetEnv, DCB_fDtrControl, DTR_CONTROL_ENABLE
IfEqual, DCB_fDtrControl, 10, SetEnv, DCB_fDtrControl, DTR_CONTROL_HANDSHAKE

IfEqual, DCB_fRtsControl, 00, SetEnv, DCB_fRtsControl, RTS_CONTROL_DISABLE
IfEqual, DCB_fRtsControl, 01, SetEnv, DCB_fRtsControl, RTS_CONTROL_ENABLE
IfEqual, DCB_fRtsControl, 10, SetEnv, DCB_fRtsControl, RTS_CONTROL_HANDSHAKE
IfEqual, DCB_fRtsControl, 11, SetEnv, DCB_fRtsControl, RTS_CONTROL_TOGGLE

DCB_XonLim:=ExtractInteger(DCB, 14, true, 2)
DCB_XoffLim:=ExtractInteger(DCB, 16, true, 2)
DCB_ByteSize:=ExtractInteger(DCB, 18, true, 1)

DCB_Parity:=ExtractInteger(DCB, 19, true, 1)
IfEqual, DCB_Parity, 2, SetEnv, DCB_Parity, Even
IfEqual, DCB_Parity, 3, SetEnv, DCB_Parity, Mark
IfEqual, DCB_Parity, 0, SetEnv, DCB_Parity, None
IfEqual, DCB_Parity, 1, SetEnv, DCB_Parity, Odd
IfEqual, DCB_Parity, 4, SetEnv, DCB_Parity, Space

DCB_StopBits:=ExtractInteger(DCB, 20, true, 1)
IfEqual, DCB_StopBits, 2, SetEnv, DCB_StopBits, 2
IfEqual, DCB_StopBits, 1, SetEnv, DCB_StopBits, 1,5
IfEqual, DCB_StopBits, 0, SetEnv, DCB_StopBits, 1

DCB_XonChar:=ExtractInteger(DCB, 21, true, 1)
DCB_XoffChar:=ExtractInteger(DCB, 22, true, 1)
DCB_ErrorChar:=ExtractInteger(DCB, 23, true, 1)
DCB_EofChar:=ExtractInteger(DCB, 24, true, 1)
DCB_EvtChar:=ExtractInteger(DCB, 25, true, 1)

ch:=DllCall("CloseHandle", "Uint", h)
If (ch = 0 or ErrorLevel != 0)
return, -3
return, 0
} ;</23.01.000001>
;{ subfunction for GetCommState
DecToBin(In_Val) {
	local bit, bin, dec
	if In_Val is not integer
	return, "ERROR"
	dec:=In_Val
	Loop
	{
		bit:=mod(dec, 2)
		dec:=dec//2
		bin=%bit%%bin%
		IfEqual, dec, 0, break
  }
	return, %bin%
}
;} ;</23.01.000001>
;<23.01.000002>
pauseSuspendScript(ScriptTitle, suspendHotkeys := False, pauseScript := False) {	;-- function to suspend/pause another script

	/*                              	EXAMPLE(s)

			f1::
			msgbox % pauseSuspendScript("test2.ahk", True, True)
			return

	*/


	prevDetectWindows := A_DetectHiddenWindows
	prevMatchMode := A_TitleMatchMode
	DetectHiddenWindows, On
	SetTitleMatchMode, 2
	if (script_id := WinExist(ScriptTitle " ahk_class AutoHotkey"))
	{
		; Force the script to update its Pause/Suspend checkmarks.
		SendMessage, 0x211,,,, ahk_id %script_id%  ; WM_ENTERMENULOOP
		SendMessage, 0x212,,,, ahk_id %script_id%  ; WM_EXITMENULOOP
		; Get script status from its main menu.
		mainMenu := DllCall("GetMenu", "uint", script_id)
		fileMenu := DllCall("GetSubMenu", "uint", mainMenu, "int", 0)
		isPaused := DllCall("GetMenuState", "uint", fileMenu, "uint", 4, "uint", 0x400) >> 3 & 1
		isSuspended := DllCall("GetMenuState", "uint", fileMenu, "uint", 5, "uint", 0x400) >> 3 & 1
		DllCall("CloseHandle", "uint", fileMenu)
		DllCall("CloseHandle", "uint", mainMenu)
		if (suspendHotkeys && !isSuspended) || (!suspendHotkeys && isSuspended)
			PostMessage, 0x111, 65305, 1,,  ahk_id %script_id% ; this toggles the current suspend state.
		if (pauseScript && !isPaused) || (!pauseScript && isPaused)
			PostMessage, 0x111, 65403,,,  ahk_id %script_id% ; this toggles the current pause state.
	}
	DetectHiddenWindows, %prevDetectWindows%
	SetTitleMatchMode, %prevMatchMode%
	return script_id
} ;</23.01.000002>
;<23.01.000003>
RtlGetVersion() {																											;-- retrieves version of installed windows system

	; https://github.com/jNizM/ahk_pi-hole/blob/master/src/pi-hole.ahk
	 ; https://msdn.microsoft.com/en-us/library/mt723418(v=vs.85).aspx
	; 0x0A00 - Windows 10
	; 0x0603 - Windows 8.1
	; 0x0602 - Windows 8 / Windows Server 2012
	; 0x0601 - Windows 7 / Windows Server 2008 R2
	; 0x0600 - Windows Vista / Windows Server 2008
	; 0x0502 - Windows XP 64-Bit Edition / Windows Server 2003 / Windows Server 2003 R2
	; 0x0501 - Windows XP
	; 0x0500 - Windows 2000
	; 0x0400 - Windows NT 4.0
	static RTL_OSV_EX, init := NumPut(VarSetCapacity(RTL_OSV_EX, A_IsUnicode ? 284 : 156, 0), RTL_OSV_EX, "uint")
	if (DllCall("ntdll\RtlGetVersion", "ptr", &RTL_OSV_EX) != 0)
		throw Exception("RtlGetVersion failed", -1)
	return ((NumGet(RTL_OSV_EX, 4, "uint") << 8) | NumGet(RTL_OSV_EX, 8, "uint"))
} ;</23.01.000003>
;<23.01.000004>
PostMessageUnderMouse(Message, wParam = 0, lParam=0) {									;-- Post a message to the window underneath the mouse cursor, can be used to do things involving the mouse scroll wheel

	/*                              	DESCRIPTION

			 Func: PostMessageUnderMouse
			 Post a message to the window underneath the mouse cursor. I mostly uses to do things involving the mouse
			 scroll wheel. Note you should only call this from a hotkey.
			 All the parameters are the same as for PostMessage.
			 See \c SendMessage in AHK Help.


	*/

	oldCoordMode:= A_CoordModeMouse
	CoordMode, Mouse, Screen
	MouseGetPos X, Y, , , 2
	hWnd := DllCall("WindowFromPoint", "int", X , "int", Y)
	PostMessage %Message%, %wParam%, %lParam%, , ahk_id %hWnd%
	CoordMode, Mouse, %oldCoordMode%
  } ;</23.01.000004>
;<23.01.000005>
WM_SETCURSOR(wParam, lParam) { 																			;-- Prevent "sizing arrow" cursor when hovering over window border
		/*                              	DESCRIPTION

				Link: https://gist.github.com/grey-code/5304819
				WM_SETCURSOR := 0x0020
				standard arrow cursor

	*/
	static HARROW := DllCall("LoadCursor", "Ptr", 0, "Ptr", 32512, "UPtr")

	HTCODE := lParam & 0xFFFF
	if (HTCODE > 9) && (HTCODE < 19) { ; cursor is on a border
		DllCall("SetCursor", "Ptr", HARROW) ; show arrow cursor
		return true ; prevent further processing
	}
} ;</23.01.000005>
;<23.01.000006>
FoxitInvoke(command, FoxitID:="") {		                                                         			;-- wm_command wrapper for FoxitReader Version:  9.1
	/*    	DESCRIPTION of function FoxitInvoke() ID: 23.01.00006
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:	a WM_command wrapper for FoxitReader V9.1 by Ixiko
										this function is intended to facilitate the automation of FoxitReader
			Link              	:
			Author         	:	Ixiko
			Date             	:	28.11.2018
			AHK-Version	:	AHK_L
			License         	:
			Parameter(s)	:	using a valid Foxit handle, the command is sent to the FoxitReader
										otherwise this function returns the command code
				                		Remark: 	You have to control the success of the sendmessage command yourself!
											    		and there is no error handling on wrong FoxitID
			Return value	:
			Remark(s)    	:	I intentionally use a text first and then convert it to a key:value object,
										so you can swap out the object data to a file if needed
		                           		not all commands are listed at now!
			Dependencies	:	non
			KeyWords    	:	wm_command, wrapper, application remote,
        	-------------------------------------------------------------------------------------------------------------------
	*/

	/*    Example(s)

			FRCmd("Show_FullPage") 				  ; this one only returns the Foxit command, to use for yourself with send- oder postmessage
			FRCmd("Place_Signature", FoxitID)   ; PostMessage Place_Signature to the FoxitReader window with the ID: FoxitID and it returns the command
		---------------------------------------------------------------------------------------------------

	*/

	static FoxitCommand:= [], run:=0

	If !run {
		split:=[]
		FoxitCommands =
		(Comments
			SaveAs                                                             	: 1299
			Close                                                               	: 57602
			Hand                                                                	: 1348       	;Home - Tools
			Select_Text                                                       	: 46178     	;Home - Tools
			Select_Annotation                                              	: 46017     	;Home - Tools
			Snapshot                                                         	: 46069     	;Home - Tools
			Clipboard_SelectAll                                            	: 57642     	;Home - Tools
			Clipboard_Copy                                               	: 57634     	;Home - Tools
			Clipboard_Paste                                                 	: 57637     	;Home - Tools
			Actual_Size                                                      	: 1332       	;Home - View
			Fit_Page                                                           	: 1343       	;Home - View
			Fit_Width                                                         	: 1345        	;Home - View
			Reflow                                                             	: 32818     	;Home - View
			Zoom_Field                                                      	: 1363       	;Home - View
			Zoom_Plus                                                       	: 1360       	;Home - View
			Zoom_Minus                                                   	: 1362       	;Home - View
			Rotate_Left                                                      	: 1340       	;Home - View
			Rotate_Right                                                    	: 1337       	;Home - View
			Highlight                                                         	: 46130     	;Home - Comment
			Typewriter                                                        	: 46096     	;Home - Comment, Comment - TypeWriter
			Open_From_File                                                 	: 46140     	;Home - Create
			Open_Blank                                                     	: 46141     	;Home - Create
			Open_From_Scanner                                          	: 46165     	;Home - Create
			Open_From_Clipboard                                       	: 46142     	;Home - Create - new pdf from clipboard
			PDF_Sign                                                          	: 46157     	;Home - Protect
			Create_Link                                                         	: 46080     	;Home - Links
			Create_Bookmark                                               	: 46070     	;Home - Links
			File_Attachment                                               	: 46094     	;Home - Insert
			Image_Annotation                                              	: 46081     	;Home - Insert
			Audio_and_Video                                              	: 46082     	;Home - Insert
			Comments_Import                                          	: 46083     	;Comments
			Highlight                                                         	: 46130     	;Comments - Text Markup
			Squiggly_Underline                                          	: 46131     	;Comments - Text Markup
			Underline                                                         	: 46132     	;Comments - Text Markup
			Strikeout                                                          	: 46133     	;Comments - Text Markup
			Replace_Text                                                      	: 46134     	;Comments - Text Markup
			Insert_Text                                                       	: 46135     	;Comments - Text Markup
			Note                                                                	: 46137     	;Comments - Pin
	    	File                                                                   	: 46095     	;Comments - Pin
	    	Callout                                                                	: 46097     	;Comments - Typewriter
	    	Textbox                                                              	: 46098     	;Comments - Typewriter
	    	Rectangle                                                           	: 46101     	;Comments - Drawing
	    	Oval                                                                 	: 46102     	;Comments - Drawing
	    	Polygon                                                           	: 46103     	;Comments - Drawing
	    	Cloud                                                               	: 46104     	;Comments - Drawing
	    	Arrow                                                               	: 46105     	;Comments - Drawing
	    	Line                                                                  	: 46106     	;Comments - Drawing
	    	Polyline                                                            	: 46107     	;Comments - Drawing
	    	Pencil                                                               	: 46108     	;Comments - Drawing
	    	Eraser                                                               	: 46109     	;Comments - Drawing
	    	Area_Highligt                                                     	: 46136     	;Comments - Drawing
	    	Distance                                                          	: 46110     	;Comments - Measure
	    	Perimeter                                                          	: 46111     	;Comments - Measure
	    	Area                                                                 	: 46112     	;Comments - Measure
	    	Stamp				                                                	: 46149     	;Comments - Stamps , opens only the dialog
	    	Create_custom_stamp                                        	: 46151     	;Comments - Stamps
	    	Create_custom_dynamic_stamp                         	: 46152     	;Comments - Stamps
	    	Summarize_Comments                                   	: 46188     	;Comments - Manage Comments
	    	Import                                                              	: 46083     	;Comments - Manage Comments
	    	Export_All_Comments                                      	: 46086     	;Comments - Manage Comments
	    	Export_Highlighted_Texts                                   	: 46087     	;Comments - Manage Comments
	    	FDF_via_Email                                                   	: 46084     	;Comments - Manage Comments
	    	Comments                                                       	: 46088     	;Comments - Manage Comments
	    	Comments_Show_All                                        	: 46089     	;Comments - Manage Comments
	    	Comments_Hide_All                                        	: 46090     	;Comments - Manage Comments
	    	Popup_Notes                                                    	: 46091     	;Comments - Manage Comments
	    	Popup_Notes_Open_All                                    	: 46092     	;Comments - Manage Comments
	    	Popup_Notes_Close_All                                    	: 46093     	;Comments - Manage Comments
			firstPage                                                          	: 1286       	;View - Go To
			lastPage                                                           	: 1288       	;View - Go To
        	nextPage                                                         	: 1289       	;View - Go To
        	previousPage                                                   	: 1290       	;View - Go To
        	previousView                                                   	: 1335       	;View - Go To
        	nextView                                                          	: 1346       	;View - Go To
        	ReadMode                                                       	: 1351       	;View - Document Views
        	ReverseView                                                    	: 1353       	;View - Document Views
        	TextViewer                                                       	: 46180     	;View - Document Views
        	Reflow                                                             	: 32818     	;View - Document Views
        	turnPage_left                                                   	: 1340       	;View - Page Display
        	turnPage_right                                                 	: 1337       	;View - Page Display
        	SinglePage                                                      	: 1357       	;View - Page Display
        	Continuous                                                      	: 1338       	;View - Page Display
        	Facing                                                              	: 1356       	;View - Page Display - two pages side by side
        	Continuous_Facing                                           	: 1339       	;View - Page Display - two pages side by side with scrolling enabled
        	Separate_CoverPage                                         	: 1341       	;View - Page Display
        	Horizontally_Split                                              	: 1364       	;View - Page Display
        	Vertically_Split                                                  	: 1365       	;View - Page Display
        	Spreadsheet_Split                                             	: 1368       	;View - Page Display
        	Guides                                                             	: 1354       	;View - Page Display
        	Rulers                                                              	: 1355       	;View - Page Display
        	LineWeights                                                    	: 1350       	;View - Page Display
        	AutoScroll                                                        	: 1334       	;View - Assistant
        	Marquee                                                          	: 1361       	;View - Assistant
        	Loupe                                                              	: 46138     	;View - Assistant
        	Magnifier                                                         	: 46139     	;View - Assistant
        	Read_Activate                                                  	: 46198     	;View - Read
        	Read_CurrentPage                                           	: 46199     	;View - Read
        	Read_from_CurrentPage                                  	: 46200     	;View - Read
        	Read_Stop                                                       	: 46201     	;View - Read
        	Read_Pause                                                     	: 46206     	;View - Read
			Navigation_Panels                                           	: 46010      	;View - View Setting
			Navigation_Bookmark                                     	: 45401      	;View - View Setting
			Navigation_Pages                                            	: 45402     	;View - View Setting
			Navigation_Layers                                           	: 45403     	;View - View Setting
			Navigation_Comments                                    	: 45404     	;View - View Setting
			Navigation_Appends                                       	: 45405     	;View - View Setting
			Navigation_Security                                        	: 45406     	;View - View Setting
			Navigation_Signatures                                    	: 45408     	;View - View Setting
			Navigation_WinOff                                          	: 1318       	;View - View Setting
			Navigation_ResetAllWins                                	: 1316       	;View - View Setting
			Status_Bar                                                        	: 46008       	;View - View Setting
			Status_Show                                                    	: 1358       	;View - View Setting
			Status_Auto_Hide                                               	: 1333       	;View - View Setting
			Status_Hide                                                     	: 1349       	;View - View Setting
			WordCount                                                     	: 46179     	;View - Review
			Form_to_sheet                                                    	: 46072     	;Form - Form Data
			Combine_Forms_to_a_sheet                            	: 46074     	;Form - Form Data
			DocuSign                                                            	: 46189     	;Protect
			Login_to_DocuSign                                           	: 46190     	;Protect
			Sign_with_DocuSign                                          	: 46191     	;Protect
			Send_via_DocuSign                                          	: 46192     	;Protect
			Sign_and_Certify                                              	: 46181     	;Protect
			Place_Signature1                                              	: 46182     	;Protect
			Place_Signature2                                              	: 46183     	;Protect
			Validate                                                            	: 46185     	;Protect
			Time_Stamp_Document                                    	: 46184     	;Protect
			Digital_IDs                                                        	: 46186     	;Protect
			Trusted_Certificates                                            	: 46187     	;Protect
			Email                                                                 	: 1296       	;Share - Send To - same like Email current tab
			Email_All_Open_Tabs                                       	: 46012       	;Share - Send To
			Tracker                                                               	: 46207       	;Share - Tracker
			User_Manual                                                      	: 1277       	;Help - Help
			Help_Center                                                     	: 558        	;Help - Help
			Command_Line_Help                                         	: 32768        	;Help - Help
			Post_Your_Idea                                                  	: 1279        	;Help - Help
			Check_for_Updates                                            	: 46209        	;Help - Product
			Install_Update                                                    	: 46210        	;Help - Product
			Set_to_Default_Reader                                    	: 32770        	;Help - Product
			Foxit_Plug-Ins                                                    	: 1312        	;Help - Product
			About_Foxit_Reader                                           	: 57664        	;Help - Product
			Register                                                           	: 1280        	;Help - Register
			Open_from_Foxit_Drive                                   	: 1024        	;Extras - maybe this is not correct!
			Add_to_Foxit_Drive                                           	: 1025        	;Extras - maybe this is not correct!
			Delete_from_Foxit_Drive                                    	: 1026        	;Extras - maybe this is not correct!
			Options                                                           	: 243           	;the following one's are to set directly any options
			Use_single-key_accelerators_to_access_tools 	: 128           	;Options/General
			Use_fixed_resolution_for_snapshots                	: 126           	;Options/General
			Create_links_from_URLs                                   	: 133           	;Options/General
			Minimize_to_system_tray                                 	: 138           	;Options/General
			Screen_word-capturing                                    	: 127           	;Options/General
			Make_Hand_Tool_select_text                          	: 129           	;Options/General
			Double-click_to_close_a_tab                           	: 91             	;Options/General
			Auto-hide_status_bar                                      	: 162           	;Options/General
			Show_scroll_lock_button                                 	: 89             	;Options/General
			Automatically_expand_notification_message  	: 1725          	;Options/General - only 1 can be set from these 3
			Dont_automatically_expand_notification        	: 1726          	;Options/General - only 1 can be set from these 3
			Dont_show_notification_messages_again     		: 1727          	;Options/General - only 1 can be set from these 3
			Collect_data_to_improve_user_&experience   	: 111           	;Options/General
			Disable_all_features_which_require_internet 		: 562           	;Options/General
			Show_Start_Page                                             	: 160           	;Options/General
			Change_Skin                                                    	: 46004
			Filter_Options                                                  	: 46167        	;the following are searchfilter options
			Whole_words_only                                          	: 46168        	;searchfilter option
			Case-Sensitive                                                 	: 46169        	;searchfilter option
			Include_Bookmarks                                         	: 46170        	;searchfilter option
			Include_Comments                                          	: 46171        	;searchfilter option
			Include_Form_Data                                          	: 46172        	;searchfilter option
			Highlight_All_Text                                           	: 46173        	;searchfilter option
			Filter_Properties                                              	: 46174        	;searchfilter option
			Print                                                                 	: 57607
			Properties                                                        	: 1302          	;opens the PDF file properties dialog
			Mouse_Mode                                                  	: 1311
			Touch_Mode                                                   	: 1174
			predifined_Text                                               	: 46099
			set_predefined_Text                                        	: 46100
			Create_Signature                                             	: 26885     	;Signature
			Draw_Signature                                               	: 26902     	;Signature
			Import_Signature                                            	: 26886     	;Signature
			Paste_Signature                                               	: 26884     	;Signature
			Type_Signature                                                	: 27005     	;Signature
			Pdf_Sign_Close                                                	: 46164     	;Pdf-Sign
		)

		FoxitCommands:= StrReplace(FoxitCommands, A_Space, "")

		Loop, Parse, FoxitCommands, `n
		{
				line:= RegExReplace(A_LoopField, ";.*", "")
				split:= StrSplit(line, ":")
				key:= Trim(split[1])
				value:= Trim(split[2])
				FoxitCommand[key]:= value
		}

		run=1

	}

	If FoxitID {
		SendMessage, 0x111, % FoxitCommand[command],,, ahk_id %FoxitID%
		return ErrorLevel
	} else {
		return FoxitCommand[command]
	}

} ;</23.01.000006>
;<23.01.000007>
MoveMouse_Spiral(cx, cy, r, s, a) { 															        			;-- move mouse in a spiral

	/*    	DESCRIPTION

			Link:	        	https://autohotkey.com/boards/viewtopic.php?t=58006
			Author:    	wolf_II

	*/

	/*    	EXAMPLE(s)

			CoordMode, Mouse, Screen
			#SingleInstance Force
			Sleep 1000 ; ms

			KeyWait, LControl, D
			KeyWait, LButton, D


			MouseGetPos x, y
			MoveMouse_Spiral(x, y, 20, 36, 6) ; 36 steps per arm, 6 arms
			MouseClick, Left, cx, cy,, 0, U
			return


	*/

;-----------------------------------------------------------------------------
;----------------------------------------------------------------------------
    ; cx, cy = center coordinates    ; s = number of steps

    ; r = radius---
    ; a = number of spiral arms
    ;---------------------------------------------------------------------------
    $Pi := 4 * ATan(1)
    MouseClick, Left, cx, cy,, 0, D

    Loop, % s * a

			MouseMove

            , cx + r * Cos(A_Index * 2 * $Pi / s) * A_Index / s
            , cy + r * Sin(A_Index * 2 * $Pi / s) * A_Index / s
            Sleep 1 ; ms
            ,, 0
            Sleep 1 ; ms

} ;</23.01.000007>
;<23.01.000008>
ScaleToFit(width_max, height_max, width_actual, height_actual) {                         	;-- returns the dimensions of the scaled source rectangle that fits within the destination rectangle

	/*	DESCRIPTION OF FUNCTION: -- ScaleToFit --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	Accepts the dimensions of a source rectangle and the dimensions of a destination rectangle.
								Returns the dimensions of the scaled source rectangle that fits within the destination rectangle,
								at the largest possible size and while maintaining aspect ratio.
								Also returns the x and y offsets which center the scaled source rectangle within the
								destination rectangle.
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=3514
	Author         	:	LinearSpoon
	Date             	:	May, 14., 2014
	AHK-Version	:	V1
	License         	:
	Syntax          	:
	Parameter(s)	:
	Return value	:
	Remark(s)    	:
	Dependencies	:	none
	KeyWords    	:	Math, Gui, Graphic
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	ActualWidth := 200
	ActualHeight := 300

	Gui, Add, Picture, w%ActualWidth% h%ActualHeight% Border vpictureControl
	Gui, +Resize
	Gui, Show

	GuiSize:
	  dimensions := ScaleToFit(A_GuiWidth, A_GuiHeight, ActualWidth, ActualHeight)
	  GuiControl, Move, pictureControl, % "w" dimensions.width " h" dimensions.height " x" dimensions.x " y" dimensions.y
	return

	GuiClose:
	  ExitApp
	return

	*/

  width_ratio := width_actual / width_max
  height_ratio := height_actual / height_max
  if (width_ratio > height_ratio)
  {
    new_height := height_actual // width_ratio
    return {width:width_max, height:new_height, x:0, y:(height_max-new_height)//2}
  }
  else
  {
    new_width := width_actual // height_ratio
    return {width:new_width, height:height_max, x:(width_max-new_width)//2, y:0}
  }
} ;</23.01.000008>
;<23.01.000009>
LockCursorToPrimaryMonitor(lock = true) {                                                           	;-- prevents the cursor from leaving the primary monitor

	/*	DESCRIPTION OF FUNCTION: -- LockCursorToPrimaryMonitor --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	prevents the cursor from leaving the primary monitor
	Link              	:	https://gist.github.com/tmplinshi/889a14874ac943a2fe8245338feaca37
	Author         	:	tmplinshi
	Date             	:	--
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	cursor
	-------------------------------------------------------------------------------------------------------------------
	<	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	; Holding down left Control key to lock, release to unlock.
	~LControl::
		LockCursorToPrimaryMonitor(true)
		KeyWait, LControl
		LockCursorToPrimaryMonitor(false)
	return
	*/

	; Get mouse position on screen
	VarSetCapacity( pt, 8, 0 )
	DllCall("GetCursorPos", "Ptr", &pt)
	x := NumGet(pt, 0, "Int")

	; If the cursor already on the second monitor, then leave it there.
	if (x > A_ScreenWidth) {
		return
	}

	; ClipCursor -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms648383(v=vs.85).aspx
	if (lock) {
		VarSetCapacity(rect, 16, 0)
		NumPut(A_ScreenWidth, rect, 8)
		NumPut(A_ScreenHeight, rect, 12)
		DllCall("ClipCursor", "ptr", &rect)
	} else {
		DllCall("ClipCursor", "ptr", 0)
	}
} ;</23.01.000009>
;<23.01.000010>
GetCaretPos(ByRef x, ByRef y) {                                                                                	;-- Alternative to A_CaretX & A_CaretY (maybe not better)

	/*	DESCRIPTION OF FUNCTION: -- https://www.autohotkey.com/boards/viewtopic.php?t=64101&p=274740 --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	alternative to A_CaretX & A_CaretY - but maybe not better
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?t=64101&p=274740
	Author         	:	feiyue
	Date             	:	29-Apr-2019
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	--
	Remark(s)    	:	--
	Dependencies	:	none
	KeyWords    	:	Caret, input, gui, position
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	F1::
	CoordMode, Caret, Screen
	GetCaretPos(x, y)
	MsgBox, % "MY :`t" x ", " y "`nAHK:`t" A_CaretX ", " A_CaretY
	return
	-------------------------------------------------------------------------------------------------------------------
	*/

	/* typedef struct tagGUITHREADINFO {
	  DWORD cbSize;        //4
	  DWORD flags;         //4
	  HWND  hwndActive;    //A_PtrSize
	  HWND  hwndFocus;     //A_PtrSize
	  HWND  hwndCapture;   //A_PtrSize
	  HWND  hwndMenuOwner; //A_PtrSize
	  HWND  hwndMoveSize;  //A_PtrSize
	  HWND  hwndCaret;     //A_PtrSize
	  RECT  rcCaret;       //16
	} GUITHREADINFO
	*/

  static Size:=8+(A_PtrSize*6)+16, hwndCaret:=8+A_PtrSize*5
  Static CaretX:=8+(A_PtrSize*6), CaretY:=CaretX+4
  VarSetCapacity(Info, Size, 0), NumPut(Size, Info, "Int")
  DllCall("GetGUIThreadInfo", "UInt", 0, "Ptr", &Info), x:=y:=""
  if !(HWND:=NumGet(Info, hwndCaret, "Ptr"))
    return, 0
  x:=NumGet(Info, CaretX, "Int"), y:=NumGet(Info, CaretY, "Int")
  VarSetCapacity(pt, 8), NumPut(y, NumPut(x, pt, "Int"), "Int")
  DllCall("ClientToScreen", "Ptr", HWND, "Ptr", &pt)
  x:=NumGet(pt, 0, "Int"), y:=NumGet(pt, 4, "Int")
  return, 1
} ;</23.01.000010>
;<23.01.000011>
StdErr_Write(LineNumber, text, spec = "") {                                                            	;-- write directly to stderr for custom error messages

	/*	DESCRIPTION OF FUNCTION: -- StdErr_Write_ --
	-------------------------------------------------------------------------------------------------------------------
	Description  	:	this can be used to write own error messages to stderr
	Link              	:	https://www.autohotkey.com/boards/viewtopic.php?f=6&t=978
	Author         	:	"Lexikos" (edited by Holle: "Use the same format like the other error messages" ...testet with SciTE4AutoHotkey Version 3.0.04)
                                 Original thread: http://www.autohotkey.com/board/topic/50306-can-a-script-write-to-stderr/?hl=errorstdout#entry314658
	Date             	:	2013 / 12 / 12
	AHK-Version	:	AHK_L
	License         	:	--
	Syntax          	:	--
	Parameter(s)	:	--
	Return value	:	---
	Remark(s)    	:	testet with SciTE4Autohotkey Version 3.0.04
	Dependencies	:	StdErr_Write_
	KeyWords    	:	stderr, debug
	-------------------------------------------------------------------------------------------------------------------
	|	EXAMPLE(s)
	-------------------------------------------------------------------------------------------------------------------
	StdErr_Write(A_LineNumber,"This function needs pairs of parameter.","odd number")
    month<1 || month>12 ? StdErr_Write(A_LineNumber,"The variable month must have a value between 1 and 12.","month := " month)
	*/

	text := A_ScriptFullPath " (" LineNumber ") : ==>  " . text
	text .= spec?"`n     Specifically: " spec "`n":
    if A_IsUnicode
        return StdErr_Write_("astr", text, StrLen(text))
    return StdErr_Write_("uint", &text, StrLen(text))
}
StdErr_Write_(type, data, size) {
    static STD_ERROR_HANDLE := -12
    if (hstderr := DllCall("GetStdHandle", "uint", STD_ERROR_HANDLE)) = -1
        return false
    return DllCall("WriteFile", "uint", hstderr, type, data, "uint", size, "uint", 0, "uint", 0)
} ;</23.01.000011>

}
;|   pauseSuspendScript(01)          	|   GetCommState(02)                  	|   RtlGetVersion(03)                     	|   PostMessageUnderMouse(04)  	|
;|   WM_SETCURSOR(05)              	|   FoxitInvoke(06)                        	|   MoveMouse_Spiral(07)             	|   ScaleToFit(08)                          	|
;|   LockCursorToPrimaryMonitor(9)	|   GetCaretPos(10)                       	|   StdErr_Write(11)                       	|
;---------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------------------------------------------------------------

{ ; RegEx   - 																																						baseID: <24>

	;1. ####### AHK Code finders ###########


		; a) https://autohotkey.com/boards/viewtopic.php?f=60&t=29996
		; If you would like, this is the RegEx I use to find function definitions, it could probably be improved on still for efficiency, but it might save people a step if they have those multi-line function definitions.
			funcdef:=	"^[ \t]*(?!(if\(|while\(|for\())([\w#!^+&<>*~$])+\d*\([^)]*\)([\s]|(/\*.*?\*)/|((?<=[\s]);[^\r\n]*?$))*?[\s]*\{"
						or
			funcfinder01:= "^\s*\w+\(.*?\)\s*(;?.*\n(^\s*(;.*|)\n)*?^\s*|)\{"		;from https://autohotkey.com/board/topic/7807-editor/#entry48536
			funcfinder02:= "^[a-zA-Z0-9_].*(\(.*\))"											;tested works most in SciTE find dialog
			funcfinder03:= "[a-zA-Z0-9_]*\([a-zA-Z0-9_\,]*\)\s*\{*.*\}*"			;tested works in AHK Code - finds all functions

		; If you want it to not find functions with no parameters I believe you just need to change a * to a + like:
			funcdefNoParams:= 			"^[ \t]*(?!(if\(|while\(|for\())([\w#!^+&<>*~$])+\d*\([^)]+\)([\s]|(/\*.*?\*)/|((?<=[\s]);[^\r\n]*?$))*?[\s]*\{"
		; finds all in () including the brackets
			findAllinBrackets:= 				"(\(.*\))"
			SpaceAtLineBeginning:= 	"^[\s]*"
		; find alphanumeric words
			findAllWordsIncludingDoubleNames:= ([A-Za-z|-])+   ;finds Peter Tiger-Woods => Match1: Peter , Match2: Tiger-Woods

			Code := RegExReplace(Code,"mS)(?:^| );.*$") 																;remove single line comments
			Code := RegExReplace(Code,"msS)^ */\*.*?\r\n *\*/") 												;remove multiline comments
			Code := RegExReplace(Code,"S)""(?:[^""]|"""")*""","|") 												;remove string literals
			Code := RegExReplace(Code,"mS)^ *([\w#_@\$%]+) *=.*?$","$1") 							;remove classic assignment text

		; strip ahk_ from start and .ahk from end
			ApplicationName    := RegExReplace(A_ScriptName,"i)(ahk_)(.*)([.]ahk)","$2")

	;2. ####### scite ##############
			finds ahk functions ^\([a-zA-Z]\w*(.*).*{\)
			finds every tab except it was followed from signs: (\t)[^;\w\d\(\)\[\]\:]
			finds every tab except it was not forwarded and followed from signs: [^\t;\w\d\(\)\[\]\:\{\}\-](\t)[^;\w\d\(\)\[\]\:\{\}\-]
			\t+[^(\t;\w)|(\t,)|(\t\{)|(\t\()|(\t\})|(\t\/)|(\t\*)|(\t\-)|(\t\:)|(\t\?)]

}
;|                                                   	|                                                   	|                                                   	|                                                   	|
;|  1. Regex Strings to find functions	|

}





;{
	/*    	DESCRIPTION of function
        	-------------------------------------------------------------------------------------------------------------------
			Description  	:
			Link              	:
			Author         	:
			Date             	:
			AHK-Version	:
			License         	:
			Parameter(s)	:
			Return value	:
			Remark(s)    	:
			Dependencies	:
			KeyWords    	:
        	-------------------------------------------------------------------------------------------------------------------
	*/


	/*    	EXAMPLE(s)



	*/

;}



























