gpt4 book ai didi

c# - C# 和 VBA 之间的通信

转载 作者:太空狗 更新时间:2023-10-29 19:56:04 25 4
gpt4 key购买 nike

应老板的要求,我创建了一小组脚本,用于定期监控某些设备和进程的状态。此信息随后使用相对复杂的 VBA 模块进行处理,该模块收集所有信息、应用公式、设置范围并生成图表等。

但是有两个问题:我是一名业余程序员,所以我的 VBA 例程效率很低。这对我来说不是什么大问题(我只是在它运行时起床喝杯咖啡),但对于其他用户来说这可能是个麻烦,因为他们不知道为什么要花这么长时间。我想要进度的图形表示。应用程序的配置是通过文本文件完成的。我想提供一个像样的 GUI 来设置配置。

为了实现这一点,我正在寻找一种方法让我的 C# WinForms 应用程序与我的 VBA 应用程序进行通信。我知道如何从我的 C# 应用程序运行 VBA 例程,但我不知道如何让它们实时通信。

以下是我特别想要实现的两件事:

  • 我已经有一个在 VBA 例程结束时保存的日志文件。而不是那个我想发送日志/调试消息到我的 C# 应用程序实时(不仅仅是在结束时应用程序)以便消息可以显示在我的 GUI 应用程序中由 VBA 应用程序生成。
  • 我还希望 VBA 应用发送信息关于我的 GUI 应用程序的实时进度,以便我可以创建图形我的 GUI 应用程序中的进度条

我已经考虑过通过标准输出进行通信。我知道如何使用 C#/.Net 从标准输出中读取,但我不确定如何使用 VBA 写入 StdOut 流。

我敢肯定很多人会指出我试图实现的目标是愚蠢和过时的(或者完全没有必要),但作为一个业余程序员,这对我来说似乎是一个真正具有挑战性和有趣的项目,可以教我有一两件事。

最佳答案

创建 C# COM 可见类非常简单,而且(正如您在评论中所说)很有趣。这是一个小样本。

在一个新的 C# 库项目中,添加:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace CSharpCom
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
//The 3 GUIDs in this file need to be unique for your COM object.
//Generate new ones using Tools->Create GUID in VS2010
[Guid("18C66A75-5CA4-4555-991D-7115DB857F7A")]
public interface ICSharpCom
{
string Format(string FormatString, [Optional]object arg0, [Optional]object arg1, [Optional]object arg2, [Optional]object arg3);
void ShowMessageBox(string SomeText);
}

//TODO: Change me!
[Guid("5D338F6F-A028-41CA-9054-18752D14B1BB")] //Change this
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
interface ICSharpComEvents
{
//Add event definitions here. Add [DispId(1..n)] attributes
//before each event declaration.
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICSharpComEvents))]
//TODO: Change me!
[Guid("C17C5EAD-AA14-464E-AD32-E9521AC17134")]
public sealed class CSharpCom : ICSharpCom
{
public string Format(string FormatString, [Optional]object arg0, [Optional]object arg1, [Optional]object arg2, [Optional]object arg3)
{
return string.Format(FormatString, arg0, arg1, arg2, arg3);
}

public void ShowMessageBox(string SomeText)
{
MessageBox.Show(SomeText);
}
}
}

您需要进入您的项目属性,到“签名”选项卡,选中复选框以对您的程序集进行签名,然后创建一个新的“强名称 key 文件”。这将有助于防止您注册的 DLL 出现版本控制问题。

编译它,并在 Visual Studio 命令提示符下使用 regasm 注册 DLL。您将使用 32 位或 64 位 regasm,具体取决于您使用的 Office 版本...您将在 C:\windows\Microsoft.NET\FrameworkC: 中找到 RegAsm\windows\Microsoft.NET\Framework64(分别为 32 位和 64 位):

C:\windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe/codebase/tlb CSharpCom.dll

这会将您的 DLL 注册到 Windows,所以现在在 VBA 编辑器中,您应该能够转到工具 -> 引用并找到您的 COM 的命名空间“CSharpCom”。选中该框,现在您应该能够在 VBA 中创建 COM 对象:

Sub TestCom()
Dim c As CSharpCom.CSharpCom
Set c = New CSharpCom.CSharpCom
c.ShowMessageBox c.Format("{0} {1}!", "Hello", "World")
End Sub

您可以向 COM 对象添加表单,并在 VBA 调用特定方法时打开它们;您应该能够使用它来创建带有进度条的表单。不过,需要考虑的一件事是 VBA 是单线程的。这意味着在您的代码运行时其他一切都会被卡住,因此事情可能会变得有点棘手。

在我的脑海中,您可以在 COM 可见类中创建 3 个方法:一个用于打开表单,一个用于更新进度(在您的 VBA 调用 update() 方法之后立即调用 VBA 的 DoEvents() 方法您的 COM 对象,以允许 Office 处理屏幕更新)和一个关闭它。您应该在表单上调用 Dispose();这可以在“close”方法中完成,但我认为如果您的 VBA 崩溃并且您的 close 方法永远不会被调用,它可能会导致内存泄漏/问题——只是需要考虑的其他事情。

关于c# - C# 和 VBA 之间的通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13436028/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com