(winapi) RegNotifyChangeKeyValue Access is denied.

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
MiM
Posts: 61
Joined: 20 Apr 2021, 04:31

(winapi) RegNotifyChangeKeyValue Access is denied.

Post by MiM » 04 Aug 2022, 18:00

Code: Select all

#Persistent
#SingleInstance, Force

RegWrite, REG_SZ, HKEY_LOCAL_MACHINE\SOFTWARE\TestKey, MyValueName, One
DllCall("Advapi32.dll\RegOpenKeyEx" (A_IsUnicode?"W":"A"), "UInt", 0x80000002, "UInt", 0, "UInt", 0, "Int", 0x1, "UIntP", hKey)
Result := DllCall("Advapi32.dll\RegNotifyChangeKeyValue"
                , "UPtr", hKey
                , "Int",  True
                , "UInt", 0x00000004L
                , "Ptr",  RegisterCallback("Test")
                , "Int",  False)
MsgBox, % FormatMessageFromSystem(Result)
RegWrite, REG_SZ, HKEY_LOCAL_MACHINE\SOFTWARE\TestKey, MyValueName, Two ; Should run Test()
Return

FormatMessageFromSystem(ErrorCode) {
  VarSetCapacity(Buffer, 2000)
  DllCall("FormatMessage", "UInt", 0x1000, "UInt", 0, "UInt", ErrorCode, "UInt", 0x800 , "Str", Buffer, "UInt", 500, "UInt", 0)
  Return Buffer
}

Test() {
  MsgBox, Success!
}
As title says.
Am i doing something horribly wrong?

The RegNotifyChangeKeyValue function parameters section states:
The key must have been opened with the KEY_NOTIFY access right. For more information, see Registry Key Security and Access Rights.
But i'm too dumb to figure it out :I

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by swagfag » 04 Aug 2022, 19:00

Advapi32.dll would probably have to be LoadLibraryied in prior to calling functions returning pointers to resources(ie the key, in this case), otherwise DllCall would automatically release the DLL and invalidate the pointers between calls

0x00000004L is not a valid AHK hexadecimal

The RegNotifyChangeKeyValue function parameters section also states:
[in, optional] hEvent

A handle to an event. If the fAsynchronous parameter is TRUE, the function returns immediately and changes are reported by signaling this event. If fAsynchronous is FALSE, hEvent is ignored.
to which uve decided for whatever reason to pass a pointer to an ahk function instead of what was asked of u - a handle to an Event. additionally, ure passing false to fAsynchronous, so even if u had structured the DllCall correctly, the call would have been a blocking one(until a regchange occurred) instead of signalling the event

User avatar
MiM
Posts: 61
Joined: 20 Apr 2021, 04:31

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MiM » 04 Aug 2022, 19:33

swagfag wrote:
04 Aug 2022, 19:00
Advapi32.dll would probably have to be LoadLibraryied in prior to calling functions returning pointers to resources(ie the key, in this case), otherwise DllCall would automatically release the DLL and invalidate the pointers between calls
So add

Code: Select all

hModule := DllCall("LoadLibrary", "Str", "C:\Windows\System32\Advapi32.dll" , "Ptr")
before the dllcalls?
swagfag wrote:
04 Aug 2022, 19:00
0x00000004L is not a valid AHK hexadecimal
Welp i used REG_NOTIFY_CHANGE_LAST_SET idk what to do about that.
swagfag wrote:
04 Aug 2022, 19:00
uve decided for whatever reason to pass a pointer to an ahk function instead of what was asked of u - a handle to an Event.
Yeah i just put whatever there, i was gonna read the Event docs but before that i got stuck on the "Access is denied." part c.c
swagfag wrote:
04 Aug 2022, 19:00
additionally, ure passing false to fAsynchronous, so even if u had structured the DllCall correctly, the call would have been a blocking one(until a regchange occurred) instead of signalling the event
Uhm.. here i'm lost because 0x00000004L is
Notify the caller of changes to a value of the key. This can include adding or deleting a value, or changing an existing value.
which is what i want (Run Test() function when reg key is modified)

