이번에는 DLL만들기에 도전해 보겠습니다.

간단하게
DLL은 클래스와 메서드를 제공하고, 실행중 연결되는 동적 연결 라이브러리 입니다. (Dynamic Linked Lybrary..맞나요? ㅋ)
실행파일과 내부 포멧은 같지만 진입점(Main같은녀석)이 없어서 혼자 실행은 안됩니다.
하지만 실행파일이나 다른 DLL에게 서비스를 제공하는 역할을 하죠
(때문에. 혹은 덕분에 여러명이 분담을 해서 여러 모듈을 만들고 통합해서 사용이 가능하겠죠)
DLL역시 형태만 다를뿐 어셈블리라는 면에서는 실행파일과 같습니다.

DLL, 실행파일 => 두개의 어셈블리로 구성된 프로그램을 만들어 볼께요.

먼저
파일 -> 새로만들기 -> 프로젝트 를 선택해서
템플릿에서 클래스 라이브러리를 선택합니다.
이름은 DLLTest로 할께요.

기본적으로 몇개의 using과 namespace가 있고.
기본으로 Class1이라고 코드가 만들어져 있지만.
Class는 지우고 새로 만들께요.
간단하게 덧셈과 뺄셈을 하는 메서드 두개를 정의했습니다.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace testDLL
{
    public class IntCalulator
    {
        public static int Add(int a, int b) { return a + b; }
        public static int Sub(int a, int b) { return a - b; }
    }
}

DLL이 외부로 공개할수 있는건
클래스, 구조체, 열거형, 인터페이스등인데 주로 클래스를 제공합니다.
C#은 완전 객체지향 언어이므로 메서드만 단독으로 제공할수는 없고
무조건 클래스를 통해서만 제공이 가능합니다.
(다 클래스 안에 때려 박아야겠죠. ㅠ)
꼭 필요한건 아니지만.
네임스페이스도 만들고. 클래스도 만들고
그 안에 Add와 Sub라는 메서드를 만들었습니다.

주의 할점은
외부로 공개할 클래스는 반드시 public이여야 한드는겁니다.(당연한소리죠)
(DLL내부에서만 쓰는 클래스라면 다르겠죠. (또 당연한... ))

이제 빌드를 하면 testDLL.dll이 만들어 집니다.

그럼 이제. 클라이언트 프로그램을 만들께요.
아예 다른 프로젝트를 만들어서 해볼께요.
파일 => 새로만들기 => 프로젝트 를 선택하고 콘솔응용프로그램을 만듭니다. 이름은 Client로 할께요.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using testDLL;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("5+5 = {0}", IntCalculator.Add(5, 5));
            Console.WriteLine("5-5 = {0}", IntCalculator.Sub(5,5));
        }
    }
}


이런 코드를 작성하고 나면
컴파일을 하고 자시고 할것도 없이
빨간줄이 쭉쭉 그어집니다.

testDLL을 using하긴 했지만.
이게 어디있는 놈인지. 진짜 있긴 한건지.
알수가 없으니 안되겠죠.

멍청한(--;;) 컴파일러에게 친절하게
testDLL이 어디 있는지를 가르쳐 줘야 합니다.
솔루션탐색기에서 참조란을 우클릭하고 참조추가를 한후
아까 만들어진 testDLL이 있는 위치를 찾아 추가를 해주면 되요.


그러면 빨간줄도 없어지고.
컴파일도 잘 됩니다.

testDLL은 참조추가를 해서 Client 프로젝트 디렉토리로 복사가 됐습니다.
client 프로젝트 폴더에서 찾아보면 다음과 같이 실제로 testDLL이 복사가 되어 있는걸 볼수 있어요.




 

by 피요히코~ 2009. 4. 29. 23:48
오늘은 미천한 저에게는 너무나 어렵고 난감하고. 헷깔리는 어셈블리에 대해 더 알아보겠습니다.

어셈블리란
- 응용프로그램을 구성하는 기본단위
- 배포, 설치, 버전관리, 보안권한 지정의 단위
  (exe나 dll같은 실행파일 하나를 칭하는 개념?)
