6

我正在使用此代码静音/取消静音系统主音量:

const
  APPCOMMAND_VOLUME_MUTE = $80000;
  WM_APPCOMMAND = $319;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // toggle mute/unmute
  SendMessageW(Handle, WM_APPCOMMAND, Handle, APPCOMMAND_VOLUME_MUTE);
end;

(从https://stackoverflow.com/a/154128/1140885获取代码)

它在 XP 上运行良好(尚未在 Win7 上测试过)。
我需要一种方法来检查(获取)当前的“静音”状态是什么?是静音还是不静音。
有任何想法吗?


更新:对于XP,我最终使用了这里的代码:如何在 windows xp 中获取主卷?(感谢@Sertac Akyuz)

我只需要更改一行:

mxlc.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;

至:

mxlc.dwControlType := MIXERCONTROL_CONTROLTYPE_MUTE;

返回值为 0(非静音)或 1(静音)。

4

3 回答 3

13

从 Windows Vista 开始,您必须使用Core Audio SDK 来控制 Windows 音频。要检查主音量是否已静音,您必须使用该IAudioEndpointVolume.GetMute方法。

试试这个示例代码

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  ActiveX,
  ComObj;

const
  CLASS_IMMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';

type
  IAudioEndpointVolumeCallback = interface(IUnknown)
  ['{657804FA-D6AD-4496-8A60-352752AF4F89}']
  end;

  IAudioEndpointVolume = interface(IUnknown)
    ['{5CDF2C82-841E-4546-9722-0CF74078229A}']
    function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): HRESULT; stdcall;
    function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): HRESULT; stdcall;
    function GetChannelCount(out PInteger): HRESULT; stdcall;
    function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): HRESULT; stdcall;
    function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetMasterVolumeLevel(out fLevelDB: single): HRESULT; stdcall;
    function GetMasterVolumeLevelScaler(out fLevelDB: single): HRESULT; stdcall;
    function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): HRESULT; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): HRESULT; stdcall;
    function SetMute(bMute: Boolean; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetMute(out bMute: Boolean): HRESULT; stdcall;
    function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): HRESULT; stdcall;
    function VolumeStepUp(pguidEventContext: PGUID): HRESULT; stdcall;
    function VolumeStepDown(pguidEventContext: PGUID): HRESULT; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask): HRESULT; stdcall;
    function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): HRESULT; stdcall;
  end;

  IAudioMeterInformation = interface(IUnknown)
  ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
  end;

  IPropertyStore = interface(IUnknown)
  end;

  IMMDevice = interface(IUnknown)
  ['{D666063F-1587-4E43-81F1-B948E807363F}']
    function Activate(const refId: TGUID; dwClsCtx: DWORD;  pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
    function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
    function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
    function GetState(out State: Integer): HRESULT; stdcall;
  end;


  IMMDeviceCollection = interface(IUnknown)
  ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
  end;

  IMMNotificationClient = interface(IUnknown)
  ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
  end;

  IMMDeviceEnumerator = interface(IUnknown)
  ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
    function EnumAudioEndpoints(dataFlow: TOleEnum; deviceState: SYSUINT; DevCollection: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

function IsMasterVolumeMute : Boolean;
var
  pEndpointVolume: IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
  bMute: Boolean;
begin
  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
   RaiseLastOSError;
  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
   RaiseLastOSError;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
   RaiseLastOSError;

  if not Succeeded(pEndpointVolume.GetMute(bMute)) then
   RaiseLastOSError
  else
  Result:=bMute;
end;


begin
 try
    CoInitialize(nil);
    try
      Writeln(Format('Master Volume is Mute ? : %s',[BoolToStr(IsMasterVolumeMute, True)]));
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.
于 2013-05-21T19:41:02.907 回答
2

使用这个剪断,我已经测试过它并为我工作。
这将检查并设置主音量。(从http://www.swissdelphicenter.ch/torry/showcode.php?id=1630复制)
我希望这会有所帮助:

 uses
      MMSystem;

    function GetMasterMute(
      Mixer: hMixerObj;
      var Control: TMixerControl): MMResult;
      // Returns True on success
    var
      Line: TMixerLine;
      Controls: TMixerLineControls;
    begin
      ZeroMemory(@Line, SizeOf(Line));
      Line.cbStruct := SizeOf(Line);
      Line.dwComponentType := MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
      Result := mixerGetLineInfo(Mixer, @Line,
        MIXER_GETLINEINFOF_COMPONENTTYPE);
      if Result = MMSYSERR_NOERROR then
      begin
        ZeroMemory(@Controls, SizeOf(Controls));
        Controls.cbStruct := SizeOf(Controls);
        Controls.dwLineID := Line.dwLineID;
        Controls.cControls := 1;
        Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_MUTE;
        Controls.cbmxctrl := SizeOf(Control);
        Controls.pamxctrl := @Control;
        Result := mixerGetLineControls(Mixer, @Controls,
          MIXER_GETLINECONTROLSF_ONEBYTYPE);
      end;
    end;

    procedure SetMasterMuteValue(
      Mixer: hMixerObj;
      Value: Boolean);
    var
      MasterMute: TMixerControl;
      Details: TMixerControlDetails;
      BoolDetails: TMixerControlDetailsBoolean;
      Code: MMResult;
    begin
      Code := GetMasterMute(0, MasterMute);
      if Code = MMSYSERR_NOERROR then
      begin
        with Details do
        begin
          cbStruct := SizeOf(Details);
          dwControlID := MasterMute.dwControlID;
          cChannels := 1;
          cMultipleItems := 0;
          cbDetails := SizeOf(BoolDetails);
          paDetails := @BoolDetails;
        end;
        LongBool(BoolDetails.fValue) := Value;
        Code := mixerSetControlDetails(0, @Details,
    MIXER_SETCONTROLDETAILSF_VALUE);
      end;
      if Code <> MMSYSERR_NOERROR then
        raise Exception.CreateFmt('SetMasterMuteValue failure, '+
          'multimedia system error #%d', [Code]);
    end;

    // Example:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SetMasterMuteValue(0, CheckBox1.Checked); // Mixer device #0 mute on/off
    end;
于 2013-05-22T05:50:56.870 回答
1

GetMute 方法的参数应该是 BOOL 而不是布尔值。对于 SetMute 也是如此。——</p>

好吧,也就是说.. 是的,不是.. 是的 Delphi BOOL(实际上是 LongBool)可以存储 C-BOOL。不,因为它不能用于写入 C-BOOL 属性。你会得到一个 0x80070057 = "Wrong Parameter" 结果。

原因很简单,在 Delphi 中 True 的意思是“除了 0 之外的一切”并且代表 -1。然而,C-BOOL True 表示 1 且仅表示 1。

因此,使用 LongBool 不起作用,您应该使用使用 INT、LongInt、Integer 或您自己正确定义的“BOOL”的解决方法来避免“错误参数”结果。

这是一个示例(在 Delphi XE7 中工作并使用 SDK 版本 10.0.10586.15 进行了测试:

// Workaround for BOOL
type TcBOOL = (cFalse = Integer(0),
               cTrue = Integer(1));

// IAudioEndpointVolume
function SetMute(bMute: BOOL; pguidEventContext: PGUID): HRESULT; stdcall;
function GetMute(out pbMute: BOOL): HRESULT; stdcall;


// Client functions
function TMfpMixer.GetMute(): TcBOOL;
var
  hr: HResult;
  Res: BOOL;

begin
  hr:= FAudioEndpoint.GetMute(Res);

  if FAILED(hr) then
    OleCheck(hr);

  Result:= TcBOOL(Res);
end;

//
procedure TMfpMixer.SetMute(Value: TcBOOL);
var
  hr: HResult;

begin
  // This is a workaround on the Delphi BOOL issue. 
  hr:= FAudioEndpoint.SetMute(BOOL(Value),
                              Nil);
  OleCheck(hr);
end;
于 2016-08-09T19:46:39.443 回答