문제


질문

내 질문은 다음과 같습니다. C#은 후반에 늦은 바인딩 IDISPATCH를 지원합니까?


인 척하다 고객이 설치 한 버전과 호환되는 동안 사무실을 자동화하려고합니다.

.NET World에서 Office 2000 설치로 개발 한 경우, 모든 개발자 및 모든 고객은 지금부터 시간이 끝날 때까지 Office 2000을 가져야합니다.

.NET 이전의 세계에서 우리는 사용했습니다 com 사무실 신청서와 대화합니다.

예를 들어:

1) 버전 Independent Progid를 사용하십시오

"Excel.Application"

다음으로 해결됩니다.

clsid = {00024500-0000-0000-C000-000000000046}

그런 다음 COM을 사용 하여이 클래스 중 하나가 개체로 인스턴스화하도록 요청합니다.

IUnknown unk;
CoCreateInstance(
    clsid, 
    null,
    CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    IUnknown, 
    out unk);

그리고 이제 우리는 경주에서 벗어났습니다 - 내 응용 프로그램 내부에서 Excel을 사용할 수 있습니다. 당연하지 만약 진짜 객체를 사용하려면 전화 방법이 있어야합니다.

우리 ~할 수 있었다 다양한 것을 얻으십시오 상호 작용 우리의 언어로 번역 된 선언. 이 기술은 우리가 얻기 때문에 좋습니다

  • 초기 바인딩
  • 코드 안내
  • 유형 구문 검사를 컴파일합니다

코드는 다음과 같습니다.

Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;

그러나 인터페이스 사용의 단점이 있습니다. 우리는 다양한 인터페이스 선언을 받아야하며 언어로 전환해야합니다. 그리고 우리는 메소드 기반 호출을 사용하여 모든 매개 변수를 지정해야합니다.

ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);

이것은 실제 세계에서 우리가 기꺼이 포기할 그러한 단점을 가지고 있음을 증명했습니다.

  • 초기 바인딩
  • 코드 안내
  • 시간 구문 확인을 컴파일합니다

대신 사용합니다 Idispatch 늦은 바인딩 :

Variant xl = (IDispatch)unk;
Variant newWorksheet = xl.Worksheets.Add();

Excel Automation은 VB 스크립트 용으로 설계되었으므로 오버로드가없는 경우에도 많은 매개 변수를 획득 할 수 있습니다.

메모: idispatch를 사용하고 싶은 이유와 Excel의 예제를 혼동하지 마십시오. 모든 com 객체가 탁월한 것은 아닙니다. 일부 COM 객체는 idispatch를 통한 것 외에는 지원이 없습니다.

도움이 되었습니까?

해결책

상대적으로 C#에서 늦은 바인딩 Idispatch 바인딩을 사용할 수 있습니다.

http://support.microsoft.com/kb/302902

Excel을 사용하기위한 샘플이 있습니다. 이렇게하면 Microsoft의 Bloaty PIA에 불필요한 종속성을 추가 할 필요가 없습니다.

//Create XL
Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

//Get the workbooks collection.
//   books = xl.Workbooks;
Object books = xl.GetType().InvokeMember( "Workbooks", 
      BindingFlags.GetProperty, null, xl, null);

//Add a new workbook.
//   book = books.Add();
Objet book = books.GetType().InvokeMember( "Add", 
      BindingFlags.InvokeMethod, null, books, null );

//Get the worksheets collection.
//   sheets = book.Worksheets;
Object sheets = book.GetType().InvokeMember( "Worksheets",
      BindingFlags.GetProperty, null, book, null );

Object[] parameters;

//Get the first worksheet.
//   sheet = sheets.Item[1]
parameters = new Object[1];
parameters[0] = 1;
Object sheet = sheets.GetType().InvokeMember( "Item", 
      BindingFlags.GetProperty, null, sheets, parameters );

//Get a range object that contains cell A1.
//   range = sheet.Range["A1];
parameters = new Object[2];
parameters[0] = "A1";
parameters[1] = Missing.Value;
Object range = sheet.GetType().InvokeMember( "Range",
      BindingFlags.GetProperty, null, sheet, parameters );

