PROGRAMMING WORKSHOP

VB.Net | Assembly To COM dll

윈도우의 시스템화일에 들어가면 dll확장자의 화일이 산같이 쌓여있다
언놈을 하나 잘못 지웠다가는 여러분의 컴퓨터에서는
어떤 일이 벌어질지 모른다
엑셀프로그램이 깔려있는 폴더를 찾아 들어가도 DLL화일이
좌악깔려있다..
언놈 하나 지웠다가는 엑셀이 버벅거림을 보장받을 것이다
엑셀프로그램을 실행한다고 할때
엑셀이 갖고 있는 모든 자원을 메모리에 띄우지 않는다
모든 프로그램은 개체지향적이라고 했다..
엑셀을 작업하다가 어떤 메뉴명령을 주면 갑자기 속도가
뻐~~어하게 속도가 떨어지는 경우가 있을 것이다
이것은 엑셀이 갖고 있는 개체군단중에서 아직 실행되지 않고 있던..
즉 메모리(환경시스템이 엑셀에 할당한 메모리)중에 해당
개체는 아직 올라오지 않았던 상태였기 때문이다
이렇게 여러개의 DLL화일은 해당프로그램에게 필요한 개체
--하나의 DLL화일에는 여러개의 개체들이 있을수도 있고
하나의 개체만 있을수도 있고..--
필요한 개체만 메모리상에 올라오게 되는 것이다
무식하게 한꺼번에 몽땅 올라오지 않는다
또한 엑셀이 참조하고 있는 DLL을 오피스전반에서 공통으로
사용하고 있는 것도 있을 것이다
예를 들면 메뉴같은 것은 생김새도 똑같고 하는짓도 같은 것이 많은데
별도로 만들 필요가 없지 않은가..???
그래서 나누어서 공동으로 사용하게 되는 것이 있기도 하고
또 윈도우시스템의 DLL을 사용하게 되는 것도 있는 것이다
DLL..이름 그대로 Dynamic Link Library 인 것이다
필요할때 동적으로(Dynamic) 연결되어서(Link) 기능을
제공하는 라이브러리화일(Libray)인 것이다

이런 라이브러리를 조합하여 하나의 목적하는 프로그램이 되는 것이다
그러니..다른 사람들이 이미 만들어 놓은 것을 잘 활용,응용하는것이
또한 프로그래밍인 것이다

그런데 이 Win32를 프렛폼으로 하여 만드는 COM dll은 이제
Traditional COM ...전통적인..예전에 사용하던 COM
Classic COM...고전적 COM (component 부속품)등등으로 불린다
그러나..사용하는 사람들은 많고..이것이 대세였던 것이고..
.Net FrameWork가 나오게 된 것은 위의 것들의 단점들을
보완하려고 만들어진 새로운 프렛폼인 것이다
COM 라이브러리의 가장 큰 골칫거리는

1)Versioning(버전의 관리) 문제인 것이다

프로그램은 계속개선되고 확장되고 발전한다
같은 이름의 프로젝트로 개발되는 라이브러리는 버전이 업그레이드 된다
이때 이 버전의 관리상의 충돌이 말씀이 아닌 것이다
흔히 그들이 말하는
the most common versioning problem is what we call DLL Hell
가장 일반적인 버전상의 문제는 [DLL 지옥]이라고 부른다..
라고 할 정도로 머리를 쥐어짜고..헷갈림의 극치가 된다는 것이였다
예를 들어서 어떤 DLL화일을 A라는 프로그램에서도 사용하고(Shared Components)
B라는 프로그램에서도 사용하게 될때..
B라는 프로그램이 업그레이드 했다..
그런데 A라는 프로그램은 아직 업그레드하고 자시고 할 입장이 아니다
서로 다른 상황이 되었는데 같은 DLL화일을 사용하고 있었다면
지옥인 셈이다
A를 만든 사람이 B를 만든 사람에게 ..우리 DLL이 버전이 업글되었으니
바꾸시지요..라고 할수도 없고..
세상 모든 사람이 퍼서 사용하는데..어떻게 알리고 자시고 하겠는가??
이렇게 공통으로 사용하는 DLL은 시스템 Register에 등록되고
상호 호출 사용하는 것이였다
또한 어떤 웹에서 ActiveX콘트롤을 다운로드 받았다
이 콘트롤(이것도 하나의 DLL)이 같은 종류의 것을 버전을 확바꿔버렸다고
치자..그러면 이미 깔려있던 다른 프로그램이 이전 버전을 사용하고
있었다면..갑자기 작동이 되지 않을 가능성도 있게 되는 셈이다

