首页 > 解决方案 > 使用 DispEventAdvise 时应用程序退出异常

问题描述

我有以下测试设置,用 Visual Studio 2015 编写,并使用 Windows SDK 7.1:

在 Debug 中编译并运行测试应用程序时,该功能似乎可以正常工作,并且按预期处理事件。问题是,应用程序在退出时崩溃,到目前为止我未能弄清楚原因。非常感谢这里的任何人的帮助。

现在了解详细信息:应用程序如下所示:

#include <windows.h>
#include <initguid.h>
#include <atlbase.h>
#include <streams.h>

// {E705C8D3-EE60-4012-9E83-3CFE4A11D1B5}
DEFINE_GUID(CLSID_TestFilter,
    0xe705c8d3, 0xee60, 0x4012, 0x9e, 0x83, 0x3c, 0xfe, 0x4a, 0x11, 0xd1, 0xb5);

void Test()
{
    CComPtr<IBaseFilter> pFilter;
    HRESULT hr = CoCreateInstance(CLSID_TestFilter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pFilter);
    if (FAILED(hr))
        return;
}

void main()
{
    CoInitialize(NULL);
    Test();
    CoUninitialize();
}

退出主函数范围时发生崩溃,我无法从调用堆栈中获取任何内容。

CS测试定义了如下接口

using System;
using System.Runtime.InteropServices;

namespace TestCs
{
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IFireTestCsEvents
    {
        [DispId(1)]
        void NotifyEvent(string message);
    }

    public delegate void NotifyEventEventHandler(string message);

    public interface ITestCs : IDisposable
    {
        event NotifyEventEventHandler NotifyEvent;

        bool Run(string fileName);

        void Close();
    }
}

这是接口的实现

using System.Runtime.InteropServices;

namespace TestCs
{
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IFireTestCsEvents))]
    public class TestCsImp : ITestCs
    {
        public event NotifyEventEventHandler NotifyEvent;

        public TestCsImp()
        {
        }

        public bool Run(string fileName)
        {
            NotifyEvent?.Invoke(fileName);
            return true;
        }

        public void Close()
        {
        }

        public void Dispose()
        {
            Close();
        }
    }
}

至于TestFilter,它是基于TransInPlace类,并添加TestCsWrapper对象到宿主TestCs 这是头文件

#pragma once

#import "TestCs.tlb"
using namespace TestCs;

class TestCsWrapper :
    public IDispEventSimpleImpl<1, TestCsWrapper, &__uuidof(IFireTestCsEvents)>
{
public:
    BEGIN_SINK_MAP(TestCsWrapper)
        SINK_ENTRY_INFO(1, __uuidof(IFireTestCsEvents), 0x1, HandleEvent, &NotifyEvent)
    END_SINK_MAP()

    void __stdcall HandleEvent(BSTR message);
public:
    TestCsWrapper();
    virtual ~TestCsWrapper();

    bool Open();
    void Close();

    bool IsValid();

    bool Load(const wchar_t *fileName);
private:
    ITestCsPtr m_pTestCs;

    static _ATL_FUNC_INFO NotifyEvent;
};

这就是实现

#include "Pch.h"
#include "TestCsWrapper.h"

_ATL_FUNC_INFO TestCsWrapper::NotifyEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR } };

#define CREATE_CRASH

void __stdcall TestCsWrapper::HandleEvent(BSTR message)
{
    ::SysFreeString(message);
}

TestCsWrapper::TestCsWrapper()
{
}

TestCsWrapper::~TestCsWrapper()
{
    Close();
}

bool TestCsWrapper::Open()
{
    m_pTestCs = ITestCsPtr(__uuidof(TestCsImp));
    if(!IsValid())
        return false;

#ifdef CREATE_CRASH
    DispEventAdvise(m_pTestCs);
#endif
    return true;
}

void TestCsWrapper::Close()
{
    if(IsValid())
    {
#ifdef CREATE_CRASH
        DispEventUnadvise(m_pTestCs);
#endif
        m_pTestCs->Close();
        m_pTestCs->Release();
        m_pTestCs.Detach();
    }
}

bool TestCsWrapper::IsValid()
{
    return (m_pTestCs != NULL);
}


bool TestCsWrapper::Load(const wchar_t *fileName)
{
    if(!IsValid())
        return false;

    BSTR bstr = ::SysAllocString(fileName);
    VARIANT_BOOL success = m_pTestCs->Run(bstr);
    ::SysFreeString(bstr);
    return success == VARIANT_TRUE;
}

当我禁用 DispEventAdvise 代码时,应用程序无任何异常退出。

在过滤器的 CreateInstance 调用中,我添加了以下代码

bool TestFilter::Open()
{
    if (!m_testCs.Open())
        return false;

    m_testCs.Load(L"some messsage");
    return true;
}

完整的 Visual Studio 解决方案代码可用于演示这一点,如果需要,可以提供

希望找出我做错了什么。谢谢

标签: c#c++com

解决方案


推荐阅读