带[ComSourceInterfaces]属性的C# DLL在VBA WithEvents中无法正常工作
C# COM DLL事件在VBA中调用的问题解决
问题概述
- 运行VBA的
TestTaskRunner子过程时,执行eventHandler.taskRunner.RunTask "Test Input"报错:Method or data member not found - 不确定C#代码中
[ComSourceInterfaces]属性的使用是否正确
问题1:"Method or data member not found" 错误修复
原因
TaskRunner类标记了[ClassInterface(ClassInterfaceType.None)],该设置会阻止.NET自动生成COM可见的类接口,导致VBA无法识别类中的RunTask方法。
修复步骤
添加COM可见的类接口
新增ITaskRunner.cs文件,定义类的公共方法接口:using System.Runtime.InteropServices; namespace ComEventTest { [ComVisible(true)] [Guid("f2a7b5d0-1c3e-4d2f-8a9c-123456789abc")] // 生成新的唯一GUID(可通过VS工具生成) [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface ITaskRunner { void RunTask(string input); } }让TaskRunner类实现接口
修改TaskRunner.cs,让类继承ITaskRunner接口,同时优化线程同步避免跨线程问题:using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Threading; namespace ComEventTest { [ComVisible(true)] [Guid("ac9de195-73e8-44ae-8cf1-d8f110421923")] [ClassInterface(ClassInterfaceType.None)] [ComSourceInterfaces(typeof(ITaskRunnerEvents))] public class TaskRunner : ITaskRunner { public delegate void TaskCompletedEventHandler(string result); public event TaskCompletedEventHandler OnTaskCompleted; public void RunTask(string input) { // 获取当前同步上下文,确保事件在VBA主线程触发 var syncContext = SynchronizationContext.Current; Task.Run(async () => { await Task.Delay(5000); // 模拟任务执行 syncContext.Post(_ => { OnTaskCompleted?.Invoke($"Task completed with input: {input}"); }, null); }); } } }重新注册DLL
修改代码后,重新注册COM组件:- .NET Framework项目:打开管理员命令提示符,执行
regasm /codebase ComEventTest.dll - .NET Core/.NET 5+:使用对应版本的
regasm工具,或通过项目属性启用COM互操作后重新编译
- .NET Framework项目:打开管理员命令提示符,执行
问题2:[ComSourceInterfaces]属性的正确性验证
你的[ComSourceInterfaces(typeof(ITaskRunnerEvents))]使用是正确的,完全符合COM事件暴露的规范:
ITaskRunnerEvents标记了[ComVisible(true)]和[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)],满足COM事件接口要求- 类中的
TaskCompletedEventHandler委托签名与ITaskRunnerEvents中的OnTaskCompleted方法签名完全匹配 - 事件名称
OnTaskCompleted与接口方法名一致,符合COM事件的命名惯例
VBA代码验证
修改C#代码并重新注册后,原VBA代码无需修改即可正常运行:
TaskRunnerEventHandler类中的WithEvents变量能正确捕获OnTaskCompleted事件RunTask方法可被VBA正常调用,任务完成后会弹出包含结果的消息框
内容的提问来源于stack exchange,提问作者Adrijano Toys Shop
相关产品推荐
相关产品推荐

