출처 : http://blog.tobegin.net/38  / Writer by 정은성

 

 회차
[C# 4.0] New Features in C# : 01. C# Programing Trend
[C# 4.0] New Features in C# : 02. C# 4.0 Overview
[C# 4.0] New Features in C# : 03. Dynamically Typed Objects #1 : DLR
[C# 4.0] New Features in C# : 04. Dynamically Typed Objects #2 : Dynamic Lookup
[C# 4.0] New Features in C# : 05. Optional and Named Parameters
[C# 4.0] New Features in C# : 06. Com-specific interop features
[C# 4.0] New Features in C# : 07. Covariance and Contravariance

 
06| COM특성 상호운용 개선사항

 
(COM-Specific Interop. Improvements)

구독자 여러분 안녕하세요

이번 다뤄볼 내용은 바로 COM특성 어떻게 향상 되었는지 개선사항에 대해 알아보도록 하겠습니다.

COM은 소프트웨어 컴포넌트를 통합을 위해서 표준화된 인터페이스로  다양한 언어로 만들어 다른 소프트웨어와 공유를 할수 있도록 이진 레벨을 구성하고 있습니다. 대중화된 OS인 윈도우에서도 굉장히 많이 사용하고 있는데요.


흔히 오피스 오토메이션 프로그래밍을 할때 Office API에 관련된 PIA를 등록하여 실행 때마다 PIA에 맵핑되는 타입으로 형변환을 해주어야하며 성능상으로 좋지 않았습니다.

C# 4.0에서는 가져온 PIA 형식 정보 대신 포함된 형식 정보를 응용 프로그램에 포함시켜 배포를 할수 있게 되었습니다.
코드를 보시면서 살펴보도록 하겠습니다.

[코드 1] COM-Specific Interop Sample Fx4 이하
var missing = System.Type.Missing;
Excel.Workbook workBook =
                             excel.Workbooks.Open("filename.xlsx",  missing, missing, missing, missing,
                             missing, missing, missing, missing, missing, missing, missing, missing, missing,missing);             Excel.Worksheet workSheet =  (Excel.Worksheet)workBook.ActiveSheet;

 지금보시는 코드[코드 1]는 MS 오피스 프로그램의 오토메이션 되는 코드 조각입니다.
코드를 보시면 단순히 시트 하나를 Open 할 뿐인데 코드가 매우 복합한데다가 알 수 없는 타입과 함께 작성을 해줘야 하는 모습을 볼 수 있습니다. 전체 코드 작성된 기준으로 본다면 WorkSheet를 포함하여 ExcelApplication.WorkBook등 모두 기술을 했다면 코드가 생각보다 길어질것입니다.

또한 코드가 길어지는건 두번째로 볼때 코딩을 작성하다보면 도대체 이 인수가 어떻게 사용되는지 모를 뿐만 아니라 사용하지 않는 파라메터에 대해서는 ref 처리를 해줘야하는 불편한 개발을 할 수 밖에 없었는데요.
기존 VB개발자시라면 " 아 불편해!!! " 라고 생각이 드실겁니다.

그렇다면 Com 상호운용성이 어떻게 개선이 됬는지 확인 해보도록 하겠습니다.

[코드 2] COM-Specific Interop Sample Fx4
Excel.Workbook workBook = excel.Workbooks.Open("filename.xlsx“);
Excel.Worksheet workSheet =workBook.ActiveSheet;

와우 많고 불필요한 코드들이 단 두 줄로 줄어들었습니다. Option Parameters기능을 활용하여 정말 간소화 된 모습을 볼 수 있는데요. 어떤 내용들이 개선이 되었는지 스펙을 확인해보도록 하겠습니다.

* COM 상호 운용의 개선된 사항 
- Automatic Object -> dynamic mapping
- Optional and Named Parameters
- Indexed properties
- Optional “ref” modifier
- PIA embedding (“NO-PIA”)

COM 상호운용성이 위와 같이 개선이 되었습니다. 우선 Automatic Object 방법이 Dynamic mapping으로 변경이 되었고
Optional and named Parameters 기능이 지원함으로써 메소드가 간소화 된 모습을 볼수 있습니다.이 말은 이전에 사용하지 않던 매개변수에 대해서 ref missing을 처리를 해주었는데요. 이제는 사용을 안하셔도 된다는 이야기입니다. 그리고 기존의 오피스 프로그래밍을 하시다보면 PIA라는 인터페이스의 정의를 참조하여 호출을 하였고 어떤 인터페이스를 사용 할지 알수 없었기 때문에 형변환을 해줘야하는 지져분한 코드를 사용해야 만 했었고 더구나 성능상으로 좋지 않았습니다.

이제는 컴파일 타임에서 PIA를 직접적으로 사용하지 않으셔도 됩니다. PIA형식 정보를 응용프로그램에 포함 시키는 기능이 새롭게 추가 되었습니다. 즉, 해당 어셈블리에 대해서 옵션을 지정 할 수 있는데요.
Embed introp Type 을 지정해주므로써 필요한 PIA 인터페이스를 코드에 삽입하므로써 COM 객체와 좀더 퍼펙트한 상호 운용이 가능하게 되었습니다.

그럼 간단한 코드를 통해서 알아보도록 하겠습니다.

[코드 3] COM-Specific Interop Sample Fx4 이하
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

namespace HelloFx4_3_OfficeAutomaticSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var excel = new Excel.Application();
            excel.Workbooks.Add(Type.Missing);
            excel.Visible = true;
            ((Excel.Range)excel.Cells[1, 1]).Value2 = "Process Name";
            ((Excel.Range)excel.Cells[1, 2]).Value2 = "Memory Usage";
            var processes =
                    from p in Process.GetProcesses()
                    orderby p.WorkingSet64 descending
                    select p;
             int i = 2;
             foreach (var p in processes.Take(10))
            {
                ((Excel.Range)excel.Cells[i, 1]).Value2 = p.ProcessName;
                ((Excel.Range)excel.Cells[i, 2]).Value2 = p.WorkingSet64;
                i++;
            }
            Excel.Range range = (Excel.Range)excel.Cells[1, 1];
            Excel.Chart chart = (Excel.Chart)excel.ActiveWorkbook.Charts.Add(
                                                  Type.Missing, excel.ActiveSheet, Type.Missing, Type.Missing);             
            chart.ChartWizard(
                range.CurrentRegion,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                "Memory Usage in " + Environment.MachineName, Type.Missing,
                Type.Missing, Type.Missing);

                chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
                                           Excel.XlCopyPictureFormat.xlBitmap,
                                           Excel.XlPictureAppearance.xlScreen);
            var word = new Word.Application();
            word.Visible = true;
            var missing = Type.Missing;
            word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
            word.Selection.Paste();
        }
    }
}

[코드 3-1] (코드3) 코드 조각
var excel = new Excel.Application();
excel.Workbooks.Add(Type.Missing);
excel.Visible = true;

((Excel.Range)excel.Cells[1, 1]).Value2 = "Process Name";
((Excel.Range)excel.Cells[1, 2]).Value2 = "Memory Usage";


코드를 보시면 excelApplication를 인스턴스화 하여 위에 WorkBooks를 추가하였고 셀 1,1과 1,2에 문자열을 대입하였습니다. 

[코드 3-2] (코드3) 코드 조각
var processes =
    from p in Process.GetProcesses()
    orderby p.WorkingSet64 descending
    select p;
int i = 2;
foreach (var p in processes.Take(10))
{
    ((Excel.Range)excel.Cells[i, 1]).Value2 = p.ProcessName;
    ((Excel.Range)excel.Cells[i, 2]).Value2 = p.WorkingSet64;

    i++;
}

그리고 현재 컴퓨터의 운영중인 프로세스를 조회한 다음 링큐와 enumable 타입을 사용하여 각 셀에 바인딩하는 모습도 볼수 가 있습니다. 다음으로는 차트 생성 메소드를 활용하여 차트를 생성하고 새로운 워드 문서에 차트 이미지를 복사를 하는 데이터 플로우 입니다.

[코드 3-3] (코드3) 코드 조각
Excel.Chart chart = (Excel.Chart)excel.ActiveWorkbook.Charts.Add(
Type.Missing, excel.ActiveSheet, Type.Missing, Type.Missing);

chart.ChartWizard( range.CurrentRegion, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
"Memory Usage in " + Environment.MachineName, Type.Missing, Type.Missing, Type.Missing);

chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
      Excel.XlCopyPictureFormat.xlBitmap,
      Excel.XlPictureAppearance.xlScreen);

var word = new Word.Application();
word.Visible = true;
var missing = Type.Missing;
word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
word.Selection.Paste();

지금부터 개선된 특징을 적용 시켜야 할텐데요. 우선 그 대상이 무엇인지 살펴보면서 코드를 변경 해보도록 하겠습니다.
여러분들은 코드 3-1, 3-2, 3-3에서 블록 처리 되어 있는 코드를 살펴보시면 됩니다.

우선 [코드3-1]에 workbook에 Add 메소드에 매개변수가 그 변경 대상이 되며 다음으로는 형변환을 포함하여 Value2 프로퍼티가 변경 대상이 되며 다음과 같이 수정을 할 수 있습니다.

[코드 4-1] (코드 3-1)을 Fx4 특징으로 변경 
var excel = new Excel.Application();
excel.Workbooks.Add(Type.Missing);
excel.Workbooks.Add();
excel.Visible = true;

((Excel.Range)excel.Cells[1, 1]).Value2 = "Process Name";
((Excel.Range)excel.Cells[1, 2]).Value2 = "Memory Usage";

excel.Cells[1, 1].Value = "Process Name";
excel.Cells[1, 2].Value = "Memory Usage";


[코드3-2]에서 foreach문 내부의 range 부분도 또한 다음과 같이 수정이 가능합니다.

 [코드 4-2] (코드3-2)을 Fx4 특징으로 변경 
var processes =
    from p in Process.GetProcesses()
    orderby p.WorkingSet64 descending
    select p;
int i = 2;
foreach (var p in processes.Take(10))
{
    ((Excel.Range)excel.Cells[i, 1]).Value2 = p.ProcessName;
    ((Excel.Range)excel.Cells[i, 2]).Value2 = p.WorkingSet64;

    excel.Cells[i, 1].Value = p.ProcessName;
    excel.Cells[i, 2].Value = p.WorkingSet64;

    i++;
}

[코드3-3] 차트에서도 형변환을 포함하여 Add 메소드에 매개변수인  missing, activeSheet, Missing, Missing 인자들도 그 변경 대상이 됩니다. 표현하고자 하는 데이터는 두번째 매개변수이며 파라미터 명칭을 찾아보시면 After이름을 가졌네요.

[그림 1] (코드3-3) Charts.Add 인첼리스트

[코드 4-3] (코드3-3)을 Fx4 특징으로 변경
Excel.Chart chart = (Excel.Chart)excel.ActiveWorkbook.Charts.Add(
Type.Missing, excel.ActiveSheet, Type.Missing, Type.Missing);

Excel.Chart chart = excel.ActiveWorkbook.Charts.Add(After: excel.ActiveSheet);


코드를 다시 내려다 보시면 알수 없는 타입이 선언 되어 있는데요.
(Type.Missing, Type.Missing, Type.Missing, Type.Missing....)  이 코드 또한 변환 대상이 됩니다.

똑같이 적용을 해보면 다음과 같습니다.

[코드 4-4] (코드3-3)을 Fx4 특징으로 변경
chart.ChartWizard( range.CurrentRegion, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
"Memory Usage in " + Environment.MachineName, Type.Missing, Type.Missing, Type.Missing);
chart.ChartWizard(Source: range.CurrentRegion, Title: "Memory Usage in " + Environment.MachineName);

[그림 2] (코드3-3) chart.ChartWizard 인첼리스트



다시 아래 코드를 보시면 새로운 워드 문서를 추가하는 코드를 볼수 있습니다.
missing 타입을 ref 형태로 전달을 하기에 이것 또한 변경을 해줘야겠죠?

[코드 4-5] (코드3-3)을 Fx4 특징으로 변경
var word = new Word.Application();
word.Visible = true;
var missing = Type.Missing;
word.Documents.Add(ref missing, ref missing, ref missing, ref missing);

word.Documents.Add();

word.Selection.Paste();

이렇게 코드를 다시 정리를 해보면 다음과 같습니다.
[코드 5] COM-Specific Interop Sample Fx4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

namespace HelloFx4_3_OfficeDynamicMappingSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var excel = new Excel.Application();
            excel.Workbooks.Add();
            excel.Visible = true;
            excel.Cells[1, 1].Value = "Process Name";
            excel.Cells[1, 2].Value = "Memory Usage";

            var processes =
                    from p in Process.GetProcesses()
                    orderby p.WorkingSet64 descending
                    select p;

            int i = 2;
            foreach (var p in processes.Take(10))
            {
                excel.Cells[i, 1].Value = p.ProcessName;
                excel.Cells[i, 2].Value = p.WorkingSet64;
                i++;
            }

            Excel.Range range = excel.Cells[1, 1];
            Excel.Chart chart = excel.ActiveWorkbook.Charts.Add(After: excel.ActiveSheet);

            chart.ChartWizard(Source: range.CurrentRegion, Title: "Memory Usage in " + Environment.MachineName);

            chart.CopyPicture(Excel.XlPictureAppearance.xlScreen,
                   Excel.XlCopyPictureFormat.xlBitmap,
                   Excel.XlPictureAppearance.xlScreen);

            var word = new Word.Application();
            word.Visible = true;

            word.Documents.Add();
            word.Selection.Paste();
        }
    }
}

