TimRude Posted Saturday at 08:01 PM Posted Saturday at 08:01 PM (edited) I was looking for a simple function to quickly tell me whether the master volume is muted or not. Most of what I found was old stuff that no longer applies to current versions of Windows. Nothing I found was simple. So this is what I wrote: expandcollapse popup#include <WinAPIProc.au3> ; needed for _WinAPI_EnumProcessWindows function Switch IsMuted() Case 0 MsgBox(0, "Master Volume", "Not Muted") Case 1 MsgBox(0, "Master Volume", "Muted") Case Else MsgBox(0, "Master Volume", "Unable to determine Muted Status") EndSwitch Func IsMuted() ; Returns 1 if master volume is muted. ; Returns 0 if master volume is not muted. ; In case of a problem, will return -1 and will set @error to -1 also. Local Const $eUnmute = "unmute" ; magic word to look for in text of Volume Mixer window to determine if muted or not ; this word may be different in non-English Windows installs Local $iPID ; PID of SndVol.exe process Local $bCloseProcWhenDone ; First check to see if SndVol.exe is already running. ; If so, use it. If not start a hidden instance of SndVol.exe. $iPID = ProcessExists("SndVol.exe") If $iPID = 0 Then ; No existing process, need to run SndVol.exe. $iPID = Run(@SystemDir & "\SndVol.exe", "", @SW_HIDE) $bCloseProcWhenDone = True Else $bCloseProcWhenDone = False EndIf ; Target window of process will have no Title but will have Class of #32770. ; Text of target window will include the magic word ('unmute' in English) only if mute is on. ; Need to be able to see text on a hidden window Local $iPriorOpt = Opt("WinDetectHiddenText", 1) Local $iTries = 1 ; rather than arbitrary pauses to give window time to exist, will try up to 5 times with a small pause between each Local $hWnd = 0 ; will be handle of target window Local $sText = "" ; will be text of target window Do Local $aWin = _WinAPI_EnumProcessWindows($iPID, False) If IsArray($aWin) Then For $w = 1 To $aWin[0][0] If $aWin[$w][1] = "#32770" Then $hWnd = $aWin[$w][0] $sText = WinGetText($hWnd) Opt("WinDetectHiddenText", $iPriorOpt) ; reset back to original setting ; uncomment for debugging ;~ ConsoleWrite("ProcID: " & $iPID & @CRLF) ;~ ConsoleWrite("Tries: " & $iTries & @CRLF) ;~ ConsoleWrite("hWnd: " & $hWnd & @CRLF) ;~ ConsoleWrite("Class: " & $aWin[$w][1] & @CRLF) ;~ ConsoleWrite("Title: " & WinGetTitle($hWnd) & @CRLF) ;~ ConsoleWrite("Text: " & StringReplace($sText, @LF, "|") & @CRLF) If $bCloseProcWhenDone Then ProcessClose($iPID) If StringInStr($sText, $eUnmute, 2) <> 0 Then Return 1 ; mute is on Else Return 0 ; mute is off EndIf EndIf Next EndIf $iTries += 1 If $iTries <= 5 Then Sleep(20) Until $iTries > 5 ; Unable to determine the Mute status - give up and report failure. Opt("WinDetectHiddenText", $iPriorOpt) ; reset back to original setting If $iPID <> 0 And $bCloseProcWhenDone Then ProcessClose($iPID) Return SetError(-1, 0, -1) EndFunc ;==>IsMuted This doesn't check to see if your specific app is muted. It just checks the master volume setting. And this doesn't let you change the status of that master volume mute setting. But to do that, it's common knowledge to toggle the mute setting by just doing this: Send("{VOLUME_MUTE}") Hopefully someone may find this useful. Edited Saturday at 08:17 PM by TimRude
argumentum Posted Saturday at 10:14 PM Posted Saturday at 10:14 PM (edited) expandcollapse popup#include <MsgBoxConstants.au3> ; Returns 1 if muted, 0 if not muted, and sets @error on failure (-1 returned) Func IsMasterVolumeMuted() Local Const $CLSCTX_ALL = 0x17 Local Const $eRender = 0 Local Const $eConsole = 0 ; COM GUIDs Local Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}" Local Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}" Local Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}" Local Const $sIID_IAudioEndpointVolume = "{5CDF2C82-841E-4546-9722-0CF74078229A}" ; COM Interface Method Tags Local Const $sTag_IMMDeviceEnumerator = "EnumAudioEndpoints hresult(int;dword;ptr*);" & _ "GetDefaultAudioEndpoint hresult(int;int;ptr*);" Local Const $sTag_IMMDevice = "Activate hresult(struct*;dword;ptr;ptr*);" Local Const $sTag_IAudioEndpointVolume = "RegisterControlChangeNotify hresult(ptr);" & _ "UnregisterControlChangeNotify hresult(ptr);" & _ "GetChannelCount hresult(uint*);" & _ "SetMasterVolumeLevel hresult(float;ptr);" & _ "SetMasterVolumeLevelScalar hresult(float;ptr);" & _ "GetMasterVolumeLevel hresult(float*);" & _ "GetMasterVolumeLevelScalar hresult(float*);" & _ "SetChannelVolumeLevel hresult(uint;float;ptr);" & _ "SetChannelVolumeLevelScalar hresult(uint;float;ptr);" & _ "GetChannelVolumeLevel hresult(uint;float*);" & _ "GetChannelVolumeLevelScalar hresult(uint;float*);" & _ "SetMute hresult(bool;ptr);" & _ "GetMute hresult(bool*);" ; MMDeviceEnumerator COM object Local $oEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $sTag_IMMDeviceEnumerator) If @error Or Not IsObj($oEnumerator) Then Return SetError(1, 0, -1) ; Get Default Audio Endpoint Pointer Local $pDevice = 0 Local $hResult = $oEnumerator.GetDefaultAudioEndpoint($eRender, $eConsole, $pDevice) If $hResult <> 0 Or Not $pDevice Then Return SetError(2, 0, -1) ; Wrap IMMDevice interface pointer Local $oDevice = ObjCreateInterface($pDevice, $sIID_IMMDevice, $sTag_IMMDevice) If @error Or Not IsObj($oDevice) Then Return SetError(3, 0, -1) ; IAudioEndpointVolume IID string to binary struct for Activate Local $tIID_EndpointVol = DllStructCreate("byte[16]") DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $sIID_IAudioEndpointVolume, "struct*", $tIID_EndpointVol) ; Activate IAudioEndpointVolume interface Local $pEndpointVolume = 0 $hResult = $oDevice.Activate($tIID_EndpointVol, $CLSCTX_ALL, 0, $pEndpointVolume) If $hResult <> 0 Or Not $pEndpointVolume Then Return SetError(4, 0, -1) ; Wrap IAudioEndpointVolume interface pointer Local $oEndpointVolume = ObjCreateInterface($pEndpointVolume, $sIID_IAudioEndpointVolume, $sTag_IAudioEndpointVolume) If @error Or Not IsObj($oEndpointVolume) Then Return SetError(5, 0, -1) ; Query Mute state Local $bMuted = False $hResult = $oEndpointVolume.GetMute($bMuted) If $hResult <> 0 Then Return SetError(6, 0, -1) Return ($bMuted ? 1 : 0) EndFunc ;==>IsMasterVolumeMuted Local $iMuted = IsMasterVolumeMuted() If @error Then MsgBox($MB_SYSTEMMODAL, "Error", "Failed to query volume status. Code: " & @error) Else MsgBox($MB_SYSTEMMODAL, "Master Volume Status", ($iMuted ? "MUTED" : "NOT MUTED")) EndIf try this one Edit: This will help too expandcollapse popup#include <MsgBoxConstants.au3> ; Returns master volume as a percentage (0 to 100), and sets @error on failure Func GetMasterVolumeLevel() Local Const $CLSCTX_ALL = 0x17, $eRender = 0, $eConsole = 0 Local Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}" Local Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}" Local Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}" Local Const $sIID_IAudioEndpointVolume = "{5CDF2C82-841E-4546-9722-0CF74078229A}" Local Const $sTag_IMMDeviceEnumerator = "EnumAudioEndpoints hresult(int;dword;ptr*);" & _ "GetDefaultAudioEndpoint hresult(int;int;ptr*);" Local Const $sTag_IMMDevice = "Activate hresult(struct*;dword;ptr;ptr*);" Local Const $sTag_IAudioEndpointVolume = "RegisterControlChangeNotify hresult(ptr);" & _ "UnregisterControlChangeNotify hresult(ptr);" & _ "GetChannelCount hresult(uint*);" & _ "SetMasterVolumeLevel hresult(float;ptr);" & _ "SetMasterVolumeLevelScalar hresult(float;ptr);" & _ "GetMasterVolumeLevel hresult(float*);" & _ "GetMasterVolumeLevelScalar hresult(float*);" & _ "SetChannelVolumeLevel hresult(uint;float;ptr);" & _ "SetChannelVolumeLevelScalar hresult(uint;float;ptr);" & _ "GetChannelVolumeLevel hresult(uint;float*);" & _ "GetChannelVolumeLevelScalar hresult(uint;float*);" & _ "SetMute hresult(bool;ptr);" & _ "GetMute hresult(bool*);" Local $oEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $sTag_IMMDeviceEnumerator) If @error Or Not IsObj($oEnumerator) Then Return SetError(1, 0, -1) Local $pDevice = 0 If $oEnumerator.GetDefaultAudioEndpoint($eRender, $eConsole, $pDevice) <> 0 Or Not $pDevice Then Return SetError(2, 0, -1) Local $oDevice = ObjCreateInterface($pDevice, $sIID_IMMDevice, $sTag_IMMDevice) If @error Or Not IsObj($oDevice) Then Return SetError(3, 0, -1) Local $tIID_EndpointVol = DllStructCreate("byte[16]") DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $sIID_IAudioEndpointVolume, "struct*", $tIID_EndpointVol) Local $pEndpointVolume = 0 If $oDevice.Activate($tIID_EndpointVol, $CLSCTX_ALL, 0, $pEndpointVolume) <> 0 Or Not $pEndpointVolume Then Return SetError(4, 0, -1) Local $oEndpointVolume = ObjCreateInterface($pEndpointVolume, $sIID_IAudioEndpointVolume, $sTag_IAudioEndpointVolume) If @error Or Not IsObj($oEndpointVolume) Then Return SetError(5, 0, -1) Local $fScalar = 0.0 ; GetMasterVolumeLevelScalar returns a float value between 0.0 (0%) and 1.0 (100%) If $oEndpointVolume.GetMasterVolumeLevelScalar($fScalar) <> 0 Then Return SetError(6, 0, -1) Return Round($fScalar * 100) EndFunc Local $iVol = GetMasterVolumeLevel() If @error Then MsgBox($MB_SYSTEMMODAL, "Error", "Failed to query volume level. Code: " & @error) Else MsgBox($MB_SYSTEMMODAL, "Master Volume Level", "Current Volume: " & $iVol & "%") EndIf Edited Saturday at 10:35 PM by argumentum more TimRude and Danyfirex 1 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
TimRude Posted Saturday at 11:41 PM Author Posted Saturday at 11:41 PM (edited) I figured there were probably much more robust and complicated methods to get info about the master volume settings. And yep, sure enough there are. 😂 Quite impressive looking samples and both work well. And these are probably more future-proof and probably have no issues with non-English installations. I had started to research the IAudioEndpointVolume interface but quickly got totally lost in the weeds. Google's AI even barfed up some AutoIt code about it but of course it didn't even begin to work. For now I think I'll stick with my method for the specific app I wrote it for, since I can actually understand it and trouble-shoot if there's a problem. But I've saved these other methods to my archive for future use as little-black-box functions if necessary. Thanks! Edited Saturday at 11:42 PM by TimRude argumentum 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now