I've been looking to control the volume of different applications on my PC using AHK. From some searching, I came across the following threads:
1. Control the Volume of each program; thanks to @Flipeador and @Bunker D for their input on this thread.
2. Control the volume of the current program; thanks to @mikeyww for his contribution on this thread.
Using these two as a guide, I created my own script. What it does -
1. F1 = Mutes all applications.
2. F2 = Sets all applications to 25% of the master volume.
3. F3 = Sets all applications to 50% of the master volume.
4. F4 = Prompts the user if they wish to set all applications to 100% of the master volume.
5. F5 = Increases the volume of the current application in steps of 10% of the master volume until 90% of the volume, and then mutes. This is a continuous cycle, pressing F5 steps through each stage.
I'd like to neaten up my code, specifically if I can completely remove FindAppVolume(appName), as this is just a copy of @Bunker D's ShiftAppVolume( appName, incr ) code, just without changing the volume. The only reason I copied it was that I didn't understand exactly how to extract PrevVolume without increasing the volume as well. Any pointers / descriptions / understanding / explanations would be greatly appreciated. Thanks!
Code: Select all
#NoEnv
#SingleInstance Force
SetBatchLines -1
ProcessPID := "" ;The ID of the current program
;Cycling through all the active processes, see here - https://www.autohotkey.com/boards/viewtopic.php?p=180272#p180272
;Changing the volumes of programs - https://www.autohotkey.com/boards/viewtopic.php?p=210533&sid=7424e9efc9c2600470b2492266161dbb#p210533
OUT_LIST := "" ;The variable for storing the list of open processes.
COUNT_NO_PATHS := 0 ;The count of open processes.
;AccessRights_EnableSeDebug() ;Commented out this as works without.
;Enables the SE_DEBUG_PRIVILEGE for the current process. Maybe it can be useful to resolve some "access denied" stuff when dealing with processes.
;https://www.autohotkey.com/boards/viewtopic.php?t=2039
;Clipboard := OUT_LIST ;used for placing all process IDs into the clipboard so it can sent to an application.
;This is to reset any tool tip
RemoveToolTip: ;;Tooltip reset
ToolTip
;---------------------------------------------
F12::
run, C:\Windows\System32\SndVol.exe ;Show the volume mixer
Return
F1::
SetAllVolume(0)
msg:= "All applications muted."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
Return
F2::
SetAllVolume(25)
msg:= "All applications set to 25% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
Return
F3::
SetAllVolume(50)
msg:= "All applications set to 50% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
Return
F4::
SetAllVolume_100()
msg:= "All applications set to 100% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
Return
F5::
;Cycle through the volume levels for the active program.
VolumeCycle(VolCycleLevel)
Return
;---------------------------------------
;=======================================
SetAllVolume(VolValue)
{
for i, v in WTSEnumerateProcessesEx()
{
SetAppVolume(v.ProsessID, VolValue)
;FullEXEPath := GetModuleFileNameEx( v.ProsessID )
;OUT_LIST := OUT_LIST . "Name: " . v.ProcessName . "`nPath: " . FullEXEPath . "`nLegal: " . FileGetInfo( FullEXEPath ).LegalCopyright . "`n`n"
}
}
Return
SetAllVolume_100()
{
MsgBox, 4,, WARNING! `r`rThis will set ALL volume to 100. Would you like to continue? (press Yes or No)
IfMsgBox Yes
for i, v in WTSEnumerateProcessesEx()
{
FullEXEPath := GetModuleFileNameEx( v.ProsessID )
SetAppVolume(v.ProsessID, 100)
;OUT_LIST := OUT_LIST . "Name: " . v.ProcessName . "`nPath: " . FullEXEPath . "`nLegal: " . FileGetInfo( FullEXEPath ).LegalCopyright . "`n`n"
}
}
Return
VolumeCycle(VolCycleLevel)
{
;First, find the active program (name and PID).
DetectHiddenWindows on
WinGet, PID, PID, A
IfWinExist ahk_pid %PID%
{
WinGet, ProcessEXE, ProcessName
WinGet, ProcessPID, PID
}
;msgbox % "PID is: " ProcessPID "`rEXE is: " ProcessEXE
;Find the volume level of the current program.
CurrentVolLevel := FindAppVolume(ProcessEXE)
;msgbox % "Current Volume level of " ProcessEXE " is: " CurrentVolLevel " of the Master volume level"
Switch
{
case CurrentVolLevel == 0: ;Change from mute to 10%.
SetAppVolume(ProcessPID, 10)
msg:= ProcessEXE . " set to 10% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.1: ;Change from 10% to 20%.
SetAppVolume(ProcessPID, 20)
msg:= ProcessEXE . " set to 20% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.2: ;Change from 20% to 30%.
SetAppVolume(ProcessPID, 30)
msg:= ProcessEXE . " set to 30% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.3: ;Change from 30% to 40%.
SetAppVolume(ProcessPID, 40)
msg:= ProcessEXE . " set to 40% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.4: ;Change from 40% to 50%.
SetAppVolume(ProcessPID, 50)
msg:= ProcessEXE . " set to 50% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.5: ;Change from 50% to 60%.
SetAppVolume(ProcessPID, 60)
msg:= ProcessEXE . " set to 60% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.6: ;Change from 60% to 70%.
SetAppVolume(ProcessPID, 70)
msg:= ProcessEXE . " set to 70% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.7: ;Change from 70% to 80%.
SetAppVolume(ProcessPID, 80)
msg:= ProcessEXE . " set to 80% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.8: ;Change from 80% to 90%.
SetAppVolume(ProcessPID, 90)
msg:= ProcessEXE . " set to 90% of master volume."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
case CurrentVolLevel <= 0.9: ;Change from 90% to mute.
SetAppVolume(ProcessPID, 0)
msg:= ProcessEXE . " muted."
ToolTip, %msg%
SetTimer, RemoveToolTip, -700
msg := ""
}
}
Return
; ==============================================================
; WTSEnumerateProcessesEx() By JNIZM - https://autohotkey.com/boards/viewtopic.php?t=19323
;==============================================================
Return
WTSEnumerateProcessesEx()
{
static hWTSAPI := DllCall("LoadLibrary", "str", "wtsapi32.dll", "ptr")
if !(DllCall("wtsapi32\WTSEnumerateProcessesEx", "ptr", 0, "uint*", 0, "uint", -2, "ptr*", buf, "uint*", TTL))
throw Exception("WTSEnumerateProcessesEx failed", -1)
addr := buf
WTS_PROCESS_INFO := []
loop % TTL
{
WTS_PROCESS_INFO[A_Index, "SessionID"] := NumGet(addr+0, "uint")
WTS_PROCESS_INFO[A_Index, "ProsessID"] := NumGet(addr+4, "uint")
WTS_PROCESS_INFO[A_Index, "ProcessName"] := StrGet(NumGet(addr+8, "ptr"))
WTS_PROCESS_INFO[A_Index, "UserSID"] := NumGet(addr+8+A_PtrSize, "ptr")
addr += 8 + (A_PtrSize * 2)
}
if !(DllCall("wtsapi32\WTSFreeMemoryEx", "int", 0, "ptr", buf, "uint", TTL))
throw Exception("WTSFreeMemoryEx failed", -1)
return WTS_PROCESS_INFO
}
Return
; =================================================================================================
; GetModuleFileNameEx() By Shimanov as cited by SKAN - https://autohotkey.com/board/topic/41197-getting-a-full-executable-path-from-a-running-process/
; Modified to use GetModuleFileNameExW if A_IsUnicode - By Gio - 03-11-17
;=================================================================================================
GetModuleFileNameEx( p_pid ) ; by shimanov - www.autohotkey.com/forum/viewtopic.php?t=9000
{
if A_OSVersion in WIN_95,WIN_98,WIN_ME
{
MsgBox, This Windows version (%A_OSVersion%) is not supported.
return
}
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
if ( ErrorLevel or h_process = 0 )
return
name_size = 255
VarSetCapacity( name, name_size )
If A_IsUnicode
result := DllCall( "psapi.dll\GetModuleFileNameExW", "uint", h_process, "uint", 0, "str" , name, "uint", name_size )
Else
result := DllCall( "psapi.dll\GetModuleFileNameExA", "uint", h_process, "uint", 0, "str" , name, "uint", name_size )
DllCall( "CloseHandle", h_process )
return, name
}
SetAppVolume(pid, MasterVolume) ; WIN_V+
{
IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}")
DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+4*A_PtrSize), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 1, "UPtrP", IMMDevice, "UInt")
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr", &GUID)
DllCall(NumGet(NumGet(IMMDevice+0)+3*A_PtrSize), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 23, "UPtr", 0, "UPtrP", IAudioSessionManager2, "UInt")
ObjRelease(IMMDevice)
DllCall(NumGet(NumGet(IAudioSessionManager2+0)+5*A_PtrSize), "UPtr", IAudioSessionManager2, "UPtrP", IAudioSessionEnumerator, "UInt")
ObjRelease(IAudioSessionManager2)
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+3*A_PtrSize), "UPtr", IAudioSessionEnumerator, "UIntP", SessionCount, "UInt")
Loop % SessionCount
{
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+4*A_PtrSize), "UPtr", IAudioSessionEnumerator, "Int", A_Index-1, "UPtrP", IAudioSessionControl, "UInt")
IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}")
ObjRelease(IAudioSessionControl)
DllCall(NumGet(NumGet(IAudioSessionControl2+0)+14*A_PtrSize), "UPtr", IAudioSessionControl2, "UIntP", ProcessId, "UInt")
If (pid == ProcessId)
{
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall(NumGet(NumGet(ISimpleAudioVolume+0)+3*A_PtrSize), "UPtr", ISimpleAudioVolume, "Float", MasterVolume/100.0, "UPtr", 0, "UInt")
ObjRelease(ISimpleAudioVolume)
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
}
ShiftAppVolume( appName, incr )
{
if !appName
{
WinGet, activePID, ID, A
WinGet, activeName, ProcessName, ahk_id %activePID%
appName := activeName
}
IMMDeviceEnumerator := ComObjCreate( "{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}" )
DllCall( NumGet( NumGet( IMMDeviceEnumerator+0 ) + 4*A_PtrSize ), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 1, "UPtrP", IMMDevice, "UInt" )
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity( GUID, 16 )
DllCall( "Ole32.dll\CLSIDFromString", "Str", "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr", &GUID)
DllCall( NumGet( NumGet( IMMDevice+0 ) + 3*A_PtrSize ), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 23, "UPtr", 0, "UPtrP", IAudioSessionManager2, "UInt" )
DllCall( NumGet( NumGet( IAudioSessionManager2+0 ) + 5*A_PtrSize ), "UPtr", IAudioSessionManager2, "UPtrP", IAudioSessionEnumerator, "UInt" )
ObjRelease( IAudioSessionManager2 )
DllCall( NumGet( NumGet( IAudioSessionEnumerator+0 ) + 3*A_PtrSize ), "UPtr", IAudioSessionEnumerator, "UIntP", SessionCount, "UInt" )
levels := []
maxlevel := 0
targets := []
t := 0
ISAVs := []
Loop % SessionCount
{
DllCall( NumGet( NumGet( IAudioSessionEnumerator+0 ) + 4*A_PtrSize ), "UPtr", IAudioSessionEnumerator, "Int", A_Index-1, "UPtrP", IAudioSessionControl, "UInt" )
IAudioSessionControl2 := ComObjQuery( IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}" )
ObjRelease( IAudioSessionControl )
DllCall( NumGet( NumGet( IAudioSessionControl2+0 ) + 14*A_PtrSize ), "UPtr", IAudioSessionControl2, "UIntP", PID, "UInt" )
PHandle := DllCall( "OpenProcess", "uint", 0x0010|0x0400, "Int", false, "UInt", PID )
if !( ErrorLevel or PHandle = 0 )
{
name_size = 1023
VarSetCapacity( PName, name_size )
DllCall( "psapi.dll\GetModuleFileNameEx" . ( A_IsUnicode ? "W" : "A" ), "UInt", PHandle, "UInt", 0, "Str", PName, "UInt", name_size )
DllCall( "CloseHandle", PHandle )
SplitPath PName, PName
if incr
{
t += 1
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 4*A_PtrSize ), "UPtr", ISimpleAudioVolume, "FloatP", level, "UInt" ) ; Get volume
if ( PName = appName )
{
level += incr
targets.push( t )
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 5*A_PtrSize ), "UPtr", ISimpleAudioVolume, "Int", 0, "UPtr", 0, "UInt" ) ; Unmute
}
ISAVs.push( ISimpleAudioVolume )
levels.push( level )
maxlevel := max( maxlevel, level )
}
else
{
if ( PName = appName )
{
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 6*A_PtrSize ), "UPtr", ISimpleAudioVolume, "IntP", muted ) ; Get mute status
maxlevel := maxlevel or muted
ISAVs.push( ISimpleAudioVolume )
}
}
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
if incr
{
if ( maxlevel = 0.0 ) or ( maxlevel = 1.0 )
{
for i, t in targets
DllCall( NumGet( NumGet( ISAVs[t]+0 ) + 3*A_PtrSize ), "UPtr", ISAVs[t], "Float", levels[t], "UPtr", 0, "UInt" )
}
else
{
VarSetCapacity( GUID, 16 )
DllCall( "Ole32.dll\CLSIDFromString", "Str", "{5CDF2C82-841E-4546-9722-0CF74078229A}", "UPtr", &GUID)
DllCall( NumGet( NumGet( IMMDevice+0 ) + 3*A_PtrSize ), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 7, "UPtr", 0, "UPtrP", IEndpointVolume, "UInt" )
DllCall( NumGet( NumGet( IEndpointVolume+0 ) + 9*A_PtrSize ), "UPtr", IEndpointVolume, "FloatP", MasterLevel ) ; Get master level
DllCall( NumGet( NumGet( IEndpointVolume+0 ) + 7*A_PtrSize ), "UPtr", IEndpointVolume, "Float", MasterLevel * maxlevel, "UPtr", 0, "UInt" ) ; Set master level
ObjRelease( IEndpointVolume )
for i, ISimpleAudioVolume in ISAVs
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 3*A_PtrSize ), "UPtr", ISimpleAudioVolume, "Float", min( 1.0, levels[i] / maxlevel ) , "UPtr", 0, "UInt" ) ; Set volume
}
}
else
{
for i, ISimpleAudioVolume in ISAVs
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 5*A_PtrSize ), "UPtr", ISimpleAudioVolume, "Int", !maxlevel, "UPtr", 0, "UInt" ) ; Toggle mute status
}
ObjRelease( IMMDevice )
for i, ISimpleAudioVolume in ISAVs
ObjRelease(ISimpleAudioVolume)
}
;created by submeg 05/06/2022
;modified the code I found here by Bunker D - https://www.autohotkey.com/boards/viewtopic.php?style=19&p=433963#p433963
FindAppVolume(appName)
{
if !appName
{
WinGet, activePID, ID, A
WinGet, activeName, ProcessName, ahk_id %activePID%
appName := activeName
}
IMMDeviceEnumerator := ComObjCreate( "{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}" )
DllCall( NumGet( NumGet( IMMDeviceEnumerator+0 ) + 4*A_PtrSize ), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 1, "UPtrP", IMMDevice, "UInt" )
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity( GUID, 16 )
DllCall( "Ole32.dll\CLSIDFromString", "Str", "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr", &GUID)
DllCall( NumGet( NumGet( IMMDevice+0 ) + 3*A_PtrSize ), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 23, "UPtr", 0, "UPtrP", IAudioSessionManager2, "UInt" )
ObjRelease( IMMDevice )
DllCall( NumGet( NumGet( IAudioSessionManager2+0 ) + 5*A_PtrSize ), "UPtr", IAudioSessionManager2, "UPtrP", IAudioSessionEnumerator, "UInt" )
ObjRelease( IAudioSessionManager2 )
DllCall( NumGet( NumGet( IAudioSessionEnumerator+0 ) + 3*A_PtrSize ), "UPtr", IAudioSessionEnumerator, "UIntP", SessionCount, "UInt" )
Loop % SessionCount
{
DllCall( NumGet( NumGet( IAudioSessionEnumerator+0 ) + 4*A_PtrSize ), "UPtr", IAudioSessionEnumerator, "Int", A_Index-1, "UPtrP", IAudioSessionControl, "UInt" )
IAudioSessionControl2 := ComObjQuery( IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}" )
ObjRelease( IAudioSessionControl )
DllCall( NumGet( NumGet( IAudioSessionControl2+0 ) + 14*A_PtrSize ), "UPtr", IAudioSessionControl2, "UIntP", PID, "UInt" )
PHandle := DllCall( "OpenProcess", "uint", 0x0010|0x0400, "Int", false, "UInt", PID )
if !( ErrorLevel or PHandle = 0 )
{
name_size = 1023
VarSetCapacity( PName, name_size )
DllCall( "psapi.dll\GetModuleFileNameEx" . ( A_IsUnicode ? "W" : "A" ), "uint", PHandle, "uint", 0, "str", PName, "uint", name_size )
DllCall( "CloseHandle", PHandle )
SplitPath PName, PName
if ( PName = appName )
{
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall( NumGet( NumGet( ISimpleAudioVolume+0 ) + 4*A_PtrSize ), "UPtr", ISimpleAudioVolume, "FloatP", PrevVolume, "UInt" )
ObjRelease(ISimpleAudioVolume)
}
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
Return PrevVolume
}
;Scripts called above that are currently commented out.
/*
;=================================================================================================
; AccessRights_EnableSeDebug() By Cyruz - https://autohotkey.com/boards/viewtopic.php?t=2039
;=================================================================================================
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: AccessRights_EnableSeDebug
; Description ..: Enable the SE_DEBUG_PRIVILEGE on the current script instance.
; AHK Version ..: AHK_L x32/64 Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: Feb. 5, 2014 - v0.1 - First version.
; ----------------------------------------------------------------------------------------------------------------------
AccessRights_EnableSeDebug() {
hProc := DllCall( "OpenProcess", UInt,0x0400, Int,0, UInt,DllCall("GetCurrentProcessId"), "Ptr" )
DllCall( "Advapi32.dll\OpenProcessToken", Ptr,hProc, UInt,0x0020|0x0008, PtrP,hToken )
VarSetCapacity(LUID, 8, 0)
DllCall( "Advapi32.dll\LookupPrivilegeValue", Ptr,0, Str,"SeDebugPrivilege", Ptr,&LUID )
VarSetCapacity( TOKPRIV, 16, 0 ) ; TOKEN_PRIVILEGES structure: http://goo.gl/AGXeAp.
NumPut( 1, &TOKPRIV, 0, "UInt" ) ; TOKEN_PRIVILEGES > PrivilegeCount.
NumPut( NumGet( &LUID, 0, "UInt" ), &TOKPRIV, 4, "UInt" ) ; TOKEN_PRIVILEGES > LUID_AND_ATTRIBUTES > LUID > LoPart.
NumPut( NumGet( &LUID, 4, "UInt" ), &TOKPRIV, 8, "UInt" ) ; TOKEN_PRIVILEGES > LUID_AND_ATTRIBUTES > LUID > HiPart.
NumPut( 2, &TOKPRIV, 12, "UInt" ) ; TOKEN_PRIVILEGES > LUID_AND_ATTRIBUTES > Attributes.
; SE_PRIVILEGE_ENABLED = 2.
DllCall( "Advapi32.dll\AdjustTokenPrivileges", Ptr,hToken, Int,0, Ptr,&TOKPRIV, UInt,0, Ptr,0, Ptr,0 )
DllCall( "CloseHandle", Ptr,hToken )
DllCall( "CloseHandle", Ptr,hProc )
}
; ==================================================
; FileGetInfo() By Lexikos - https://autohotkey.com/boards/viewtopic.php?t=4282
;===================================================
FileGetInfo( lptstrFilename) {
List := "Comments InternalName ProductName CompanyName LegalCopyright ProductVersion"
. " FileDescription LegalTrademarks PrivateBuild FileVersion OriginalFilename SpecialBuild"
dwLen := DllCall("Version.dll\GetFileVersionInfoSize", "Str", lptstrFilename, "Ptr", 0)
dwLen := VarSetCapacity( lpData, dwLen + A_PtrSize)
DllCall("Version.dll\GetFileVersionInfo", "Str", lptstrFilename, "UInt", 0, "UInt", dwLen, "Ptr", &lpData)
DllCall("Version.dll\VerQueryValue", "Ptr", &lpData, "Str", "\VarFileInfo\Translation", "PtrP", lplpBuffer, "PtrP", puLen )
sLangCP := Format("{:04X}{:04X}", NumGet(lplpBuffer+0, "UShort"), NumGet(lplpBuffer+2, "UShort"))
i := {}
Loop, Parse, % List, %A_Space%
DllCall("Version.dll\VerQueryValue", "Ptr", &lpData, "Str", "\StringFileInfo\" sLangCp "\" A_LoopField, "PtrP", lplpBuffer, "PtrP", puLen )
? i[A_LoopField] := StrGet(lplpBuffer, puLen) : ""
return i
}
Return
*/