小编Rut*_*ing的帖子

如何在ActiveX方法调用期间防止WPF事件处理程序的重入?

我们在WPF和STA应用程序中调用ActiveX组件上的方法.此调用是通过以下方式执行的:

res = ocx.GetType().InvokeMember(methodName, flags, null, ocx, args);
Run Code Online (Sandbox Code Playgroud)

...其中ocx是使用System.Windows.Forms.AxHost.GetOcx()方法检索的ActiveX对象.

此调用是在WPF事件处理程序中执行的,例如"鼠标单击".

现在问题.如果我们双击'鼠标点击'事件将触发,运行InvokeMember().但是,此调用期间,我们看到重新输入了"鼠标单击"事件.所以在同一个线程中,我们在调用堆栈上看到两次事件处理程序.这是非常意外的,我们正在努力防止这种情况发生.我们怎样才能防止这种情况发生?

我们能想到的唯一原因,为什么它偏偏就是:

  • COM对象是在另一个STA中创建的,因此我们正在执行需要编组的跨STA调用
  • 跨线程STA调用使用Windows消息向COM组件发送RPC请求
  • 跨线程STA调用使用Windows消息泵来接收RPC应答
  • 在等待期间,会出现另一种类型的事件(如"鼠标点击"),并在处理RPC应答之前处理此事件.
  • 这个RPC答案得到处理

我们试图解决问题的方法:

  • 在所有事件处理程序中使用lock().这不起作用,因为lock()将锁定一个线程,在这种情况下,它是重新进入事件处理程序的相同线程.
  • 使用自定义锁定,如'bool locked = false; if(!locked){locked = true; 的InvokeMethod(); ...; locked = false; }".这部分工作:它会丢弃事件而不是将它们排队等待,并且需要对我们所有的事件处理程序进行大量更改,这样做并不好.
  • 使用Dispatcher.DisableProcessing来停止(其他)消息的处理.这没有帮助:它会抛出异常,因为无论如何都要处理消息.
  • 在新线程中创建第二个调度程序,并通过Dispatcher.Invoke()运行ocx.InvokeMehod()以使其由另一个线程处理.这给出了'一个事件无法调用任何订阅者(来自HRESULT的异常:0x80040201)'(是的,我们还订阅了ActiveX对象的COM事件).
  • 使用Dispatcher.PushFrame()来停止发生事件处理.这也失败了.

一个可能有效,但不知道如何实现这一点的疯狂想法将创建一个新的消息泵作为WPF消息泵,可配置为临时只处理RPC调用.这与http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/430/WPF-MediaKit-Updates.aspx一致,但仍与此情况有所不同.

所以问题归结为我们如何能够像我们预期的那样同步进行ActiveX调用而不是异步?

更新

为了更清楚地说明所涉及的机制不仅仅是关于鼠标事件,而是"在执行旧事件时处理新事件"这一更普遍的问题,我将给出另一个堆栈跟踪示例:

上下文:我们有一个WPF网格,我们得到一个鼠标点击(Grid_MouseDown),我们有一个ActiveX对象,我们在其上执行方法'CloseShelf'.打开架子需要时间,所以我们订阅了事件'EventShelfClosed',它在EventShelfClosed的事件处理程序中将调用'ListShelf'来知道剩下哪些架子.

这就是托管堆栈跟踪的样子(Hans要求一个非托管堆栈跟踪,但我不知道如何获得一个):

MyAxWrapper.dll!MyAxWrapper.MyAxWrapper.InvokeMember(string methodName, System.Reflection.BindingFlags flags, object[] args, int refArgIdx) Line 53 C#
MyAxWrapper.dll!MyAxWrapper.LoggingMyAxWrapper.InvokeMember(string methodName, System.Reflection.BindingFlags flags, object[] args, int refArgIdx) Line 151 + 0x14 bytes    C#
MyAxWrapper.dll!MyAxWrapper.MyAxWrapper.InvokeMethod(string methodName, object[] args) …
Run Code Online (Sandbox Code Playgroud)

.net c# com wpf activex

9
推荐指数
1
解决办法
3719
查看次数

标签 统计

.net ×1

activex ×1

c# ×1

com ×1

wpf ×1