1

我将一段 VBA 代码从 .Net 注入到 Microsoft Access 数据库中。

它只是运行宏的一行代码。宏所做的只是在模块内运行一段 VBA 代码。

我遇到的问题是这一切都发生在一个新的 MSAccess 会话中,我什至看不到它,而不是用户当前打开的会话。

相反,是否有可能与用户当前的 MSAccess 会话进行交互?这样做的重点是在每次发生 .Net 事件时在 MSAccess 会话中打开一个特定的表单。我的 C# 代码如下:

using Microsoft.Office.Interop.Access;

var msAccess = new Application();

msAccess.OpenCurrentDatabase(@"x:\foo\bar.accdb", false);
msAccess.DoCmd.RunMacro("macCTI");
msAccess.CloseCurrentDatabase();

谢谢

4

2 回答 2

2

如果您正在运行单个 Access 实例,则可以使用Marshal.GetActiveObject

using Microsoft.Office.Interop.Access;
using System.Runtime.InteropServices
...
try
{
    var msAccess = (Application)Marshal.GetActiveObject("Access.Application");
    msAccess.DoCmd.RunMacro("macCTI");
}
catch (COMException ex)
{
    // handle error
}

或者,如果有多个实例正在运行,并且没有两个实例打开相同的数据库,则可以使用Marshal.BindToMoniker

var msAccess = (Application) Marshal.BindToMoniker(@"x:\foo\bar.accdb"); 

注意:这篇Microsoft 知识库文章是这样说的:

COM 服务器是单用途(多实例)还是多用途(单实例)可能会影响您决定使用 GetActiveObject 来获取对该服务器的引用。因为可能会运行多个 Word、Excel 或 Microsoft Access 实例,所以特定服务器上的 GetActiveObject 可能会返回一个您没有预料到的实例。首先在 ROT 中注册的实例通常是 GetActiveObject 返回的实例。如果要获取对 Word、Excel 或 Microsoft Access 的特定运行实例的自动化引用,请使用 BindToMoniker 和在该实例中打开的文件的名称。对于像 PowerPoint 这样的多用途(单实例)服务器,这并不重要,因为自动化引用指向同一个运行实例。

于 2012-05-01T12:58:26.033 回答
0

要不获取新的 Access 实例,您必须查看实例是否已存在。Marshal.GetActiveObject按照马特的建议使用:

Application GetAccessApplication() {
  var application = (Application) Marshal.GetActiveObject("Access.Application");
  return application ?? new Application();
}

请注意,这里有一个轻微的脱节,因为您必须使用 ProgID 来获取现有的 Access 实例,但要创建一个新实例,您需要使用互操作程序集。

然后,您可以使 Access 应用程序可见:

var msAccess = GetAccessApplication();
msAccess.Visible = true;
于 2012-05-01T13:09:26.863 回答