Excel的互操作加载XLLs和DLL(Excel interop loading XLLs and

2019-07-04 03:07发布

我与彭博API(使用简单的调用像= BDP(“MS公平”,“问”))脱颖而出。 我也有打开一个Excel文件(通过互操作),使用彭博API C#应用程序。 我已阅读在这里 ,当你加载通过互操作加载项优于未加载。 我甚至建议使用那里的代码尝试。 然而,这似乎只为XLL和XLAM文件的工作,它看起来像彭博社还使用了没有得到加载的DLL文件。 有没有办法让所有这些加载项中通过互操作加载?

Answer 1:

我认为,如果你开始手动擅长的加载项加载正确。

如果是这样,你可以通过调用得到与装BB-加载项的Excel互操作对象Process p = Process.Start("excel.exe"); 然后使用AccessibleObjectFromWindow方法获取互操作对象。

如何做到这一点的例子可以发现在这里 。


快速演练

我决定以显示我的经历得到一个步骤Excel.Interop.Application加载彭博加载项实例。 也许有人着眼于这一点,并发现它是有用的,或者知道哪里我错过了什么,以获得更完美的解决方案。

我假设你已经安装了客户端上的彭博终端,并且可以申请基准和历史数据(BDP和BDH)从Excel中。 否则,这可能是不适合你......

最简单的方法行不通

var excel = new Microsoft.Office.Interop.Excel.Application();
excel.Workbooks.Open(filePath);
excel.Run("RefreshAllStaticData");

Run()将抛出COMException

不能运行宏“RefreshAllStaticData”。 宏可能无法在此工作簿是可用还是所有宏可能会被禁用。

手工加载加载项不起作用

var excel = new Microsoft.Office.Interop.Excel.Application();
var addIn = ex.AddIns.Add(filename);
addIn.Installed = true;
Console.WriteLine(addIn.IsOpen);

但是,如果启动Excel地单击Windows任务栏上,加载项正在很好地加载中...所以,我想通过启动可执行文件“EXCEL.EXE”启动Excel。

使用的Process.Start( “EXCEL.EXE”)的作品!

使用Excel中开始System.Diagnostics.Process类加载彭博加载项。 (我可以看到Bloomberg-RibbonTab 。)

现在我需要的是Excel进程的互操作,对象。 我可以用得到它上面的例子

我实现它

//From http://blogs.officezealot.com/whitechapel/archive/2005/04/10/4514.aspx
public 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 Microsoft.Office.Interop.Excel.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 Microsoft.Office.Interop.Excel.Application GetExcelInterop(int? processId = null)
    {
        var p = processId.HasValue ? Process.GetProcessById(processId.Value) : Process.Start("excel.exe");
        try
        {
            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 Microsoft.Office.Interop.Excel.Application SearchExcelInterop(Process p)
    {
        Microsoft.Office.Interop.Excel.Window ptr = null;
        int hwnd = 0;

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

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

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

        return ptr.Application;
    }
}

现在,我可以使用下面的代码行获得一个Excel.Interop.Application与加载彭博加载项实例!

var excel = ExcelInteropService.GetExcelInterop();
excel.Workbooks.Open(filename);
excel.Run("RefreshAllStaticData");
// works "like a charm"

我希望这免去别人我这个浪费那么多时间,如果有人有一个更好的解决方案,并希望分享它,这将是大加赞赏。



Answer 2:

我是能够得到使用了类似的结果NetOffice 。 这种特殊的功能将检索上次启动Excel进程的实例,或者创建如果确实存在一个新的。 从那里,你可以自由地打开/创建新工作簿。

有关使用netoffice而这种做法的好处是,它不依赖于特定版本的DLL互操作,如果你处置NetOffice对象,那么所有的Excel的COM对象被正确地清理。

using Xl = NetOffice.ExcelApi;    
private static Xl.Application GetOrStartExcel(bool started = false)
{
    Xl.Application application = null;

    try
    {
        object nativeProxy = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
        application = new Xl.Application(null, nativeProxy);
        return application;
    }
    catch (Exception ex)
    {
        if (!started) Process.Start("excel.exe");
        Thread.Sleep((int) TimeSpan.FromSeconds(1).TotalMilliseconds);
        return GetOrStartExcel(true);
    }
}

用法:

using (var excel = GetOrStartExcel())
{
    //Do work with excel object
}


Answer 3:

我意识到,它已经一段时间,因为这个问题已经被问。 不过我想分享我的经验,我遇到了同样的问题来了。 一个简单的解决办法是继续进行如在建议https://blogs.msdn.microsoft.com/accelerating_things/2010/09/16/loading-excel-add-ins-at-runtime/通过.Installed第一设置为false,然后为true:

this._application = new Application
                {
                    EnableEvents = true,
                    Visible = true
                };

                //Load Bloomberg Add-In
                for (var i = 1; i <= this._application.AddIns.Count; i++)
                {
                    var currentAddIn = this._application.AddIns.Item[i];

                    if (currentAddIn.Name != "BloombergUI.xla") continue;

                    currentAddIn.Installed = false;
                    currentAddIn.Installed = true;
                }


Answer 4:

如果你想要加载DLL到Excel加载项,则必须使用RegAsm注册此DLL文件。 并检查HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Excel\AddIns ,看看是否它成功注册。



文章来源: Excel interop loading XLLs and DLLs