我们在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().但是,在此调用期间,我们看到重新输入了"鼠标单击"事件.所以在同一个线程中,我们在调用堆栈上看到两次事件处理程序.这是非常意外的,我们正在努力防止这种情况发生.我们怎样才能防止这种情况发生?
我们能想到的唯一原因,为什么它偏偏就是:
我们试图解决问题的方法:
一个可能有效,但不知道如何实现这一点的疯狂想法将创建一个新的消息泵作为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)