How do I get the *actual* host application instance?

回眸只為那壹抹淺笑 提交于 2019-12-10 17:16:51

问题


I have this code in a C# add-in for the VBE (emphasis "VBE": it's not a MS-Office add-in):

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

Where TApplication is a MS-Office interop Application class, for example, a Microsoft.Office.Interop.Excel.Application type; here the applicationName parameter would be "Excel" for, well, Excel.

The problem is that Marshal.GetActiveObject seems to only ever return the first instance created, and that's not necessarily the instance that's hosting the current VBE environment, and this causes issues.

How can I get ahold of the actual host application instance?


回答1:


For the sake of slaying a zombie, you can get the name of the VBE's host by:

  • Inspecting the caption of the CommandBarButton that takes you to the host. The button is on the Standard Toolbar, but also in the View Menu.

  • Inspecting the names of the references. Typically the first reference that isn't VBA but is BuiltIn.

  • Inspecting the Application.Name property of document component's Properties collection.

And to reliably get a reference to the VBE's host, you have to use the Properties collection of the document-type components. For example, once you know that the name of the host is "Microsoft Excel", you just need to find the Workbook document-component (typically named ThisWorkbook), then you can get the host from the component's Properties collection.

            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");
            }

But not all vbProjects have document-type components, so for such projects you'll have to resort to the GetActiveObject approach.



来源:https://stackoverflow.com/questions/32953450/how-do-i-get-the-actual-host-application-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!