7 votes

Comment accéder à un fichier Excel déjà ouvert en C# ?

J'ai ouvert un classeur Excel en double-cliquant dessus dans l'explorateur Windows, mais je ne peux pas y accéder dans le code.

Excel.Application xlApp = (Application)Marshal.GetActiveObject("Excel.Application");
Excel.Workbooks xlBooks = xlApp.Workbooks;

xlBooks.Count est égal à 0, pourquoi ne fait-il pas référence à mon classeur ouvert ?

EDITAR

Voici les différents scénarios et ce qui se passe :

Scénario 1 : Si le fichier n'est pas déjà ouvert

  • Le code ouvre le cahier d'exercices, je suis content.

Scénario 2 : Si le fichier est initialement ouvert à partir du code et que je ferme et rouvre l'application

  • Le code fait référence au fichier correctement xlBooks.Count équivaut à 1, je suis heureux.

Scénario 3 : Si le fichier est initialement ouvert non pas à partir du code, mais en double-cliquant sur le fichier dans l'explorateur

  • Le code ouvre une autre instance du fichier xlBooks.Count est égal à 0, Je suis en colère !

Voici le code complet tel qu'il se présente actuellement

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

public class ExcelService : IExcelService
{
    const string _filePath = @"C:\Somewhere";
    const string _fileName = @"TestFile.xlsb";
    string _fileNameAndPath = Path.Combine(_filePath, _fileName);

    Application xlApp;
    Workbooks xlBooks;
    Workbook xlBook;
    Worksheet xlSheet;

    public ExcelService()
    {
        try
        {
            xlApp = (Application)Marshal.GetActiveObject("Excel.Application");
            xlBooks = xlApp.Workbooks;

            var numBooks = xlBooks.Count;
            Log.Info("Number of workbooks: {0}".FormatWith(numBooks));
            if (numBooks > 0)
            {
                xlBook = xlBooks[1];
                Log.Info("Using already opened workbook");
            }
            else
            {
                xlBook = xlBooks.Open(_fileNameAndPath);
                Log.Info("Opening workbook: {0}".FormatWith(_fileNameAndPath));
            }

            xlSheet = (Worksheet)xlBook.Worksheets[1];

            // test reading a named range
            string value = xlSheet.Range["TEST"].Value.ToString();
            Log.Info(@"TEST: {0}".FormatWith(value));

            xlApp.Visible = true;
        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }
    }

    ~ExcelService()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        try
        {
            Marshal.FinalReleaseComObject(xlSheet);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlBook);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlBooks);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlApp);
        }
        catch { }
    }
}

12voto

Nathan Points 168

Je sais que ce fil est un peu ancien, mais j'ai trouvé une autre façon de procéder. Lorsque vous créez un nouveau Excel.Application vous devez créer l'objet WorkBooks. Lorsque vous accédez à un fichier Excel déjà ouvert, l'objet WorkBooks est déjà créé, il suffit donc d'ajouter un nouveau WorkBook à celui qui existe déjà. La solution de @Tipx fonctionne très bien si vous avez accès au nom du WorkBook, mais dans mon cas, le nom du WorkBook actuel est toujours aléatoire. Voici la solution que j'ai trouvée pour contourner ce problème :

Excel.Application excelApp = null;
Excel.Workbooks wkbks = null;
Excel.Workbook wkbk = null;

bool wasFoundRunning = false;

Excel.Application tApp = null;
//Checks to see if excel is opened
try
{
    tApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
    wasFoundRunning = true;
}
catch (Exception)//Excel not open
{
    wasFoundRunning = false;
}
finally
{
    if (true == wasFoundRunning)
    {
        excelApp = tApp;
        wkbk = excelApp.Workbooks.Add(Type.Missing);                    
    }
    else
    {
        excelApp = new Excel.Application();
        wkbks = excelApp.Workbooks;
        wkbk = wkbks.Add(Type.Missing);
    }
    //Release the temp if in use
    if (null != tApp) { Marshal.FinalReleaseComObject(tApp); }
    tApp = null;
}
//Initialize the sheets in the new workbook

Ce n'est peut-être pas la meilleure solution, mais elle a fonctionné pour mes besoins. J'espère que cela aidera quelqu'un :)

5voto

Tipx Points 1622

Si tous vos classeurs sont ouverts dans la même instance Excel (vous pouvez le vérifier en contrôlant si vous pouvez passer de l'un à l'autre à l'aide de la touche Alt-tab). Vous pouvez simplement vous référer à l'autre en utilisant Workbooks("[FileName]") . Ainsi, par exemple :

Dim wb as Workbook //for C#, type Excel.Workbook wb = null;
Set wb = Workbooks("MyDuperWorkbook.xlsx") //for C#, type wb = Excel.Workbooks["MyDuperWorkbook.xlsx"];
wb.Sheets(1).Cells(1,1).Value = "Wahou!"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X