2010-07-01 5 views

답변

12

올바른 방법은 Application.Workbooks 개체를 검사하는 것입니다. VBA에서는 작성합니다 즉

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 

는 통합 문서가 배열을 (또는 VBA 조건, 컬렉션에) 열려있는 모든 통합 문서의.

는 C#에서 다음과 같은 코드가 작동합니다

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; 
    } 

당신은 아마 자신이 Excel.Application에 대한 참조를 전달하려는 것입니다.

+0

내 친구 고맙습니다. – Rabin

+1

C# 버전이 현재 나를 위해 작동하지 않습니다. 항상 예외를 발생시키고 false를 반환합니다. w69rdy 솔루션이 나를 위해 트릭을했습니다. –

+0

Excel.Application에 대한 참조는 무엇입니까? – Devid

8

이 시도 :

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

    s.Close(); 

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

이 독점적으로 파일을 열 tryand 것입니다. 파일이 이미 열려 있으면 예외를 throw하여 닫고 시도를 계속할 수 있습니다.

+0

이것은 또한 다른 문제에 대한 오류를 발생시킬 수 있으며 반드시 통합 문서가 열려 있어야합니다. – cjk

+0

예, 오류 메시지를 확인하여 해당 오류 메시지가 단순히 예외를 다시 발생시키지 않으면 찾고있는 것인지 확인하십시오! – w69rdy

+0

더 좋은 제안 ck가 없다면 그걸 할 수있는 유일한 방법은 ?? – w69rdy

0

이것은 특히 좋지 않습니다. 우리는 파일을 열어보고 실패 할 경우 예외를 검사 할 것입니다. C#에서 다른 선택 사항이 있는지 확신하지 못합니다.

그러나 올바른 예외 만 처리하는 것이 중요합니다. 기본적으로 공유를 허용하지 않고 파일을 열어 봅니다. 실패한 경우 올바른 유형의 예외를 가져오고 예외가 발생하면 올바른 메시지를받습니다. 그러면 해당 메시지가 열려 있음을 알 수 있습니다.

// 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 이런 종류의 접근법은 .Net의 추후 릴리스에서 변경 될 예외 메시지와 관련하여 취약합니다. 이러한 기능을 의도적으로 파일을 잠그는 테스트로 보완하고이 파일을 호출하여 메시지를 올바르게 검색했는지 확인할 수 있습니다.

+0

영어 환경 밖에서 작동하지 않습니다 !! –

0

당신이 워크 시트를 가지고 통합 문서를 개체를 경우 부모를 체크합니다

을 할 수있는 경우 (sheet.Parent == 통합 문서) 시도 - 캐치를 사용 방지 한 라이너에 관심있는 사람들을위한

1

.. .

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

또는 정규화 된 이름을 가진

...

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; 

물론, 이것을 조금씩 나눌 수도 있습니다. 요점은 try-catch 대신 LINQ를 사용하여 통합 문서의 존재 여부를 확인하는 것입니다.

참고 1 :Marshal.GetActiveObject("Excel.Application")은 Excel의 인스턴스가 열려 있지 않으면 오류가 발생합니다. 달리 보장되거나 처리되지 않는 한 항상 try-catch 내에 있어야합니다.

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

주 2 :Marshal.GetActiveObject("Excel.Application") 만의 Excel에서 하나 개의 인스턴스를 반환합니다. Excel의 가능한 인스턴스를 검색해야 할 경우 아래 코드가 더 나은 대안 일 수 있습니다.


더 나은 대안

당신이 헬퍼 클래스를 추가 괜찮다면 아래의 코드가 더 나은 대안이 될 수 있습니다. 열려있는 Excel 인스턴스를 검색 할 수있는 것 외에도 전체 경로를 확인하고 실제 통합 문서 개체가 있으면 반환 할 수도 있습니다. 또한 Excel 인스턴스가 열리지 않으면 오류가 발생하지 않습니다.

사용은


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); 
} 

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

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

또는

나는 here에서 위의 코드에서 GetRunningObjects() 방법을 적용 ... 이렇게 될 것입니다.

0

Excel 응용 프로그램이 현재 실행되고 있지 않으면 martin의 대답이 작동하지 않습니다. 당신은 다음과 같은 코드를 modifiy 할 수 있습니다 :

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; 
} 

이 관심을 가져 주셔서 감사합니다. 감사합니다

관련 문제