어떻게 하면 프로그램들이 독립적이면서 이런 버전의 충돌에서
피할까..고민중의 하나였던 것이다

2)또한 배포와 설치(Deploying and Installation)에 있어서

셋업화일로 설치가 시작되면 이런 저런 화일을 설치하면서
필요한 DLL을 System Registery 데이타베이스에 설치하고
(COM dll을 나누어서 사용하는 것을 기본으로 하다 보니
통합적인 관리를 하여야 하고 이것을 시스템데이타관리장소인
Registry에서 하게 되는 것이고..)
등등 다양한 분산된 정보를 하나의 프로그램에서 갖게 되어
관리하는데 애로가 많게 되는 것이다
어떤 경우에는 손으로(Manually) Registery등에 기록을 하여야
하는 불편함도 생기고...프로그램을 제거할때
관련된 것을 모두 깨끗히 제거를 못하고 쓰레기등이 이 곳,저 곳에
쌓여버리게 되는 경우도 있게 되는 셈이다

이런 상황을 개선하기 목적중의 하나가 .Net FrameWork이 나타나게 되는 것이고

요약하면
Zero-impact(충격제로)
No registry entries are made on the machine.
각자의 PC 에 Registtry기록을 남기지 않는다

Incremental download(필요한 부분만 추가적 다운로드).
Pieces of an assembly are downloaded only as they are referenced.
해당 Assembly를 접근할때마 추가된 사항이 기록된 Assembly화일을 다운로드한다
Download isolated to the application(다운로드된 것들은 독립적이다).
Code downloaded on behalf of one application cannot affect others on the machine.
어떤 프로그램을 위하여 다운 받는 코드들은 PC상의 다른 프로그램에 영향을 주지 않는다

VBA서라도 많은 코딩을 해 본 경험이 있다면
아마도 어떤 변수들은 일반모듈에 주욱 기록하고
이것을 이곳 저곳의 프로시져에서 참조를 하기도 하고
그러다 보니 이것을 참조하고 있던 어떤 프로시져에서 참조하고 있던 변수를
자신의 프로시져만 생각하고 바꾸어 버리면(대개가 어떤 변수가 어디,어디에
관련이 되어있는지 복잡해지면 관리하기가 복잡해진다..)
이것을 참조하고 있던 다른 프로시져들은 졸지에 변을 당하게 된다

그래서 또..
프로시져단위로 변수관리를 하고 프로시져단위에서 모든 것을 결정하게 한다
다른 곳을 참조하지 않도록 한다..
라고 방법을 바꿀수도 있고....
이런 것과 같은 것이다

그래서 독자적인 자체 프로그램에만 영향을 주는 dll을 만들게 되고
이 dll은 기존의 win32의 dll과 전혀 다른 컨셉이 되는 것이다
.Net을 기반으로 하는 dll을 Assembly라고 부른다
아주 오래된 프로그래밍언어인 어셈브리언어와는 전혀 관계가 없는
그냥 Assembly인 것이다
이 말이 의미하는 것은 .Net dll화일에 대한 족보가 한곳에 모여있다는 것을 말한다
이 dll은 누가 만들었고..
이 dll은 버전이 현재 몇번째이고..
이 dll의 인증관련 정보는 이러..저러하고
이 dll의 만든 날짜는 어떻고..
이 dll이 참조하고 있는 .Net자원은 어떤..어떤 Assembly이고..
등등의 관련된 기본정보(메타데이타)가 자체적으로 하나의 화일로
Assemble 되어 있다고 하여 Assembly인 것이다
시스템 Registry에 등록하고 자시고 하지 않는다
그래서 Registry지옥에서 벗어나게 한것이 .Net 기반의 dll즉 Assembly화일인것이다
독립적인 것이다..
이 놈도 쓰고 ..저놈도 쓰고하지 않는 다는 것이 기존의 win32기반의 dll, activeX와
다른 개념인 것이다

