c# - 使用 DispEventAdvise 时应用程序退出异常
问题描述
我有以下测试设置,用 Visual Studio 2015 编写,并使用 Windows SDK 7.1:
- 具有 COM 属性的 C# 项目 (TestCs)。它公开了一个“运行”方法,并调用了“NotifyEvent”事件
- C++ DirectShow 过滤器 (TestFilter)。它建立在 TransInPlace 样本之上,并托管 TestCs
- C++ 控制台应用程序 (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 解决方案代码可用于演示这一点,如果需要,可以提供
希望找出我做错了什么。谢谢
解决方案
推荐阅读
- c++ - 如何在 Qt 3D 中设置平面的双面纹理?
- javascript - 如何使 API 调用过期/唯一并返回一次数据?
- docusignapi - 是否可以通过 API 填写文档模板并将完成的文档发送到 Carbon Copies 而无需任何人“签名”?
- python - 如何隐藏用户的输入
- javascript - 在 mouseenter 上使图标从左向右滑动
- sql - Cloudera Impala 从许多文件创建表
- kotlin - 如何在 kotlin 中使用 JasonElement
- python - 我无法过滤从我的网址获取数据以保存到
- python - Django - 如何根据输入的输入数字或单击添加更多按钮添加多个表单
- javascript - 我可以使用另一个应用程序的关键字参数将两个不同应用程序的 URL 连接在一起吗?