简体   繁体   English

如何使用 Interop 加载 Excel 插件

[英]How to load an Excel Addin using Interop

I have an AddIn which I want to invoke through Excel interop from a C# winforms application.我有一个 AddIn,我想通过 Excel 互操作从 C# winforms 应用程序调用它。

I can't get the addin etc. to load unless I uninstall and resinstall it each time (this is apparantly something to do with Excel not loading addins when you use interop - btw, can't get their example to work in C#).除非我每次都卸载并重新安装它,否则我无法加载插件等(这显然与Excel 在使用互操作时未加载插件有关 - 顺便说一句,无法让他们的示例在 C# 中工作)。 Unfortunately this is slow and annoying to the user so I need to streamline it.不幸的是,这对用户来说很慢而且很烦人,所以我需要简化它。

I want to have one instance of Excel but load an already installed addin without forcing this install/reinstall problem.我想要一个 Excel 实例,但加载一个已安装的插件而不强制此安装/重新安装问题。

I've searched and searched but everything I find on google gives the solution to install/reinstall.我已经搜索并搜索过,但我在谷歌上找到的所有内容都提供了安装/重新安装的解决方案。 Is there any other way?有没有其他办法? The add-in is installed, I just want excel to load it.插件已安装,我只想用excel加载它。

This is what I am doing at the moment (taken from google'd advice):这就是我目前正在做的事情(取自谷歌的建议):

// loop over the add-ins and if you find it uninstall it.
foreach (AddIn addIn in excel.AddIns)
    if (addIn.Name.Contains("My Addin"))
        addin.Installed = false;

    // install the addin
    var addin = excel.AddIns.Add("my_addin.xll", false);
        addin.Installed = true;

After a while I found the answer hidden in strange places in the MS help : and this blog post .过了一会儿,我发现答案隐藏在MS 帮助中奇怪的地方:和这篇博文

That isn't all the info you need though.但这还不是您需要的全部信息。 Things to note: you must have at least one workbook open or otherwise Excel barfs.注意事项:您必须至少打开一个工作簿,否则 Excel barfs。 Here's some rudementry code to get started:下面是一些入门代码:

var excel = new Application();
var workbook = excel.workbooks.Add(Type.Missing);
excel.RegisterXLL(pathToXll);
excel.ShowExcel();

If you want you can close the temporary workbook (if you've run some macros etc.) and remember to tidy everything up with plenty of calls to Marshal.ReleaseComObject!如果您愿意,您可以关闭临时工作簿(如果您已经运行了一些宏等)并记住通过大量调用 Marshal.ReleaseComObject 来整理所有内容!

It seems that you have to get the correct Excel process to work with.似乎您必须获得正确的 Excel 流程才能使用。 Use this class to open the Excel document:使用这个类打开 Excel 文档:

 class ExcelInteropService
{
    private const string EXCEL_CLASS_NAME = "EXCEL7";

    private const uint DW_OBJECTID = 0xFFFFFFF0;

    private static Guid rrid = new Guid("{00020400-0000-0000-C000-000000000046}");

    public delegate bool EnumChildCallback(int hwnd, ref int lParam);

    [DllImport("Oleacc.dll")]
    public static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, ref Window ptr);

    [DllImport("User32.dll")]
    public static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam);

    [DllImport("User32.dll")]
    public static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);

    public static Application GetExcelInterop(int? processId = null)
    {
        var p = processId.HasValue ? Process.GetProcessById(processId.Value) : Process.Start("excel.exe");
        try
        {
            Thread.Sleep(5000);
            return new ExcelInteropService().SearchExcelInterop(p);
        }
        catch (Exception)
        {
            Debug.Assert(p != null, "p != null");
            return GetExcelInterop(p.Id);
        }
    }

    private bool EnumChildFunc(int hwndChild, ref int lParam)
    {
        var buf = new StringBuilder(128);
        GetClassName(hwndChild, buf, 128);
        if (buf.ToString() == EXCEL_CLASS_NAME) { lParam = hwndChild; return false; }
        return true;
    }

    private Application SearchExcelInterop(Process p)
    {
        Window ptr = null;
        int hwnd = 0;

        int hWndParent = (int)p.MainWindowHandle;
        if (hWndParent == 0) throw new Exception();

        EnumChildWindows(hWndParent, EnumChildFunc, ref hwnd);
        if (hwnd == 0) throw new Exception();

        int hr = AccessibleObjectFromWindow(hwnd, DW_OBJECTID, rrid.ToByteArray(), ref ptr);
        if (hr < 0) throw new Exception();

        return ptr.Application;
    }
}

Use the class in your application like this:在您的应用程序中使用该类,如下所示:

static void Main(string[] args)
{
    Microsoft.Office.Interop.Excel.Application oExcel = ExcelInteropService.GetExcelInterop();
    foreach (AddIn addIn in oExcel.AddIns)
        {
            addIn.Installed = true;
        }
}

I had a similar problem and none of the above solutions seemed to work for me.我遇到了类似的问题,上述解决方案似乎都不适合我。 So, I finally came up with the idea of simply opening the ".xla" file as a workbook :所以,我终于想出了简单地将“.xla”文件作为工作簿打开的想法:

//I first get the path to file, in my case it was in the same dir as the .exe
var XLA_NAME = Path.Combine(Directory.GetCurrentDirectory(), ".xla");

Excel.Application xlRep = new Excel.Application();
xlRep.visible = true;
xlRep.Workbooks.Open("XLA_NAME");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM