Исключение при выходе из приложения при использовании DispEventAdvise - PullRequest
0 голосов
/ 09 марта 2019

У меня есть следующая настройка теста, написанная в Visual Studio 2015 и использующая Windows SDK 7.1:

  • C # проект (TestCs) с атрибутами COM.Он предоставляет метод Run и вызывает событие NotifyEvent
  • C ++ DirectShow filter (TestFilter).Он построен на примере TransInPlace и содержит TestCs
  • C ++ Console Application (TestApp).Он просто загружает TestFilter

При компиляции в 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, который при необходимости может быть предоставлен

Надеюсь узнать, что я делаю не так.Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...