How to respond to WM_SettingChange inside an AutoHotKey script
(This question is similar to Delphi: How t开发者_高级运维o respond to WM_SettingChange/WM_WinIniChange? but for the AutoHotKey language. This is not about sending WM_SETTINGCHANGE from inside AutoHotKey.)
In another Windows process ("sender"), I change the PATH environment variable by modifying the HK_CURRENT_USER registry. Then I send/publish a WM_SETTINGCHANGE message using the SendMessageTimeout API.
My concurrently running AutoHotKey script ("receiver"), which I use as a program launcher, does not seem to be aware of the change. I want to capture this message in order to refresh the script's local copy of the PATH variable. Is it possible?
For example, the "sender" could be the System Properties dialog box, or some another AutoHotKey script:
EnvUpdate
or some other handy third-party Windows binary like nircmd:
nircmd sysrefresh environment
or some Ruby code :
### This is a -*- ruby -*- script
require 'Win32API'
module Windows::EnvByReg
def self.envupdate()
result = 0
wParam_unused = 0
timeout_ms = 5000
SendMessageTimeout.call(HWND_BROADCAST, WM_SETTINGCHANGE,
wParam_unused, 'Environment',
SMTO_ABORTIFHUNG, timeout_ms, result)
end
SendMessageTimeout = Win32API.new('user32', 'SendMessageTimeout',
'LLLPLLP', 'L')
HWND_BROADCAST = 0xffff
WM_SETTINGCHANGE = 0x001A
SMTO_ABORTIFHUNG = 2
end#module
if __FILE__ == $PROGRAM_NAME
Windows::EnvByReg.envupdate
end
Use the OnMessage function to respond to the message.
Here is a sample script.
;;; This is an AutoHotKey -*- ahk -*- script
;;;
;;; ABOUT
;;; Respond to WM_SETTINGCHANGE messages and update this process's PATH
;;; environment variable.
;;;
;;; USAGE
;;; Run the script directly (e.g. double-click) or drag and drop onto
;;; the AutoHotKey application.
;;;
;;; DEBUG
;;; Optionally define a key binding to debug_show_recv_count, e.g.:
;;; #space:: debug_show_recv_count()
;;;
;;; AUTHOR
;;; piyo @ StackOverflow
;;;
;;
;; Register an AHK function as a callback.
;;
OnMessage( (WM_SETTINGCHANGE:=0x1A), "recv_WM_SETTINGCHANGE")
;;
;; Respond to the WM_SETTINGCHANGE message.
;;
recv_WM_SETTINGCHANGE(wParam, lParam, msg, hwnd)
{
global g_recv_WM_SETTINGCHANGE_count
g_recv_WM_SETTINGCHANGE_count := g_recv_WM_SETTINGCHANGE_count + 1
;;debug;; ToolTip Received a WM_SETTINGCHANGE !
reset_env_path_from_registry()
}
;;
;; Import the recently changed Path environment variable from the
;; Windows Registry. Import from the System and User environments.
;;
reset_env_path_from_registry()
{
sys_path := ""
sys_subkey := "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
RegRead, sys_path, HKEY_LOCAL_MACHINE, %sys_subkey%, Path
cu_path := ""
cu_subkey := "Environment"
RegRead, cu_path, HKEY_CURRENT_USER, %cu_subkey%, Path
new_path := sys_path . ";" . cu_path
;;debug;; MsgBox,% new_path
EnvSet, PATH,% new_path
}
;;;
; Debug var for interactive sanity checking
g_recv_WM_SETTINGCHANGE_count := 0
; Debug function for interactive sanity checking
debug_show_recv_count() {
global g_recv_WM_SETTINGCHANGE_count
path := ""
EnvGet, path, PATH
msg := "g_recv_WM_SETTINGCHANGE := " . g_recv_WM_SETTINGCHANGE_count
msg := msg . "!`n" . path
MsgBox,% msg
}
;;; end
The user NoobSawce on the AutoHotKey forums posted this function to refresh environment variables.
My AutoHotKey.ahk script calls that function before each Run statement so that any apps launched from AutoHotKey get the current system environment, not the environment that AutoHotKey captured at the time it was launched.
For example:
+#b::
RefreshEnvironment()
run c:\cygwin\bin\run.exe c:\cygwin\bin\rxvt.exe -geometry 80x40
return
+#g::
RefreshEnvironment()
run c:\gnu\emacs\bin\runemacs.exe
return
精彩评论