- 기계어 코드와 1:1 로 대응되는 어셈블리와는 동음이의어일뿐!!

어셈블리는 크게 4가지로 구성됩니다.

 어셈블리 메타 데이터
 타입 메타 데이터
 MSIL코드
 리소스

위의 두개 메타데이터는 일종의 헤더이고
아래의 두개 코드와 리소스는 어셈블리의 실제내용입니다.
(이중 일부는 어셈블리의 종류에 따라 생략될 수 도 있습니다.)

어셈블리 메타데이터를 저장하는 장소를 매니페스트(Manifest, 지난번에 나왔었죠. 어려운말)라고 하는데
보통 어셈블리에 통합되 있지만 별도 파일에 둘수도 있습니다.

어셈블리에는
이름, 버전번호, 컬처, 강력한 이름, 파일 목록, 참조 타입, 참조하는 타입등의 기본정보 외에도
커스텀 어트리뷰트로 상표, 저작권, 개발사 등 추가정보를 더 넣을수도 있습니다.
때문에 레지스트리를 쓸 필요가 없는것이죠.


어셈블리를 스스로 설명 가능한 모듈이라 하는데 이는 자신의 모든 정보를 스스로 포함하고 있기 때문입니다.
 
역시나 저에게는 어셈블리는 너무나 멀고도 험한 개념인듯 해요. :(

by 피요히코~ 2009. 4. 29. 23:19
확장메소드에 대해 써볼께요.
MSDN에는 이렇게 나와있다고 하네요

확장 메서드는 형식으 ㅣ인스턴스 메서드인 것처럼 호출할수 있도록 형식과 연결된 수 있는
정적 메서드 입니다.
이 기능을 사용하면 실제로 기존 형식을 수정하지 않고도 기존 형ㅅ익에 새 메서드를 추가할수 있습니다.

Javascript에서도 이런 기능이 있죠.(Prototype)

C#에서는 IEnumerable<T> interface가 구현된 모든 타입에서 구현이 가능합니다.

간단한 소스를 봐보면요
    public static class MyExtensions
    {
        public static int wordCount(this string str)
        {
            return str.Length;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string s = "Extension Methods";
            Console.WriteLine(s.wordCount().ToString());
        }
    }

 

확장메서드의 가장 큰 장점(?) 은 원래 부터 정의되어 있는 메서드 처럼 사용할수 있다는거죠.
실제로 String에는 wordCount() 라는 메서드가 없잖아요.
근데 그냥 . 찍고 wordCount() 해주면 새로 정의한 메서드가 호출되는거죠.
(사용자가 사용하기가 참 편하겠죠)
차이가 있다면 인텔리센스에서 메서드표시 옆에 화살표가 표시되는것과
이름옆에 (확장)이라고 표시되는거죠.



라인1 부터 7 까지가 확장메서드 입니다.
간단하게 string값의 길이(length)를 반환하는 메서드를 작성했어요(출력값은 17 이에요)

MyExtentions 라는 정적 클래스를 선언하고 그 안에 wordCount라는 메서드를 선언했어요.
인수는 string 객체이며 this 키워드를 붙입니다.
여기서 this는 호출객체를 의미하는 참조자가 아니라 뒤의 클래스에 대한 확장메서드임을 의미하는
지정자에요.  wordCount가 string의 확장메서드라는 의미죠.

코드에서는 인수를 한개만 받았지만 실제로 인수는 제한이 없습니다.
두번째 인수부터는 실제 연산에 필요한 값들을 받으면 되는거죠.

(아무 의미가 없지만. --)string의 length에 특정 숫자를 붙인 int를 받는 메서드를 작성하고 싶으면


     public static class MyExtensions
    {
        public static int wordCount(this string str, int add)
        {
            return str.Length+add;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string s = "Extension Methods";
            Console.WriteLine(s.wordCount(5).ToString());
        }
    }


이렇게 해주면 되죠.(출력값은 17+5 해서 22가 나오겠죠?)

확장메서드는 인스턴스 메서드처럼 사용되지만 소속은 분명히 클래스 외부입니다.
그러므로(당연히) 확장하는 클래스의 숨겨진 멤버들에는 접근을 할수가 없어요.
그래서 확장 메서드로 클래스를 확장한다고 캡슐화를 위한바는것도 아니고.
보안상으로도 별 문제가 없다고 하네요.

by 피요히코~ 2009. 4. 26. 18:45
이번엔 익명형식이라는 녀석에 대해 알아볼께요.

익명형식은 이렇게 사용해요.

var anonyValue = new {Name = "피요히코", Age=30 };

아주 간단하죠?
이렇게 하면 내부적으로
이렇게 바꿔준다네요


internal class???
{
     string _Name;
     int _Age;
     public string Name
     {
          get{return _Name;} set {_Name = value;}
     }
     public int Age
     {
          get{return _Age;} set{_Age = value;}
     }
}

알아서 해주는거죠.
대신 이렇게 알아서 하기 위해서
compile시에는 느려지게 됩니다.
(complie때 알아서 알아서 하려면 어쩔수 었겠죠)

대신 컴파일 되고 나서는 성능에 대한 문제는 없다네요

이런 익명형식은
- 이름을 컨트롤 할수가 없어요. (complie시에 알아서 알아서)
- 항상 System.Object를 확장해요
- 필드와 프로퍼티는 항상 read-only에요
- 이벤트나 커스텀메소드등을 지원안해요.
- 항상 묵시적으로 selead에요(상속같은건 못해요)
- 항상 기본생성자를 사용해서 생성되요.


출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 13:56

토요일에 있었던 김수영MVP님의 교육을 다녀온 후에
좋은 내용을 너무 많이 듣고 와서
정리의 필요성을 느끼고 정리합니다. ㅋ
(수영님 다시한번 감사~ )

C# 3.0에서 새로 생긴 타입(?) 인 var는 Javascript에서 많이 보던 녀석이죠.
int나 string처럼 변수에 들어가는 녀석들의 종류가 미리 명시되는게 아니라
변수에 값이 대입되고 나서야 타입이 정해지는(맞죠? ;;;)
여러면서에 C#의 Object타입과도 비슷하지만.
다른녀석이죠

C#의 Object와 비교해 본다면
Object타입은 .NET에서의 모든 자료형은 Object를 상속받기 때문에
어떤형식도 Object에 넣을수는 있지만. Object는 타입을 추정할수가 없지요

예를들어서 제가

object objType = "초기화";
var varType = "초기화";

이런 코드를 작성했다고 할때

이 변수를 가지고 뭔가를 하려고 할때 . 을 찍어보면 차이가 확 나타나요




var 타입의 경우는
'이녀석이 string이구만~ ' 이라고 타입을 추정해서 인텔리센스세 string이 지원하는 메소드등등이 줄줄 보이는데요
object의 경우는 그렇지 않죠.
아주아주아주 기본적인 (이게 Object형식이면 모두 지원되는 메소드 겠죠?) 메소드 딸랑 4개만 보이네요.

또 다른 차이는
var타입의 경우는 Compile 때 타입을 검사하고 Object는 Runtime시에 검사를 한다는 겁니다.
이말은
var타입의 경우는 compile시에 타입이 확정되기 때문에
불필요한 boxing 이나 unboxing등이 생기지 않는다는거죠
compile때 이미
'이녀석은 int구나..'
혹은
'이녀석은 string이구나' 등이 정해지니
그럴일이 없겠죠.

또한 compile시에 타입을 검사하고 확정하기 떄문에 타입이 변경될수 없어요.
처음에 var타입에 숫자를 넣었다면 앞으로 그 변수에는 숫자만 넣어야 한다는거죠.

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 13:42
영어를 잘 못해서 그런건지.. (잘 해도 어려울꺼 같은)
메니페스트는.. 일단 말부터 너무 어려운거 같아요..

일단 메니페스트가 뭔지. (더불어 어셈블리가 뭔지 한번 정리를 해보죠... 제가 잘 몰라서.. )




네이뇬이 이렇게 가르쳐 주네요...
하지만 제가 원하는 대답은 아니네요..

이제 곧 영국으로 가버리는(이제 얼굴좀 익혔는데. ㅠ) 경훈씨가 HOONS에 올린 글을 보면..


.NET Assembly

닷넷을 어느정도 공부해본 사람들은 어셈블리(assembly)에 대한 말을 많이 듣게 되는데, 닷넷 어셈블리가 무엇인지, 어떻게 사용하는 것인지 한번 생각해 보도록 합시다.

 

어셈블리란 무엇인가

1. 어셈블리는 코드들의 논리적인 묶음이다.

2. 어셈블리는 물리적으로 DLL또는 EXE로 존재한다.

3. 한 개의 어셈블리는 한 개이상의 파일을 포함할 수 있다.

4. 어셈블리안에는 어떤 형태의 파일도 포함될 수 있다(예: 텍스트 파일, 이미지파일등)

5. 작성된 소스코드가 어셈블리로 묶여지지 않다면, 다른 어플리케이션에서는 이용할 수가 없다.

6. 어셈블리파일엔 자체정보를 가지고 있는데 이를 어셈블리 메니페스트(Manifest)라 한다.

 

어셈블리 메니페스트(manifest) 대해

1. 어셈블리 메니페스트는 해당 어셈블리의 정보들을 저장하고 있는 데이터 구조(data structure)이다.

2. 이러한 정보는 어셈블리 파일(DLL/EXE) 자체에 포함되어 있다.

3. 메니페스트는 버전정보나, 구성된 파일의 리스트등을 포함하고 있다.

 

Private assembly VS Shared assemly

단일 어플리케이션에만 사용되는 어셈블리를 private assembly라 한다. 예를 들어서, 여러분이 업무로직을 가지고 있는 DLL을 하나 만들었다면, 그리고 DLL을 사용하는 클라이언트 어플리케이션이 오직 한 개이라면, 그것은 대부분 private assembly인 것이다. 이 때 프로그램이 제대로 동작되기 위해서는 프로그램이 설치된 같은 폴더에 DLL이 존재해야만 한다. 

이와 반대로, 만약 하나의 DLL을 만들고 나서 이를 여러 어플리케이션에서 사용하도록 만들었다면, 각 어플리케이션의 해당 폴더마다 복사본이 존재하는 것이 아니라, DLL을 Global Assembly Cache에 위치시켜야만 한다. 이러한 어셈블리를 shared assembly라 한다.

 

Global Assembly Cache ?

GAC(Global Assembly Cache)는 모든 shared assembly가 저장되는 특정 폴더일 뿐이다.

이 폴더의 위치는 <드라이브명>:/winnt/assembly 이다. 실제 이 폴더에 들어가보면, 많은 전역 어셈블리들을 볼 수 있다.

 

어셈블리는 DLL 지옥을 해결하였다는데

앞에서 언급했듯이 직접 작성한 대부분의 어셈블리는 private이다. 그러므로 각 어플리케이션은 자체적으로 설치된 폴더에 있는 어셈블리를 참조한다. Private형식에서는 같은 이름의 여러버전이 있다하더라도 충돌을 피할 수 있다.

이해를 돕기위해 한가지 예를 들어본다.

1. Assembly1이라는 이름의 어셈블리를 제작한다.

2. Assembly1을 이용하는 Client1이라는 어플리케이션을 만든다.

3. 클라이언트 프로그램을 c:\MyApp1이라는 폴더에 설치하고, Assembly1도 이 폴더에 설치한다.

4. 며칠이 지난 후에 Assembly1이 수정이 되었다고 가정한다.

5. 수정된 Assembly1을 이용한 클라이언트 어플리케이션(Client2)를 제작한다.

6. 이 클라이언트 프로그램을 c:\MyApp2라는 폴더에 설치하고 Assembly1도 이 폴더에 설치한다.

7. 각각의 프로그램은 같은 이름의 Assembly1이라는 어셈블리를 사용하고 있지만, 버전은 서로 다른 것이며, 아무 문제없이 충돌없이 동작된다.

 

여기까지는 Private Assembly의 예를 든것이다. 이처럼 어셈블리는 각각의 폴더에 설치되어 있기 때문에 직접 변경이 되지 않는 한 버전변경에 영향을 받지 않는다고 할 수 있다. 그럼 이번에는 Shared 어셈블리에 대해 알아보겠다. 이 경우에서는 버전이 매우 중요하다. 버전번호는 다음과 같은 형태로 생성된다.

major.mino,build.revision

만약 어셈블리에 변경을 가했을 경우, major, minor버전이 같다면 변경된 어셈블리는 기존 것과 호환된다고 할 수 있다. 만약 클라이언트 프로그램에서 어셈블리의 사용을 요청하게 되면, major,minor버전이 맞는 것중에서 가장 최근의 build와 revision을 갖는 어셈블리가 제공된다.

 

Shared Aassembly 만드는 

1. DLL/EXE를 제작할 소스코드를 준비한다.

2. SN 유틸리티를 이용하여 유니크(unique)한 어셈블리명을 생성한다.

3. AssemblyInfo 파일을 수정하여 private key를 서명한다.

4. DLL/EXE를 컴파일한다.

5. 생성된 DLL/EXE를 GACUTIL 유틸리티를 이용하여 global assembly cache에 위치시킨다.

이렇게만 하면, shared 어셈블리가 작성이 된다. 그러면 한가지씩 자세하게 알아보도록 하자.

 

Unique Assembly Name 생성법

마이크로 소프트에서는 어셈블리의 유일성을 보장하기 위해서 public-private key(공개키/개인키)기반의 로직을 이용한다. 이 공개키/개인키의 짝(pair)은 SN.EXE 라는 유틸리티를 이용해서 생성한다.(SN은 shared name의 의미를 갖고있다) 여러가지 다양한 옵션이 있지만, 일반적인 syntax는 다음과 같다.

sn -k 생성될 파일명

k는 키(key)를 생성하겠다는 의미이며, 이를 실행하면 파일이 하나 생성된다.

 

전자서명

어셈블리를 shared cache에 위치시키기 위해서는, sn유틸리티를 이용해서 만든 키를 이용하여 서명을 해야한다. 이 때 서명에 관련한 정보들을 담는 특별한 파일이 AssemblyInfo파일이다. AssemblyInfo 파일에 다음을 추가한다.

<Assembly: Assemblykeyfile("파일명")>

 

Global Assembly Cache에 등록하기

GACUTIL /i my_dll.dll

이렇다고 하네요. 아주 깔끔하게 정리가 잘 되어있네요. ㅎㅎ
(원본은 개발자가 알아두면 좋은 ASP.NET 지식 (어셈블리) 405 0 minotech@join )

자 그러면 어셈블리의 메니페스트에 저장되는 정보에는 어떤것이 있는지 보죠..

Assembly name : 어셈블리의 이름을 나타냅니다.

Versioning information :  이녀석은 4개의 부분으로 되어있고, 버전넘버가 저장되어 있습니다. 개정및 빌드넘버/ major 버전넘버와 minor 버전넘버도 포함되어 있어요

An (optional) shared name and signed assembly hash : 여긴 어셈블리 배포정보가 있어요.

Files : 어셈블리에 있는 모든 파일의 목록이 있습니다.

Referenced assemblies : 메니페스트의 어셈블리에서 직접 참조하는 모든 외부 어셈블리 목록이 있습니다.

Types : 타입이 저장되어있는 모듈과 매핑된 어셈블리의 모든 타입에 대한 목록이 포함되 있습니다. 
         
Security permissions : 어셈블리에서 명시적으로 거부된 보안사용권한(permission)의 목록입니다

Custom attributes : 타입에 따라 사용자정의(custom) 어트리뷰트는 리플렉션시 빠르게 접근하기 위해서 어셈블리의 메니페스트에 저장됩니다.

Product information Company, Trademark, Product, Copyright 값도 저장되어 있습니다




짧은 지식으로 지금 일을 하고 있지만
역시나 알아야 할것(인지는 모르겠지만ㅎㅎ)이 참 많네요.
부지런해야 겠습니다.

by 피요히코~ 2009. 4. 24. 00:34
아주 간단한 소스코드를 빌드를 하고
IL DASM로 불러들였습니다.

namespace insideCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("OTZ");
        }
    }
}