그래서 얼마전에 어느분의 질문..
.Net 에서 만든 dll을 Excel에서 외부 Com라이브러리 참조로
참조할수 없나요??
라는 것에 대한 답이다...안됩니다!!! 가 답인것이다

그럼 대개가..에이!@!#@ 할수 있지만 자원은 나우어 쓰라고
있는 것이니..
.Net Assembly를 Com으로의 변환이라는 문제가 나오게 되는 것이다
독립적이면서 나누어 쓰게..independent but sharing together...
정말 많은 자원을 들여서 COM dll을 만들었는데 버리면 안된다
이것을 .Net 기반에서도 참조하여야 하고
.Net기반에서 만든 것도 Win32기반의 것에서도 참조하여 사용하여야 한다..
그렇다면 기존으로 사용하던 COM 시스템의 프로그램은
.Net FrameWork에서 개발한 라이브러리를 어떻게 접근하게 만들 것인가??
가 이 페이지에서 이야기 하게 되는 것이다
쉽게 말해서 엑셀에서 COM라이브러리 참조하듯이
.Net FrameWork에서 만든 라이브러리를 엑셀에서도 참조하게 할수 없냐는
이야기다..
COM라이브러리는 System Registery에서 기록된 것들만 나타나게 된다
즉 여러분의 VBA편집기의 참조창에 나타나는 COM dll은
Registery에 등록된 것만 나타나게 되는 것이다

또한 .Net FrameWork 에서 만든 라이브러리를
관리형코드(Managed Code)라고 하고
COM 라이브러리는 비관리형 코드(Unmanaged Code)라고 하는데 이는 또 뭔소린가??
관리형은 좋아보이고 비관리형은 나빠보이나..?
그것이 아니고..
여러분의 컴퓨터에 깔린 .Net FrameWork의 CLR(common language runtime)에
의한 관리가 되는 것을 관리형코드라고 그냥 부르는 것이고
.Net FrameWork의 CLR이 상관하지 않는 기존의 것은 비관리형이 되는 셈이다
위에서 열나 떠들어도..뭔가 전달이 잘 되지 않은 기분이 든다
열나떠드는 것 보다는 한장의 그림이 더 좋을 것이다
아래와 같다고 보시면 그림이 잡힐 것이다



아무튼..
.Net FrameWork에서 만든 크래스라이브러리를 COM(component object model)과
같이 나타나게 해보도록 하자..
이것을 만드는데는 Visual Studio Tools For Office (VSTO)는 필요없다
그냥 VisualStudio의 크래스라이브러프로젝트를 만들면 된다

먼저 크래스라이브러리를 만들때는 어떤 내용을 만들 것인지
잘 생각해 보아야 할 것이다
아무튼 그것은 각자가 알아서 할 일이고
여기에서는 어떻게 만들면 COM라이브러리 사용하듯아 하느냐의 문제이니까..
그냥 간단하게..
크래스라이브러리 프로젝트를 만드는 것이니까..
소류션창에는 크래스모듈하나 달랑 만들어 지고 ..이것을 열고
아래와 같이 작성하고

Public Class UNO_COM Sub SayHello() MsgBox("Assembly화일을 Com에서 사용하도록 합니다") End Sub Function ReverseString(ByVal sX As String) Dim iLen As Integer = Len(sX) Dim sTemp As String = "" For iX As Integer = iLen To 1 Step -1 sTemp += Mid(sX, iX,1) Next Return sTemp End Function ReadOnly Property MyComupterName() As String Get Return My.Computer.Name End Get End Property End Class

