How to load an Excel Addin using Interop

前端 未结 2 903
你的背包
你的背包 2020-12-17 02:11

I have an AddIn which I want to invoke through Excel interop from a C# winforms application.

I can\'t get the addin etc. to load unless I uninstall and resinstall it

相关标签:
2条回答
  • 2020-12-17 03:15

    After a while I found the answer hidden in strange places in the MS help: and this blog post.

    That isn't all the info you need though. Things to note: you must have at least one workbook open or otherwise 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!

    0 讨论(0)
  • 2020-12-17 03:15

    It seems that you have to get the correct Excel process to work with. Use this class to open the Excel document:

     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;
            }
    }
    
    0 讨论(0)
提交回复
热议问题