정말 간단한 소스네요....

이걸 IL DASM으로 불러들이면


이렇게 보입니다.
여기서 두번째 줄에 있는 MANIFEST를 더블클릭하면 어셈블리 정보를 설명하는
메타데이터 정보를 볼수가 있어요

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly insideCSharp
{
  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                              00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 0C 42 6C 61 63 6B 45 64 69 74 69 6F 6E 00   // ...BlackEdition.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 1E 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright ..
                                                                                                  42 6C 61 63 6B 45 64 69 74 69 6F 6E 20 32 30 30   // BlackEdition 200
                                                                                                  39 00 00 )                                        // 9..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 64 63 37 31 35 34 62 61 2D 30 30 65 34   // ..$dc7154ba-00e4
                                                                                                  2D 34 33 62 31 2D 61 30 30 61 2D 34 36 62 32 61   // -43b1-a00a-46b2a
                                                                                                  35 62 37 64 32 33 36 00 00 )                      // 5b7d236..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..

  // --- 다음 사용자 지정 특성이 자동으로 추가됩니다. 주석 처리를 제거하지 마십시오. -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )

  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module insideCSharp.exe
// MVID: {8A57E23A-CCB3-4592-9075-A79E5D701B7F}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x03F60000

참 기네요..
이걸 처음봤을때는(지금도 물론) 눈앞이 캄캄하네요....
가뜩이나 가로로 쭉쭉 늘어선 글을 붙여넣으니 당췌 뭐가뭔지 모르겠네요...