정리를 하였지만 아직 PIA 인터페이스를 응용 프로그램에 포함시키지 않았습니다.

내장하려면 참조되고 있는 어셈블리어 Excel, word, Core등의 어셈블리어를 선택하시고 프로퍼티에 Embed Interop Type 옵션을 True로 변경 해야합니다. 

[그림 3] Embed Interop Type 설정


이렇게 True로 설정하게 되면 컴파일 타임에서 등록해야하는 레지스터리를 사전에 코드에 내장을 하여 불필요한 타입 패턴을 일치 하실 필요가 없으며 런타임 시점에서 dynamic mapping을 하게 됩니다.

[소스 참고]Hello .NET Framework 4 세미나[세션3] 발표자료와 소스 : 
http://blog.tobegin.net/35

참고 문헌
1. PDC2008 : The Future of C# - Anders Hejlsberg
    :
http://channel9.msdn.com/pdc2008/TL16/

2. New Features in C# 4.0 - Mads Torgersen, C# Language PM, April 2010
    :
http://msdn.microsoft.com/ko-kr/vcsharp/ff628440(en-us).aspx
3. 방법: Visual C# 2010 기능을 사용하여 Office Interop 개체에 액세스(C# 프로그래밍 가이드)
    :
http://msdn.microsoft.com/ko-kr/library/dd264733.aspx


포스팅을 마치며...

짧게 리뷰를 해보았는데요. 어떠셨는지 모르겟어요 ^^;
제법 강력해졌다라고 표현을 해드리고 싶습니다. 또한 NO-PIA 옵션으로 하위 버전에서 해당 구문이 실행이 가능하다는 사실 잊지마시구요 이제 NO-PIA 옵션을 활용 해보세요 : )

더 궁금하신점이 있으시면 댓글 혹은
http://blog.tobegin.net/notice/1 프로필정보를 통해 문의 바랍니다.

다음 포스팅은 공변성과 반공변성(Co-Variance and Contra-Variance)에 대해서 살펴보도록 하겠습니다.
감사합니다.

정은성 드림


PS. 이번주는 태풍이 온다네요. 우산 꼭 챙기세요 ^ㅁ^
 
출처 : http://blog.tobegin.net/38  / Writer by 정은성
Posted by Sting!

댓글을 달아 주세요