.NET 代码中的关键概念是将事件定义为单独接口上的方法,并通过[ComSourceInterfacesAttribute] 将其连接到类。在示例中,这是通过代码[ComSourceInterfaces(typeof(IEvents))] 完成的,其中IEvents 接口定义了应该在COM 客户端上处理的事件。
事件命名注意事项:
c# 类中定义的事件名称和接口上定义的接口方法名称必须相同。在此示例中,IEvents::OnDownloadCompleted 对应于 DemoEvents::OnDownloadCompleted。
然后定义第二个接口,它代表类本身的公共 API,这里称为IDemoEvents。在此接口上定义了在 COM 客户端上调用的方法。
C# 代码(构建到 COMVisibleEvents.dll)
using System;
using System.EnterpriseServices;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace COMVisibleEvents
{
[ComVisible(true)]
[Guid("8403C952-E751-4DE1-BD91-F35DEE19206E")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IEvents
{
[DispId(1)]
void OnDownloadCompleted();
}
[ComVisible(true)]
[Guid("2BF7DA6B-DDB3-42A5-BD65-92EE93ABB473")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IDemoEvents
{
[DispId(1)]
Task DownloadFileAsync(string address, string filename);
}
[ComVisible(true)]
[Guid("56C41646-10CB-4188-979D-23F70E0FFDF5")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IEvents))]
[ProgId("COMVisibleEvents.DemoEvents")]
public class DemoEvents
: ServicedComponent, IDemoEvents
{
public delegate void OnDownloadCompletedDelegate();
private event OnDownloadCompletedDelegate OnDownloadCompleted;
public string _address { get; private set; }
public string _filename { get; private set; }
private readonly string _downloadToDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public async Task DownloadFileAsync(string address, string filename)
{
try
{
using (WebClient webClient = new WebClient())
{
webClient.Credentials = new NetworkCredential(
"user", "psw", "domain");
string file = Path.Combine(_downloadToDirectory, filename);
await webClient.DownloadFileTaskAsync(new Uri(address), file)
.ContinueWith(t =>
{
// https://stackoverflow.com/q/872323/
var ev = OnDownloadCompleted;
if (ev != null)
{
ev();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
catch (Exception ex)
{
// Log exception here ...
}
}
}
}
再高潮
C:\Windows\Microsoft.NET\Framework\v4.0.30319>regasm C:\Temp\COMVisibleEvents\bin\Debug\COMVisibleEvents.dll /tlb: C:\Temp\COMVisibleEvents\bin\Debug\COMVisibleEvents.tlb
VBA 客户端对*.tlb 文件的引用
添加对由regasm 生成的*tlb 的引用。这里tlb 文件的名称是COMVisibleEvents。
这里使用 Excel 用户表单作为 VBA 客户端。单击按钮后,方法DownloadFileAsync 被执行,当此方法完成时,事件被处理程序m_eventSource_OnDownloadCompleted 捕获。在此示例中,您可以从我的 Dropbox 下载 C# 项目 COMVisibleEvents.dll 的源代码。
VBA 客户端代码 (MS Excel 2007)
Option Explicit
Private WithEvents m_eventSource As DemoEvents
Private Sub DownloadFileAsyncButton_Click()
m_eventSource.DownloadFileAsync "https://www.dropbox.com/s/0q3dskxopelymac/COMVisibleEvents.zip?dl=0", "COMVisibleEvents.zip"
End Sub
Private Sub m_eventSource_OnDownloadCompleted()
MsgBox "Download completed..."
End Sub
Private Sub UserForm_Initialize()
Set m_eventSource = New COMVisibleEvents.DemoEvents
End Sub
结果