c# - 使用反射在 C# 中处理 COM 事件
问题描述
我有一个带有主界面和事件界面的 COM 对象(来自 IDL 文件):
[
uuid(<interfaceId>,
helpstring("AxBitViewerWidget Interface")
]
dispinterface IAxBitViewerWidget
{
...
};
[
uuid(<eventsId>),
helpstring("AxBitViewerWidget Events Interface")
]
dispinterface IAxBitViewerWidgetEvents
{
...
};
[
aggregatable,
helpstring("AxBitViewerWidget Class"),
uuid(<mainClassId>),
control
]
coclass AxBitViewerWidget
{
[default] dispinterface IAxBitViewerWidget;
[default, source] dispinterface IAxBitViewerWidgetEvents;
};
它是由 Active Qt 自动创建的。然后在 C# 中(在另一个 dll 中)我想连接到这个 COM 对象并处理它的事件。C# 类继承自AxHost
. 在我的示例中,所有 COM 类型都是动态的,并通过反射使用。这是片段:
public class BitViewerEx : AxHost
{
public BitViewerEx()
: base(<mainClassId>)
{
}
private void Initialize()
{
try
{
object ocx = GetOcx();
if (ocx != null)
{
Type ocxType = ocx.GetType();
Guid eventsGuid = new Guid(<eventsId>);
Type eventsType = Type.GetTypeFromCLSID(eventsGuid);
var sinkEventsInterfaceObj = CreateInstanceCore(eventsGuid);
// runtime error here
var cookie = new ConnectionPointCookie(ocx, sinkEventsInterfaceObj, eventsType);
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}
}
从上面调用 ConnectionPointCookie 时 - 发生错误(大约从本地化消息翻译):“无法为事件接口 '__ComObject' 执行 Advise()”。
我的代码正确吗?如何正确地将 AxBase 连接到 COM 对象事件?(对于动态类型的情况,不能在 C# 代码中使用 IAxBitViewerWidgetEvents 等)
PS:类方法(不是事件)的调用没有问题,例如:
ocx.GetType().InvokeMember("initialize", System.Reflection.BindingFlags.InvokeMethod,
null, ocx, new object[] { this.argum1, this.argum2 });
PS2:以下代码返回一个空数组:
System.Reflection.EventInfo[] arr = ocx.GetType().GetEvents();
解决方案
最后我让它工作了。主类是这样继承的
public class BitViewerEx : AxHost, IBitViewerEvents
在哪里IBitViewerEvents
(基于相应自动生成的 .idl 文件的内容)
// Methods should be like signals in the Qt active-x class with the bit viewer.
// DispIds are taken from the .idl file for the corresponding methods.
[ComImport, Guid(<eventsId>)]
public interface IBitViewerEvents
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)]
void started();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(9)]
void stopped();
}
然后将所有事件的连接代码简化为:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
...
private void Initialize() // BitViewerEx class member
{
try
{
object ocx = GetOcx();
if (ocx != null)
{
ocx.GetType().InvokeMember("initialize", System.Reflection.BindingFlags.InvokeMethod,
null, ocx, new object[] { this.deviceAddress, this.cellAddress });
var cookie = new ConnectionPointCookie(ocx, this, typeof(IBitViewerEvents));
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}
推荐阅读
- html - 如何在不完全重新加载页面的情况下更改 HTML/模板
- mysql - count(distinct(person_id)) 不能与 MySQL 数据库中的窗口函数一起使用
- ios - CoreBluetooth Peripheral 需要很长时间才能将值写入 Characteristic
- swift - Swift:正则表达式函数返回空数组
- c++ - 仅使用 boost 库中的属性树
- jquery - 编辑引导模式弹出窗口未加载部分视图
- c# - 读取 Arduino 的串口超时
- apl - 迭代器协议的 K 模式
- php - php if condition 有正式的任务?地点
- r - 为由两个不同列标识的每个公共行更新第三列 - R