从 Excel vba 调用 c# .net 库方法并传递工作簿对象
Call c# .net library method from Excel vba and pass the Workbook object
情况..
对于我的项目,我需要对某些 Excel 文档的内容执行一些复杂的操作。所以我认为用 c# 编写逻辑比在 VBA 宏中编写逻辑要方便得多。由于我需要在不止一个文档中使用此逻辑,并且在不同的文档中需要此逻辑的不同部分,因此我想从 VBA 宏中调用 c# 方法。
所以..
我是this answer来的,它确实完美地解决了这个问题。但是,似乎因为我需要将 ThisWorkbook 对象从 VBA 传递到 .net 方法中,所以 Excel.exe 在关闭应用程序(任务管理器 > 详细信息)后在后台保持活动状态。下次我打开 Excel 时,它立即崩溃,然后 Excel.exe 正确关闭。
这是我遇到的唯一问题,我很沮丧我无法解决它。有什么想法吗?
我考虑过的..
一个可行的(不完美的)解决方案是制作文档级 VSTO 加载项。但是对于需要为每个不同的文档进行小的更改和重新编译整个项目,我并不感到非常兴奋。如果我可以集中 C# 逻辑并从不同文档中要求它,那就更好了。
制作应用程序级别的 VSTO 插件也是不可取的,因为我工作的公司的所有用户都需要安装 VSTO 插件才能打开任何需要它的文档。这是太大的风险和努力。我宁愿集中它,以防止重复并确保始终调用最新版本。
我的代码..
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace ExcelVSTOUtils
{
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
public class Utilities
{
public Excel.Workbook _ThisWorkbook { get; private set; }
// parameterless constructor since vba does not support it
public Utilities(/*Excel.Workbook ThisWorkbook*/)
{
}
// helper function to set the workbook property after all
public void Initialize(Excel.Workbook ThisWorkbook)
{
_ThisWorkbook = ThisWorkbook;
}
// method 1
public void Method1()
{
// doing something complex with _ThisWorkbook ..
}
// method 2
public void Method2()
{
// doing something complex with _ThisWorkbook ..
}
}
}
'ThisWorkbook object
Private Utilities As New ExcelVSTOUtils.Utilities
Private Sub Workbook_Open()
Utilities.Initialize ThisWorkbook
End Sub
Sub Method1()
Utilities.Method1
End Sub
Sub Method2()
Utilities.Method2
End Sub
因此,我决定使用应用程序级别的插件,并在每个需要它的工作簿中签入 Workbook_Open
Sub(如果在继续之前安装了插件)。为实现这一目标,我遵循了 this tutorial 并且它运行良好。但是,这是应用程序级别,但我需要 class 个绑定到特定工作簿的实例。
解决方法:
public partial class ThisAddIn
{
private AddInUtilities utilities;
protected override object RequestComAddInAutomationService()
{
if (utilities == null)
utilities = new AddInUtilities();
return utilities;
}
}
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
public class AddInUtilities
{
public WbVSTO GetWbVSTO()
{
return new WbVSTO(Globals.ThisAddIn.Application.ThisWorkbook);
}
}
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
public class WbVSTO
{
private Excel.Workbook _ThisWorkbook;
public WbVSTO(Excel.Workbook ThisWorkbook)
{
_ThisWorkbook = ThisWorkbook;
}
}
'ThisWorkbook object
Private AppVSTO As Object
Private WbVSTO As Object
Private Sub Workbook_Open()
Set AppVSTO = Application.COMAddIns("AppVSTO").Object
Set WbVSTO = AppVSTO.GetWbVSTO()
End Sub
非常重要的是让所有需要暴露的classes都Excel ComVisible。
情况..
对于我的项目,我需要对某些 Excel 文档的内容执行一些复杂的操作。所以我认为用 c# 编写逻辑比在 VBA 宏中编写逻辑要方便得多。由于我需要在不止一个文档中使用此逻辑,并且在不同的文档中需要此逻辑的不同部分,因此我想从 VBA 宏中调用 c# 方法。
所以..
我是this answer来的,它确实完美地解决了这个问题。但是,似乎因为我需要将 ThisWorkbook 对象从 VBA 传递到 .net 方法中,所以 Excel.exe 在关闭应用程序(任务管理器 > 详细信息)后在后台保持活动状态。下次我打开 Excel 时,它立即崩溃,然后 Excel.exe 正确关闭。
这是我遇到的唯一问题,我很沮丧我无法解决它。有什么想法吗?
我考虑过的..
一个可行的(不完美的)解决方案是制作文档级 VSTO 加载项。但是对于需要为每个不同的文档进行小的更改和重新编译整个项目,我并不感到非常兴奋。如果我可以集中 C# 逻辑并从不同文档中要求它,那就更好了。
制作应用程序级别的 VSTO 插件也是不可取的,因为我工作的公司的所有用户都需要安装 VSTO 插件才能打开任何需要它的文档。这是太大的风险和努力。我宁愿集中它,以防止重复并确保始终调用最新版本。
我的代码..
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace ExcelVSTOUtils
{
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
public class Utilities
{
public Excel.Workbook _ThisWorkbook { get; private set; }
// parameterless constructor since vba does not support it
public Utilities(/*Excel.Workbook ThisWorkbook*/)
{
}
// helper function to set the workbook property after all
public void Initialize(Excel.Workbook ThisWorkbook)
{
_ThisWorkbook = ThisWorkbook;
}
// method 1
public void Method1()
{
// doing something complex with _ThisWorkbook ..
}
// method 2
public void Method2()
{
// doing something complex with _ThisWorkbook ..
}
}
}
'ThisWorkbook object
Private Utilities As New ExcelVSTOUtils.Utilities
Private Sub Workbook_Open()
Utilities.Initialize ThisWorkbook
End Sub
Sub Method1()
Utilities.Method1
End Sub
Sub Method2()
Utilities.Method2
End Sub
因此,我决定使用应用程序级别的插件,并在每个需要它的工作簿中签入 Workbook_Open
Sub(如果在继续之前安装了插件)。为实现这一目标,我遵循了 this tutorial 并且它运行良好。但是,这是应用程序级别,但我需要 class 个绑定到特定工作簿的实例。
解决方法:
public partial class ThisAddIn
{
private AddInUtilities utilities;
protected override object RequestComAddInAutomationService()
{
if (utilities == null)
utilities = new AddInUtilities();
return utilities;
}
}
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
public class AddInUtilities
{
public WbVSTO GetWbVSTO()
{
return new WbVSTO(Globals.ThisAddIn.Application.ThisWorkbook);
}
}
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
public class WbVSTO
{
private Excel.Workbook _ThisWorkbook;
public WbVSTO(Excel.Workbook ThisWorkbook)
{
_ThisWorkbook = ThisWorkbook;
}
}
'ThisWorkbook object
Private AppVSTO As Object
Private WbVSTO As Object
Private Sub Workbook_Open()
Set AppVSTO = Application.COMAddIns("AppVSTO").Object
Set WbVSTO = AppVSTO.GetWbVSTO()
End Sub
非常重要的是让所有需要暴露的classes都Excel ComVisible。