在 IMMDeviceEnumerator 上调用 SAFE_RELEASE 时崩溃

Crash when SAFE_RELEASE is called on IMMDeviceEnumerator

本文关键字:RELEASE 崩溃 SAFE IMMDeviceEnumerator 调用      更新时间:2023-10-16

>我正在使用服务来检测头组的连接。当麦克风连接和断开连接时,我会收到通知。问题是,当我手动结束服务时,我在做SAFE_RELEASE时面临服务崩溃。这是代码...

NotifyHandsetConnectionStatus::NotifyHandsetConnectionStatus() : _cRef(1), _pEnumerator(NULL){}
NotifyHandsetConnectionStatus::~NotifyHandsetConnectionStatus()
{
 //   SAFE_RELEASE(_pEnumerator)
    if (_pEnumerator)
    { 
        _pEnumerator->Release(); // CRASH
        _pEnumerator = NULL;
    }
}
void NotifyHandsetConnectionStatus::Init(DWORD threadID)
{
    PTTThreadID = threadID;
    HRESULT hr = S_OK;
    CoInitialize(NULL);
    if (_pEnumerator == NULL)
    {
        // Get enumerator for audio endpoint devices.
        hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
            __uuidof(IMMDeviceEnumerator), (void**)&_pEnumerator);
    }
    if (hr == S_OK)
    {
        _pEnumerator->RegisterEndpointNotificationCallback(this);
    }
}

这是类声明...

class NotifyHandsetConnectionStatus : public IMMNotificationClient
{
    LONG _cRef;
    IMMDeviceEnumerator *_pEnumerator;
    DWORD PTTThreadID;
public:
    NotifyHandsetConnectionStatus();
    ~NotifyHandsetConnectionStatus();
    void Init(DWORD threadID);
    ULONG STDMETHODCALLTYPE AddRef() override;
    virtual ULONG STDMETHODCALLTYPE Release() override;
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) override;
    HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) override;
    HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) override
    {
        return S_OK;
    }
    HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) override
    {
        return S_OK;
    }
    HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) override
    {
        return S_OK;
    }
    HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) override
    {
        return S_OK;
    }
};

您发布的代码不会崩溃,即使没有取消注册回调也不会崩溃。 通过复制粘贴您拥有的内容并添加您没有的内容来检查。 IUnknow的方法丢失了,但不太可能与它有任何关系。 只要确保你的 Release() 函数不会被频繁调用,delete this只工作一次。

像这样的代码崩溃的原因有很多,堆损坏是每个C++程序员讨厌的大声邻居,他永远最有可能在最不合时宜的时刻出现。 由于程序退出很可能是让邻居将拨盘转到 11 的时间,这是您触摸一段时间不需要的堆部分的时候。 很难调试,损坏发生得更早。

隔离问题,首先将服务转换为执行所有相同动作的控制台模式应用,以便更易于调试。 您可以使用堆诊断工具,如 UMHD.exe。 为单个代码块编写单元测试。

似乎

需要Unregister the IMMDeviceEnumerator before calling Release().

_pEnumerator->UnregisterEndpointNotificationCallback(this);