//Write "Hello, World!" in cell A1.
//   range.Value = "Hello, World!";
parameters = new Object[1];
parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, 
      null, range, parameters );

//Return control of Excel to the user.
//   xl.Visible = true;
//   xl.UserControl = true;
parameters = new Object[1];
parameters[0] = true;
xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty,
      null, xl, Parameters );
xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty,
      null, xl, Parameters );

다른 팁

당신은 당신이 찾고있는 늦은 바인딩을 얻기 위해 C# 4.0이 나올 때까지 기다려야합니다. 인터롭 기능이 필요할 때마다 VB.NET 모드로 다시 전환하여 C#이 부족한 것으로 보이는 COM 기능을 활용할 수 있습니다.

내가 사용하는 간단한 방법은 vb.net에서 idispatch 작업을 수행하는 클래스를 작성한 다음 래퍼의 메소드로 사용하려는 메소드를 노출 한 다음 C# 코드에서 마음대로 호출 할 수 있습니다. 가장 우아한 솔루션은 아니지만 지난 몇 개월 동안 잼에서 두 번 떨어졌습니다.

C# 4 dynamic 키워드는 Idispatch 및 늦은 바인딩을 지원합니다. Sam Ng 's를 읽을 수 있습니다 동적 시리즈 자세한 내용은

아, 그리고 C# 4는 오늘 CTP로만 제공됩니다. Visual Studio VNEXT를 기다리거나 베타 (Windows Server 2008 Virtual PC에서 실행되는 베타)를 사용하여 사용해야합니다.

아마도 C# 2.0/3.0에서 훨씬 더 좋은 코드로 도망 갈 수있을 것입니다. 객체에 원하는 메소드와 속성이 포함 된 인터페이스를 작성하고 일부 속성을 추가하는 데 시간이 걸리면 메모리에서 글을 쓰지 않으므로 세부 사항이 아닙니다. 맞아, 나는 그것이 나를 위해 일했다고 맹세한다 ...)

    using System.Runtime.Interopservices;

    [Guid("00024500-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    interface IExcel
    {
      // sample property
      string Name{get;}
      // more properties
    }

    // and somewhere else
    void main()
    {
      Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
      IExcel excel = (IExcel)xl;
      string name = xl.name
    }

언급했듯이 코드는 상자에서 작동하지 않으며 MSDN에서 무엇을 파는지 더 힌트입니다.

다른 사람들이 말했듯이 C#4의 "동적"키워드 암석을 사용합니다. 간단한 예는 다음과 같습니다.

dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
dynamic books = xl.Workbooks;
dynamic book = books.Add();

Console.WriteLine(books.Count);     //Writes 1

foreach (dynamic b in books)        
{
Console.WriteLine(b.Name);      //Writes "Book1"
}

이봐,이 문제를 해결하기 위해 현재 2 개의 코드 플렉스 프로젝트가 있습니다.

첫 번째는 LateBindingApi.excel입니다 http://excel.codeplex.com잘 알려진 객체 모델로 호출을 호출하는 맵핑. 이것은 다음 프로젝트의 테스트 프로젝트였습니다.

두 번째는 CodeGenerator입니다 http://latebindingapi.codeplex.com이 도구는 COM 유형 라이브러리에서 C# 프로젝트를 만듭니다. 생성 된 프로젝트에는 Latebind가 COM 서버에 액세스하는 맵퍼 객체가 포함됩니다. 하이라이트는 도구가 다른 버전의 Libs를 하나의 단일 프로젝트 (예 : Excel 9,10,11)로 변환하고 모든 엔티티를 자체 정의 된 supportBylibrary 속성으로 표시 한 것입니다. 이 도구를 사용하여 버전 9,10,11,12,14의 모든 사무실 앱을 분석하고 메인 페이지에서 샘플 코드로 테스트 된 베타로 사용할 수있는 AC# 솔루션을 생성했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top