如何获得*实际的*主机应用实例?

本文关键字:应用 实例 主机 何获得 | 更新日期: 2023-09-27 18:16:17

我在VBE的c#插件中有这段代码(强调"VBE":它是而不是一个MS-Office插件):

public abstract class HostApplicationBase<TApplication> : IHostApplication
    where TApplication : class
{
    protected readonly TApplication Application;
    protected HostApplicationBase(string applicationName)
    {
        Application = (TApplication)Marshal.GetActiveObject(applicationName + ".Application");
    }

其中TApplication为MS-Office互操作Application类,例如:a Microsoft.Office.Interop.Excel.Application类型;这里的applicationName参数将是"Excel",用于Excel。

问题是Marshal.GetActiveObject似乎只返回创建的第一个实例,而这不一定是承载当前VBE环境的实例,这导致了问题。

如何获取实际的主机应用实例?

如何获得*实际的*主机应用实例?

为了杀死僵尸,您可以通过以下方式获取VBE主机的名称:

  • 检查带您到主机的CommandBarButton的标题。该按钮在标准工具栏上,但也在视图菜单中。

  • 检查引用的名称。通常第一个引用不是VBA,而是BuiltIn

  • 正在检查应用程序。

并且为了可靠地获得对VBE主机的引用,您必须使用文档类型组件的Properties集合。例如,一旦你知道主机的名称是"Microsoft Excel",你只需要找到工作簿文档组件(通常名为ThisWorkbook),然后你可以从组件的属性集合中获得主机。

            var appProperty = vbe.VBProjects
                .Cast<VBProject>()
                .Where(project => project.Protection == vbext_ProjectProtection.vbext_pp_none)
                .SelectMany(project => project.VBComponents.Cast<VBComponent>())
                .Where(component => component.Type == vbext_ComponentType.vbext_ct_Document
                && component.Properties.Count > 1)
                .SelectMany(component => component.Properties.OfType<Property>())
                .FirstOrDefault(property => property.Name == "Application");
            if (appProperty != null)
            {
                Application = (TApplication)appProperty.Object;
            }
            else
            {
                Application = (TApplication)Marshal.GetActiveObject(applicationName + ".Application");
            }

但是并不是所有的vbProjects都有文档类型的组件,所以对于这样的项目,你必须求助于GetActiveObject方法。