PageRenderTime 66ms CodeModel.GetById 22ms app.highlight 24ms RepoModel.GetById 2ms app.codeStats 1ms

/MiscFunctions.ahk

http://7plus.googlecode.com/
AutoHotKey | 1982 lines | 1583 code | 138 blank | 261 comment | 252 complexity | 24a07046b0c280babd51b8a14b0415d3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1;This file contains various functions for all kinds of things. YAY!
   2
   3#include *i %A_ScriptDir%\lib\Array.ahk
   4
   5;Gets a localized string from a resource file.
   6;usage example:
   7;x := TranslateMUI("shell32.dll",31236)
   8TranslateMUI(resDll, resID)
   9{
  10	VarSetCapacity(buf, 256) 
  11	hDll := DllCall("LoadLibrary", "str", resDll, "Ptr") 
  12	Result := DllCall("LoadString", "Ptr", hDll, "uint", resID, "str", buf, "int", 128)
  13	return buf
  14}
  15
  16;Finds the path of the Shell32.dll.mui file
  17LocateShell32MUI()
  18{
  19	VarSetCapacity(buffer, 85*2)
  20	length:=DllCall("GetUserDefaultLocaleName","UIntP",buffer,"UInt",85)
  21	if(A_IsUnicode)
  22		locale := StrGet(buffer)
  23	shell32MUIpath:=A_WinDir "\winsxs\*_microsoft-windows-*resources*" locale "*" ;\x86_microsoft-windows-shell32.resources_31bf3856ad364e35_6.1.7600.16385_de-de_b08f46c44b512da0\shell32.dll.mui
  24	loop %shell32MUIpath%,2,0
  25		if(FileExist(A_LoopFileFullPath "\shell32.dll.mui"))
  26			return A_LoopFileFullPath "\shell32.dll.mui"
  27}
  28
  29;Splits a command into command and arguments
  30SplitCommand(fullcmd, ByRef cmd, ByRef args)
  31{
  32	if(InStr(fullcmd, """") = 1)
  33	{
  34		pos := InStr(fullcmd, """" , 0, 2)
  35		cmd := SubStr(fullcmd, 2,pos - 2)
  36		args := SubStr(fullcmd, pos + 1)
  37		args := strTrim(args, " ")
  38	}
  39	else if(pos:=InStr(fullcmd, " " , 0, 1))
  40	{
  41		cmd := SubStr(fullcmd, 1, pos-1)
  42		args := SubStr(fullcmd, pos+1)
  43		args := strTrim(args, " ")
  44	}
  45	else
  46	{
  47		cmd := fullcmd
  48		args := ""
  49	}
  50}
  51
  52;Gets a free gui number.
  53/* Group: About
  54	o v0.81 by majkinetor.
  55	o Licenced under BSD <http://creativecommons.org/licenses/BSD/> 
  56*/
  57GetFreeGuiNum(start, prefix = ""){
  58	loop
  59	{
  60		Gui %prefix%%start%:+LastFoundExist
  61		IfWinNotExist
  62			return prefix start
  63		start++
  64		if(start = 100)
  65			return 0
  66	}
  67	return 0
  68}
  69
  70;Checks if a specific window is under the cursor.
  71IsWindowUnderCursor(hwnd)
  72{
  73	MouseGetPos, , , win
  74	if hwnd is number
  75		return win = hwnd
  76	else
  77		return InStr(WinGetClass("ahk_class " win), hwnd)
  78}
  79
  80;Checks if a specific control is under the cursor and returns its ClassNN if it is.
  81IsControlUnderCursor(ControlClass)
  82{
  83	MouseGetPos, , , , control
  84	if(InStr(Control, ControlClass))
  85		return control
  86	return false
  87}
  88
  89;Sets window event hook
  90API_SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags) {
  91   return DllCall("SetWinEventHook", "uint", eventMin, "uint", eventMax, "Ptr", hmodWinEventProc, "uint", lpfnWinEventProc, "uint", idProcess, "uint", idThread, "uint", dwFlags, "Ptr") 
  92} 
  93
  94;Unhooks window event hook
  95API_UnhookWinEvent( hWinEventHook ) { 
  96   return DllCall("UnhookWinEvent", "Ptr", hWinEventHook) 
  97} 
  98
  99;disables or restores original minimize anim setting
 100DisableMinimizeAnim(disable)
 101{
 102	static original,lastcall	
 103	if(disable && !lastcall) ;Backup original value if disabled is called the first time after a restore call
 104	{
 105		lastcall:=1
 106		RegRead, original, HKCU, Control Panel\Desktop\WindowMetrics , MinAnimate
 107	}
 108	else if(!disable) ;this is a restore call, on next disable backup may be created again
 109		lastcall:=0
 110	;Disable Minimize/Restore animation
 111	VarSetCapacity(struct, 8, 0)	
 112	NumPut(8, struct, 0, "UInt")
 113	if(disable || !original)
 114		NumPut(0, struct, 4, "Int")
 115	else
 116		NumPut(1, struct, 4, "UInt")
 117	DllCall("SystemParametersInfo", "UINT", 0x0049,"UINT", 8,"Ptr", &struct,"UINT", 0x0003) ;SPI_SETANIMATION            0x0049 SPIF_SENDWININICHANGE 0x0002
 118}
 119
 120/* 
 121Performs a hittest on the window under the mouse and returns the WM_NCHITTEST Result
 122#define HTERROR             (-2) 
 123#define HTTRANSPARENT       (-1) 
 124#define HTNOWHERE           0 
 125#define HTCLIENT            1 
 126#define HTCAPTION           2 
 127#define HTSYSMENU           3 
 128#define HTGROWBOX           4 
 129#define HTSIZE              HTGROWBOX 
 130#define HTMENU              5 
 131#define HTHSCROLL           6 
 132#define HTVSCROLL           7 
 133#define HTMINBUTTON         8 
 134#define HTMAXBUTTON         9 
 135#define HTLEFT              10 
 136#define HTRIGHT             11 
 137#define HTTOP               12 
 138#define HTTOPLEFT           13 
 139#define HTTOPRIGHT          14 
 140#define HTBOTTOM            15 
 141#define HTBOTTOMLEFT        16 
 142#define HTBOTTOMRIGHT       17 
 143#define HTBORDER            18 
 144#define HTREDUCE            HTMINBUTTON 
 145#define HTZOOM              HTMAXBUTTON 
 146#define HTSIZEFIRST         HTLEFT 
 147#define HTSIZELAST          HTBOTTOMRIGHT 
 148#if(WINVER >= 0x0400) 
 149#define HTOBJECT            19 
 150#define HTCLOSE             20 
 151#define HTHELP              21 
 152*/ 
 153MouseHitTest()
 154{
 155	CoordMode, Mouse, Screen
 156	MouseGetPos, MouseX, MouseY, WindowUnderMouseID 
 157	WinGetClass, winclass , ahk_id %WindowUnderMouseID%
 158	if winclass in BaseBar,D2VControlHost,Shell_TrayWnd,WorkerW,ProgMan  ; make sure we're not doing this on the taskbar
 159		return -2
 160	; WM_NCHITTEST 
 161	SendMessage, 0x84,, ( (MouseY&0xFFFF) << 16 )|(MouseX&0xFFFF),, ahk_id %WindowUnderMouseID%
 162	return ErrorLevel
 163}
 164
 165;Returns true if there is an available internet connection
 166IsConnected(URL="http://code.google.com/p/7plus/")
 167{
 168	return DllCall("Wininet.dll\InternetCheckConnection", "Str", URL,"UInt", 1, "UInt",0, "UInt")
 169}
 170
 171/*! TheGood (modified a bit by Fragman)
 172    Checks if a window is in fullscreen mode. 
 173    ______________________________________________________________________________________________________________ 
 174    sWinTitle       - WinTitle of the window to check. Same syntax as the WinTitle parameter of, e.g., WinExist(). 
 175    bRefreshRes     - Forces a refresh of monitor data (necessary if resolution has changed) 
 176    UseExcludeList  - returns false if window class is in FullScreenExclude (explorer, browser etc)
 177    UseIncludeList  - returns true if window class is in FullScreenInclude (applications capturing gamepad input)
 178    Return value    o If window is fullscreen, returns the index of the monitor on which the window is fullscreen. 
 179                    o If window is not fullscreen, returns False. 
 180    ErrorLevel      - Sets ErrorLevel to True if no window could match sWinTitle 
 181    
 182        Based on the information found at http://support.microsoft.com/kb/179363/ which discusses under what 
 183    circumstances does a program cover the taskbar. Even if the window passed to IsFullscreen is not the 
 184    foreground application, IsFullscreen will check if, were it the foreground, it would cover the taskbar. 
 185*/ 
 186IsFullscreen(sWinTitle = "A", UseExcludeList = true, UseIncludeList=true) { 
 187    Static 
 188    Local iWinX, iWinY, iWinW, iWinH, iCltX, iCltY, iCltW, iCltH, iMidX, iMidY, iMonitor, c, D, iBestD 
 189    ErrorLevel := False
 190	;Without admin mode processes launched with admin permissions aren't detectable, so better treat all windows as non-fullscreen.
 191	if(!A_IsAdmin)
 192		return false
 193		
 194    ;Get the active window's dimension 
 195    hWin := WinExist(sWinTitle) 
 196    If Not hWin { 
 197        ErrorLevel := True 
 198        Return False 
 199    }
 200    
 201    ;Make sure it's not desktop 
 202    WinGetClass, c, ahk_id %hWin% 
 203    If (hWin = DllCall("GetDesktopWindow", "Ptr") Or (c = "Progman") Or (c = "WorkerW")) 
 204        Return False 
 205    ;Fullscreen include list
 206    if(UseIncludeList)
 207	{
 208		FullscreenInclude := Settings.Misc.FullScreenInclude
 209    	if c in %FullscreenInclude%
 210			return true
 211	}
 212    ;Fullscreen exclude list
 213    if(UseExcludeList)
 214	{
 215		FullscreenExclude := Settings.Misc.FullScreenExclude
 216    	if c in %FullscreenExclude%
 217			return false
 218	}
 219    ;Resolution change would only need to be detected every few seconds or so, but since it doesn't add anything notably to cpu usage, just do it always
 220    SysGet, Mon0, MonitorCount 
 221    SysGet, iPrimaryMon, MonitorPrimary 
 222    Loop %Mon0% { ;Loop through each monitor 
 223        SysGet, Mon%A_Index%, Monitor, %A_Index% 
 224        Mon%A_Index%MidX := Mon%A_Index%Left + Ceil((Mon%A_Index%Right - Mon%A_Index%Left) / 2) 
 225        Mon%A_Index%MidY := Mon%A_Index%Top + Ceil((Mon%A_Index%Top - Mon%A_Index%Bottom) / 2) 
 226    }    
 227			
 228    ;Get the window and client area, and style 
 229    VarSetCapacity(iWinRect, 16), VarSetCapacity(iCltRect, 16) 
 230    DllCall("GetWindowRect", "Ptr", hWin, "Ptr", &iWinRect) 
 231	DllCall("GetClientRect", "Ptr", hWin, "Ptr", &iCltRect)
 232    WinGet, iStyle, Style, ahk_id %hWin% 
 233    
 234    ;Extract coords and sizes 
 235    iWinX := NumGet(iWinRect, 0), iWinY := NumGet(iWinRect, 4) 
 236    iWinW := NumGet(iWinRect, 8) - NumGet(iWinRect, 0) ;Bottom-right coordinates are exclusive 
 237    iWinH := NumGet(iWinRect, 12) - NumGet(iWinRect, 4) ;Bottom-right coordinates are exclusive 
 238    iCltX := 0, iCltY := 0 ;Client upper-left always (0,0) 
 239    iCltW := NumGet(iCltRect, 8), iCltH := NumGet(iCltRect, 12) 
 240    ; outputdebug iCltW %iCltW% iCltH %iCltH%
 241    ;Check in which monitor it lies 
 242    iMidX := iWinX + Ceil(iWinW / 2) 
 243    iMidY := iWinY + Ceil(iWinH / 2) 
 244    
 245   ;Loop through every monitor and calculate the distance to each monitor 
 246   iBestD := 0xFFFFFFFF 
 247    Loop % Mon0 { 
 248      D := Sqrt((iMidX - Mon%A_Index%MidX)**2 + (iMidY - Mon%A_Index%MidY)**2) 
 249      If (D < iBestD) { 
 250         iBestD := D
 251         iMonitor := A_Index 
 252      } 
 253   } 
 254	
 255    ;Check if the client area covers the whole screen 
 256    bCovers := (iCltX <= Mon%iMonitor%Left) And (iCltY <= Mon%iMonitor%Top) And (iCltW >= Mon%iMonitor%Right - Mon%iMonitor%Left) And (iCltH >= Mon%iMonitor%Bottom - Mon%iMonitor%Top) 
 257    If(bCovers)
 258		Return True
 259    ;Check if the window area covers the whole screen and styles 
 260    bCovers := (iWinX <= Mon%iMonitor%Left) And (iWinY <= Mon%iMonitor%Top) And (iWinW >= Mon%iMonitor%Right - Mon%iMonitor%Left) And (iWinH >= Mon%iMonitor%Bottom - Mon%iMonitor%Top) 
 261    If (bCovers) ;WS_THICKFRAME or WS_CAPTION 
 262	{
 263        bCovers &= Not (iStyle & 0x00040000) Or Not (iStyle & 0x00C00000) 
 264		Return bCovers ? iMonitor : False 
 265    } 
 266	Else 
 267		Return False 
 268}
 269
 270;Returns the workspace area covered by the active monitor
 271GetActiveMonitorWorkspaceArea(ByRef MonLeft, ByRef MonTop, ByRef MonW, ByRef MonH,hWndOrMouseX, MouseY = "")
 272{
 273	mon := GetActiveMonitor(hWndOrMouseX, MouseY)
 274	if(mon>=0)
 275	{
 276		SysGet, Mon, MonitorWorkArea, %mon%
 277		MonW := MonRight - MonLeft
 278		MonH := MonBottom - MonTop
 279	}
 280}
 281
 282;Returns the monitor the mouse or the active window is in
 283GetActiveMonitor(hWndOrMouseX, MouseY = "")
 284{
 285	if(MouseY="")
 286	{
 287		WinGetPos,x,y,w,h,ahk_id %hWndOrMouseX%
 288		if(!x && !y && !w && !h)
 289		{
 290			MsgBox GetActiveMonitor(): invalid window handle!
 291			return -1
 292		}
 293		x := x + Round(w/2)
 294		y := y + Round(h/2)
 295	}
 296	else
 297	{
 298		x := hWndOrMouseX
 299		y := MouseY
 300	}
 301	;Loop through every monitor and calculate the distance to each monitor 
 302	iBestD := 0xFFFFFFFF 
 303	SysGet, Mon0, MonitorCount
 304	Loop %Mon0% { ;Loop through each monitor 
 305        SysGet, Mon%A_Index%, Monitor, %A_Index% 
 306        Mon%A_Index%MidX := Mon%A_Index%Left + Ceil((Mon%A_Index%Right - Mon%A_Index%Left) / 2) 
 307        Mon%A_Index%MidY := Mon%A_Index%Top + Ceil((Mon%A_Index%Top - Mon%A_Index%Bottom) / 2) 
 308    }
 309    Loop % Mon0 { 
 310      D := Sqrt((x - Mon%A_Index%MidX)**2 + (y - Mon%A_Index%MidY)**2) 
 311      If (D < iBestD) { 
 312         iBestD := D 
 313         iMonitor := A_Index 
 314      } 
 315   }
 316   return iMonitor
 317}
 318;Returns the (signed) minimum of the absolute values of x and y 
 319absmin(x,y)
 320{
 321	return abs(x) > abs(y) ? y : x
 322}
 323
 324;Returns the (signed) maximum of the absolute values of x and y
 325absmax(x,y)
 326{
 327	return abs(x) < abs(y) ? y : x
 328}
 329
 330;Returns 1 if x is positive or 0 and -1 if x is negative
 331sign(x)
 332{
 333	return x < 0 ? -1 : 1
 334}
 335
 336;returns the maximum of xdir and y, but with the sign of xdir
 337dirmax(xdir,y)
 338{
 339	if(xdir = 0)
 340		return 0
 341	if(abs(xdir) > y)
 342		return xdir
 343	return xdir / abs(xdir) * abs(y)
 344}
 345
 346;returns the maximum of xdir and y, but with the sign of xdir
 347dirmin(xdir,y)
 348{
 349	if(xdir = 0)
 350		return 0
 351	if(abs(xdir) < y)
 352		return xdir
 353	return xdir / abs(xdir) * abs(y)
 354}
 355
 356;Formats a number in hexadecimal
 357DecToHex( ByRef var ) 
 358{ 
 359	f := A_FormatInteger
 360   SetFormat, Integer, Hex 
 361   var += 0
 362   ; SetFormat, Integer, %f%
 363   return var
 364}
 365
 366;Determines if a string starts with another string. NOTE: It's a bit faster to simply use InStr(string, start) = 1
 367strStartsWith(string,start)
 368{	
 369	return InStr(string, start) = 1
 370}
 371
 372;Determines if a string ends with another string
 373strEndsWith(string, end)
 374{
 375	return strlen(end) <= strlen(string) && Substr(string, -strlen(end) + 1) = end
 376}
 377
 378;Removes all occurences of trim at the beginning and end of string
 379;trim can be an array of strings that should be removed.
 380strTrim(string, trim)
 381{
 382	return strTrimLeft(strTrimRight(string, trim), trim)
 383}
 384
 385;Removes all occurences of trim at the beginning of string
 386;trim can be an array of strings that should be removed.
 387strTrimLeft(string, trim)
 388{
 389	if(!IsObject(trim))
 390		trim := [trim]
 391	for index, trimString in trim
 392	{
 393		len := strLen(trimString)
 394		while(InStr(string, trimString) = 1)
 395			StringTrimLeft, string, string, %len%
 396	}
 397	return string
 398}
 399
 400;Removes all occurences of trim at the end of string
 401;trim can be an array of strings that should be removed.
 402strTrimRight(string, trim)
 403{
 404	if(!IsObject(trim))
 405		trim := [trim]
 406	for index, trimString in trim
 407	{
 408		len := strLen(trimString)
 409		while(strEndsWith(string, trimString))
 410			StringTrimRight, string, string, %len%
 411	}
 412	return string
 413}
 414
 415;Finds the first window matching specific criterias.
 416FindWindow(title, class="", style="", exstyle="", processname="", allowempty = false)
 417{
 418	WinGet, id, list,,, Program Manager
 419	Loop, %id%
 420	{
 421		this_id := id%A_Index%
 422		WinGetClass, this_class, ahk_id %this_id%
 423		if(class && class!=this_class)
 424			Continue
 425		WinGetTitle, this_title, ahk_id %this_id%
 426		if(title && title!=this_title)
 427			Continue
 428		WinGet, this_style, style, ahk_id %this_id%
 429		if(style && style!=this_style)
 430			Continue
 431		WinGet, this_exstyle, exstyle, ahk_id %this_id%
 432		if(exstyle && exstyle!=this_exstyle)
 433			Continue			
 434		WinGetPos ,,,w,h,ahk_id %this_id%
 435		if(!allowempty && (w=0 || h=0))
 436			Continue		
 437		WinGet, this_processname, processname, ahk_id %this_id%
 438		if(processname && processname!=this_processname)
 439			Continue
 440		return this_id
 441	}
 442	return 0
 443}
 444
 445
 446;Gets the process name from a window handle.
 447GetProcessName(hwnd)
 448{
 449	WinGet, ProcessName, processname, ahk_id %hwnd%
 450	return ProcessName
 451}
 452
 453;Gets the path of a process by its pid
 454GetModuleFileNameEx(pid) 
 455{ 
 456   if A_OSVersion in WIN_95,WIN_98,WIN_ME 
 457   { 
 458      MsgBox, This Windows version (%A_OSVersion%) is not supported. 
 459      return 
 460   } 
 461
 462   /* 
 463      #define PROCESS_VM_READ           (0x0010) 
 464      #define PROCESS_QUERY_INFORMATION (0x0400) 
 465   */ 
 466   h_process := DllCall("OpenProcess", "uint", 0x10|0x400, "int", false, "uint", pid, "Ptr") 
 467   if (ErrorLevel || h_process = 0) 
 468   { 
 469      outputdebug [OpenProcess] failed. PID = %pid%
 470      return 
 471   } 
 472    
 473   name_size := A_IsUnicode ? 510 : 255 
 474   VarSetCapacity(name, name_size) 
 475    
 476   result := DllCall("psapi.dll\GetModuleFileNameEx", "Ptr", h_process, "uint", 0, "str", name, "uint", name_size) 
 477   if(ErrorLevel || result = 0) 
 478      outputdebug [GetModuleFileNameExA] failed 
 479    
 480   DllCall("CloseHandle", "Ptr", h_process)
 481   return name 
 482}
 483
 484; Extract an icon from an executable, DLL or icon file. 
 485ExtractIcon(Filename, IconNumber = 0, IconSize = 64) 
 486{ 
 487    ; LoadImage is not used.. 
 488    ; ..with exe/dll files because: 
 489    ;   it only works with modules loaded by the current process, 
 490    ;   it needs the resource ordinal (which is not the same as an icon index), and 
 491    ; ..with ico files because: 
 492    ;   it can only load the first icon (of size %IconSize%) from an .ico file. 
 493    
 494    ; If possible, use PrivateExtractIcons, which supports any size of icon. 
 495	; r:=DllCall("PrivateExtractIcons" , "str", Filename, "int", IconNumber-1, "int", IconSize, "int", IconSize, "Ptr*", h_icon, "PTR*", 0, "uint", 1, "uint", 0, "int") 
 496	;if !ErrorLevel 
 497	;	return h_icon 
 498	r := DllCall("Shell32.dll\SHExtractIconsW", "str", Filename, "int", IconNumber-1, "int", IconSize, "int", IconSize, "Ptr*", h_icon, "Ptr*", pIconId, "uint", 1, "uint", 0, "int")
 499	If (!ErrorLevel && r != 0)
 500    	return h_icon
 501    return 0
 502}
 503
 504;Gets the visible window at a screen coordinate
 505GetVisibleWindowAtPoint(x,y,IgnoredWindow)
 506{
 507	DetectHiddenWindows,off
 508	WinGet, id, list,,,
 509	Loop, %id%
 510	{
 511	    this_id := id%A_Index%
 512	    ;WinActivate, ahk_id %this_id%
 513	    WinGetClass, this_class, ahk_id %this_id%
 514	    WinGetPos , WinX, WinY, Width, Height, ahk_id %this_id%
 515	    if(IsInArea(x,y,WinX,WinY,Width,Height)&&this_class!=IgnoredWindow)
 516	    {
 517	    	DetectHiddenWindows,on
 518	    	return this_class
 519	    }
 520	}
 521	DetectHiddenWindows,on
 522}
 523
 524;checks if a point is in a rectangle
 525IsInArea(px,py,x,y,w,h)
 526{
 527	return (px > x && py > y && px < x + w && py < y + h)
 528}
 529
 530;Checks if two rectangles overlap
 531RectsOverlap(x1,y1,w1,h1,x2,y2,w2,h2)
 532{
 533	Union := RectUnion(x1,y1,w1,h1,x2,y2,w2,h2)
 534	return Union.w && Union.h
 535}
 536
 537;Checks if two rectangles are separate
 538RectsSeparate(x1,y1,w1,h1,x2,y2,w2,h2)
 539{
 540	Union := RectUnion(x1,y1,w1,h1,x2,y2,w2,h2)
 541	return Union.w = 0 && Union.h = 0
 542}
 543
 544;Check if the first rectangle includes the second one
 545RectIncludesRect(x1,y1,w1,h1,ix,iy,iw,ih)
 546{
 547	Union := RectUnion(x1,y1,w1,h1,ix,iy,iw,ih)
 548	return Union.x = ix && Union.y = iy && Union.w = iw && Union.h = ih
 549}
 550
 551;Calculates the union of two rectangles
 552RectUnion(x1,y1,w1,h1,x2,y2,w2,h2)
 553{
 554	x3 := ""
 555	y3 := ""
 556	
 557	;X Axis
 558	if(x1 > x2 && x1 < x2 + w2)
 559		x3 := x1
 560	else if(x2 > x1 && x2 < x1 + w1)
 561		x3 := x2
 562		
 563	if(y1 > y2 && y1 < y2 + h2)
 564		y3 := y1
 565	else if(y2 > y1 && y2 < y1 + h1)
 566		y3 := y2
 567	
 568	if(x3 != x1 && x3 != x2) ;Not overlapping
 569		w3 := 0
 570	else
 571		w3 := w1 - (x3 - x1) < w2 - (x3 - x2) ? w1 - (x3 - x1) : w2 - (x3 - x2) ;Choose the smaller width
 572	if(y3 != y1 && y3 != y2) ;Not overlapping
 573		h3 := 0
 574	else
 575		h3 := h1 - (y3 - y1) < h2 - (y3 - y2) ? h1 - (y3 - y1) : h2 - (y3 - y2) ;Choose the smaller height
 576	if(w3 = 0)
 577		h3 := 0
 578	else if(h3 = 0)
 579		w3 := 0
 580	return Object("x", x3, "y", y3, "w", w3, "h", h3)
 581}
 582
 583;Gets window position using workspace coordinates (-> no taskbar)
 584WinGetPlacement(hwnd, ByRef x="", ByRef y="", ByRef w="", ByRef h="", ByRef state="") 
 585{ 
 586    VarSetCapacity(wp, 44), NumPut(44, wp) 
 587    DllCall("GetWindowPlacement", "Ptr", hwnd, "Ptr", &wp) 
 588    x := NumGet(wp, 28, "int") 
 589    y := NumGet(wp, 32, "int") 
 590    w := NumGet(wp, 36, "int") - x 
 591    h := NumGet(wp, 40, "int") - y
 592	state := NumGet(wp, 8, "UInt")
 593	;outputdebug get x%x% y%y% w%w% h%h% state%state%
 594}
 595
 596;Sets window position using workspace coordinates (-> no taskbar)
 597WinSetPlacement(hwnd, x="",y="",w="",h="",state="")
 598{
 599	WinGetPlacement(hwnd, x1, y1, w1, h1, state1)
 600	if(x = "")
 601		x := x1
 602	if(y = "")
 603		y := y1
 604	if(w = "")
 605		w := w1
 606	if(h = "")
 607		h := h1
 608	if(state = "")
 609		state := state1
 610	VarSetCapacity(wp, 44), NumPut(44, wp)
 611	if(state = 6)
 612		NumPut(7, wp, 8) ;SW_SHOWMINNOACTIVE
 613	else if(state = 1)
 614		NumPut(4, wp, 8) ;SW_SHOWNOACTIVATE
 615	else if(state = 3)
 616		NumPut(3, wp, 8) ;SW_SHOWMAXIMIZED and/or SW_MAXIMIZE
 617	else
 618		NumPut(state, wp, 8)
 619	NumPut(x, wp, 28, "Int")
 620    NumPut(y, wp, 32, "Int")
 621    NumPut(x+w, wp, 36, "Int")
 622    NumPut(y+h, wp, 40, "Int")
 623	DllCall("SetWindowPlacement", "Ptr", hwnd, "Ptr", &wp) 
 624}
 625
 626;Checks if the current LClick hotkey comes from a double click
 627IsDoubleClick()
 628{	
 629	return A_TimeSincePriorHotkey < DllCall("GetDoubleClickTime") && A_ThisHotkey=A_PriorHotkey
 630}
 631
 632;Checks if a specific control class is active. Matches by start of ClassNN.
 633IsControlActive(controlclass)
 634{
 635	if(WinVer >= WIN_7)
 636		ControlGetFocus active, A
 637	else
 638		active := XPGetFocussed()
 639	if(InStr(active, controlclass))
 640		return true
 641	return false
 642}
 643
 644; This script retrieves the ahk_id (HWND) of the active window's focused control. 
 645; This script requires Windows 98+ or NT 4.0 SP3+. 
 646/*
 647typedef struct tagGUITHREADINFO {
 648  DWORD cbSize;
 649  DWORD flags;
 650  HWND  hwndActive;
 651  HWND  hwndFocus;
 652  HWND  hwndCapture;
 653  HWND  hwndMenuOwner;
 654  HWND  hwndMoveSize;
 655  HWND  hwndCaret;
 656  RECT  rcCaret;
 657} GUITHREADINFO, *PGUITHREADINFO;
 658*/
 659GetFocusedControl() 
 660{ 
 661   guiThreadInfoSize := 8 + 6 * A_PtrSize + 16
 662   VarSetCapacity(guiThreadInfo, guiThreadInfoSize, 0) 
 663   NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
 664   ; DllCall("RtlFillMemory" , "PTR", &guiThreadInfo, "UInt", 1 , "UChar", guiThreadInfoSize)   ; Below 0xFF, one call only is needed 
 665   If(DllCall("GetGUIThreadInfo" , "UInt", 0   ; Foreground thread 
 666         , "PTR", &guiThreadInfo) = 0) 
 667   { 
 668      ErrorLevel := A_LastError   ; Failure 
 669      Return 0 
 670   } 
 671   focusedHwnd := NumGet(guiThreadInfo,8+A_PtrSize, "Ptr") ; *(addr + 12) + (*(addr + 13) << 8) +  (*(addr + 14) << 16) + (*(addr + 15) << 24) 
 672   Return focusedHwnd 
 673} 
 674
 675; Force kill program on Alt+F5 and on right click close button
 676CloseKill(hwnd)
 677{
 678	WinGet, pid, pid, ahk_id %hwnd%
 679	WinKill ahk_id %hwnd%
 680	if(WinExist("ahk_id " hwnd))
 681		Process, close, %pid%
 682}
 683
 684/*
 685Converts a string list with separators to an array. It also removes and splits at quotes
 686To be parsed:
 687
 688file a
 689file b
 690
 691"file a"
 692"file b"
 693
 694"file a" "file b"
 695
 696"file a"|"file b"
 697
 698file a|file b
 699
 700*/
 701ToArray(SourceFiles, ByRef Separator = "`n", ByRef wasQuoted = 0)
 702{
 703	if(IsArray(SourceFiles))
 704		return SourceFiles
 705	files := Array()
 706	pos := 1
 707	wasQuoted := 0
 708	Loop
 709	{
 710		if(pos > strlen(SourceFiles))
 711			break
 712			
 713		char := SubStr(SourceFiles, pos, 1)
 714		if(char = """" || wasQuoted) ;Quoted paths
 715		{
 716			file := SubStr(SourceFiles, InStr(SourceFiles, """", 0, pos) + 1, InStr(SourceFiles, """", 0, pos + 1) - pos - 1)
 717			if(!wasQuoted)
 718			{
 719				wasQuoted := 1
 720				Separator := SubStr(SourceFiles, InStr(SourceFiles, """", 0, pos + 1) + 1, InStr(SourceFiles, """", 0, InStr(SourceFiles, """", 0, pos + 1) + 1) - InStr(SourceFiles, """", 0, pos + 1) - 1)
 721			}
 722			if(file)
 723			{
 724				files.Insert(file)
 725				pos += strlen(file) + 3
 726				continue
 727			}
 728			else
 729				Msgbox Invalid source format %SourceFiles%
 730		}
 731		else
 732		{
 733			file := SubStr(SourceFiles, pos, max(InStr(SourceFiles, Separator, 0, pos + 1) - pos, 0)) ; separator
 734			if(!file)
 735				file := SubStr(SourceFiles, pos) ;no quotes or separators, single file
 736			if(file)
 737			{
 738				files.Insert(file)
 739				pos += strlen(file) + strlen(Separator)
 740				continue
 741			}
 742			else
 743				Msgbox Invalid source format
 744		}
 745		pos++ ;Shouldn't happen
 746	}
 747	return files
 748}
 749
 750;Flattens an array to a list with separators
 751ArrayToList(array, separator = "`n", quote = 0)
 752{
 753	Loop % array.MaxIndex()
 754		result .= (A_Index != 1 ? separator : "") (quote ? """" : "") array[A_Index] (quote ? """" : "")
 755	return result
 756}
 757
 758;Compares two (already separated) version numbers. Returns 1 if 1st is greater, 0 if equal, -1 if second is greater
 759CompareVersion(major1,major2,minor1,minor2,bugfix1,bugfix2)
 760{
 761	if(major1 > major2)
 762		return 1
 763	else if(major1 = major2 && minor1 > minor2)
 764		return 1
 765	else if(major1 = major2 && minor1 = minor2 && bugfix1 > bugfix2)
 766		return 1
 767	else if(major1 = major2 && minor1 = minor2 && bugfix1 = bugfix2)
 768		return 0
 769	else
 770		return -1
 771}
 772
 773;Returns true if x is a number
 774IsNumeric(x)
 775{
 776   If x is number 
 777      Return 1 
 778   Return 0 
 779}
 780
 781;Performs quote unescaping of a string. Transforms \" to " and \\ to \
 782StringUnescape(String)
 783{
 784	return StringReplace(StringReplace(StringReplace(String, "\\", Chr(1), 1), "\""", """", 1), Chr(1), "\", 1)
 785}
 786;Performs quote escaping of a string. Transforms " to \" and \ to \\
 787StringEscape(String)
 788{
 789	return StringReplace(StringReplace(String, "\", "\\", 1), """", "\""", 1)
 790}
 791;Decodes a URL
 792uriDecode(str) { 
 793   Loop 
 794      If RegExMatch(str, "i)(?<=%)[\da-f]{1,2}", hex) 
 795         StringReplace, str, str, `%%hex%, % Chr("0x" . hex), All 
 796      Else Break 
 797   Return, str 
 798}
 799
 800; modified from jackieku's code (http://www.autohotkey.com/forum/post-310959.html#310959)
 801UriEncode(str, Enc = "UTF-8")
 802{
 803	try
 804	{
 805	    oSC := ComObjCreate("ScriptControl")
 806	    oSC.Language := "JScript"
 807	    Script := "var Encoded = encodeURIComponent(""" . str . """)"
 808	    oSC.ExecuteStatement(Script)
 809	    encoded := oSC.Eval("Encoded")
 810	    Return encoded
 811	}
 812	catch e
 813	{
 814		StrPutVar(str, Var, Enc)
 815		f := A_FormatInteger
 816		SetFormat, IntegerFast, H
 817		Loop
 818		{
 819			Code := NumGet(Var, A_Index - 1, "UChar")
 820			If (!Code)
 821				Break
 822			If (Code >= 0x30 && Code <= 0x39 ; 0-9
 823			 || Code >= 0x41 && Code <= 0x5A ; A-Z
 824			 || Code >= 0x61 && Code <= 0x7A) ; a-z
 825				Res .= Chr(Code)
 826			Else
 827				Res .= "%" . SubStr(Code + 0x100, -1)
 828		}
 829		SetFormat, IntegerFast, %f%
 830		Return, Res
 831	}
 832}
 833
 834StrPutVar(Str, ByRef Var, Enc = "")
 835{
 836   Len := StrPut(Str, Enc) * (Enc = "UTF-16" || Enc = "CP1200" ? 2 : 1)
 837   VarSetCapacity(Var, Len, 0)
 838   Return, StrPut(Str, &Var, Enc)
 839}
 840
 841;Old function for codepage conversions. AHK_L can do this now.
 842Unicode2Ansi(ByRef wString, ByRef sString, CP = 0) 
 843{ 
 844	nSize := DllCall("WideCharToMultiByte" , "Uint", CP, "Uint", 0 , "UintP", wString , "int",  -1 , "Uint", 0 , "int",  0 , "Uint", 0 , "Uint", 0) 
 845	VarSetCapacity(sString, nSize) 
 846	DllCall("WideCharToMultiByte" , "Uint", CP , "Uint", 0 , "UintP", wString , "int",  -1 , "str",  sString , "int",  nSize , "Uint", 0 , "Uint", 0) 
 847}
 848
 849;Old function for codepage conversions. AHK_L can do this now.
 850Ansi2Unicode(ByRef sString, ByRef wString, CP = 0) 
 851{ 
 852	nSize := DllCall("MultiByteToWideChar" , "Uint", CP , "Uint", 0 , "UintP", sString , "int",  -1 , "Uint", 0 , "int",  0) 
 853	VarSetCapacity(wString, nSize * 2) 
 854	DllCall("MultiByteToWideChar" , "Uint", CP , "Uint", 0 , "UintP",  sString , "int",  -1 , "UintP", wString , "int",  nSize) 
 855}
 856
 857;Performs a fuzzy search for string2 in string1.
 858;return values range from 0.0 = identical to 1.0 = completely different. 0.4 seems appropriate
 859FuzzySearch(longer, shorter, UseFuzzySearch = false)
 860{
 861	if(longer = shorter)
 862		return 1
 863
 864	lenl := StrLen(longer)
 865	lens := StrLen(shorter)
 866
 867	if(lens > lenl)
 868		return 0
 869
 870	;Check if the shorter string is a substring of the longer string
 871	Contained := InStr(longer, shorter)
 872	if(Contained)
 873		return Contained = 1 ? 1 : 0.8
 874
 875	;Check if string can be matched by omitting characters
 876	if(lens < 5)
 877	{
 878		pos := 0
 879		matched := 0
 880		Loop % lens
 881		{
 882			char := SubStr(shorter, A_Index, 1)
 883			StringUpper, char, char
 884			Loop % lenl - pos
 885			{
 886				if(SubStr(longer, pos + A_Index, 1) == char)
 887				{
 888					pos := A_Index
 889					matched++
 890					break
 891				}
 892				else
 893					continue
 894			}
 895		}
 896		if(matched = lens)
 897			return 0.9 ;Slightly worse than direct matches
 898	}
 899	;Calculate fuzzy string difference
 900	if(UseFuzzySearch)
 901	{
 902		max := 0
 903		Loop % lenl - lens + 1
 904		{
 905			distance := 1 - StringDifference(shorter, SubStr(longer, A_Index, lens))
 906			if(distance < max)
 907				max := distance
 908		}
 909		return max
 910	}
 911	return 0
 912}
 913;By Toralf:
 914;basic idea for SIFT3 code by Siderite Zackwehdex 
 915;http://siderite.blogspot.com/2007/04/super-fast-and-accurate-string-distance.html 
 916;took idea to normalize it to longest string from Brad Wood 
 917;http://www.bradwood.com/string_compare/ 
 918;Own work: 
 919; - when character only differ in case, LSC is a 0.8 match for this character 
 920; - modified code for speed, might lead to different results compared to original code 
 921; - optimized for speed (30% faster then original SIFT3 and 13.3 times faster than basic Levenshtein distance) 
 922;http://www.autohotkey.com/forum/topic59407.html 
 923StringDifference(string1, string2, maxOffset=3) {    ;returns a float: between "0.0 = identical" and "1.0 = nothing in common" 
 924  If (string1 = string2) 
 925    Return (string1 == string2 ? 0/1 : 0.2/StrLen(string1))    ;either identical or (assumption:) "only one" char with different case 
 926  If (string1 = "" OR string2 = "") 
 927    Return (string1 = string2 ? 0/1 : 1/1) 
 928  StringSplit, n, string1 
 929  StringSplit, m, string2 
 930  ni := 1, mi := 1, lcs := 0 
 931  While((ni <= n0) AND (mi <= m0)) { 
 932    If (n%ni% == m%mi%) 
 933      EnvAdd, lcs, 1 
 934    Else If (n%ni% = m%mi%) 
 935      EnvAdd, lcs, 0.8 
 936    Else{ 
 937      Loop, %maxOffset%  { 
 938        oi := ni + A_Index, pi := mi + A_Index 
 939        If ((n%oi% = m%mi%) AND (oi <= n0)){ 
 940            ni := oi, lcs += (n%oi% == m%mi% ? 1 : 0.8) 
 941            Break 
 942        } 
 943        If ((n%ni% = m%pi%) AND (pi <= m0)){ 
 944            mi := pi, lcs += (n%ni% == m%pi% ? 1 : 0.8) 
 945            Break 
 946        } 
 947      } 
 948    } 
 949    EnvAdd, ni, 1 
 950    EnvAdd, mi, 1 
 951  } 
 952  Return ((n0 + m0)/2 - lcs) / (n0 > m0 ? n0 : m0) 
 953}
 954
 955;Returns true if the string is in URL format. Use CouldBeURL() for weaker checks.
 956IsURL(string)
 957{
 958	return RegexMatch(strTrim(string, " "), "(?:(?:ht|f)tps?://|www\.).+\..+") > 0
 959}
 960;Returns true if the string could be a URL. Use IsURL() to be sure.
 961CouldBeURL(string)
 962{
 963	return RegexMatch(strTrim(string, " "), "(?:(?:ht|f)tps?://|www\.)?.+\..+") > 0
 964}
 965
 966;Tests for write access to a specific file
 967WriteAccess( F ) {
 968	if(FileExist(F))
 969		Return ((h := DllCall("_lopen", AStr, F, Int, 1, "Ptr")) > 0 ? 1 : 0) (DllCall("_lclose", "Ptr", h) + NULL) 
 970	else
 971	{
 972		SplitPath, F,,Dir
 973		F := FindFreeFilename(Dir)
 974		FileAppend, x, %F%
 975		Success := !ErrorLevel
 976		FileDelete, %F%
 977		return !ErrorLevel
 978	}
 979}
 980
 981;Generates MD5 value of a file
 982FileMD5(sFile´= "", cSz = 4 )
 983{ ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910 
 984	cSz := (cSz < 0 || cSz > 8) ? 2 ** 22 : 2 ** (18 + cSz)
 985	VarSetCapacity(Buffer, cSz, 0) 
 986	hFil := DllCall("CreateFile", Str, sFile, UInt, 0x80000000, Int, 1, Int, 0, Int, 3, Int, 0, Int, 0, "Ptr") 
 987	if(hFil < 1)
 988		return hFil
 989	DllCall("GetFileSizeEx", Ptr, hFil, Ptr, &Buffer)
 990	fSz := NumGet(Buffer, 0, "Int64")
 991	VarSetCapacity(MD5_CTX, 104, 0)
 992	DllCall("advapi32\MD5Init", PTR, &MD5_CTX)
 993	Loop % (fSz // cSz + !!Mod(fSz, cSz))
 994	DllCall("ReadFile", PTR, hFil, PTR, &Buffer, UInt, cSz, UIntP, bytesRead, UInt, 0)
 995	DllCall("advapi32\MD5Update", PTR, &MD5_CTX, PTR, &Buffer, UInt,bytesRead)
 996	DllCall("advapi32\MD5Final", PTR, &MD5_CTX )
 997	DllCall("CloseHandle", PTR, hFil)
 998	Loop % StrLen(Hex := "123456789ABCDEF0")
 999	{
1000		N := NumGet(MD5_CTX, 87 + A_Index, "Char")
1001		MD5 .= SubStr(Hex, N >> 4, 1) SubStr(Hex, N & 15, 1)
1002	}
1003	return MD5
1004}
1005
1006;Formats a file size in bytes to a human-readable size string
1007FormatFileSize(Bytes, Decimals = 1, Prefixes = "B,KB,MB,GB,TB,PB,EB,ZB,YB")
1008{
1009	StringSplit, Prefix, Prefixes, `,
1010	Loop, Parse, Prefixes, `,
1011		if(Bytes < e := 1024 ** A_Index)
1012			return % Round(Bytes / (e / 1024), decimals) Prefix%A_Index%
1013}
1014
1015;Returns a string containing the formatted object keys and values
1016ExploreObj(Obj, NewRow = "`n", Equal = "  =  ", Indent = "`t", Depth = 12, CurIndent = "")
1017{
1018    for k,v in Obj
1019        ToReturn .= CurIndent k (IsObject(v) && depth > 1 ? NewRow ExploreObj(v, NewRow, Equal, Indent, Depth - 1, CurIndent Indent) : Equal v) NewRow
1020    return RTrim(ToReturn, NewRow)
1021}
1022
1023
1024GetFullPathName(SPath)
1025{
1026	VarSetCapacity(lPath,A_IsUnicode ? 520 : 260, 0)
1027	DllCall("GetLongPathName", Str, SPath, Str, lPath, UInt, 260)
1028	Return lPath 
1029}
1030
1031;This function calls a function of an event on every key in it
1032objDeepPerform(obj, function, Event)
1033{
1034	if(!IsFunc(function))
1035		return
1036	if(obj.HasKey("base"))
1037		objDeepPerform(obj.base, function, Event)
1038	enum := obj._newenum() 
1039	while enum[key, value] 
1040	{
1041		if(IsObject(value))
1042			objDeepPerform(value, function, Event)
1043		else
1044			obj[key] := %function%(Event, value)
1045	}
1046}
1047
1048;Finds a non-existing filename for Filepath by appending a number in brackets to the name
1049FindFreeFileName(FilePath)
1050{
1051	SplitPath, FilePath,, dir, extension, filename
1052	Testpath := FilePath ;Return path if it doesn't exist
1053	i := 1
1054	while FileExist(TestPath)
1055	{
1056		i++
1057		Testpath := dir "\" filename " (" i ")" (extension = "" ? "" : "." extension)
1058	}
1059	return TestPath
1060}
1061
1062;Attaches a window as a tool window to another window from a different process. QUESTION: Is this still needed?
1063AttachToolWindow(hParent, GUINumber, AutoClose)
1064{
1065	global ToolWindows
1066	outputdebug AttachToolWindow %GUINumber% to %hParent%
1067	if(!IsObject(ToolWindows))
1068		ToolWindows := Object()
1069	if(!WinExist("ahk_id " hParent))
1070		return false
1071	Gui %GUINumber%: +LastFoundExist
1072	if(!(hGui := WinExist()))
1073		return false
1074	;SetWindowLongPtr is defined as SetWindowLong in x86
1075	if(A_PtrSize = 4)
1076		DllCall("SetWindowLong", "Ptr", hGui, "int", -8, "PTR", hParent) ;This line actually sets the owner behavior
1077	else
1078		DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", hParent) ;This line actually sets the owner behavior
1079	ToolWindows.Insert(Object("hParent", hParent, "hGui", hGui,"AutoClose", AutoClose))
1080	Gui %GUINumber%: Show, NoActivate
1081	return true
1082}
1083
1084DeAttachToolWindow(GUINumber)
1085{
1086	global ToolWindows
1087	Gui %GUINumber%: +LastFoundExist
1088	if(!(hGui := WinExist()))
1089		return false
1090	Loop % ToolWindows.MaxIndex()
1091	{
1092		if(ToolWindows[A_Index].hGui = hGui)
1093		{
1094			;SetWindowLongPtr is defined as SetWindowLong in x86
1095			if(A_PtrSize = 4)
1096				DllCall("SetWindowLong", "Ptr", hGui, "int", -8, "PTR", 0) ;Remove tool window behavior
1097			else
1098				DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", 0) ;Remove tool window behavior
1099			DllCall("SetWindowLongPtr", "Ptr", hGui, "int", -8, "PTR", 0)
1100			ToolWindows.Remove(A_Index)
1101			break
1102		}
1103	}
1104}
1105
1106;Adds a tooltip to a control.
1107AddToolTip(con, text, Modify = 0)
1108{
1109	Static TThwnd,GuiHwnd
1110	l_DetectHiddenWindows := A_DetectHiddenWindows
1111	If(!TThwnd)
1112	{
1113		Gui, +LastFound
1114		GuiHwnd := WinExist()
1115		TThwnd := CreateTooltipControl(GuiHwnd)
1116		Varsetcapacity(TInfo, 6 * 4 + 6 * A_PtrSize, 0)
1117		Numput(6 * 4 + 6 * A_PtrSize, TInfo, "UInt")
1118		Numput(1 | 16, TInfo, 4, "UInt")
1119		Numput(GuiHwnd, TInfo, 8, "PTR")
1120		Numput(GuiHwnd, TInfo, 8 + A_PtrSize, "PTR")
1121		;Numput(&text,TInfo,36)
1122		Detecthiddenwindows, on
1123		Sendmessage, 1028, 0, &TInfo, , ahk_id %TThwnd%
1124		SendMessage, 1048, 0, 300, , ahk_id %TThwnd%
1125	}
1126	Varsetcapacity(TInfo, 6 * 4 + 6 * A_PtrSize, 0)
1127	Numput(6 * 4 + 6 * A_PtrSize, TInfo, "UInt")
1128	Numput(1 | 16, TInfo, 4, "UInt")
1129	Numput(GuiHwnd, TInfo, 8, "PTR")
1130	Numput(con, TInfo, 8 + A_PtrSize, "PTR")
1131	VarSetCapacity(ANSItext, StrPut(text, ""))
1132    StrPut(text, &ANSItext, "")
1133	Numput(&ANSIText, TInfo, 6 * 4 + 3 * A_PtrSize, "PTR")
1134
1135	Detecthiddenwindows, on
1136	if(Modify)
1137		SendMessage, 1036, 0, &TInfo, , ahk_id %TThwnd%
1138	else
1139	{
1140		Sendmessage, 1028, 0, &TInfo, , ahk_id %TThwnd%
1141		SendMessage, 1048, 0, 300, , ahk_id %TThwnd%
1142	}
1143	DetectHiddenWindows %l_DetectHiddenWindows%
1144}
1145CreateTooltipControl(hwind)
1146{
1147	Ret := DllCall("CreateWindowEx"
1148	,"Uint", 0
1149	,"Str", "TOOLTIPS_CLASS32"
1150	,"PTR", 0
1151	,"Uint", 2147483648 | 3
1152	,"Uint", -2147483648
1153	,"Uint", -2147483648
1154	,"Uint", -2147483648
1155	,"Uint", -2147483648
1156	,"PTR", hwind
1157	,"PTR", 0
1158	,"PTR", 0
1159	,"PTR", 0, "PTR")
1160	return Ret
1161}
1162
1163;Gets width of all screens combined. NOTE: Single screens may have different vertical resolutions so some parts of the area returned here might not belong to any screens!
1164GetVirtualScreenCoordinates(ByRef x, ByRef y, ByRef w, ByRef h)
1165{
1166	SysGet, x, 76 ;Get virtual screen coordinates of all monitors
1167	SysGet, y, 77
1168	SysGet, w, 78
1169	SysGet, h, 79
1170}
1171;Determines if a window is visible completely on the screen. Returns 1 if it is, 2 if it's partially on a screen (also if between monitors) and 0 if it's outside of all screens.
1172IsWindowOnScreen(hwnd)
1173{
1174	if(IsObject(hwnd))
1175	{
1176		x := hwnd.x
1177		y := hwnd.y
1178		w := hwnd.w
1179		h := hwnd.h
1180	}
1181	else
1182		WinGetPos, x, y, w, h, ahk_id %hwnd%
1183	Monitors := GetMonitors()
1184	for index, Monitor in Monitors
1185	{
1186		if(RectIncludesRect(Monitor.x, Monitor.y, Monitor.w, Monitor.h, x, y, w, h))
1187			return 1
1188		if(RectsOverlap(Monitor.x, Monitor.y, Monitor.w, Monitor.h, x, y, w, h))
1189			return 2
1190	}
1191	return 0
1192}
1193GetMonitors()
1194{
1195	Monitors := []
1196	SysGet, Mon0, MonitorCount
1197	;Loop through each monitor
1198    Loop %Mon0%
1199    { 
1200        SysGet, Mon, Monitor, %A_Index%
1201        Monitor := {}
1202        Monitor.X := MonLeft
1203        Monitor.Y := MonTop
1204        Monitor.Width := MonRight - Monitor.X
1205        Monitor.Height := MonBottom - Monitor.Y
1206        Monitors.Insert(Monitor)
1207    }
1208    return Monitors
1209}
1210GetMonitorWorkAreas()
1211{
1212	Monitors := []
1213	SysGet, Mon0, MonitorCount
1214	;Loop through each monitor
1215    Loop %Mon0%
1216    { 
1217        SysGet, Mon, MonitorWorkArea, %A_Index%
1218        Monitor := {}
1219        Monitor.X := MonLeft
1220        Monitor.Y := MonTop
1221        Monitor.Width := MonRight - Monitor.X
1222        Monitor.Height := MonBottom - Monitor.Y
1223        Monitors.Insert(Monitor)
1224    }
1225    return Monitors
1226}
1227;WinGetPos function wrapper
1228WinGetPos(WinTitle = "", WinText = "", ExcludeTitle = "", ExcludeText = "")
1229{
1230	WinGetPos, x, y, w, h, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
1231	return Object("x", x, "y", y, "w", w, "h", h)
1232}
1233
1234;WinMove function wrapper
1235WinMove(WinTitle, Rect, WinText = "", ExcludeTitle = "", ExcludeText = "")
1236{
1237	WinMove, %WinTitle%, %WinText%, % Rect.x, % Rect.y, % Rect.w, % Rect.h, %ExcludeTitle%, %ExcludeText%
1238}
1239
1240;Returns true if a window is visible in Alt+Tab list
1241IsAltTabWindow(hwnd)
1242{
1243	if(!hwnd)
1244		return false
1245	WinGet, ExStyle, ExStyle, ahk_id %hwnd%
1246	if(ExStyle & 0x80) ;WS_EX_TOOLWINDOW
1247		return false
1248	hwndWalk := DllCall("GetAncestor", "PTR", hwnd, "INT", 3, "PTR")
1249
1250	; See if we are the last active visible popup
1251	while((hwndTry := DllCall("GetLastActivePopup", "PTR", hwndWalk, "PTR")) != hwndWalk)
1252	{
1253		if(DllCall("IsWindowVisible", "PTR", hwndTry)) 
1254			break
1255		hwndWalk := hwndTry
1256	}
1257	return hwndWalk = hwnd
1258}
1259
1260;Gets ClassNN from hwnd
1261HWNDToClassNN(hwnd)
1262{
1263	win := DllCall("GetParent", "PTR", hwnd, "PTR")
1264	WinGet ctrlList, ControlList, ahk_id %win%
1265	; Built an array indexing the control names by their hwnd 
1266	Loop Parse, ctrlList, `n 
1267	{
1268		ControlGet hwnd1, Hwnd, , %A_LoopField%, ahk_id %win%
1269		if(hwnd1=hwnd)
1270			return A_LoopField
1271	}
1272}
1273
1274;Gets focused control in XP to prevent blocking double clicks like with ControlGetFocus
1275XPGetFocussed()
1276{
1277  WinGet ctrlList, ControlList, A 
1278  ctrlHwnd:=GetFocusedControl()
1279  ; Built an array indexing the control names by their hwnd 
1280  Loop Parse, ctrlList, `n 
1281  {
1282    ControlGet hwnd, Hwnd, , %A_LoopField%, A 
1283    hwnd += 0   ; Convert from hexa to decimal 
1284    if(hwnd=ctrlHwnd)
1285      return A_LoopField
1286  } 
1287}
1288
1289;Watches a directory/file for file changes
1290;By HotKeyIt
1291;Docs: http://www.autohotkey.com/forum/viewtopic.php?p=398565#398565
1292WatchDirectory(p*){ 
1293   global _Struct 
1294   ;Structures 
1295   static FILE_NOTIFY_INFORMATION:="DWORD NextEntryOffset,DWORD Action,DWORD FileNameLength,WCHAR FileName[1]" 
1296   static OVERLAPPED:="ULONG_PTR Internal,ULONG_PTR InternalHigh,{struct{DWORD offset,DWORD offsetHigh},PVOID Pointer},HANDLE hEvent" 
1297   ;Variables 
1298   static running,sizeof_FNI=65536,WatchDirectory:=RegisterCallback("WatchDirectory","F",0,0) ;,nReadLen:=VarSetCapacity(nReadLen,8)
1299   static timer,ReportToFunction,LP,nReadLen:=VarSetCapacity(LP,(260)*(A_PtrSize/2),0) 
1300   static @:=Object(),reconnect:=Object(),#:=Object(),DirEvents,StringToRegEx="\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*" 
1301   ;ReadDirectoryChanges related 
1302   static FILE_NOTIFY_CHANGE_FILE_NAME=0x1,FILE_NOTIFY_CHANGE_DIR_NAME=0x2,FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4 
1303         ,FILE_NOTIFY_CHANGE_SIZE=0x8,FILE_NOTIFY_CHANGE_LAST_WRITE=0x10,FILE_NOTIFY_CHANGE_CREATION=0x40 
1304         ,FILE_NOTIFY_CHANGE_SECURITY=0x100 
1305   static FILE_ACTION_ADDED=1,FILE_ACTION_REMOVED=2,FILE_ACTION_MODIFIED=3 
1306         ,FILE_ACTION_RENAMED_OLD_NAME=4,FILE_ACTION_RENAMED_NEW_NAME=5 
1307   static OPEN_EXISTING=3,FILE_FLAG_BACKUP_SEMANTICS=0x2000000,FILE_FLAG_OVERLAPPED=0x40000000 
1308         ,FILE_SHARE_DELETE=4,FILE_SHARE_WRITE=2,FILE_SHARE_READ=1,FILE_LIST_DIRECTORY=1 
1309   If p.MaxIndex(){ 
1310      If (p.MaxIndex()=1 && p.1=""){ 
1311         for i,folder in # 
1312            DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent) 
1313            ,@.Remove(folder) 
1314         #:=Object() 
1315         DirEvents:=new _Struct("HANDLE[1000]") 
1316         DllCall("KillTimer","Uint",0,"Uint",timer) 
1317         timer= 
1318         Return 0 
1319      } else { 
1320         if p.2 
1321            ReportToFunction:=p.2 
1322         If !IsFunc(ReportToFunction) 
1323            Return -1 ;DllCall("MessageBox","Uint",0,"Str","Function " ReportToFunction " does not exist","Str","Error Missing Function","UInt",0) 
1324         RegExMatch(p.1,"^([^/\*\?<>\|""]+)(\*)?(\|.+)?$",dir) 
1325         if (SubStr(dir1,0)="\") 
1326            StringTrimRight,dir1,dir1,1 
1327         StringTrimLeft,dir3,dir3,1 
1328         If (p.MaxIndex()=2 && p.2=""){ 
1329            for i,folder in # 
1330               If (dir1=SubStr(folder,1,StrLen(folder)-1)) 
1331                  Return 0 ,DirEvents[i]:=DirEvents[#.MaxIndex()],DirEvents[#.MaxIndex()]:=0 
1332                           @.Remove(folder),#[i]:=#[#.MaxIndex()],#.Remove(i) 
1333            Return 0 
1334         } 
1335      } 
1336      if !InStr(FileExist(dir1),"D") 
1337         Return -1 ;DllCall("MessageBox","Uint",0,"Str","Folder " dir1 " does not exist","Str","Error Missing File","UInt",0) 
1338      for i,folder in # 
1339      { 
1340         If (dir1=SubStr(folder,1,StrLen(folder)-1) || (InStr(dir1,folder) && @[folder].sD)) 
1341               Return 0 
1342         else if (InStr(SubStr(folder,1,StrLen(folder)-1),dir1 "\") && dir2){ ;replace watch 
1343            DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent),reset:=i 
1344         } 
1345      } 
1346      LP:=SubStr(LP,1,DllCall("GetLongPathName","Str",dir1,"Uint",&LP,"Uint",VarSetCapacity(LP))) "\" 
1347      If !(reset && @[reset]:=LP) 
1348         #.Insert(LP) 
1349      @[LP,"dir"]:=LP 
1350      @[LP].hD:=DllCall("CreateFile","Str",StrLen(LP)=3?SubStr(LP,1,2):LP,"UInt",0x1,"UInt",0x1|0x2|0x4 
1351                  ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 
1352      @[LP].sD:=(dir2=""?0:1) 
1353
1354      Loop,Parse,StringToRegEx,| 
1355         StringReplace,dir3,dir3,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A 
1356      StringReplace,dir3,dir3,%A_Space%,\s,A 
1357      Loop,Parse,dir3,| 
1358      { 
1359         If A_Index=1 
1360            dir3= 
1361         pre:=(SubStr(A_LoopField,1,2)="\\"?2:0) 
1362         succ:=(SubStr(A_LoopField,-1)="\\"?2:0) 
1363         dir3.=(dir3?"|":"") (pre?"\\\K":"") 
1364               . SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ) 
1365               . ((!succ && !InStr(SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ),"\"))?"[^\\]*$":"") (succ?"$":"") 
1366      } 
1367      @[LP].FLT:="i)" dir3 
1368      @[LP].FUNC:=ReportToFunction 
1369      @[LP].CNG:=(p.3?p.3:(0x1|0x2|0x4|0x8|0x10|0x40|0x100)) 
1370      If !reset { 
1371         @[LP].SetCapacity("pFNI",sizeof_FNI) 
1372         @[LP].FNI:=new _Struct(FILE_NOTIFY_INFORMATION,@[LP].GetAddress("pFNI")) 
1373         @[LP].O:=new _Struct(OVERLAPPED) 
1374      } 
1375      @[LP].O.hEvent:=DllCall("CreateEvent","Uint",0,"Int",1,"Int",0,"UInt",0) 
1376      If (!DirEvents) 
1377         DirEvents:=new _Struct("HANDLE[1000]") 
1378      DirEvents[reset?reset:#.MaxIndex()]:=@[LP].O.hEvent 
1379      DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 
1380               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 
1381      Return timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 
1382   } else { 
1383      Sleep, 0 
1384      for LP in reconnect 
1385      { 
1386         If (FileExist(@[LP].dir) && reconnect.Remove(LP)){ 
1387            DllCall("CloseHandle","Uint",@[LP].hD) 
1388            @[LP].hD:=DllCall("CreateFile","Str",StrLen(@[LP].dir)=3?SubStr(@[LP].dir,1,2):@[LP].dir,"UInt",0x1,"UInt",0x1|0x2|0x4 
1389                  ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 
1390            DllCall("ResetEvent","UInt",@[LP].O.hEvent) 
1391            DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 
1392               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 
1393         } 
1394      } 
1395      if !( (r:=DllCall("MsgWaitForMultipleObjectsEx","UInt",#.MaxIndex() 
1396               ,"UInt",DirEvents[],"UInt",0,"UInt",0x4FF,"UInt",6))>=0 
1397               && r<#.MaxIndex() ){ 
1398         return 
1399      } 
1400      DllCall("KillTimer", UInt,0, UInt,timer) 
1401      LP:=#[r+1],DllCall("GetOverlappedResult","UInt",@[LP].hD,"UInt",@[LP].O[],"UIntP",nReadLen,"Int",1) 
1402      If (A_LastError=64){ ; ERROR_NETNAME_DELETED - The specified network name is no longer available. 
1403         If !FileExist(@[LP].dir) ; If folder does not exist add to reconnect routine 
1404            reconnect.Insert(LP,LP) 
1405      } else 
1406         Loop { 
1407            FNI:=A_Index>1?(new _Struct(FILE_NOTIFY_INFORMATION,FNI[]+FNI.NextEntryOffset)):(new _Struct(FILE_NOTIFY_INFORMATION,@[LP].FNI[])) 
1408            If (FNI.Action < 0x6){ 
1409               FileName:=@[LP].dir . StrGet(FNI.FileName[""],FNI.FileNameLength/2,"UTF-16") 
1410               If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME) 
1411                     FileFromOptional:=FileName 
1412               If (@[LP].FLT="" || RegExMatch(FileName,@[LP].FLT) || FileFrom) 
1413                  If (FNI.Action=FILE_ACTION_ADDED){ 
1414                     FileTo:=FileName 
1415                  } else If (FNI.Action=FILE_ACTION_REMOVED){ 
1416                     FileFrom:=FileName 
1417                  } else If (FNI.Action=FILE_ACTION_MODIFIED){ 
1418                     FileFrom:=FileTo:=FileName 
1419                  } else If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME){ 
1420                     FileFrom:=FileName 
1421                  } else If (FNI.Action=FILE_ACTION_RENAMED_NEW_NAME){ 
1422                     FileTo:=FileName 
1423                  } 
1424          If (FNI.Action != 4 && (FileTo . FileFrom) !="") 
1425                  @[LP].Func(FileFrom=""?FileFromOptional:FileFrom,FileTo) 
1426            } 
1427         } Until (!FNI.NextEntryOffset || ((FNI[]+FNI.NextEntryOffset) > (@[LP].FNI[]+sizeof_FNI-12))) 
1428      DllCall("ResetEvent","UInt",@[LP].O.hEvent) 
1429      DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 
1430               ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 
1431      timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 
1432      Return 
1433   } 
1434   Return 
1435}
1436
1437;Clamps a value
1438Clamp(value, min, max)
1439{
1440	if(value < min)
1441		value := min
1442	else if(value > max)
1443		value := max
1444	return value
1445}
1446
1447;Generates 7plus version string
1448VersionString(Short = 0)
1449{
1450	global
1451	if(Short)
1452		return MajorVersion "." MinorVersion "." BugfixVersion
1453	else
1454		return MajorVersion "." MinorVersion "." BugfixVersion "." PatchVersion
1455}
1456
1457;Generates an UUID
1458uuid(c = false) { ; v1.1 - by Titan 
1459   static n = 0, l, i 
1460   f := A_FormatInteger, t := A_Now, s := "-" 
1461   SetFormat, Integer, H 
1462   t -= 1970, s 
1463   t := (t . A_MSec) * 10000 + 122192928000000000 
1464   If !i and c { 
1465      Loop, HKLM, System\MountedDevices 
1466      If i := A_LoopRegName 
1467         Break 
1468      StringGetPos, c, i, %s%, R2 
1469      StringMid, i, i, c + 2, 17 
1470   } Else { 
1471      Random, x, 0x100, 0xfff 
1472      Random, y, 0x10000, 0xfffff 
1473      Random, z, 0x100000, 0xffffff 
1474      x := 9 . SubStr(x, 3) . s . 1 . SubStr(y, 3) . SubStr(z, 3) 
1475   } t += n += l = A_Now, l := A_Now 
1476   SetFormat, Integer, %f% 
1477   Return, SubStr(t, 10) . s . SubStr(t, 6, 4) . s . 1 . SubStr(t, 3, 3) . s . (c ? i : x) 
1478}
1479
1480;Extracted from HotkeyIts WatchDirectory function
1481ConvertFilterStringToRegex(FilterString)
1482{
1483	StringToRegEx := "\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*"
1484	Loop,Parse,StringToRegEx,|
1485		StringReplace,FilterString,FilterString,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A
1486	StringReplace,FilterString,FilterString,%A_Space%,\s,A
1487	return "i)" FilterString
1488}
1489
1490;Gets client area of a window
1491GetClientRect(hwnd)
1492{
1493	VarSetCapacity(rc, 16)
1494	result := DllCall("GetClientRect", "PTR", hwnd, "PTR", &rc, "UINT")
1495	return {x : NumGet(rc, 0, "int"), y : NumGet(rc, 4, "int"), w : NumGet(rc, 8, "int"), h : NumGet(rc, 12, "int")}
1496}
1497
1498;Gets the selected text by copying it to the clipboard.
1499;OnClipboardChange ignores this due to MuteClipboardList flag, however, calling this function changes the clipboard owner to AHK.
1500GetSelectedText()
1501{
1502	global MuteClipboardList
1503	MuteClipboardList := true
1504	clipboardbackup := clipboardall
1505	clipboard := ""
1506	WaitForEvent("ClipboardChange", 100)
1507	Send ^c
1508	WaitForEvent("ClipboardChange", 100)
1509	result := clipboard
1510	clipboard := clipboardbackup
1511	WaitForEvent("ClipboardChange", 100)
1512	MuteClipboardList := false
1513	return result
1514}
1515
1516;Gets all kind of window information of open windows.
1517GetWindowInfo()
1518{
1519	global WindowList
1520	WS_EX_CONTROLPARENT :=0x10000
1521	WS_EX_DLGMODALFRAME :=0x1
1522	WS_CLIPCHILDREN :=0x2000000
1523	WS_EX_APPWINDOW :=0x40000
1524	WS_EX_TOOLWINDOW :=0x80
1525	WS_DISABLED :=0x8000000
1526	WS_VSCROLL :=0x200000
1527	WS_POPUP :=0x80000000
1528	
1529	windows := Array()
1530	DetectHiddenWindows, Off
1531	WinGet, Window_List, List ; Gather a list of running programs
1532	hInstance := GetModuleHandle(0)
1533	order := 0
1534	Loop, %Window_List%
1535	{
1536		wid := Window_List%A_Index%
1537		WinGetTitle, wid_Title, ahk_id %wid%
1538		WinGet, Style, Style, ahk_id %wid%
1539
1540		If ((Style & WS_DISABLED) or ! (wid_Title)) ; skip unimportant windows ; ! wid_Title or 
1541			Continue
1542
1543		WinGet, es, ExStyle, ahk_id %wid%
1544		Parent := Parent := GetParent(wid)
1545		WinGet, Style_parent, Style, ahk_id %Parent%
1546		Owner := Owner := …

Large files files are truncated, but you can click here to view the full file