여기서 첫번째 블럭은 외부어셈블리를 참조하는데 사용되는 .assembly 레코드입니다.

어셈블리의 가장 큰 장점중 하나는 버전관리가 가능하다는 것... 이라고 하는데요. 아직 저에게는 그다지 와닿지 않는 내용입니다. --ㅋ
제가 컴파일한 insideCSharp  어셈블리는 mscorlib 어셈블리의 2.0.0.0 버전을 사용하고 있다네요.

두번째 블럭은 이 어셈블리에 대한 정보를 포함하고 있습니다.
책에서 본 바로는 명시적으로 빌드 프로세스중에 버전 넘버를 지정하지 않으면 0.0.0.0 이라고 하는데
왜 저는 1.0.0.0 인걸까요.........

책이 version 2003이니.. 바뀐걸수도 있겠고. 제가 모르는 무언가가 있는지도 모르겠네요... ㅠ
위에 노란블럭안을 보면 몇가지 어트리뷰트가 나와 있는데요.
위의 어트리뷰트에 대한 내용들은 공부가 더 진행된후에 다시 언급하도록 할께요.
(그나저나 책에서는 Debug쪽 어트리뷰트만 나오더니. 제꺼에서는 상당히 많은 어트리뷰트가 보이는군요....
 책과 다르면 매우 난감한데요....)

