2010-07-01 22 views

Respuesta

12

La manera correcta es examinar el objeto Application.Workbooks. En VBA usted escribiría:

Dim wb as Workbook 
On Error Resume Next      '//this is VBA way of saying "try"' 
Set wb = Application.Workbooks(wbookName) 
If err.Number = 9 then      '//this is VBA way of saying "catch"' 
    'the file is not opened...' 
End If 

En otras palabras, libros de trabajo es una matriz (o en términos de VBA, Collection) de todos los libros abiertos.

En C# el código siguientes obras:

static bool IsOpened(string wbook) 
    { 
     bool isOpened = true; 
     Excel.Application exApp; 
     exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"); 
     try 
     { 
      exApp.Workbooks.get_Item(wbook); 
     } 
     catch (Exception) 
     { 
      isOpened = false; 
     } 
     return isOpened; 
    } 

es probable que desee para pasar la referencia a Excel.Application mismo.

+0

Gracias amigo mío. – Rabin

+1

La versión de C# no funciona para mí en este día. Siempre levante una excepción y devuelva falso. La solución w69rdy hizo el truco para mí. –

+0

¿Cuál es la referencia para Excel.Application? – Devid

8

Prueba esto:

try 
{ 
    Stream s = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None); 

    s.Close(); 

    return true; 
} 
catch (Exception) 
{ 
    return false; 
} 

Esto se tryand abrir el archivo exclusivamente. Si el archivo ya está abierto arrojará una excepción, donde podrá (intentar) cerrarlo y continuar.

+0

Esto también generaría errores en otros problemas, bot necesariamente que el libro esté abierto. – cjk

+0

Sí, así que verifique el mensaje de error para ver si es el mensaje de error que está buscando, si no es simplemente volver a lanzar la excepción. – w69rdy

+0

Es la única forma en que puede hacerlo, a menos que tenga una mejor sugerencia ck ?? – w69rdy

0

Esto no es especialmente bueno, intentaremos abrir el archivo y examinar la excepción si falla. No estoy seguro de que tengas otras opciones en C#.

Sin embargo, es importante manejar solo la excepción correcta: básicamente tratamos de abrir el archivo sin compartirlo. Si falla, Y obtenemos el tipo correcto de excepción Y recibimos el mensaje correcto en la excepción, entonces sabemos que está abierto.

// open the file with no sharing semantics (FileShare.None) 
using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None)) 
{ 
    try 
    { 
     stream.ReadByte(); 
     return false; 
    } 
    catch (IOException ex) 
    { 
     // catch ONLY the exception we are interested in, and check the message too 
     if (ex.Message != null 
      && ex.Message.Contains("The process cannot access the file")); 
     { 
      return true; 
     } 

     // if the message was incorrect, this was not the IOException we were looking for. Rethrow it. 
     throw; 
    } 
} 

Obviosuly este tipo de enfoque es frágil con respecto al mensaje de excepción que se cambia en una versión futura de .Net. Es posible que desee complementar dicha funcionalidad con una prueba que bloquea deliberadamente un archivo y luego lo llama para verificar que detecta correctamente el mensaje.

+0

¡Eso no funciona fuera de un entorno inglés! –

0

Si tiene hoja de trabajo y libro en objetos que puede hacer cheque padres

si (== sheet.Parent libro)

1

Para cualquier persona interesada en un chiste que evita el uso de un try-catch .. .

