├── Base64.ahk ├── BrowserEmulation.ahk ├── CpyData.ahk ├── EnumIncludes.ahk ├── ExecScript.ahk ├── Guid.ahk ├── Include.ahk ├── IsUpdated.ahk ├── MemBlk.ahk ├── OnExitF.ahk ├── OnWin.ahk ├── StdOutToVar.ahk ├── Subprocess.ahk ├── TskDlg.ahk ├── UUIDCreate.ahk ├── WinEnum.ahk ├── eol.ahk ├── googl.ahk ├── range.ahk └── vtype.ahk /Base64.ahk: -------------------------------------------------------------------------------- 1 | /* Library: Base64 2 | * Functions for Base64 (en|de)coding 3 | * Version: 4 | * v1.0.00.00 5 | * Requirements: 6 | * AutoHotkey v1.1.20.00+ OR v2.0-a+ (latest preferred) 7 | * Windows XP or higher 8 | * Installation: 9 | * Use #Include or copy to a function library folder 10 | * Remarks: 11 | * Based on similar lib(s) found in the forum. 12 | */ 13 | 14 | 15 | /* Function: Base64_Encode 16 | * Encode data to Base64 17 | * Syntax: 18 | * bytes := Base64_Encode( ByRef data, len, ByRef out [ , mode := "A" ] ) 19 | * Parameter(s): 20 | * bytes [retval] - on success, the number of bytes copied to 'out'. 21 | * data [in, ByRef] - data to encode 22 | * len [in] - size in bytes of 'data'. Specify '-1' to automtically 23 | * calculate the size. 24 | * out [out, ByRef] - out variable containing the Base64 encoded data 25 | * mode [in, opt] - Specify 'A'(default) to use the ANSI version of 26 | * 'CryptBinaryToString'. Otherwise, 'W' for UNICODE. 27 | */ 28 | Base64_Encode(ByRef data, len:=-1, ByRef out:="", mode:="A") 29 | { 30 | if !InStr("AW", mode := Format("{:U}", mode), true) 31 | mode := "A" 32 | BytesPerChar := mode=="W" ? 2 : 1 33 | if (Round(len) <= 0) 34 | len := StrLen(data) * (A_IsUnicode ? 2 : 1) 35 | 36 | ; CRYPT_STRING_BASE64 := 0x00000001 37 | if DllCall("Crypt32\CryptBinaryToString" . mode, "Ptr", &data, "UInt", len 38 | , "UInt", 0x00000001, "Ptr", 0, "UIntP", size) 39 | { 40 | VarSetCapacity(out, size *= BytesPerChar, 0) 41 | if DllCall("Crypt32\CryptBinaryToString" . mode, "Ptr", &data, "UInt", len 42 | , "UInt", 0x00000001, "Ptr", &out, "UIntP", size) 43 | return size * BytesPerChar 44 | } 45 | } 46 | 47 | /* Function: Base64_Decode 48 | * Decode Base64 encoded data 49 | * Syntax: 50 | * bytes := Base64_Decode( ByRef data, ByRef out [ , mode := "A" ] ) 51 | * Parameter(s): 52 | * bytes [retval] - on success, the number of bytes copied to 'out'. 53 | * data [in, ByRef] - data(NULL-terminated) to decode 54 | * out [out, ByRef] - out variable containing the decoded data 55 | * mode [in, opt] - Specify 'A'(default) to use the ANSI version of 56 | * 'CryptStringToBinary'. Otherwise, 'W' for UNICODE. 57 | */ 58 | Base64_Decode(ByRef data, ByRef out, mode:="A") 59 | { 60 | if !InStr("AW", mode := Format("{:U}", mode), true) 61 | mode := "A" 62 | 63 | ; CRYPT_STRING_BASE64 := 0x00000001 64 | if DllCall("Crypt32\CryptStringToBinary" . mode, "Ptr", &data, "UInt", 0 65 | , "UInt", 0x00000001, "Ptr", 0, "UIntP", size, "Ptr", 0, "Ptr", 0) 66 | { 67 | VarSetCapacity(out, size, 0) 68 | if DllCall("Crypt32\CryptStringToBinary" . mode, "Ptr", &data, "UInt", 0 69 | , "UInt", 0x00000001, "Ptr", &out, "UIntP", size, "Ptr", 0, "Ptr", 0) 70 | return size 71 | } 72 | } -------------------------------------------------------------------------------- /BrowserEmulation.ahk: -------------------------------------------------------------------------------- 1 | /* Function: BrowserEmulation 2 | * FEATURE_BROWSER_EMULATION -> http://goo.gl/V01Frx 3 | * Requirements: 4 | * AutoHotkey v1.1.17.01+ OR v2.0-a057 5 | * Syntax: 6 | * BrowserEmulation( [ version ] ) 7 | * Parameter(s): 8 | * version [in, opt] - IE version(7+). Integer between 7 - 11, value can be 9 | * negative. If omitted, current setting is returned. 10 | * If 'version' is the word "edge", installed IE version 11 | * is used. See table below for possible values: 12 | * Parameter "version" values table: 13 | * (values that are negative ignore !DOCTYPE directives, see http://goo.gl/V01Frx) 14 | * 7: 7000 ; 0x1B58 - IE7 Standards mode. 15 | * 8: 8000, -8: 8888 ; 0x1F40 | 0x22B8 - IE8 mode, IE8 Standards mode 16 | * 9: 9000, -9: 9999 ; 0x2328 | 0x270F - IE9 mode, IE9 Standards mode 17 | * 10: 10000, -10: 10001 ; 0x02710 | 0x2711 - IE10 Standards mode 18 | * 11: 11000, -11: 11001 ; 0x2AF8 | 0x2AF9 - IE11 edge mode 19 | * Remarks: 20 | * This function modifes the registry. 21 | */ 22 | BrowserEmulation(version:="*") ;// FEATURE_BROWSER_EMULATION -> http://goo.gl/V01Frx 23 | { 24 | static fbe := Format( ;// registry path 25 | (LTrim Join, Q 26 | "HKCU\Software\{1}Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\{2}" 27 | A_Is64bitOS ? "Wow6432Node\" : "" 28 | A_IsCompiled ? A_ScriptName : StrGet(DllCall("Shlwapi\PathFindFileName", "Str", A_AhkPath)) 29 | )) 30 | static WshShell := ComObjCreate("WScript.Shell"), prev := "*" 31 | if (prev == "*") ;// init 32 | try prev := WshShell.RegRead(fbe) 33 | catch ;// value does not exist 34 | prev := "" 35 | ;// __Get() 36 | if (version == "*") 37 | { 38 | try value := WshShell.RegRead(fbe) 39 | catch ;// value does not exist 40 | value := "" ;// throw Exception()?? 41 | finally 42 | return value 43 | } 44 | ;// __Set() 45 | if version 46 | { 47 | if (version = "edge") ;// use version of IE installed 48 | version := Round(WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Internet Explorer\svcVersion")) ;// static var?? 49 | static val := { 7:7000, 8:8000, -8:8888, 9:9000, -9:9999, 10:10000, -10:10001, 11:11000, -11:11001 } 50 | if !(version := val[version + 0]) 51 | throw Exception("Failed to resolve value.") 52 | try WshShell.RegWrite(fbe, version, "REG_DWORD") 53 | } 54 | else 55 | try (prev != "") ? WshShell.RegWrite(fbe, prev, "REG_DWORD") : WshShell.RegDelete(fbe) 56 | catch error 57 | throw error 58 | finally 59 | return BrowserEmulation() ;// OR return the value itself 60 | } -------------------------------------------------------------------------------- /CpyData.ahk: -------------------------------------------------------------------------------- 1 | /* Function: CpyData_Send 2 | * Send a string to another script using WM_COPYDATA 3 | * Syntax: 4 | * el := CpyData_Send( str, rcvr [ , data := 0 ] ) 5 | * Return Value: 6 | * SendMessage %WM_COPYDATA% ErrorLevel 7 | * Parameters: 8 | * str [in, ByRef] - string to send (lpData member of COPYDATASTRUCT) 9 | * rcvr [in] - receiver script, argument can be anything that fits 10 | * the WinTitle parameter. 11 | * data [in, opt] - dwData member of COPYDATASTRUCT 12 | */ 13 | CpyData_Send(ByRef str, rcvr, data:=0) 14 | { 15 | VarSetCapacity(CDS, 4 + 2*A_PtrSize, 0) ; http://goo.gl/9wOljy 16 | , NumPut(&str ; lpData 17 | , NumPut((StrLen(str)+1) * (A_IsUnicode ? 2 : 1) ; cbData 18 | , NumPut(data, CDS), "UInt")) ; dwData 19 | 20 | prev_DHW := A_DetectHiddenWindows, prev_TMM := A_TitleMatchMode 21 | DetectHiddenWindows On 22 | SetTitleMatchMode 2 23 | SendMessage 0x4a, %A_ScriptHwnd%, % &CDS,, % "ahk_id " . WinExist(rcvr) 24 | DetectHiddenWindows %prev_DHW% 25 | SetTitleMatchMode %prev_TMM% 26 | 27 | return ErrorLevel 28 | } 29 | /* Function: CpyData_OnRcv 30 | * Set the callback function to call anytime a scripts receives WM_COPYDATA 31 | * Syntax: 32 | * CpyData_OnRcv( [ fn ] ) 33 | * Parameters: 34 | * fn [in, opt] - a callback function, either the name or a Func object. 35 | * If omitted, the current callback function(if any) is 36 | * returned as a Func object. If explicitly blank (""), 37 | * monitoring is disabled. 38 | */ 39 | CpyData_OnRcv(fn:=0) ;// GET=0, SET=Func, DEL="" 40 | { 41 | return _CpyData_OnRcv(fn ? (IsObject(fn) ? fn : Func(fn)) : fn, "CPYDATA") 42 | } 43 | /* PRIVATE 44 | */ 45 | _CpyData_OnRcv(wParam, lParam) ;// wParam=hSender, lParam=COPYDATASTRUCT 46 | { 47 | static callback 48 | 49 | if (lParam == "CPYDATA") ;// called by CpyData_OnRcv() 50 | return wParam == 0 ? callback : OnMessage(0x4a, (callback := wParam) ? A_ThisFunc : "") 51 | 52 | ;// args := [ lpData, hSender, dwData ] 53 | %callback%(StrGet(NumGet(lParam + 2*A_PtrSize)), wParam, NumGet(lParam + 0)) 54 | return true 55 | } -------------------------------------------------------------------------------- /EnumIncludes.ahk: -------------------------------------------------------------------------------- 1 | /** 2 | * Function: EnumIncludes 3 | * Enumerates all #Include files in the specified script by passing the 4 | * the full path to each included file, in turn, to the specified callback 5 | * function. 6 | * Syntax: 7 | * count := EnumIncludes( AhkScript, callback [, AhkExe ] ) 8 | * Parameter(s): 9 | * count [retval] - total number of identified #Include(s) 10 | * AhkScript [in] - AutoHotkey script file to scan 11 | * callback [in] - callback function, must be a "Function object" 12 | * AhkExe [in, opt] - if specified, must be the path to the AutoHotkey.exe 13 | * to use as reference for the standard library 14 | * folder location. Defaults to A_AhkPath 15 | * IgnoreInclAgain [in, opt] - Set to 'true' to ignore subsequently found 16 | * #IncludeAgain(s) which were already processed 17 | * previously. Default is 'false'. 18 | * Remarks: 19 | * To continue enumeration, the callback function must return true(1); to stop 20 | * enumeration, it must return false(0) or blank(""). 21 | */ 22 | EnumIncludes(AhkScript, callback, AhkExe:="", IgnoreInclAgain:=false) 23 | { 24 | if !IsObject(callback) 25 | throw Exception("Invalid parameter -> object expected", -1, callback) 26 | 27 | static FullPath 28 | if !VarSetCapacity(FullPath) 29 | VarSetCapacity(FullPath, 260 * (A_IsUnicode ? 2 : 1)) 30 | 31 | if DllCall("GetFullPathName", "Str", AhkScript, "UInt", 260, "Str", FullPath, "Ptr", 0, "UInt") 32 | AhkScript := FullPath 33 | SplitPath, % AhkScript ,, AhkScriptDir 34 | 35 | if ((AhkExe != "") && DllCall("GetFullPathName", "Str", AhkExe, "UInt", 260, "Str", FullPath, "Ptr", 0, "UInt")) 36 | AhkExe := FullPath 37 | if ((AhkExe == "") || !FileExist(AhkExe)) 38 | AhkExe := A_AhkPath 39 | 40 | cwd := A_WorkingDir 41 | SetWorkingDir, %AhkScriptDir% 42 | 43 | e := false ; Exception 44 | WshExec := "" ; for /iLib (auto-includes) 45 | includes := {}, count := 0 46 | queue := [ [AhkScript, AhkScript] ] 47 | while queue.Length() { 48 | args := queue.RemoveAt(1) 49 | if !(f := IsObject(args[1]) ? args.RemoveAt(1) : FileOpen(args.RemoveAt(1), 0|4)) { 50 | e := Exception((A_Index==1 ? "Script" : "#Include") . " file cannot be opened", -1, args[1]) 51 | break 52 | } 53 | 54 | IsBlockComment := false 55 | IsContSection := false 56 | 57 | AtEOF := ComObjType(f) ? "AtEndOfStream" : "AtEOF" 58 | while !f[AtEOF] { 59 | line := Trim(f.ReadLine(), " `t`r`n") 60 | if (line == "") 61 | continue 62 | 63 | if (!IsBlockComment && !IsContSection) 64 | if !(IsBlockComment := InStr(line, "/*") == 1) && (InStr(line, "(") == 1) 65 | IsContSection := line ~= "i)^\((?:\s*(?(?<=\s)(?!;)|(?<=\())(\bJoin\S*|[^\s)]+))*(?$") { 81 | lib := Trim(SubStr(this_include, 2, -1), " `t") 82 | if (lib_pfx := InStr(lib, "_",, 2)) 83 | lib_pfx := SubStr(lib, 1, lib_pfx-1) 84 | 85 | libs := [AhkScriptDir . "\Lib", A_MyDocuments . "\AutoHotkey\Lib", AhkExe . "\..\Lib"] 86 | for i, lib_dir in libs { 87 | if FileExist(this_include := Format("{1}\{2}.ahk", lib_dir, lib)) 88 | || (lib_pfx && FileExist(this_include := Format("{1}\{2}.ahk", lib_dir, lib_pfx))) 89 | break 90 | this_include := "" 91 | } 92 | 93 | } else { 94 | this_include := StrReplace(this_include, "`%A_ScriptDir`%", AhkScriptDir) 95 | this_include := StrReplace(this_include, "`%A_AppData`%", A_AppData) 96 | this_include := StrReplace(this_include, "`%A_AppDataCommon`%", A_AppDataCommon) 97 | this_include := StrReplace(this_include, "`%A_LineFile`%", args[1]) 98 | 99 | if InStr(FileExist(this_include), "D") { 100 | SetWorkingDir, %this_include% 101 | continue 102 | } 103 | } 104 | 105 | if ((this_include != "") && DllCall("GetFullPathName", "Str", this_include, "UInt", 260, "Str", FullPath, "Ptr", 0, "UInt")) 106 | this_include := FullPath 107 | 108 | if (IsIncludeAgain || !includes[this_include]) { 109 | if !includes[this_include] 110 | includes[this_include] := ++count ; value doesn't really matter as long as it's 'truthy' 111 | else if IgnoreInclAgain ; satisfies (IsIncludeAgain && includes[this_include] && IgnoreInclAgain) 112 | continue 113 | 114 | if (FileExist(this_include) || IgnoreFailure) { 115 | e := !callback.Call(this_include) 116 | if FileExist(this_include) 117 | queue.Push([this_include, this_include]) 118 | } else 119 | e := Exception("Required #Include file does not exist", -1, this_include) 120 | 121 | if e { 122 | f.Close(), f := "" 123 | break 2 124 | } 125 | } 126 | } ; if RegExMatch( ... ) 127 | } ; while f[AtEOF] 128 | 129 | f.Close(), f := "" ; close file/stream 130 | 131 | if (!queue.Length() && !WshExec) { 132 | cmd := Format("{1}{2}{1} /iLib * /ErrorStdOut {1}{3}{1}", Chr(34), A_AhkPath, AhkScript) 133 | WshExec := ComObjCreate("WScript.Shell").Exec(cmd) 134 | 135 | if (err := WshExec.StdErr.ReadAll()) { 136 | e := Exception("Failed to retrieve auto-included script files. Script contains syntax error(s).", -1, cmd) 137 | ; idea taken from Lexikos' LoadFile 138 | if RegExMatch(err, "Os)(.*?) \((\d+)\) : ==> (.*?)(?:\s*Specifically: (.*?))?\R?$", m) 139 | e.Message .= "`n`nReason:`t" . m[3] . "`nLine text:`t" . m[4] . "`nFile:`t" . m[1] . "`nLine:`t" . m[2] 140 | break 141 | } 142 | 143 | queue.Push([WshExec.StdOut, "*"]) 144 | } 145 | 146 | } ; while queue.Length() 147 | 148 | SetWorkingDir, %cwd% ; restore original working dir 149 | 150 | if IsObject(e) ; there was an error 151 | throw e 152 | 153 | return count ; NumGet(&includes + 4*A_PtrSize) 154 | } -------------------------------------------------------------------------------- /ExecScript.ahk: -------------------------------------------------------------------------------- 1 | /* Function: ExecScript 2 | * Run/execute AutoHotkey script[file, through named pipe(s) or from stdin] 3 | * Mod of/inspired by HotKeyIt's DynaRun() 4 | * License: 5 | * WTFPL [http://wtfpl.net/] 6 | * Syntax: 7 | * exec := ExecScript( code [ , args, kwargs* ] ) 8 | * Parameter(s)/Return Value: 9 | * exec [retval] - a WshScriptExec object [http://goo.gl/GlEzk5] 10 | * if WshShell.Exec() method is used else 0 for 11 | * WshShell.Run() 12 | * script [in] - AHK script(file) or code(string) to run/execute. 13 | * When running from stdin(*), if code contains 14 | * unicode characters, WshShell will raise an 15 | * exception. 16 | * args [in, opt] - array of command line arguments to pass to the 17 | * script. Quotes(") are automatically escaped(\"). 18 | * kwargs* [in, variadic] - string in the following format: 'option=value', 19 | * where 'option' is one or more of the following 20 | * listed in the next section. 21 | * Options(kwargs* parameter): 22 | * ahk - path to the AutoHotkey executable to use which is relative to 23 | * A_WorkingDir if an absolute path isn't specified. 24 | * name - when running through named pipes, 'name' specifies the pipe name. 25 | * If omitted, a random value is generated. Otherwise, specify an 26 | * asterisk(*) to run from stdin. This option is ignored when a file 27 | * is specified for the 'script' parameter. 28 | * dir - working directory which is assumed to be relative to A_WorkingDir 29 | * if an absolute path isn't specified. 30 | * cp - codepage [UTF-8, UTF-16, CPnnn], default is 'CP0'. 'CP' may be 31 | * omitted when passing in 'CPnnn' format. Omit or use 'CP0' when 32 | * running code from stdin(*). 33 | * child - if 1(true), WshShell.Exec() method is used, otherwise .Run(). 34 | * Default is 1. Value is ignored and .Exec() is always used when 35 | * running code from stdin. 36 | * Example: 37 | * exec := ExecScript("MsgBox", ["arg"], "name=some_name", "dir=C:\Users") 38 | * Credits: 39 | * - Lexikos for his demonstration [http://goo.gl/5IkP5R] 40 | * - HotKeyIt for DynaRun() [http://goo.gl/92BBMr] 41 | */ 42 | ExecScript(script, args:="", kwargs*) 43 | { 44 | ;// Set default values for options first 45 | child := true ;// use WshShell.Exec(), otherwise .Run() 46 | , name := "AHK_" . A_TickCount 47 | , dir := "" 48 | , ahk := A_AhkPath 49 | , cp := 0 50 | 51 | for i, kwarg in kwargs 52 | if ( option := SubStr(kwarg, 1, (i := InStr(kwarg, "="))-1) ) 53 | ; the RegEx check is not really needed but is done anyways to avoid 54 | ; accidental override of internal local var(s) 55 | && ( option ~= "i)^child|name|dir|ahk|cp$" ) 56 | %option% := SubStr(kwarg, i+1) 57 | 58 | pipe := (run_file := FileExist(script)) || (name == "*") ? 0 : [] 59 | Loop % pipe ? 2 : 0 60 | { 61 | ;// Create named pipe(s), throw exception on failure 62 | if (( pipe[A_Index] := DllCall( 63 | (Join, Q C 64 | "CreateNamedPipe" ; http://goo.gl/3aJQg7 65 | "Str", "\\.\pipe\" . name ; lpName 66 | "UInt", 2 ; dwOpenMode = PIPE_ACCESS_OUTBOUND 67 | "UInt", 0 ; dwPipeMode = PIPE_TYPE_BYTE 68 | "UInt", 255 ; nMaxInstances 69 | "UInt", 0 ; nOutBufferSize 70 | "UInt", 0 ; nInBufferSize 71 | "Ptr", 0 ; nDefaultTimeOut 72 | "Ptr", 0 ; lpSecurityAttributes 73 | )) ) == -1) ; INVALID_HANDLE_VALUE 74 | throw Exception("ExecScript() - Failed to create named pipe", -1, A_LastError) 75 | } 76 | 77 | ; Command = {ahk_exe} /ErrorStdOut /CP{codepage} {file} 78 | static fso := ComObjCreate("Scripting.FileSystemObject") 79 | static q := Chr(34) ;// quotes("), for v1.1 and v2.0-a compatibility 80 | cmd := Format("{4}{1}{4} /ErrorStdOut /CP{2} {4}{3}{4}" 81 | , fso.GetAbsolutePathName(ahk) 82 | , cp="UTF-8" ? 65001 : cp="UTF-16" ? 1200 : cp := Round(LTrim(cp, "CPcp")) 83 | , pipe ? "\\.\pipe\" . name : run_file ? script : "*", q) 84 | 85 | ; Process and append parameters to pass to the script 86 | for each, arg in args 87 | { 88 | i := 0 89 | while (i := InStr(arg, q,, i+1)) ;// escape '"' with '\' 90 | if (SubStr(arg, i-1, 1) != "\") 91 | arg := SubStr(arg, 1, i-1) . "\" . SubStr(arg, i++) 92 | cmd .= " " . (InStr(arg, " ") ? q . arg . q : arg) 93 | } 94 | 95 | if cwd := (dir != "" ? A_WorkingDir : "") ;// change working directory if needed 96 | SetWorkingDir %dir% 97 | 98 | static WshShell := ComObjCreate("WScript.Shell") 99 | exec := (child || name == "*") ? WshShell.Exec(cmd) : WshShell.Run(cmd) 100 | 101 | if cwd ;// restore working directory if altered above 102 | SetWorkingDir %cwd% 103 | 104 | if !pipe ;// file or stdin(*) 105 | { 106 | if !run_file ;// run stdin 107 | exec.StdIn.WriteLine(script), exec.StdIn.Close() 108 | return exec 109 | } 110 | 111 | DllCall("ConnectNamedPipe", "Ptr", pipe[1], "Ptr", 0) ;// http://goo.gl/pwTnxj 112 | DllCall("CloseHandle", "Ptr", pipe[1]) 113 | DllCall("ConnectNamedPipe", "Ptr", pipe[2], "Ptr", 0) 114 | 115 | if !(f := FileOpen(pipe[2], "h", cp)) 116 | return A_LastError 117 | f.Write(script) ;// write dynamic code into pipe 118 | f.Close(), DllCall("CloseHandle", "Ptr", pipe[2]) ;// close pipe 119 | 120 | return exec 121 | } -------------------------------------------------------------------------------- /Guid.ahk: -------------------------------------------------------------------------------- 1 | /* Function: Guid_New 2 | * Create a GUID(__GUID) object 3 | * Syntax: 4 | * oGuid := Guid_New() 5 | */ 6 | Guid_New() 7 | { 8 | return new __GUID 9 | } 10 | /* Function: Guid_FromStr 11 | * Converts a GUID string into a GUID struct 12 | * Syntax: 13 | * pGuid := Guid_FromStr( sGuid, ByRef VarOrAddress ) 14 | * Parameter(s): 15 | * pGuid [retval] - address of the GUID struct 16 | * sGuid [in] - string representation of the GUID 17 | * VarOrAddress [ByRef, out] - GUID, memory address or variable 18 | */ 19 | Guid_FromStr(sGuid, ByRef VarOrAddress) 20 | { 21 | if IsByRef(VarOrAddress) && (VarSetCapacity(VarOrAddress) < 16) 22 | VarSetCapacity(VarOrAddress, 16) ; adjust capacity 23 | pGuid := IsByRef(VarOrAddress) ? &VarOrAddress : VarOrAddress 24 | if ( DllCall("ole32\CLSIDFromString", "WStr", sGuid, "Ptr", pGuid) < 0 ) 25 | throw Exception("Invalid GUID", -1, sGuid) 26 | return pGuid ; return address of GUID struct 27 | } 28 | /* Function: Guid_ToStr 29 | * Converts a GUID into a string of printable characters 30 | * Syntax: 31 | * sGuid := Guid_ToStr( ByRef VarOrAddress ) 32 | * Parameter(s): 33 | * sGuid [retval] - GUID string 34 | * VarOrAddress [ByRef, in] - GUID, memory address or variable 35 | */ 36 | Guid_ToStr(ByRef VarOrAddress) 37 | { 38 | pGuid := IsByRef(VarOrAddress) ? &VarOrAddress : VarOrAddress 39 | VarSetCapacity(sGuid, 78) ; (38 + 1) * 2 40 | if !DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", &sGuid, "Int", 39) 41 | throw Exception("Invalid GUID", -1, Format("", pGuid)) 42 | return StrGet(&sGuid, "UTF-16") 43 | } 44 | /* Class: __GUID 45 | * Creates an object that represents a GUID 46 | * Remarks: 47 | * Caller must use the Guid_New() function to construct a __GUID object 48 | */ 49 | class __GUID ; naming convention to avoid possible variable name conflict (global namespace) 50 | { 51 | /* Property: Ptr 52 | * Returns the address of the GUID struct 53 | * Syntax: 54 | * pGuid := oGuid.Ptr 55 | * pGuid := oGuid[] ; alternative syntax 56 | * Parameter(s): 57 | * pGuid [retval] - address of the GUID struct 58 | * oGuid [in] - a __GUID object 59 | * Ptr [in] - property name, read-only 60 | */ 61 | 62 | /* Property: Str 63 | * Returns a string represntation of the GUID 64 | * Syntax: 65 | * sGuid := oGuid.Str 66 | * Parameter(s): 67 | * pGuid [retval] - GUID string 68 | * oGuid [in] - a __GUID object 69 | * Str [in] - property name, read-only 70 | */ 71 | __Get(key:="", args*) 72 | { 73 | if (key == "") || (key = "Ptr") || (key = "Str") 74 | { 75 | if !pGuid := ObjGetAddress(this, "_GUID") 76 | { 77 | ObjSetCapacity(this, "_GUID", 94) ; 16 + (39 * 2) 78 | pGuid := ObjGetAddress(this, "_GUID") 79 | if ( DllCall("ole32\CoCreateGuid", "Ptr", pGuid) != 0 ) 80 | throw Exception("Failed to create GUID", -1, Format("", pGuid)) 81 | 82 | DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", pGuid + 16, "Int", 39) 83 | } 84 | return InStr("Ptr", key) ? pGuid : StrGet(pGuid + 16, "UTF-16") 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Include.ahk: -------------------------------------------------------------------------------- 1 | /* Function: Include 2 | * Dynamically #Include file(s) OR a string containing AHK code 3 | * License: 4 | * WTFPL [http://wtfpl.net/] 5 | * Syntax: 6 | * Include( incl [ , args* ] ) 7 | * Parameter(s): 8 | * incl [in] - File pattern (accepts wildcards) OR a string 9 | * containing AHK code. 10 | * args* [in, variadic] - Command line argument(s) to pass to the 11 | * script when reloaded/re-ran by this function. 12 | * The caller can use this to determine if a 13 | * specific Include() has been performed. 14 | * Return value: 15 | * Not relevant - I guess, since the script will be reloaded. 16 | * Remark(s): 17 | * - Subsequent call(s) will not include previously Include()-ed file(s) 18 | * OR code. It's up to the caller to keep track and re-Include() them. 19 | * - The /restart switch is used when the script is reloaded. 20 | */ 21 | Include(incl, args*) 22 | { 23 | if FileExist(incl) 24 | { 25 | fspec := incl, incl := "" 26 | if (A_AhkVersion < "2") 27 | Loop %fspec%, 0, 0 28 | incl .= "`n#Include " . A_LoopFileLongPath 29 | else 30 | Loop Files, %fspec%, % "F" ;// force expression to avoid v1.1 error 31 | incl .= "`n#Include " . A_LoopFileFullPath 32 | } 33 | 34 | ;// Create named pipes 35 | pipe := [] 36 | Loop 2 37 | { 38 | if (( pipe[A_Index] := DllCall( 39 | (Join Q C 40 | "CreateNamedPipe", ; http://goo.gl/3aJQg7 41 | "Str", "\\.\pipe\f8e5a38f-24fe-4962-9f13-6c9d7fc32197", ; lpName 42 | "UInt", 2, ; dwOpenMode = PIPE_ACCESS_OUTBOUND 43 | "UInt", 0, ; dwPipeMode = PIPE_TYPE_BYTE 44 | "UInt", 255, ; nMaxInstances 45 | "UInt", 0, ; nOutBufferSize 46 | "UInt", 0, ; nInBufferSize 47 | "Ptr", 0, ; nDefaultTimeOut 48 | "Ptr", 0 ; lpSecurityAttributes 49 | )) ) == -1) ; INVALID_HANDLE_VALUE = -1 50 | throw A_ThisFunc . "() - Failed to create named pipe.`nGetLastError: " . A_LastError 51 | } 52 | 53 | ;// Process command line argument(s) 54 | q := Chr(34) ;// double quote for v1.1 and v2.0-a compatibility 55 | params := "" 56 | for each, arg in args 57 | { 58 | i := 0 59 | while (i := InStr(arg, q,, i+1)) ;// escape '"' with '\' 60 | if (SubStr(arg, i-1, 1) != "\") 61 | arg := SubStr(arg, 1, i-1) . "\" . SubStr(arg, i++) 62 | params .= (A_Index > 1 ? " " : "") . (InStr(arg, " ") ? q . arg . q : arg) 63 | } 64 | 65 | ;// Reload script passing args(if any) 66 | Run "%A_AhkPath%" /restart "%A_ScriptFullPath%" %params% 67 | 68 | DllCall("ConnectNamedPipe", "Ptr", pipe[1], "Ptr", 0) ;// http://goo.gl/pwTnxj 69 | DllCall("CloseHandle", "Ptr", pipe[1]) 70 | DllCall("ConnectNamedPipe", "Ptr", pipe[2], "Ptr", 0) 71 | 72 | ;// Write dynamic code into pipe 73 | if !(f := FileOpen(pipe[2], "h", "UTF-8")) ;// works on both Unicode and ANSI 74 | return A_LastError 75 | f.Write(incl) 76 | f.Close(), DllCall("CloseHandle", "Ptr", pipe[2]) ;// close pipe handle 77 | } 78 | ;// pipe, do not remove. UUID generated using Python's uuid.uuid4() 79 | #Include *i \\.\pipe\f8e5a38f-24fe-4962-9f13-6c9d7fc32197 -------------------------------------------------------------------------------- /IsUpdated.ahk: -------------------------------------------------------------------------------- 1 | IsUpdated() { 2 | ver := A_AhkVersion 3 | whr := ComObjCreate("WinHttp.WinHttpRequest.5.1") 4 | whr.Open("GET", "http://ahkscript.org/download/" SubStr(ver, 1, 3) "/version.txt") 5 | whr.Send() 6 | return SubStr(ver, 1, 8+(ver<2)) >= whr.ResponseText 7 | } -------------------------------------------------------------------------------- /MemBlk.ahk: -------------------------------------------------------------------------------- 1 | /* Library: MemBlk/MemBlkView 2 | * Wrapper for the VarSetCapacity -> NumPut/NumGet/StrPut/StrGet routines 3 | * Version: 4 | * 1.1.00.00 [updated 03/22/2015] 5 | * License: 6 | * WTFPL [http://www.wtfpl.net/] 7 | * Requirements: 8 | * Latest version of AutoHotkey v1.1+ OR v2.0-a 9 | * Installation: 10 | * Use #Include MemBlk.ahk or copy into a function library folder and then 11 | * use #Include 12 | * Links: 13 | * GitHub - http://goo.gl/qNh3Ta 14 | * Forum topic - http://goo.gl/Pt4Z3U 15 | */ 16 | 17 | 18 | /* Class: MemBlk 19 | * A MemBlk object is used to represent a raw binary data buffer. This class 20 | * extends from MemBlkView allowing you to directly manipulate its contents. 21 | */ 22 | class MemBlk extends MemBlkView 23 | { 24 | /* Constructor: __New 25 | * Instantiates an object that represents a memory-block array 26 | * Syntax: 27 | * oBuf := new MemBlk( size [ , FillByte := 0 ] ) 28 | * Parameter(s): 29 | * oBuf [retval] - a MemBlk object 30 | * size [in] - size of the buffer in bytes 31 | * FillByte [in, opt] - similar to VarSetCapacity's 'FillByte' parameter 32 | */ 33 | __New(size, FillByte:=0) 34 | { 35 | ObjSetCapacity(this, "_Buffer", size) 36 | base.__New(ObjGetAddress(this, "_Buffer"),, size) 37 | 38 | if (FillByte >= 0 && FillByte <= 255) ; UChar range 39 | DllCall("RtlFillMemory", "Ptr", this[], "UPtr", size, "UChar", FillByte) 40 | } 41 | } 42 | /* Class: MemBlkView 43 | * Provides an interface for reading data from and writing it to a buffer or 44 | * memory address. API is similar to that of AutoHotkey's File object. 45 | */ 46 | class MemBlkView 47 | { 48 | /* Constructor: __New 49 | * Instantiates an object that respresents a view into a buffer. 50 | * Syntax: 51 | * oView := new MemBlkView( ByRef VarOrAddress [ , offset := 0, length ] ) 52 | * Parameter(s): 53 | * oView [retval] - a MemBlkView object 54 | * VarOrAddress [in, ByRef] - variable(initialized by VarSetCapacity) 55 | * or a memory address 56 | * offset [in, opt] - an offset, in bytes, which is added to 57 | * 'VarOrAddress' for the new view object 58 | * to reference. Defaults to 0 if omitted. 59 | * length [in, opt] - length of the view, in bytes. This parameter 60 | * is required when 'VarOrAddress' is a memory 61 | * address, else, an exception is thrown. 62 | * Remarks: 63 | * An exception is thrown if the 'offset' and 'length' result in the 64 | * specified view extending past the end of the buffer. 65 | */ 66 | __New(ByRef VarOrAddr, offset:=0, length:="") 67 | { 68 | this.__Ptr := (IsByRef(VarOrAddr) ? &VarOrAddr : VarOrAddr) + offset 69 | 70 | if (length == "") 71 | { 72 | if !IsByRef(VarOrAddr) 73 | throw Exception("Parameter 'length' must be specified when passing an address", -1, VarOrAddr) 74 | length := VarSetCapacity(VarOrAddr) 75 | } 76 | if IsByRef(VarOrAddr) && ((offset + length) > VarSetCapacity(VarOrAddr)) 77 | throw Exception("Trying to create view that extends past the buffer", -1, offset + length) 78 | 79 | this.Size := (this[] + length) - this[] 80 | this.Pos := 0 81 | } 82 | /* Property: Size 83 | * Size of the view in bytes. This property is read-only 84 | * Syntax: 85 | * size := oView.Size 86 | */ 87 | 88 | /* Property: Pos 89 | * The current position of the view pointer, where 0 is the beginning of 90 | * the view 91 | * Syntax: 92 | * pos := oView.Pos 93 | */ 94 | __Get(key:="", args*) 95 | { 96 | if !key || (key > 0 && key <= this.Size) 97 | return this.__Ptr + Round(key) 98 | } 99 | 100 | __Call(name, args*) 101 | { 102 | if (name = "Put" || name = "Get") 103 | name .= "UPtr" 104 | else if (name = "Read" || name = "Write") 105 | name .= "CP0" 106 | 107 | if (name ~= "i)^((Put|Get)(U?(Char|Short|Int|Ptr)|Double|Float|Int64)|(Read|Write)(UTF(8|16)|CP\d+))$") 108 | { 109 | static ObjPush := Func(A_AhkVersion<"2" ? "ObjInsert" : "ObjPush") 110 | 111 | n := InStr("RW", SubStr(name, 1, 1)) ? InStr(name, "r") : 0 112 | %ObjPush%(args, SubStr(name, 4 + n)) ; num type OR encoding 113 | return this[n ? "_Str" : "_Num"](SubStr(name, 1, 3 + n), args*) 114 | } 115 | } 116 | /* Method: Put[NumType] 117 | * Store a number in binary format and advances the view pointer 118 | * Syntax: 119 | * oView.PutNumType( num [ , offset ] ) 120 | * Parameter(s): 121 | * NumType - One of the following specified directly as part of 122 | * the method name: UInt, Int, Int64, Short, UShort, 123 | * Char, UChar, Double, Float, UPtr or Ptr. Defaults 124 | * to 'UPtr' if omitted. 125 | * num [in] - a number 126 | * offset [in, opt] - the offset, in bytes, from the view's start point. 127 | * If omitted, 'num' is written at the current position 128 | * of the view pointer. 129 | */ 130 | 131 | /* Method: Get[NumType] 132 | * Reads a number from the view and advances the view pointer 133 | * Syntax: 134 | * num := oView.GetNumType() 135 | * Parameter(s): 136 | * num [retval] - a number 137 | * NumType - same as that of .PutNumType() 138 | * offset [in, opt] - the offset, in bytes, from the view's start point. 139 | * If omitted, 'num' is read from the current position 140 | * of the view pointer. 141 | */ 142 | _Num(action, args*) 143 | { 144 | static sizeof := { "Char":1, "Short":2, "Int":4, "Float":4, "Double":8, "Int64":8, "Ptr":A_PtrSize } 145 | static ObjRemoveAt := Func(A_AhkVersion<"2" ? "ObjRemove" : "ObjRemoveAt") 146 | 147 | ; Process args 148 | if (action = "Put") 149 | { 150 | num := %ObjRemoveAt%(args, 1) 151 | if sizeof[ LTrim(num, "Uu") ] 152 | throw Exception("Too few parameters passed to method", -1, "Put" . num . "()") 153 | } 154 | ptr := this[] 155 | at := ObjHasKey(args, 1) && ((args[1]+0) != "") ? %ObjRemoveAt%(args, 1) : ptr + this.Pos 156 | type := ObjHasKey(args, 1) && sizeof[LTrim(args[1], "Uu")] ? args[1] : "UPtr" 157 | 158 | if (at != (ptr + this.Pos)) && (at >= 0 && at < this.Size) ; offset 159 | at += ptr 160 | 161 | if (action = "Put") 162 | return (n := NumPut(num, at + 0, type), this.Pos := n-ptr, n) ; rightmost for v2.0-a 163 | 164 | this.Seek(sizeof[ LTrim(type, "Uu") ], 1) 165 | return NumGet(at + 0, type) 166 | } 167 | /* Method: Write[Encoding] 168 | * Copies a string into the view and advances the view pointer 169 | * Syntax: 170 | * chars := oView.WriteEncoding( str [ , length ] ) 171 | * Parameter(s): 172 | * Encoding - source/target encoding in the following format: 173 | * 'CPnnn' or 'UTFn' specified directly as part of 174 | * the method name. Defaults to 'CP0' if omitted. 175 | * chars [retval] - the number of characters written 176 | * str [in] - a string 177 | * length [in, opt] - Similar to StrPut()'s 'Length' parameter. 178 | */ 179 | 180 | /* Method: Read[Encoding] 181 | * Copies a string from the view and advances the view pointer 182 | * Syntax: 183 | * str := oView.ReadEncoding( [ length ] ) 184 | * Parameter(s): 185 | * Encoding - same as that of .Write[Encoding]() 186 | * str [retval] - the requested string after performing any necessary 187 | * conversion 188 | * length [in, opt] - Similar to StrGet()'s 'Length' parameter. 189 | */ 190 | _Str(action, args*) 191 | { 192 | enc := "CP0" ; default encoding 193 | for i, arg in args 194 | { 195 | if (arg ~= "i)^UTF-?(8|16)|CP\d+$") 196 | { 197 | if InStr(enc := arg, "UTF") 198 | args[i] := enc := "UTF-" . Abs(SubStr(enc, 4)) ; normalizes if it contains a dash 199 | break 200 | } 201 | } 202 | static ObjRemoveAt := Func(A_AhkVersion<"2" ? "ObjRemove" : "ObjRemoveAt") 203 | addr := this[] + this.Pos 204 | str := action="Read" ? StrGet(addr, args*) : %ObjRemoveAt%(args, 1) 205 | 206 | BytesPerChar := (enc = "UTF-16" || enc = "CP1600") ? 2 : 1 207 | this.Seek(StrPut(str, enc) * BytesPerChar, 1) 208 | 209 | return action="Read" ? str : StrPut(str, addr, args*) 210 | } 211 | /* Method: RawRead 212 | * Copies raw binary data from the the view into the specified buffer 213 | * or memory address. Data is read from the current position of the view 214 | * pointer. 215 | * Syntax: 216 | * BytesRead := oView.RawRead( ByRef VarOrAddress, bytes ) 217 | * Parameter(s): 218 | * BytesRead [retval] - number of bytes that were read 219 | * VarOrAddress [in, ByRef] - variable or memory address to which the 220 | * data will be copied 221 | * bytes [in] - maximum number of bytes to read 222 | */ 223 | RawRead(ByRef dest, bytes) 224 | { 225 | if ((this.Pos + bytes) > this.Size) ; exceeds view's capacity 226 | bytes := this.Size - this.Pos 227 | if IsByRef(dest) && (!VarSetCapacity(dest) || (VarSetCapacity(dest) < bytes)) 228 | { 229 | if (bytes < (A_IsUnicode ? 6 : 3)) ; minimum allowed is 3 TCHARS 230 | VarSetCapacity(dest, 128), VarSetCapacity(dest, 0) ; force ALLOC_MALLOC method 231 | VarSetCapacity(dest, bytes, 0) ; initialize or adjust if capacity is 0 or < bytes 232 | } 233 | DllCall("RtlMoveMemory", "Ptr", IsByRef(dest) ? &dest : dest, "Ptr", this[] + this.Pos, "UPtr", bytes) 234 | return bytes 235 | } 236 | /* Method: RawWrite 237 | * Write raw binary data into the view. Data is written at the current 238 | * position of the view pointer. 239 | * Syntax: 240 | * BytesWritten := oView.RawWrite( ByRef VarOrAddress, bytes ) 241 | * Parameter(s): 242 | * BytesWritten [retval] - number of bytes that were written 243 | * VarOrAddress [in, ByRef] - variable containing the data or the 244 | * address of the data in memory 245 | * bytes [in] - maximum number of bytes to write 246 | */ 247 | RawWrite(ByRef src, bytes) 248 | { 249 | if ((this.Pos + bytes) > this.Size) 250 | bytes := this.Size - this.Pos 251 | DllCall("RtlMoveMemory", "Ptr", this[] + this.Pos, "Ptr", IsByRef(src) ? &src : src, "UPtr", bytes) 252 | return bytes 253 | } 254 | /* Method: Seek 255 | * Moves the view pointer 256 | * Syntax: 257 | * oView.Seek( distance [ , origin := 0 ] ) 258 | * Parameter(s): 259 | * distance [in] - distance to move, in bytes. 260 | * origin [in, opt] - starting point for the view pointer move. Must 261 | * be one of the following: 262 | * 0 - beginning of the view 263 | * 1 - current position of the pointer 264 | * 2 - end of the view, 'distance' should usually 265 | * be negative 266 | * If ommitted, 'origin' defaults to 2 if 'distance' 267 | * is negative and 0 otherwise. 268 | */ 269 | Seek(distance, origin:=0) 270 | { 271 | if (distance < 0 && origin != 2) 272 | origin := 2 273 | start := origin == 0 ? this[] ; start 274 | : origin == 1 ? this[] + this.Pos ; current 275 | : origin == 2 ? this[] + this.Size ; end 276 | : 0 277 | return start ? this.Pos := start + distance - this[] : 0 278 | } 279 | } -------------------------------------------------------------------------------- /OnExitF.ahk: -------------------------------------------------------------------------------- 1 | OnExitF(fn:="", prms*) { 2 | ; Prepend w/ '_' to make sure it gets freed first. 3 | ; Variables containing object references are freed alphabetically. 4 | static _dummy 5 | static handler := { __Delete: Func("OnExitF") } 6 | static oef := {} 7 | 8 | ; called by __Delete 9 | if (IsObject(fn) && fn.base == handler) { 10 | if !(exit_sub := oef.Remove("fn")) 11 | return 12 | return %exit_sub%(oef.prms*) 13 | } 14 | 15 | if (fn == "") { ; disable, return script to normal behavior 16 | oef.Remove("prms") 17 | return oef.Remove("fn").Name 18 | } 19 | 20 | if !IsFunc(fn) 21 | return false 22 | oef.fn := IsObject(fn) ? fn : Func(fn) 23 | oef.prms := prms 24 | if !_dummy 25 | _dummy := new handler 26 | return true 27 | } -------------------------------------------------------------------------------- /OnWin.ahk: -------------------------------------------------------------------------------- 1 | /** 2 | * Function: OnWin 3 | * Specifies a function to call when the specified window event for the 4 | * specified window occurs. 5 | * Version: 6 | * v1.1.00.02 7 | * License: 8 | * WTFPL [http://wtfpl.net/] 9 | * Requirements: 10 | * Latest stable version of AutoHotkey 11 | * Syntax: 12 | * OnWin( Event, WinTitle, Callback [, ItemId := "" ] ) 13 | * Parameter(s): 14 | * Event [in] - Window event to monitor. Valid values are: Exist, 15 | * Close, Show, Hide, Active, NotActive, Minimize, 16 | * Maximize. 17 | * WinTitle [in] - see http://ahkscript.org/docs/misc/WinTitle.htm 18 | * Callback [in] - "Function object" - see http://ahkscript.org/docs/objects/Functor.htm 19 | * ItemId [in, opt] - User-defined ID to associate with this particular 20 | * window event monitor. 21 | * Remarks: 22 | * - Script must be #Include-ed(manually or automatically) and must not be 23 | * copy-pasted into the main script. 24 | * - OnWin() uses A_TitleMatchMode 25 | * Links: 26 | * GitHub - http://goo.gl/JfzFTh 27 | * Forum Topic - http://goo.gl/sMufTt 28 | */ 29 | OnWin(args*) 30 | { 31 | return __OnWinEvent(args*) 32 | } 33 | /** 34 | * Function: OnWin_Ex 35 | * Sames as OnWin() above, however, a child process is spawned to perform the 36 | * monitoring. 37 | * Syntax: 38 | * OnWin_Ex( Event, WinTitle, Callback [, ItemId := "", ProcessName := "default" ] ) 39 | * Parameter(s): 40 | * Event [in] - Same as that of OnWin()'s 41 | * WinTitle [in] - Same as that of OnWin()'s 42 | * Callback [in] - Same as that of OnWin()'s 43 | * ItemId [in, opt] - Same as that of OnWin()'s 44 | * ProcessName [in, opt] - User-defined ID to associate with this particular 45 | * child process. Subsequent call(s) to OnWin_Ex() 46 | * will push the window event monitor info into the 47 | * queue of this particular process unless a different 48 | * name/ID is specified. 49 | */ 50 | OnWin_Ex(args*) 51 | { 52 | return __OnWinEvent(args*) 53 | } 54 | /** 55 | * Function: OnWin_Stop 56 | * Disables monitoring for the particular window event monitor info item 57 | * specified by the 'ItemId' parameter. 58 | * Syntax: 59 | * OnWin_Stop( ItemId [, ProcessName ] ) 60 | * Parameter(s): 61 | * ItemId [in] - a previously defined ItemId - see OnWin/OnWin_Ex 62 | * If explicitly blank(""), all window event monitor 63 | * are disabled. 64 | * ProcessName [in, opt] - a previously defined ProcessName - see OnWin_Ex 65 | */ 66 | OnWin_Stop(id, name*) 67 | { 68 | return __OnWinEvent(id, name*) 69 | } 70 | 71 | ; PRIVATE 72 | __OnWinEvent(args*) 73 | { 74 | static InProcess := new __OnWinEvent.Watcher 75 | static SubProcesss := new __OnWinEvent.Server 76 | 77 | static level := A_AhkVersion<"2" ? -2 : -1 78 | command := Exception("", level).What ; prevent user from calling A_ThisFunc directly, overkill?? 79 | if (command == "OnWin") 80 | return %InProcess%(args*) 81 | 82 | else if (command == "OnWin_Ex") 83 | return %SubProcesss%(args*) 84 | 85 | else if (command == "OnWin_Stop") 86 | { 87 | if ObjHasKey(args, 2) 88 | SubProcesss.Clients[args[2]].Stop(args[1]) 89 | else 90 | InProcess.Stop(args[1]) 91 | } 92 | } 93 | 94 | class __OnWinEvent ; namespace 95 | { 96 | class Callable ; base object for custom "Function" objects 97 | { 98 | __Call(method, args*) 99 | { 100 | if IsObject(method) 101 | return this.Call(method, args*) 102 | else if (method == "") 103 | return this.Call(args*) 104 | } 105 | } 106 | 107 | class Watcher extends __OnWinEvent.Callable 108 | { 109 | Queue := [] 110 | IsRunning := false 111 | Call(args*) 112 | { 113 | ObjPush(this.Queue, info := new __OnWinEvent.Info(args*)) 114 | 115 | if !this.IsRunning 116 | this.Start() 117 | } 118 | 119 | Watch() 120 | { 121 | Loop, % ObjLength(this.Queue) 122 | { 123 | if this.Queue[1].Assert() 124 | ObjRemoveAt(this.Queue, 1) 125 | else 126 | ObjPush(this.Queue, ObjRemoveAt(this.Queue, 1)) 127 | } 128 | 129 | if !this.IsRunning := ObjLength(this.Queue) ; update 'IsRunning' property 130 | this.Stop() 131 | } 132 | 133 | Start() 134 | { 135 | this.SetTimer(25) 136 | this.IsRunning := true 137 | } 138 | 139 | Stop(args*) 140 | { 141 | this.SetTimer("Off") 142 | 143 | if HasId := ObjLength(args) 144 | { 145 | id := args[1] 146 | if (id == "") && (len := ObjLength(this.Queue)) 147 | ObjRemoveAt(this.Queue, 1, len) 148 | 149 | Loop, % ObjLength(this.Queue) 150 | if (this.Queue[A_Index].Id = id) ? ObjRemoveAt(this.Queue, A_Index) : 0 151 | break 152 | } 153 | 154 | this.SetTimer(HasId ? "On" : "Delete") 155 | } 156 | 157 | SetTimer(arg3) 158 | { 159 | static number := "number" 160 | if arg3 is %number% 161 | { 162 | if !timer := this.Timer 163 | timer := this.Timer := ObjBindMethod(this, "Watch") 164 | SetTimer, %timer%, %arg3% 165 | } 166 | 167 | else if (arg3 = "On" || arg3 = "Off") 168 | { 169 | timer := this.Timer 170 | SetTimer, %timer%, %arg3% 171 | } 172 | 173 | else if (arg3 = "Delete") 174 | { 175 | if timer := ObjDelete(this, "Timer") 176 | SetTimer, %timer%, Delete 177 | } 178 | } 179 | } 180 | 181 | class WatcherEx extends __OnWinEvent.Watcher 182 | { 183 | Host := "" ; value assigned by host 184 | Name := "" ; value assigned by host 185 | __Delete() 186 | { 187 | ExitApp 188 | } 189 | 190 | Stop(args*) 191 | { 192 | base.Stop(args*) 193 | 194 | if !ObjLength(args) ; usually called from the timer routine when the queue is empty 195 | { 196 | ; there are no longer any window events to monitor. Remove object 197 | ; reference from the host script's clients list, __Delete should be 198 | ; triggered automatically. 199 | this.Host.Ptr.Clients.Delete(this.Name) 200 | this.Host := "" 201 | } 202 | } 203 | } 204 | 205 | class Server extends __OnWinEvent.Callable 206 | { 207 | Clients := {} 208 | Call(event, WinTitle, CbProc, id:="", name:="default") 209 | { 210 | if !IsObject(this.Clients[name]) 211 | { 212 | client := new __OnWinEvent.Client 213 | 214 | static q := Chr(34), quot := Func("Format").Bind("{1}{2}{1}", q) 215 | code := Format(" 216 | ( LTrim Join`r`n Comments 217 | ComObjActive({1}).Proxy := new __OnWinEvent.WatcherEx 218 | return 219 | #NoTrayIcon 220 | #Persistent 221 | #Include {2} 222 | )" 223 | , quot.Call(client.Guid["Str"]), A_LineFile) 224 | 225 | try 226 | { 227 | WshExec := ComObjCreate("WScript.Shell").Exec(quot.Call(A_AhkPath) . " /ErrorStdOut *") 228 | WshExec.StdIn.Write(code) 229 | WshExec.StdIn.Close() 230 | while (WshExec.Status == 0) && !client.Proxy 231 | Sleep, 10 232 | } 233 | finally 234 | client.Revoke() 235 | 236 | client.Proxy.Host := new this.Ref(this) ; weak reference, allows 2-way communication 237 | client.Proxy.Name := name 238 | this.Clients[name] := client.Proxy 239 | client := "" 240 | } 241 | 242 | remote := this.Clients[name] 243 | return %remote%(event, WinTitle, CbProc, id, A_TitleMatchMode) 244 | } 245 | 246 | class Ref 247 | { 248 | __New(self) 249 | { 250 | this.__Ptr := &self 251 | } 252 | 253 | Ptr[] ; allows client script(s) to retrieve a reference to the host object 254 | { 255 | get { 256 | if (pThis := this.__Ptr) && (NumGet(pThis + 0) == NumGet(&this)) 257 | return Object(pThis) 258 | } 259 | } 260 | } 261 | 262 | __Delete() ; triggers on main script's exit 263 | { 264 | ; stop remote client script(s) if any 265 | for i, client in this.Clients 266 | client.SetTimer("Delete") ; force stop and remove any extra object references(timer's BoundFunc) 267 | this.Clients := "" ; should trigger client script(s) __Delete 268 | } 269 | } 270 | 271 | class Client 272 | { 273 | __New() 274 | { 275 | HR := DllCall("oleaut32\RegisterActiveObject", "Ptr", &this, "Ptr", this.Guid["Ptr"], "UInt", 0, "UInt*", hReg, "UInt") 276 | if (HR < 0) 277 | throw Exception("RegisterActiveObject() error", -1, Format("HRESULT: 0x{:x}", HR)) 278 | this.__Handle := hReg 279 | } 280 | 281 | __Delete() 282 | { 283 | this.Revoke() 284 | } 285 | 286 | Revoke() 287 | { 288 | if hReg := this.__Handle 289 | DllCall("oleaut32\RevokeActiveObject", "UInt", hReg, "Ptr", 0) 290 | this.__Handle := 0 291 | } 292 | 293 | Guid[arg] 294 | { 295 | get { 296 | if !pGuid := ObjGetAddress(this, "_Guid") 297 | { 298 | ObjSetCapacity(this, "_Guid", 94) 299 | pGuid := ObjGetAddress(this, "_Guid") 300 | if ( DllCall("ole32\CoCreateGuid", "Ptr", pGuid) != 0 ) 301 | throw Exception("Failed to create GUID", -1, Format("", pGuid)) 302 | DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", pGuid + 16, "Int", 39) 303 | } 304 | return (arg="Ptr") ? pGuid : (arg="Str") ? StrGet(pGuid + 16, "UTF-16") : "" 305 | } 306 | } 307 | } 308 | 309 | class Info 310 | { 311 | __New(event, WinTitle, CbProc, id:="", tmm:=0) ; tmm used internally for client scripts 312 | { 313 | this.Event := event 314 | this.WinTitle := WinTitle 315 | this.Callback := CbProc 316 | this.TitleMatchMode := tmm ? tmm : A_TitleMatchMode 317 | if (id != "") 318 | this.Id := id 319 | } 320 | 321 | Assert() 322 | { 323 | event := this.Event 324 | WinTitle := this.WinTitle 325 | prev_TMM := A_TitleMatchMode 326 | this_TMM := this.TitleMatchMode 327 | SetTitleMatchMode, %this_TMM% 328 | 329 | prev_DWH := A_DetectHiddenWindows 330 | DetectHiddenWindows, On 331 | 332 | if (event = "Exist") 333 | r := WinExist(WinTitle) 334 | 335 | else if (event = "Close") 336 | r := !WinExist(WinTitle) 337 | 338 | else if (event = "Active") 339 | r := WinActive(WinTitle) 340 | 341 | else if (event = "NotActive") 342 | r := !WinActive(WinTitle) 343 | 344 | else if (event = "Show") || (event = "Hide" && hWnd := WinExist(WinTitle)) 345 | { 346 | DetectHiddenWindows, Off 347 | r := (event="Show") ? WinExist(WinTitle) : !WinExist(WinTitle) 348 | } 349 | 350 | else if (event = "Minimize" || event = "Maximize") 351 | { 352 | static WINDOWPLACEMENT 353 | if !VarSetCapacity(WINDOWPLACEMENT) 354 | VarSetCapacity(WINDOWPLACEMENT, 44, 0), NumPut(44, WINDOWPLACEMENT, 0, "UInt") ; sizeof(WINDOWPLACEMENT) 355 | 356 | hWnd := WinExist(WinTitle) 357 | showCmd := event="Minimize" ? 2 : 3 358 | DllCall("GetWindowPlacement", "Ptr", hWnd, "Ptr", &WINDOWPLACEMENT) 359 | r := NumGet(WINDOWPLACEMENT, 8, "UInt") == showCmd 360 | } 361 | 362 | 363 | SetTitleMatchMode, %prev_TMM% 364 | DetectHiddenWindows %prev_DHW% 365 | 366 | if r 367 | this.Callback.Call(this) 368 | return r 369 | } 370 | } 371 | } -------------------------------------------------------------------------------- /StdOutToVar.ahk: -------------------------------------------------------------------------------- 1 | StdOutToVar(cmd) { 2 | DllCall("CreatePipe", "PtrP", hReadPipe, "PtrP", hWritePipe, "Ptr", 0, "UInt", 0) 3 | DllCall("SetHandleInformation", "Ptr", hWritePipe, "UInt", 1, "UInt", 1) 4 | 5 | VarSetCapacity(PROCESS_INFORMATION, (A_PtrSize == 4 ? 16 : 24), 0) ; http://goo.gl/dymEhJ 6 | cbSize := VarSetCapacity(STARTUPINFO, (A_PtrSize == 4 ? 68 : 104), 0) ; http://goo.gl/QiHqq9 7 | NumPut(cbSize, STARTUPINFO, 0, "UInt") ; cbSize 8 | NumPut(0x100, STARTUPINFO, (A_PtrSize == 4 ? 44 : 60), "UInt") ; dwFlags 9 | NumPut(hWritePipe, STARTUPINFO, (A_PtrSize == 4 ? 60 : 88), "Ptr") ; hStdOutput 10 | NumPut(hWritePipe, STARTUPINFO, (A_PtrSize == 4 ? 64 : 96), "Ptr") ; hStdError 11 | 12 | if !DllCall( 13 | (Join Q C 14 | "CreateProcess", ; http://goo.gl/9y0gw 15 | "Ptr", 0, ; lpApplicationName 16 | "Ptr", &cmd, ; lpCommandLine 17 | "Ptr", 0, ; lpProcessAttributes 18 | "Ptr", 0, ; lpThreadAttributes 19 | "UInt", true, ; bInheritHandles 20 | "UInt", 0x08000000, ; dwCreationFlags 21 | "Ptr", 0, ; lpEnvironment 22 | "Ptr", 0, ; lpCurrentDirectory 23 | "Ptr", &STARTUPINFO, ; lpStartupInfo 24 | "Ptr", &PROCESS_INFORMATION ; lpProcessInformation 25 | )) { 26 | DllCall("CloseHandle", "Ptr", hWritePipe) 27 | DllCall("CloseHandle", "Ptr", hReadPipe) 28 | return "" 29 | } 30 | 31 | DllCall("CloseHandle", "Ptr", hWritePipe) 32 | VarSetCapacity(buffer, 4096, 0) 33 | while DllCall("ReadFile", "Ptr", hReadPipe, "Ptr", &buffer, "UInt", 4096, "UIntP", dwRead, "Ptr", 0) 34 | sOutput .= StrGet(&buffer, dwRead, "CP0") 35 | 36 | DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, 0)) ; hProcess 37 | DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, A_PtrSize)) ; hThread 38 | DllCall("CloseHandle", "Ptr", hReadPipe) 39 | return sOutput 40 | } -------------------------------------------------------------------------------- /Subprocess.ahk: -------------------------------------------------------------------------------- 1 | Subprocess_Run(args*) 2 | { 3 | return new Subprocess(args*) 4 | } 5 | 6 | class Subprocess 7 | { 8 | __New(cmd, cwd:="") 9 | { 10 | DllCall("CreatePipe", "Ptr*", stdin_read, "Ptr*", stdin_write, "Ptr", 0, "UInt", 0) 11 | , DllCall("SetHandleInformation", "Ptr", stdin_read, "UInt", 1, "UInt", 1) 12 | , DllCall("CreatePipe", "Ptr*", stdout_read, "Ptr*", stdout_write, "Ptr", 0, "UInt", 0) 13 | , DllCall("SetHandleInformation", "Ptr", stdout_write, "UInt", 1, "UInt", 1) 14 | , DllCall("CreatePipe", "Ptr*", stderr_read, "Ptr*", stderr_write, "Ptr", 0, "UInt", 0) 15 | , DllCall("SetHandleInformation", "Ptr", stderr_write, "UInt", 1, "UInt", 1) 16 | 17 | static _STARTUPINFO 18 | if !VarSetCapacity(_STARTUPINFO) { 19 | sizeof_si := A_PtrSize==8 ? 104 : 68 ; 40 + 7*A_PtrSize + 2*(pad := A_PtrSize==8 ? 4 : 0) 20 | VarSetCapacity(_STARTUPINFO, sizeof_si, 0) 21 | , NumPut(sizeof_si, _STARTUPINFO, "UInt") 22 | , NumPut(0x100, _STARTUPINFO, A_PtrSize==8 ? 60 : 44, "UInt") ; dwFlags=STARTF_USESTDHANDLES) 23 | } 24 | 25 | NumPut(stderr_write 26 | , NumPut(stdout_write 27 | , NumPut(stdin_read, _STARTUPINFO, A_PtrSize==8 ? 80 : 56))) 28 | 29 | static sizeof_pi := 8 + 2*A_PtrSize 30 | this.SetCapacity("PROCESS_INFORMATION", sizeof_pi) 31 | proc_info := this.GetAddress("PROCESS_INFORMATION") 32 | 33 | if IsObject(cmd) { 34 | static quot := Func("Format").Bind("{1}{2}{1}", Chr(34)) 35 | length := cmd.Length(), args := cmd, cmd := "" 36 | for i, arg in args 37 | cmd .= (InStr(arg, " ") ? quot.Call(arg) : arg) . (i CR to LF -> LF to CRLF) 26 | eols := Array(["`r`n", "`n"], ["`r", "`n"], ["`n", "`r`n"]) 27 | 28 | else if (eol == "`n") ; to LF (CRLF to LF -> CR to LF) 29 | eols := Array(["`r`n", "`n"], ["`r", "`n"]) 30 | 31 | else if (eol == "`r") ; to CR (CRLF to CR -> LF to CR) 32 | eols := Array(["`r`n", "`r"], ["`n", "`r"]) 33 | 34 | for each, nl in eols 35 | { 36 | ; v1.1+ and v2.0-a StringReplace/StrReplace workaround 37 | ; alternative: str := RegExReplace(str, nl[1], nl[2]) 38 | ; If dual-compatibilty is not required, comment this out and uncomment 39 | ; either of the one below for your respective AHK version 40 | p := A_Index>2 ? -1 : 0 41 | while p := InStr(str, nl[1],, p + StrLen(nl[2])) 42 | str := SubStr(str, 1, p-1) . nl[2] . SubStr(str, p + StrLen(nl[1])) 43 | 44 | ; v1.1+ 45 | ; StringReplace, str, str, % nl[1], % nl[2], All 46 | 47 | ; v2.0-a 48 | ; str := StrReplace(str, nl[1], nl[2]) 49 | } 50 | 51 | /* Add blank line at end(for LF and CR)?? 52 | if (eol != "`r`n") && StrLen(str) 53 | if (SubStr(str, A_AhkVersion<"2" ? 0 : -1) != eol) 54 | str .= eol 55 | */ 56 | 57 | return str 58 | } -------------------------------------------------------------------------------- /googl.ahk: -------------------------------------------------------------------------------- 1 | googl(url) { 2 | ;// Forum topic: http://goo.gl/3kR4PO 3 | static q := Chr(34) ;// double quote 4 | static api_url := " 5 | (Join LTrim C 6 | https://www.googleapis.com/urlshortener/v1/url?key= 7 | AIzaSyBXD-RmnD2AKzQcDHGnzZh4humG-7Rpdmg ;// API Key 8 | )" 9 | 10 | http := ComObjCreate("WinHttp.WinHttpRequest.5.1") 11 | http.Open("POST", api_url, false) 12 | http.SetRequestHeader("Content-Type", "application/json") 13 | http.Send("{" . q . "longUrl" . q . ": " . q . url . q . "}") 14 | res := http.ResponseText 15 | return SubStr( 16 | (Join Q C 17 | res, 18 | p := InStr(res, q . "id" . q . ": " . q)+7, 19 | InStr(res, q,, p+1)-p 20 | )) 21 | } -------------------------------------------------------------------------------- /range.ahk: -------------------------------------------------------------------------------- 1 | range(start, stop:="", step:=1) { 2 | static range := { _NewEnum: Func("_RangeNewEnum") } 3 | if !step 4 | throw "range(): Parameter 'step' must not be 0 or blank" 5 | if (stop == "") 6 | stop := start, start := 0 7 | ; Formula: r[i] := start + step*i ; r = range object, i = 0-based index 8 | ; For a postive 'step', the constraints are i >= 0 and r[i] < stop 9 | ; For a negative 'step', the constraints are i >= 0 and r[i] > stop 10 | ; No result is returned if r[0] does not meet the value constraint 11 | if (step > 0 ? start < stop : start > stop) ;// start == start + step*0 12 | return { base: range, start: start, stop: stop, step: step } 13 | } 14 | 15 | _RangeNewEnum(r) { 16 | static enum := { "Next": Func("_RangeEnumNext") } 17 | return { base: enum, r: r, i: 0 } 18 | } 19 | 20 | _RangeEnumNext(enum, ByRef k, ByRef v:="") { 21 | stop := enum.r.stop, step := enum.r.step 22 | , k := enum.r.start + step*enum.i 23 | if (ret := step > 0 ? k < stop : k > stop) 24 | enum.i += 1 25 | return ret 26 | } -------------------------------------------------------------------------------- /vtype.ahk: -------------------------------------------------------------------------------- 1 | vtype(v, assert:="") 2 | { 3 | static is_v2 := A_AhkVersion >= "2" 4 | static Type := is_v2 ? Func("Type") : "" 5 | static nMatchObj := is_v2 ? "" : NumGet(&(m, RegExMatch("", "O)", m))) 6 | static nBoundFunc := NumGet(&(f := Func("Func").Bind())) 7 | static nFileObj := NumGet(&(f := FileOpen("*", "w"))) 8 | 9 | if is_v2 10 | t := %Type%(v) ;// use v2.0-a built-in Type() 11 | 12 | else if IsObject(v) 13 | t := ObjGetCapacity(v) != "" ? "Object" 14 | : IsFunc(v) ? "Func" 15 | : ComObjType(v) != "" ? "ComObject" 16 | : NumGet(&v) == nBoundFunc ? "BoundFunc" 17 | : NumGet(&v) == nMatchObj ? "RegExMatchObject" 18 | : NumGet(&v) == nFileObj ? "FileObject" 19 | : "Property" 20 | 21 | else 22 | t := ObjGetCapacity([v], 1) != "" ? "String" : (InStr(v, ".") ? "Float" : "Integer") 23 | 24 | return assert ? InStr(t, assert) : t 25 | } --------------------------------------------------------------------------------