Code: Select all
RunAsAdmin(true)
HKEY_LOCAL_MACHINE := 0x80000002
REG_NOTIFY_CHANGE_LAST_SET := 0x00000004
KEY_NOTIFY := 0x0010
counter := 0
RegWrite, REG_SZ, HKEY_LOCAL_MACHINE\SOFTWARE\TestKey, MyValueName, % ++counter
MyEvent := new Event()
MyWaitFunc := new WaitForSingleObjectAsync(MyEvent.handle, Func("Test"))
hLib := DllCall("LoadLibrary", "Str", "Advapi32")
DllCall("Advapi32\RegOpenKeyEx", "UInt", HKEY_LOCAL_MACHINE, "Ptr", 0, "UInt", 0, "Int", KEY_NOTIFY, "PtrP", hKey)
Test(true)
Return
$F1:: RegWrite, REG_SZ, HKEY_LOCAL_MACHINE\SOFTWARE\TestKey, MyValueName, % ++counter ; Should run Test()
Esc:: ExitApp
Test(mode := false) {
global
if !mode
MsgBox,,, Success!, .4
DllCall("Advapi32\RegNotifyChangeKeyValue", "Ptr", hKey, "UInt", true
, "UInt", REG_NOTIFY_CHANGE_LAST_SET
, "Ptr", MyEvent.handle, "UInt", true)
}
class Event {
__New() {
this.handle := DllCall("CreateEvent", "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr")
}
Set() {
DllCall("SetEvent", "Ptr", this.handle)
}
__Delete() {
this.Set()
DllCall("CloseHandle", "Ptr", this.handle)
}
}
class WaitForSingleObjectAsync
{
__New(hEvent, userFunc) {
this.EventSignal := new this._EventSignal(hEvent, userFunc)
}
__Delete() {
this.EventSignal.Clear()
}
class _EventSignal {
__New(hEvent, UserFunc) {
this.WM_EVENTSIGNAL := DllCall("RegisterWindowMessage", "Str", "WM_EVENTSIGNAL")
for k, v in ["hEvent", "UserFunc"]
this[v] := %v%
this.OnEvent := ObjBindMethod(this, "On_WM_EVENTSIGNAL")
OnMessage(this.WM_EVENTSIGNAL, this.OnEvent)
this.startAddress := this.CreateWaitFunc(this.hEvent, A_ScriptHwnd, this.WM_EVENTSIGNAL)
this.Thread := new this._Thread(this.startAddress)
}
On_WM_EVENTSIGNAL(wp) {
if !(wp = this.hEvent)
Return
timer := this.UserFunc
SetTimer, % timer, -10
this.Thread.Wait()
this.Thread := new this._Thread(this.startAddress)
}
CreateWaitFunc(hEvent, hWnd, msg, timeout := -1) {
params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_EXECUTE_READWRITE := 0x40, "Ptr"]
ptr := DllCall("VirtualAlloc", "Ptr", 0, "Ptr", A_PtrSize = 4 ? 49 : 85, params*)
hModule := DllCall("GetModuleHandle", "Str", "kernel32.dll", "Ptr")
pWaitForObj := DllCall("GetProcAddress" , "Ptr", hModule, "AStr", "WaitForSingleObject", "Ptr")
hModule := DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr")
pPostMessage := DllCall("GetProcAddress" , "Ptr", hModule, "AStr", "PostMessageW", "Ptr")
NumPut(pWaitForObj , ptr + 0)
NumPut(pPostMessage, ptr + A_PtrSize)
if (A_PtrSize = 4) {
NumPut(0x68 , ptr + 8)
NumPut(timeout, ptr + 9) , NumPut(0x68 , ptr + 13)
NumPut(hEvent , ptr + 14) , NumPut(0x15FF, ptr + 18)
NumPut(ptr , ptr + 20) , NumPut(0x6850, ptr + 24)
NumPut(hEvent , ptr + 26) , NumPut(0x68 , ptr + 30)
NumPut(msg , ptr + 31) , NumPut(0x68 , ptr + 35)
NumPut(hWnd , ptr + 36) , NumPut(0x15FF, ptr + 40)
NumPut(ptr + 4, ptr + 42) , NumPut(0xC2 , ptr + 46, "UChar")
NumPut(4 , ptr + 47, "UShort")
}
else {
NumPut(0x53 , ptr + 16)
NumPut(0x20EC8348, ptr + 17) , NumPut(0xBACB8948, ptr + 21)
NumPut(timeout , ptr + 25) , NumPut(0xB948 , ptr + 29)
NumPut(hEvent , ptr + 31) , NumPut(0x15FF , ptr + 39)
NumPut(-45 , ptr + 41) , NumPut(0xB849 , ptr + 45)
NumPut(hEvent , ptr + 47) , NumPut(0xBA , ptr + 55)
NumPut(msg , ptr + 56) , NumPut(0xB948 , ptr + 60)
NumPut(hWnd , ptr + 62) , NumPut(0xC18941 , ptr + 70)
NumPut(0x15FF , ptr + 73) , NumPut(-71 , ptr + 75)
NumPut(0x20C48348, ptr + 79, "UInt"), NumPut(0xC35B , ptr + 83, "UShort")
}
Return ptr + A_PtrSize*2
}
class _Thread {
__New(startAddress) {
if !this.handle := DllCall("CreateThread", "Int", 0, "Int", 0, "Ptr", startAddress, "Int", 0, "UInt", 0, "Int", 0, "Ptr")
throw Exception("Failed to create thread.`nError code: " . A_LastError)
}
Wait() {
DllCall("WaitForSingleObject", "Ptr", this.handle, "Int", -1)
}
__Delete() {
DllCall("CloseHandle", "Ptr", this.handle)
}
}
Clear() {
this.Thread.Wait()
OnMessage(this.WM_EVENTSIGNAL, this.OnEvent, 0)
this.OnEvent := ""
DllCall("VirtualFree", "Ptr", this.startAddress - A_PtrSize*2, "Ptr", A_PtrSize = 4 ? 49 : 85, "UInt", MEM_DECOMMIT := 0x4000)
}
}
}
RunAsAdmin(exitIfNotAdmin := false) {
commandLine := DllCall("GetCommandLine", "str")
isRestarted := !!RegExMatch(commandLine, " /restart(?!\S)")
while !( A_IsAdmin || isRestarted ) {
try Run, % "*RunAs " . (A_IsCompiled ? """" . A_ScriptFullPath . """ /restart"
: """" . A_AhkPath . """ /restart """ . A_ScriptFullPath . """")
catch
break
ExitApp
}
if !A_IsAdmin {
MsgBox, Failed to run the script as admin!
if exitIfNotAdmin
ExitApp
}
}