简体   繁体   English

在IMMDeviceEnumerator上调用SAFE_RELEASE时崩溃

[英]Crash when SAFE_RELEASE is called on IMMDeviceEnumerator

I am using a service to detect the connection of head set. 我正在使用一项服务来检测耳机的连接。 When the microphone is connected and disconnected, I am getting notification. 连接和断开麦克风后,我会收到通知。 The thing is, when I end the service manually, I am facing a crash in the service while doing SAFE_RELEASE. 问题是,当我手动结束服务时,在执行SAFE_RELEASE时会遇到服务崩溃。 Here is the code... 这是代码...

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

and here is the class declaration... 这是类声明...

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

Your code as posted does not crash, not even without unregistering the callback. 您发布的代码不会崩溃,即使没有注销回调也不会崩溃。 Checked by copy-pasting what you have and adding what you didn't. 通过复制粘贴内容并添加您没有的内容进行检查。 The IUnknown methods are missing, but pretty unlikely to have anything to do with it. IUnknown方法丢失了,但是几乎不可能与它有任何关系。 Just make sure that your Release() function doesn't get called too often, delete this only works once. 只要确保您的Release()函数不会被频繁调用, delete this一次即可。

There are plenty of reasons for code like this to crash, heap corruption is every C++ programmer's nasty loud neighbor and he is forever most likely to show up at the most inopportune moment. 诸如此类的代码崩溃的原因很多,堆损坏是每个C ++程序员讨厌的大声邻居,而且他永远最有可能在最不适当的时刻出现。 With program exit being a very likely time to get that neighbor to turn the dial to eleven, that's when you touch heap sections you haven't needed for a while. 由于程序退出是使该邻居将拨盘转到11的极有可能的时间,因此当您触摸堆段时,您已经不需要了一段时间了。 Very hard to debug, the corruption happened much earlier. 很难调试,损坏发生的时间更早。

Isolate the problem, start by turning the service into a console mode app that goes through all the same motions so it is easier to debug. 要解决问题,首先将服务变成控制台模式应用程序,该应用程序会执行所有相同的动作,因此更易于调试。 And you can use heap diagnostic tools like UMHD.exe. 而且,您可以使用堆诊断工具,例如UMHD.exe。 Write unit tests for individual chunks of code. 为单个代码块编写单元测试。

似乎需要Unregister the IMMDeviceEnumerator before calling Release()

_pEnumerator->UnregisterEndpointNotificationCallback(this);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM