As the last little hack session of the year I wanted to build a AutoHotkey function to resolve all occurences of environment variables within an input string.
Normally, this would be pretty straight forward. Use WScript.Shell and call the ExpandEnvironmentStrings function with the input string.
Given that VBScript – and to my understanding WSH – are being deprecated by Microsoft, this solution would run on borrowed time.
Therefore the somewhat more clunky but more “future-proof” method is to rely on locating the %-characters and trying to parse the contents inbetween as environment variables.
We need to be wary of regular %-characters within the string to prevent accidental destruction of string values or false-positives.
So a pure AutoHotkey implementation could look like this:
; Input string
str := "This is 100% true! -- C:\Users\%USERNAME%\test -- %LOCALAPPDATA% -- %"
; Marks the last position of a %-character
lastPos := 0
Loop
{
; Find the next environment variable in the string
pos1 := InStr(str, "%", false, lastPos + 1)
if !pos1
break
pos2 := InStr(str, "%", false, pos1 + 1)
if !pos2
break
; Extract the environment variable name
envVar := SubStr(str, pos1 + 1, pos2 - pos1 - 1)
; Try to get the value of the environment variable
envValue := EnvGet(envVar)
; If the environment variable exists, replace it in the string
if envValue
str := SubStr(str, 1, pos1 - 1) . envValue . SubStr(str, pos2 + 1)
; Set the last position to the end of the replaced string
lastPos := pos1
}
; Show the result
MsgBox(str)
This is, however, not the best way to do it. Since Kernel32.dll is loaded automatically in AutoHotkey anyway, using the ExpandEnvironmentStringsW function seems like a much better option:
; Input string
str := "This is 100% true! -- C:\Users\%USERNAME%\test -- %LOCALAPPDATA% -- %"
; Allocate buffer for the expanded string
VarSetStrCapacity(&str2, 1024)
; Call ExpandEnvironmentStringsW to expand environment variables
DllCall("ExpandEnvironmentStringsW", "wstr", str, "wstr", &str2, "uint", 1024)
; Show the result
MsgBox(str2)
Why reinvent the wheel when the platform developer already provides a function for it?