【发布时间】:2016-03-29 01:18:34
【问题描述】:
使用this article,我设置了这个 COM 可见的接口来定义我的事件:
[ComVisible(true)]
[Guid("3D8EAA28-8983-44D5-83AF-2EEC4C363079")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IParserStateEvents
{
void OnParsed();
void OnReady();
void OnError();
}
这些事件是由实现此接口的类触发的:
[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 OnError;
private void _state_StateChanged(object sender, System.EventArgs e)
{
var errorHandler = OnError; // 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 处理程序不会运行:
我做错了什么?
【问题讨论】:
-
您链接到的文章说“我们需要 ClassInterface 属性,我们需要将其设置为 None。”将
ParserState上的属性更改为[[ClassInterface(ClassInterfaceType.None)]有帮助吗? -
@RomanR。
Handles语法是 VB.NET... -
我将您的声明复制/粘贴到新项目中并且效果很好 - Excel VBA 确实看到了事件界面并且事件返回 VBA。我能想到的是,你的情况不知何故线程不好,尤其是。如果您使用工作线程并在它们之间传递指针,然后在 COM 单元之间传递指针,使它们在一个线程上不可用,而在另一个线程上正常。代码 sn-p 本身并没有显示假定的线程问题。
-
@Roman 解析器状态确实是从后台线程更新的。如果您可以写一个解释需要从 UI 线程调用 COM 事件的答案(我将编辑问题中的代码以包含
_dispatcher字段),您将获得简单的代表提升!谢谢一百万!