Jump to content

Recommended Posts

Posted (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:

#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 by TimRude
Posted (edited)
#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
 

#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 by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted (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 by TimRude

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...