MrDoge
Posts: 168
Joined: 27 Apr 2020, 21:29

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MrDoge » 04 Aug 2022, 19:45

0x00000004L is not a valid AHK hexadecimal, 0x00000004L is a valid C++ hexadecimal
idek what the L does in this case, just remove it

Code: Select all

MsgBox % 0x00000004L ;this IS a syntax error, it's supposed to throw an error but AHKv1 does nothing
MsgBox % 0x00000004

MrDoge
Posts: 168
Joined: 27 Apr 2020, 21:29

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MrDoge » 04 Aug 2022, 20:47

unfortunately, this is v2

Code: Select all

#SingleInstance force
ListLines 0
KeyHistory 0
SendMode "Input" ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir A_ScriptDir ; Ensures a consistent starting directory.

hresult:=DllCall("RegOpenKeyEx"
    ; ,"Ptr",0x80000000 ;HKEY_CLASSES_ROOT
    ,"Ptr",0x80000002 ;HKEY_LOCAL_MACHINE
    ,"Ptr",0
    ; ,"Str","TestingNotify"
    ,"Uint",0
    ; ,"Uint",0x20019 ;KEY_READ
    ,"Uint",0x0010 ;KEY_NOTIFY
    ,"Ptr*",&phkResult:=0
)
; MsgBox hresult
; MsgBox phkResult
Test() {
    MsgBox "Notified!!!"
}
stopNotify:=NotifyHKey(phkResult, Test)

NotifyHKey(hKey, callback) {

    hEvent:=DllCall("CreateEvent"
        ,"Ptr",0
        ,"Int",true
        ,"Int",false
        ,"Ptr",0
    )

    hresult:=DllCall("RegNotifyChangeKeyValue"
        ,"Ptr",hKey
        ,"Int",true ;bWatchSubtree
        ,"Uint",0x00000004 ;REG_NOTIFY_CHANGE_LAST_SET
        ,"Ptr",hEvent
        ,"Int",true
    )
    ; MsgBox hresult

    SetTimer(_Tick, 100) ;inspired by WatchFolder()
    _Tick() {
        ret:=DllCall("WaitForSingleObject"
            ,"Ptr",hEvent
            ,"Uint",0 ;dwMilliseconds
        )
        if (ret==0) {
            ; Remarks: This function detects a single change. After the caller receives a notification event, it should call the function again to receive the next notification.
            hresult:=DllCall("RegNotifyChangeKeyValue"
                ,"Ptr",hKey
                ,"Int",true ;bWatchSubtree
                ,"Uint",0x00000004 ;REG_NOTIFY_CHANGE_LAST_SET
                ,"Ptr",hEvent
                ,"Int",true
            )
            callback()
        }
    }

    return stopNotify
    stopNotify() {
        DllCall("CloseHandle", "Ptr", hEvent)
        SetTimer(_Tick, 0)
    }
}

;just to show that it's "async"
; Loop {
    ; if (Mod(A_Index, 3) == 0) {
        ; ToolTip A_Index
        ; if (A_Index == 99) {
            ; stopNotify()
        ; }
    ; }
    ; Sleep 100
; }

return

f3::Exitapp

User avatar
MiM
Posts: 61
Joined: 20 Apr 2021, 04:31

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MiM » 05 Aug 2022, 04:13

MrDoge wrote:
04 Aug 2022, 20:47
unfortunately, this is v2

Code: Select all

#SingleInstance force
ListLines 0
KeyHistory 0
SendMode "Input" ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir A_ScriptDir ; Ensures a consistent starting directory.

