c# – 为什么COM事件处理程序总是为空?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 为什么COM事件处理程序总是为空?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3455字,纯文字阅读大概需要5分钟。
内容图文
使用this article,我已经设置了这个COM可见界面来定义我的事件:
[ComVisible(true)]
[Guid("3D8EAA28-8983-44D5-83AF-2EEC4C363079")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IParserStateEvents
{
void OnParsed();
void OnReady();
void one rror();
}
这些事件是由实现此接口的类触发的:
[ComVisible(true)]
public interface IParserState
{
void Initialize(VBE vbe);
void Parse();
void BeginParse();
Declaration[] AllDeclarations { get; }
Declaration[] UserDeclarations { get; }
}
这是实施:
[ComVisible(true)]
[Guid(ClassId)]
[ProgId(ProgId)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComDefaultInterface(typeof(IParserState))]
[ComSourceInterfaces(typeof(IParserStateEvents))]
[EditorBrowsable(EditorBrowsableState.Always)]
public class ParserState : IParserState
{
//...
public event Action OnParsed;
public event Action OnReady;
public event Action one rror;
private void _state_StateChanged(object sender, System.EventArgs e)
{
var errorHandler = one rror; // always null
if (_state.Status == Parsing.VBA.ParserState.Error && errorHandler != null)
{
errorHandler.Invoke();
}
var parsedHandler = OnParsed; // always null
if (_state.Status == Parsing.VBA.ParserState.Parsed && parsedHandler != null)
{
parsedHandler.Invoke();
}
var readyHandler = OnReady; // always null
if (_state.Status == Parsing.VBA.ParserState.Ready && readyHandler != null)
{
readyHandler.Invoke();
}
}
//...
_state_StateChanged处理程序正在响应从后台工作程序线程引发的事件.
COM客户端代码是一个VBA类,如下所示:
Private WithEvents state As Rubberduck.ParserState
Public Sub Initialize()
Set state = New Rubberduck.ParserState
state.Initialize Application.vbe
state.BeginParse
End Sub
Private Sub state_OnError()
Debug.Print "error"
End Sub
Private Sub state_OnParsed()
Debug.Print "parsed"
End Sub
Private Sub state_OnReady()
Debug.Print "ready"
End Sub
虽然从对象浏览器看起来一切正常:
…当VBA代码调用BeginParse时,断点会在C#代码中被触发,但所有处理程序都为null,因此VBA处理程序不会运行:
我究竟做错了什么?
解决方法:
您的COM / VBA集成是正确的,但是您需要记住COM线程模型和在单线程单元中使用COM类的规则.
您在STA线程上创建了Rubberduck.ParserState实例. VBA立即看到WithEvents说明符,并将最好的连接事件处理程序连接到COM类实现的连接点.具体来说,COM类接收COM接口指针以接受同一线程上的事件调用,并存储指针以便稍后在事件调用时使用它.
当您举起事件时,服务器(C#)和客户端(VBA)可能会也可能不会检查执行是否发生在正确的线程上(而不是正确的公寓).使用C开发,您可能有机会忽略线程不匹配(这不是一件好事但让我们假设您知道自己在做什么),而VBA和.NET COM互操作等环境则更加严格地考虑环境的完整性整体而言,如果线程错误,它们可能会失败.也就是说,你必须在正确的线程上举起你的活动!如果你有一个后台工作线程,你不能直接从它提出事件,你需要先将它传递给实际需要调用的公寓线程.
如果您的线程问题仅限于从工作线程调用,则问题将是非空事件接收器调用您将获得异常或其他情况下调用未到达您的VBA.然后你有null,所以很可能线程以另一种方式影响(从工作线程上的某些回调实例化等).无论哪种方式,一旦违反不在公寓之间传递接口指针的COM规则,指针就会变得无法使用,导致通话失败或无法提供预期演员等等).解决这个问题后,您可以使用这些活动.
奖金代码:最小的C#项目和XLS文件证明事件以最简单的形式工作(Subversion/Trac).
从Initialize调用直接引发事件:
public void Initialize()
{
if (OnReady != null)
OnReady();
}
Private Sub Worksheet_Activate()
If state Is Nothing Then Set state = New ComEvents01.ParserState
' Initialize below will have C# raise an event we'd receive state_OnReady
state.Initialize
End Sub
Private Sub state_OnReady()
' We do reach here from Initialize and Worksheet_Activate
End Sub
内容总结
以上是互联网集市为您收集整理的c# – 为什么COM事件处理程序总是为空?全部内容,希望文章能够帮你解决c# – 为什么COM事件处理程序总是为空?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。