使用C#设置Windows音量

5

我一直在网上寻找一种从C#控制计算机音频的方法。我找到了这段代码,它运行良好。

    public static float GetMasterVolume()
    {
        // get the speakers (1st render + multimedia) device
        IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
        IMMDevice speakers;
        const int eRender = 0;
        const int eMultimedia = 1;
        deviceEnumerator.GetDefaultAudioEndpoint(eRender, eMultimedia, out speakers);

        object o;
        speakers.Activate(typeof(IAudioEndpointVolume).GUID, 0, IntPtr.Zero, out o);
        IAudioEndpointVolume aepv = (IAudioEndpointVolume)o;
        float volume = aepv.GetMasterVolumeLevelScalar();
        Marshal.ReleaseComObject(aepv);
        Marshal.ReleaseComObject(speakers);
        Marshal.ReleaseComObject(deviceEnumerator);
        return volume;
    }

    [ComImport]
    [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
    private class MMDeviceEnumerator
    {
    }

    [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IAudioEndpointVolume
    {
        void _VtblGap1_6();
        float GetMasterVolumeLevelScalar();
    }

    [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IMMDeviceEnumerator
    {
        void _VtblGap1_1();

        [PreserveSig]
        int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice ppDevice);
    }

    [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IMMDevice
    {
        [PreserveSig]
        int Activate([MarshalAs(UnmanagedType.LPStruct)] Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
    }

那就是 getVolume 函数。我认为一定有一种类似的方法来设置音量。我找到了这个方法:

SetMasterVolumeLevelScalar()

HRESULT SetMasterVolumeLevelScalar(
  [in] float   fLevel,
  [in] LPCGUID pguidEventContext
);

但我无法理解第二个参数。需要帮助,谢谢。


从msdn中获取:此参数指向事件上下文GUID。如果SetMasterVolumeLevelScalar调用更改了端点的音量级别,则所有已向该端点注册IAudioEndpointVolumeCallback接口的客户端将收到通知。在其OnNotify方法的实现中,客户端可以检查事件上下文GUID以确定是它自己还是其他客户端是音量更改事件的来源。如果调用者为此参数提供了一个空指针,则通知例程将接收上下文GUID值GUID_NULL。 - Valentin
执行 aepv.SetMasterVolumeLevelScalar((float)0.89, null); 后出现了 System.ArgumentException。 - Aldridge1991
你尝试过传递任何GUID吗? - Valentin
诚实地说,我不知道 GUID 是什么。我尝试过 Guid.Empty。 - Aldridge1991
你能把整个错误信息放在问题中吗?谢谢。 - Valentin
谢谢Valentin。我已经解决了这个问题。 - Aldridge1991
2个回答

1

我看到你已经解决了问题,但是想为其他需要帮助或好奇的人提供正式答案。

当您调用 SetMasterVolumeLevelScalar 时,您传递的音量是从0.0到1.0的百分比,并且您传递一个GUID。您也可以传递Null。传递GUID的原因是,其他更改的应用程序可以检查更改并查看它们是否是自己或另一个应用程序。例如:

如果您注册了音量更改的 OnNotify,则每次更改音量时都会收到一个结构体。结构体中的第一个字段是GUID。如果您传递一个常量GUID来更改音量,则此结构将显示您自己的GUID;您可以比较它并忽略它或执行其他操作。如果结构传递NULL或不同的GUID,则您知道另一个应用程序已更改了音量,也许此时您想要执行某些不同的操作。

希望这有所帮助 :)


1
定义你的接口...
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioEndpointVolume
{
    // ...
    Int32 GetMasterVolumeLevelScalar(ref Single pfLevel);
    Int32 SetMasterVolumeLevelScalar(Single fLevel, Guid pguidEventContext);
    // ...
}

然后,在你的类中,例如:

public class EndpointVolume
{
    private readonly Guid m_GuidEventContext;
    private IAudioEndpointVolume m_AudioEndpoint;

    public EndpointVolume()
    {
        m_GuidEventContext = Guid.NewGuid();
        m_AudioEndpoint = ...
    }

    public Single MasterVolume
    {
        get
        {
            Single level = 0.0f;
            Int32 res = m_AudioEndpoint.GetMasterVolumeLevelScalar(ref level);

            if (retVal != 0)
                throw new Exception("AudioEndpointVolume.GetMasterVolumeLevelScalar()");

            return level;
        }

        set
        {
            Single level = value;

            if (level < 0.0f)
                level = 0.0f;
            else if (level > 1.0f)
                level = 0.0f;

            Int32 res = m_AudioEndpoint.SetMasterVolumeLevelScalar(level, m_GuidEventContext);

            if (res!= 0)
                throw new Exception("AudioEndpointVolume.SetMasterVolumeLevelScalar()");
        }
    }

    // ...
}
pguidEventContext参数被用于定义当前的事件上下文,以便将对主音量所做的更改反映到所有其他客户端。来自官方文档

IAudioEndpointVolumeCallback::OnNotify方法的上下文值。 此参数指向一个事件上下文GUID。如果SetMasterVolumeLevelScalar调用更改了端点的音量级别,则已在该端点上注册了IAudioEndpointVolumeCallback接口的所有客户端都将收到通知。在其OnNotify方法的实现中,客户端可以检查事件上下文GUID,以发现是其自身还是另一个客户端是音量更改事件的来源。如果调用者为此参数提供了NULL指针,则通知例程将接收上下文GUID值GUID_NULL。


我尝试了你说的,但是出现了错误消息 - "System.NullReferenceException: Object reference not set to an instance of an object",出现在这两行代码中: "Int32 res = m_AudioEndpoint.GetMasterVolumeLevelScalar(ref level);" 和 "Int32 res = m_AudioEndpoint.SetMasterVolumeLevelScalar(level, m_GuidEventContext);". 我应该在这一行中添加什么? "m_AudioEndpoint = ???" - Nick_F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接