hresult:=DllCall("RegOpenKeyEx"
    ; ,"Ptr",0x80000000 ;HKEY_CLASSES_ROOT
    ,"Ptr",0x80000002 ;HKEY_LOCAL_MACHINE
    ,"Ptr",0
    ; ,"Str","TestingNotify"
    ,"Uint",0
    ; ,"Uint",0x20019 ;KEY_READ
    ,"Uint",0x0010 ;KEY_NOTIFY
    ,"Ptr*",&phkResult:=0
)
; MsgBox hresult
; MsgBox phkResult
Test() {
    MsgBox "Notified!!!"
}
stopNotify:=NotifyHKey(phkResult, Test)

NotifyHKey(hKey, callback) {

    hEvent:=DllCall("CreateEvent"
        ,"Ptr",0
        ,"Int",true
        ,"Int",false
        ,"Ptr",0
    )

    hresult:=DllCall("RegNotifyChangeKeyValue"
        ,"Ptr",hKey
        ,"Int",true ;bWatchSubtree
        ,"Uint",0x00000004 ;REG_NOTIFY_CHANGE_LAST_SET
        ,"Ptr",hEvent
        ,"Int",true
    )
    ; MsgBox hresult

    SetTimer(_Tick, 100) ;inspired by WatchFolder()
    _Tick() {
        ret:=DllCall("WaitForSingleObject"
            ,"Ptr",hEvent
            ,"Uint",0 ;dwMilliseconds
        )
        if (ret==0) {
            ; Remarks: This function detects a single change. After the caller receives a notification event, it should call the function again to receive the next notification.
            hresult:=DllCall("RegNotifyChangeKeyValue"
                ,"Ptr",hKey
                ,"Int",true ;bWatchSubtree
                ,"Uint",0x00000004 ;REG_NOTIFY_CHANGE_LAST_SET
                ,"Ptr",hEvent
                ,"Int",true
            )
            callback()
        }
    }

    return stopNotify
    stopNotify() {
        DllCall("CloseHandle", "Ptr", hEvent)
        SetTimer(_Tick, 0)
    }
}

;just to show that it's "async"
; Loop {
    ; if (Mod(A_Index, 3) == 0) {
        ; ToolTip A_Index
        ; if (A_Index == 99) {
            ; stopNotify()
        ; }
    ; }
    ; Sleep 100
; }

return

f3::Exitapp
The whole point is to use RegNotifyChangeKeyValue instead of a settimer but anyways, your thing doesn't solve the "Access is denied." issue.
(also, i don't use v2 so it's useless to me, thanks for the effort though!)

teadrinker
Posts: 4412
Joined: 29 Mar 2015, 09:41
Contact:

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by teadrinker » 05 Aug 2022, 06:36

Try this:

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
   }
}

User avatar
MiM
Posts: 61
Joined: 20 Apr 2021, 04:31

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MiM » 05 Aug 2022, 06:52

teadrinker wrote:
05 Aug 2022, 06:36
Try this:

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
   }
}
It just loops msgbox "Success!" infinitely.
Though RegNotifyChangeKeyValue doesn't report "Access is denied." so i guess it's progress.
Unfortunate that it's in a class, i hate classes but i'll try my best to deconstruct it into functions and maybe i'll figure it out >.< thanks!

teadrinker
Posts: 4412
Joined: 29 Mar 2015, 09:41
Contact:

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by teadrinker » 05 Aug 2022, 06:57

MiM wrote: It just loops msgbox "Success!" infinitely.
This means that some application writes values in this thread.
i hate classes but i'll try my best to deconstruct it into functions and maybe i'll figure it out
Really strange idea. I'd suggest just to understand how the classes work. :)

MrDoge
Posts: 168
Joined: 27 Apr 2020, 21:29

Re: (winapi) RegNotifyChangeKeyValue Access is denied.

Post by MrDoge » 05 Aug 2022, 13:24