다음으로는 클래스의 생성자를 볼께요. (6번째줄의 .ctor : void() 를 더블클릭하면 나와요)

.method public hidebysig specialname rtspecialname
        instance void  .ctor() cil managed
{
  // 코드 크기       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method Program::.ctor

첫째줄에서 두번째줄까지는 단순히 메소드가 public이고, specialname, rtspecialname 어트리뷰트의 특징을 나타냅니다.
이러한 특정 메서드에 대한 코드는 CLI(Common Language Infrastructure)에 대한 의미를 가지고 있다고 하네요.
cil managed 어트리뷰트는 managed 메서드라는 걸 의미합니다.

메소드는 처음으로 Idarg라는 opcode를 통해 인자를 스택으로 로드합니다.
Idarg 다음의 '0'은 첫번째 인수를 뜻합니다.
두번째 call 이라는 opcode는 System.Object를 호출하는데 사용됩니다.
마지막 ret opcode는 단순히 호출메소드로 컨트롤을 반환한다고 하네요.
(코드는 쉬운데. 이놈은 어렵네요....)

이번에는 Main 메소드가 어떻게 생겼는지 볼죠..

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 코드 크기       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "OTZ"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::Main
위에서 한번 보고 나니.
조금 눈에 들어오네요

하지만 책과 또 다른!!!!
IL_0000과 000b의 nop은 뭐하는 녀석일까요...

나머지 녀석들은 위랑 비슷한데 말이죠..
Idstr은 문자열 OTZ를 스택에올려주고.
call을 사용해서 System.Console::WriteLine을 불러냅니다.

문자로된 문자열을 넘겨도. 이 값은 실제로는 System.String 클래스의 인스턴스입니다.(문자니깐요)



IL DASM으로 내부정보를 보면
개발자가 알아야할 지식을 갖추는데도 도움이 되고
개발 생산성도 높일수 있을것이라고 하니(책에서... 실제로는 어떨지 아직 모르겠군요.. 도움이 되긴 하겠죠..)
앞으로 이 녀석과 친해질수 있도록 많이 노력해야 겠네요..
by 피요히코~ 2009. 4. 24. 00:17
책을보고 공부를 하던중
ILDASM을 직접 실행해보고 싶어서 따라해봤지만.
도저히 찾을수가 없더라구요.

PATH를 등록해도. 계속 없다고 나오길래
해당폴더에 갔더니. 파일이 없더라구요.

그래서 다운을 받아보려고 했지만.
350MB정도인데. 다운로드시간이 40분....

ILDASM을 해보려고 삽질한지 한시간이 훌쩍 넘어서 시간은 1시가 넘어고.
'에잇! 안해!!' 하고 책을 덥고

혹시나 하는 마음에
시작 - 프로그램 을 뒤지는데.


IL 디스어셈블러....

책이. version 2003임을 감안해서 찾아봤어야 하는건데...
OTZ

실행해서 해보니. 잘 되더군요.(당연하겠지.....)


두둥.... ㅠㅠ
by 피요히코~ 2009. 4. 23. 23:43
일단
.NET의 가장 중요한 두가지 특징에 대해 살펴보면
1. 모든 .NET언어가 동일한 .NET 기능에 엑세스 한다는것
2. 다양한 언어로 작성된 코드가 밀접하게 상호 운용된다는 점


이런 기능을 지원하는 일등공신은 MSIL인데, .NET 컴파일러는 소스코드등을 통해 Windows PE가 아닌 MSIL을 생성한다

MSIL의 등장으로 .NET 응용프로그램은 표준적이고 공통적인 포맷으로 컴파일되므로
일관성있게 .NET 런타임 환경에서 운용된다.

.NET 응용프로그램을 컴파일하고 실행할때 어떤일이 발생할까?

1. .NET 언어를 사용해 소스코드를 작성
2. 소스코드는 컴파일되 EXE파일로 작성
3. .NET 컴파일러는 MSIL 코드와 메니페스트를 생성하고 이 정보를 EXE의 한부분으로 포함시킨다.
    .NET 컴파일러가 생성하는 EXE는 기타 EXE와 마찬가지로 표준 PE헤더를 포함하고 있다.
    (메니페스트는 .NET 바이너리의 내용과 런타임 요구사항에 대한 정보를 포함하고 있다.
     메니페스트는 .NET 바이너리 파일에 저장되는 정보를 언급한다. )
4. (가장중요한단계) 컴파일러가 산출물을 생성할 때 .NET 런타임에서 _CorExemail이라는 이름의 함수를 임포트 한다.
5. 사용자가 응용프로그램을 실행하면 운영체제는 PE파일과 관련된 DLL 파일들을 로드한다.
    이 DLL 중에는 _CorExeMail 함수가 정의되어 있는 mscoree.dll 파일들이 포함된다.
    이 파일은 모든 .NET PE 파일이 실행될때 로드된다.
6. 운영체제 로더는 PE내 진입점(entry point)으로 점프한다.(휘릭~) 모든 PE는 Windows에서 이런 프로세스에
   따라 진행된다.
7. 운영체제에서 MSIL 코드를 실행할 수 없기 때문에 진입점은 mscoree.dll의 _CorExeMail으로 점프하는
   루틴에 불과하다.
8. _CorExeMail 함수는 컴파일러에서 PE에 놓아 둔 MSIL코드를 실행한다.
9. MSIL코드는 직접 실행될수 없다.(실행가능한 형식이 아니므로. )
    따라서 CLR에서 JIT 컴파일러를 사용해 MSIL을 CPU전용 명령어로 컴파일한다.
    JIT 컴파일러에서 컴파일할 때 프로그램의 메서드로만 호출되며, 컴파일된 실해오드는 시스템에 임시로
    저장되고 소스코드가 별경될때만 재컴파일 된다.

출처 : INSIDE C#
by 피요히코~ 2009. 4. 22. 23:54
protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
ArrayList arrColumn = new ArrayList();
DataSet ds = null;
ds = getDBData
arrColumn.Add(CreateBoundColumn("code_title", "구분"));
arrColumn.Add(CreateBoundColumn("dlscnt", "제정"));
arrColumn.Add(CreateBoundColumn("dlrcnt", "개정"));
arrColumn.Add(CreateBoundColumn("dltotcnt", "Total"));
arrColumn.Add(CreateBoundColumn("lscnt", "제정"));
arrColumn.Add(CreateBoundColumn("lrcnt", "개정"));
arrColumn.Add(CreateBoundColumn("ltotcnt", "Total"));
arrColumn.Add(CreateBoundColumn("scnt", "제정"));
arrColumn.Add(CreateBoundColumn("rcnt", "개정"));
arrColumn.Add(CreateBoundColumn("totcnt", "Total
string fileName = "order" + DateTime.Now.ToString("yyyyMMdd") + ".xls";
SaveAsExcel(ds, arrColumn, "", fileName); } private void SaveAsExcel(DataSet dsResult, ArrayList columns, string subject, string fileName) { if (fileName.Equals(null) && fileName.Equals("")) fileName = DateTime.Now.ToString("yyyyMMdd") + ".xls"; System.Web.HttpContext.Current.Response.Buffer = true; DataGrid dgExcel = new DataGrid(); dgExcel.ShowHeader = true; dgExcel.Caption = subject; dgExcel.AutoGenerateColumns = false; foreach (object column in columns) dgExcel.Columns.Add((BoundColumn)column); dgExcel.HeaderStyle.BackColor = Color.FromName("powderblue"); dgExcel.HeaderStyle.HorizontalAlign = HorizontalAlign.Center; dgExcel.HeaderStyle.Height = 25; dgExcel.HeaderStyle.Font.Bold = true; dgExcel.DataSource = dsResult; dgExcel.DataBind(); System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8)); System.Web.HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("euc-kr"); System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + ";charset=euc-kr"); System.Web.HttpContext.Current.Response.ContentType = "application/unknown"; ////////////////////////////////////////////////////////// /// 한글이 깨지는 경우 web.config의 globalization을 euc-kr로 바꿔주세요. ////////////////////////////////////////////////////// System.Web.HttpContext.Current.Response.Write(""); dgExcel.EnableViewState = false; System.IO.StringWriter sWriter = new System.IO.StringWriter(); System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(sWriter); dgExcel.RenderControl(htmlWriter); System.Web.HttpContext.Current.Response.Write(sWriter.ToString()); System.Web.HttpContext.Current.Response.End(); dgExcel.Dispose(); } public BoundColumn CreateBoundColumn(string DataFieldValue, string HeaderTextValue) { // Create a BoundColumn. BoundColumn column = new BoundColumn(); // Set the properties of the BoundColumn. column.DataField = DataFieldValue; column.HeaderText = HeaderTextValue; return column; } public BoundColumn CreateBoundColumn(string DataFieldValue, string HeaderTextValue, string FormatValue, HorizontalAlign AlignValue) { // Create a BoundColumn using the overloaded CreateBoundColumn method. BoundColumn column = CreateBoundColumn(DataFieldValue, HeaderTextValue); // Set the properties of the BoundColumn. column.DataFormatString = FormatValue; column.ItemStyle.HorizontalAlign = AlignValue; return column; }
by 피요히코~ 2009. 4. 17. 14:40
| 1 2 3 4 |