2009-07-20 7 views
6

J'ai un AddIn que je veux appeler via Excel interop à partir d'une application winforms C#.Comment charger un Addin Excel à l'aide d'Interop

Je ne peux pas charger l'addin etc. à moins que je ne le désinstalle et le réinstalle à chaque fois (cela ressemble apparemment à Excel not loading addins when you use interop - btw, ne peut pas obtenir leur exemple pour fonctionner en C#). Malheureusement, cela est lent et ennuyeux pour l'utilisateur, donc je dois le rationaliser.

Je veux avoir une instance d'Excel mais charger un addin déjà installé sans forcer ce problème d'installation/réinstallation.

J'ai recherché et cherché, mais tout ce que je trouve sur google donne la solution à installer/réinstaller. Est-ce qu'il y a un autre moyen? Le complément est installé, je veux juste que Excel le charge.

C'est ce que je fais en ce moment (tiré de conseils google'd):

// 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; 
+0

Pouvez-vous expliquer pourquoi vous devez faire installer/désinstaller? J'essaie de comprendre la façon dont Excel charge addin, une fois que vous l'avez configuré pour charger à chaque fois. Pourquoi faut-il installer/désinstaller? – shahkalpesh

+0

D'où vient ce code? je suppose un autre Excel AddIn? ou juste une application C# winform? –

+0

J'ai mis à jour la question avec les points que vous avez soulevés mais rapidement: Excel ne charge pas les addins via interop, tout ce que j'ai trouvé sur le net dit que la désinstallation/installation est la solution. Le code est appelé à partir d'une application winforms C# – user35149

Répondre

7

Après un certain temps, j'ai trouvé la réponse cachée dans des endroits étranges dans le MS help: et this blog post.

Ce n'est pas toute l'information dont vous avez besoin. Choses à noter: vous devez avoir au moins un classeur ouvert ou sinon Excel barfs. Voici un code de rudementry pour commencer:

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

Si vous voulez, vous pouvez fermer le classeur temporaire (si vous avez exécuté des macros, etc.) et ne pas oublier de ranger tout avec beaucoup d'appels à Marshal.ReleaseComObject!

0

Il semble que vous deviez utiliser le bon processus Excel. Utilisez cette classe pour ouvrir le 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; 
    } 
} 

Utilisez la classe dans votre application comme ceci:

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