MiM wrote:
05 Aug 2022, 04:13
The whole point is to use RegNotifyChangeKeyValue instead of a settimer
you must understand that it will block your script if you use RegNotifyChangeKeyValue, until a ChangeKeyValue has occurred : no other code will run
if the sole purpose of your script is to watch that, then it's perfect
MiM wrote:
05 Aug 2022, 04:13
your thing doesn't solve the "Access is denied." issue.
add a RunAsTask() by SKAN at the start of script
MiM wrote:
05 Aug 2022, 04:13
i don't use v2 so it's useless to me
you wouldn't have had the error 0x80000002L gone unnoticed if you were using v2
you can turn classes into functions, so you can translate v2 into v1, the v2 is not useless to you if it works


here's a v1:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance force
ListLines Off
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines -1
#KeyHistory 0

RunAsTask()

hresult:=DllCall("RegOpenKeyEx"
    ; ,"Ptr",0x80000000 ;HKEY_CLASSES_ROOT
    ,"Ptr",0x80000001 ;HKEY_CURRENT_USER
    ; ,"Ptr",0x80000002 ;HKEY_LOCAL_MACHINE
    ; ,"Ptr",0 ;lpSubKey
    ,"Str","SOFTWARE\Classes\TestingNotify" ;lpSubKey
    ,"Uint",0
    ; ,"Uint",0x20019 ;KEY_READ
    ,"Uint",0x0010 ;KEY_NOTIFY
    ,"Ptr*",hKey)
; MsgBox % hKey
loop {
    hresult:=DllCall("RegNotifyChangeKeyValue"
        ,"Ptr",hKey
        ,"Int",false ;bWatchSubtree
        ,"Uint",0x00000004 ;REG_NOTIFY_CHANGE_LAST_SET
        ,"Ptr",0
        ,"Int",false)

    ;no need for a callback, as it's not "async"
    MsgBox % "Notified!!!"
}

return

f3::Exitapp

RunAsTask() { ; By SKAN, http://goo.gl/yG6A1F, CD:19/Aug/2014 | MD:24/Apr/2020
    ; edited by Mr. Doge
    TaskSchd := ComObjCreate("Schedule.Service"), TaskSchd.Connect()
    , TaskRoot := TaskSchd.GetFolder("\")

    CmdLine := (A_IsCompiled ? "" : """" A_AhkPath """ ") """" A_ScriptFullpath """"

    CRC32_checksum:=DllCall("NTDLL\RtlComputeCrc32", "Int", 0, "WStr", CmdLine, "UInt", StrLen(CmdLine) * 2, "UInt")
    TaskName := "[RunAsTask] " A_ScriptName " @" SubStr("000000000" CRC32_checksum, -9)

    TaskExists := true
    try {
        RunAsTask_Obj := TaskRoot.GetTask(TaskName)
    } catch {
        TaskExists := false
    }

    if (A_IsAdmin) {
        if (TaskExists) {
            return
        } else {
            XML := "<?xml version=""1.0"" ?><Task xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task""><RegistrationInfo /><Triggers /><Principals><Principal id=""Author""><LogonType>InteractiveToken</LogonType><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><MultipleInstancesPolicy>Parallel</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate><StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable><IdleSettings><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleSettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><RunOnlyIfIdle>false</RunOnlyIfIdle><DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession><UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine><WakeToRun>false</WakeToRun><ExecutionTimeLimit>PT0S</ExecutionTimeLimit></Settings><Actions Context=""Author""><Exec><Command>""" (A_IsCompiled ? A_ScriptFullpath : A_AhkPath) """</Command><Arguments>" (!A_IsCompiled ? """" A_ScriptFullpath """" : "") "</Arguments><WorkingDirectory>" A_ScriptDir "</WorkingDirectory></Exec></Actions></Task>"
            TaskRoot.RegisterTask(TaskName, XML, 2, "", "", 3) ; TASK_CREATE=2, TASK_LOGON_INTERACTIVE_TOKEN=3
            return
        }
    } else {
        if (TaskExists) {
            RunAsTask_Obj.Run("")
        } else {
            ;ask to be admin
            Run % "*RunAs " CmdLine, % A_ScriptDir
        }
        ExitApp
    }
}

Post Reply

Return to “Ask for Help (v1)”