위와 깉이 크래스이름을 짓고 해당 크래스에
SayHello라는 프로시져 하나와 ReverseString이라는 함수 하나
그리고 읽기 전용의 MycomputerName이라는 속성을 쌤플로 하나 만들었다 치고

그런데 위의 Class모듈달랑하나 들어 있는 것을 디버깅 실행을
시키고 싶은데..
어디서 저 개체를 생성하고 함수를 읽어 볼수있을까???!!!
아래와 같이 프로젝트속성창을 열고 Debug탭에서
디버그할때 외부실행화일을 엑셀로 지정해준다



디버깅실행을 하면 엑셀이 열릴 것이다
그러면 이 프로젝트에서 만든 크래스라이브러리를
VBA편집창에 들어가서 참조메뉴에서 라이브러리를 참조하면 될 것 같은데..
안될 것이다..
왜냐면 위에서 지금까지 떠든 .Net Assembly화일과 COM라이브러리는
다르다고 한 이야기때문에 아무것도 되는 것이 없다
화일찾기로 위의 프로젝트의 화일이 들어 있는 폴더에 들어가서
위의 크래스모듈을 담고 있는 dll화일을 참조시키면
아래와 같이 메시지가 뜬다



COM용 라이브러리가 아니라는 소리다

몇가지 설정을 해보자

아래의 그림과 같이 프로젝트속성대화상자의
Application 탭에서 Assembly Information버튼을 크릭하면>br /> 해당 Assembly의 기본정보가 들어 있는 창이 나오고 이대화상자의
맨밑의 Maek Assembly COM-Visible을 체크해주고
또..다른 하나는
Compile탭에서 Register COM Interop을 체크해주고



디버깅 실행을 하면 엑셀이 열리고 엑셀의 VBA편집기에서
도구/참조를 보면 해당 Assembly이름이 나타난다
그래서 아래의 그림과 같이 참조 시키고
테스트프로시져를 작성하고
프로시져내에 oX라는 개체생성을 위에서 만든 Assembly로
만들었는데..
이때
asCOMSample.UNO_COM 이라고 해주어야 한다
참조상의 리스트..asCOMSample이라는 이름은
디폴트로 만들어진 네임스페이스이고
개체를 만들어주는 크래스가 아니다...
쩜 찍으면 해당 크래스가 나타난다..여기에서는 UNO_COM이라는
크래스명...



oX라는 변수로 개체를 생성했는데 개체가 갖고 있는
메소드나 속성들이 나타나지 않는다..

물론 기억하고 있는 프로시져명을 붙여 넣고 하면

Dim oX As New asCOMSample.UNO_COM
MsgBox oX.reversestring("this is com test")

당연히 실행이 되지만..
Assembly를 COM자원에 나타나게 하고 사용할수 있게 하는데까지는
성공한 것이다
그러나..
개체가 갖고 있는 자원의 목록이 나타나지 않으면
얹찮다!!!
어떻게 하면 엑셀에서 개체변수를 사용하면 해당개체의
자원의 목록이 자동으로 나타나게 할 수 있을까?
아래의 그림과 같이



이제 크래스모듈상에서 무언가 조치를 해주어야 한다

크래스모듈 선언부에 아래와 같이 사용할 .Net FrameWork를
Import시키고

Imports System.Runtime.InteropServices Imports WIN32 = Microsoft.Win32

.Net FrameWork의 Runtime의 InteropServices이 갖고 있는
크래스들의 역할이 필요해진다
InteropServices라고 하는 것은 말 그대로
Inter Operation Service인 셈이다
.Net Assembly와 Win32 의 COM모델간의 대화를 담당하는 것들이
몰려 있는 셈이다..
...
...

***[LOG-IN]***



메소드나 속성의 목록에 작성하지 않은 메소드등이 나타나는 것은
개체지향의 3가지(상속,Inheritance|다형성,Polymorphism|캡슐화,Encapsulation)중의
상속(Inheritance) 을 통하여 모든 크래스의 바탕이 되는 Base Class의 것을
나타내는 것..
VBA의 크래스모듈은 위의 3가지중 Encapsulation만을 구현하는
약식의 크래스모듈인 셈이다