bool wbOpened = ((Application)Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null; 

O con nombres completos ...

bool wbOpened = ((Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Microsoft.Office.Interop.Excel.Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null; 

Por supuesto, es posible que desee dividir esto un poco. El punto principal es usar LINQ en lugar de try-catch para verificar la existencia del libro de trabajo.

Nota 1:Marshal.GetActiveObject("Excel.Application") arrojará un error si no hay ninguna instancia de Excel abierta. Por lo tanto, a menos que se garantice o maneje de otra manera, esto siempre debe estar dentro de un try-catch.

bool wbOpened = false; 
try 
{ 
    wbOpened = ((Application)Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null; 
} 
catch 
{ 
... 
} 

Nota 2:Marshal.GetActiveObject("Excel.Application") sólo devolverá una instancia de Excel. Si necesita buscar cualquier instancia posible de Excel, entonces el siguiente código puede ser una mejor alternativa.


mejor alternativa

Si no te importa la adición de una clase de ayuda el código de abajo puede ser una alternativa mejor. Además de poder buscar cualquier instancia abierta de Excel, también le permite verificar la ruta completa y devolver el objeto real del libro si se encuentra. También evita lanzar un error si no se abre ninguna instancia de Excel.

uso

sería así ...

If (IsOpenedWB_ByName("MyWB.xlsx")) 
{ 
    .... 
} 

o

Workbook wb = GetOpenedWB_ByPath("C:\MyWB.xlsx") 
if (wb.obj == null) //If null then Workbook is not already opened 
{ 
    ... 
} 

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

public class WBHelper 
{ 
    public static bool IsOpenedWB_ByName(string wbName) 
    { 
     return (GetOpenedWB_ByName(wbName) != null); 
    } 

    public static bool IsOpenedWB_ByPath(string wbPath) 
    { 
     return (GetOpenedWB_ByPath(wbPath) != null); 
    } 

    public static Workbook GetOpenedWB_ByName(string wbName) 
    { 
     return (Workbook)GetRunningObjects().FirstOrDefault(x => (System.IO.Path.GetFileName(x.Path) == wbName) && (x.Obj is Workbook)).Obj; 
    } 

    public static Workbook GetOpenedWB_ByPath(string wbPath) 
    { 
     return (Workbook)GetRunningObjects().FirstOrDefault(x => (x.Path == wbPath) && (x.Obj is Workbook)).Obj; 
    } 

    public static List<RunningObject> GetRunningObjects() 
    { 
     // Get the table. 
     List<RunningObject> roList = new List<RunningObject>(); 
     IBindCtx bc; 
     CreateBindCtx(0, out bc); 
     IRunningObjectTable runningObjectTable; 
     bc.GetRunningObjectTable(out runningObjectTable); 
     IEnumMoniker monikerEnumerator; 
     runningObjectTable.EnumRunning(out monikerEnumerator); 
     monikerEnumerator.Reset(); 

     // Enumerate and fill list 
     IMoniker[] monikers = new IMoniker[1]; 
     IntPtr numFetched = IntPtr.Zero; 
     List<object> names = new List<object>(); 
     List<object> books = new List<object>(); 
     while (monikerEnumerator.Next(1, monikers, numFetched) == 0) 
     { 
      RunningObject running; 
      monikers[0].GetDisplayName(bc, null, out running.Path); 
      runningObjectTable.GetObject(monikers[0], out running.Obj); 
      roList.Add(running); 
     } 
     return roList; 
    } 

    public struct RunningObject 
    { 
     public string Path; 
     public object Obj; 
    } 

    [System.Runtime.InteropServices.DllImport("ole32.dll")] 
    static extern void CreateBindCtx(int a, out IBindCtx b); 
} 

I adaptado el método GetRunningObjects() en el código anterior de here.

0

La respuesta de Martin no funciona si la aplicación Excel no se está ejecutando actualmente. Es posible que desee modifiy el código de la siguiente manera:

static bool IsOpened(string wbook) 
{ 
    bool isOpened = true; 
    Excel.Application exApp; 

    try 
    { 
     // place the following line here : 
     exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"); 
     // because it throws an exception if Excel is not running. 
     exApp.Workbooks.get_Item(wbook); 
    } 
    catch (Exception) 
    { 
     isOpened = false; 
    } 
    return isOpened; 
} 

Gracias por su atención. Saludos

Cuestiones relacionadas