C++ 在IMMDeviceEnumerator上调用安全释放时崩溃

C++ 在IMMDeviceEnumerator上调用安全释放时崩溃,c++,windows,visual-c++,audio,access-violation,C++,Windows,Visual C++,Audio,Access Violation,我正在使用一项服务来检测头套的连接。当麦克风连接和断开时,我收到通知。问题是,当我手动结束服务时, 我在执行安全释放时面临服务崩溃。 这是代码 NotifyHandsetConnectionStatus::NotifyHandsetConnectionStatus() : _cRef(1), _pEnumerator(NULL){} NotifyHandsetConnectionStatus::~NotifyHandsetConnectionStatus() { // SAFE_RELE

我正在使用一项服务来检测头套的连接。当麦克风连接和断开时,我收到通知。问题是,当我手动结束服务时, 我在执行安全释放时面临服务崩溃。 这是代码

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;
    }
};

似乎需要
在调用Release()之前注销IMMDeviceEnumerator

_pEnumerator->UnregisterEndpointNotificationCallback(this);

似乎需要
在调用Release()之前注销IMMDeviceEnumerator

_pEnumerator->UnregisterEndpointNotificationCallback(this);

您发布的代码不会崩溃,即使未注销回调也不会崩溃。通过复制粘贴您拥有的内容并添加您没有的内容进行检查。IUnknown方法缺失,但不太可能与之有任何关系。只需确保您的Release()函数不会被频繁调用,
delete this
只工作一次

有很多原因导致这样的代码崩溃,堆腐败是每个C++程序员讨厌的邻居,他最有可能在最不合适的时刻出现。由于程序退出很可能是让邻居将拨号盘拨到11的时候,这时您可以触摸堆部分,而这已经有一段时间不需要了。很难调试,损坏发生得更早


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

您发布的代码不会崩溃,即使不注销回调也不会崩溃。通过复制粘贴您拥有的内容并添加您没有的内容进行检查。IUnknown方法缺失,但不太可能与之有任何关系。只需确保您的Release()函数不会被频繁调用,
delete this
只工作一次

有很多原因导致这样的代码崩溃,堆腐败是每个C++程序员讨厌的邻居,他最有可能在最不合适的时刻出现。由于程序退出很可能是让邻居将拨号盘拨到11的时候,这时您可以触摸堆部分,而这已经有一段时间不需要了。很难调试,损坏发生得更早

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