성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>닷넷 System.ComponentModel.LicenseManager를 이용한 라이선스 적용</div> <br /> 찾아보니, 다음과 같은 글이 눈에 띄는군요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Licensed Applications using the .NET Framework ; <a target='_tab' href='http://www.codeguru.com/columns/experts/article.php/c5469'>http://www.codeguru.com/columns/experts/article.php/c5469</a> </pre> <br /> 구현 방식은 예상외로 무척 간단했습니다. 라이선스를 걸어 보호하려는 클래스가 있다면 아래와 같이 LicenseProvider 특성을 걸어주고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > [LicenseProvider(typeof(MyLicenseProvider))] public class Class1 { public Class1() { LicenseManager.Validate(typeof(Class1), this); } } </pre> <br /> 다음으로, LicenseProvider를 우리가 구현해 주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public class MyLicenseProvider : System.ComponentModel.LicenseProvider { public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) { return null; } } </pre> <br /> GetLicense 내의 코드 구현은 그야말로 천차만별이라고 보면 되겠습니다. 중요한 것은, 라이선스가 올바르다고 판단이 되면 GetLicense 메서드에서 License 개체(추상 클래스이므로 그것을 상속받은 개체)를 반환해주면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 위의 글에서 보면 닷넷 BCL에서 기본 제공되는 LicFileLicenseProvider를 설명해 주고 있는데요. 이건 매우 간단한 거라서, 해당 클래스가 라이선스가 걸린 것임을 나타내는 정도로만 쓰일 뿐 어떤 강제적인 수단을 동원하는 것은 아닙니다. 이 때문에, LicFileLicenseProvider로 보호된 클래스가 있다면 실행 파일과 같은 위치에 "{네임스페이스를 포함한 클래스 이름}.lic"라는 파일명을 두는 것으로 '라이선스 검사'에 통과할 수 있습니다.<br /> <br /> 제가 테스트 한 예제를 기준으로 한번 살펴볼까요?<br /> <br /> 우선, 다음과 같은 예제 클래스를 두고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > ===== CommercialLibrary 라이브러리 프로젝트의 Class1.cs 파일 내용 ===== namespace <b style='COLOR: blue'>CommercialLibrary</b> { <b style='COLOR: blue'>[LicenseProvider(typeof(LicFileLicenseProvider))]</b> public class <b style='COLOR: blue'>LicFileLicensedClass1</b> { public LicFileLicensedClass1() { License lic = <b style='COLOR: blue'>LicenseManager.Validate</b>(typeof(LicFileLicensedClass1), this); if (lic == null) { Console.WriteLine("lic == null"); } else { Console.WriteLine(lic); } } public void Do() { Console.WriteLine("licensed library is activated!"); } } } </pre> <br /> 이런 경우, CommercialLibrary.dll을 사용하는 ConsoleApplication1.exe 측에서는 다음과 같은 이름의 lic 파일을 exe 파일과 같은 폴더에 두어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > CommercialLibrary.LicFileLicensedClass1.lic </pre> <br /> 그리고, 그 파일의 내용에는 "{네임스페이스를 포함한 클래스 이름} is a licensed component." 같은 형식의 문자열이 포함되어 있어야 합니다. 예제에서는 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > CommercialLibrary.LicFileLicensedClass1 is a licensed component. </pre> <br /> 보시는 것처럼, 다소 허무하긴 하지만 LicFileLicenseProvider 파일은 상속이 가능하고 IsKeyValid와 GetKey 메서드를 재정의할 수 있기 때문에 약간의 부가적인 코드만 구현해 준다면 상용 라이브러리를 보호하기 위한 어느 정도의 기준은 만족시킬 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 상용 컴포넌트를 사용해 보신 분들은 lc.exe 컴파일러와 친숙하실 텐데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > System.ComponentModel.LicenseException (MSBuild의 lc.exe 빌드 과정 생략) ; <a target='_tab' href='http://www.sysnet.pe.kr/2/0/518'>http://www.sysnet.pe.kr/2/0/518</a> 64비트 OS에서의 ChartFX 라이선스 문제 ; <a target='_tab' href='http://www.sysnet.pe.kr/2/0/537'>http://www.sysnet.pe.kr/2/0/537</a> </pre> <br /> 기왕 여기까지 온 김에, 그동안 무심코 써왔던 lc.exe에 대해 "<a target='_tab' href='http://www.codeguru.com/columns/experts/article.php/c5469'>Licensed Applications using the .NET Framework</a>" 글을 통해서 이해를 해보는 것도 좋겠지요.<br /> <br /> 사실, lc.exe를 굳이 사용하지 않아도 상관없습니다. 위에서 설명한 것처럼 lic 파일을 실행 파일과 같이 두는 것은 그리 어려운 일이 아니기 때문입니다. 문제는, lic 파일에 2개 이상의 구성요소 정의가 불가능하다는 데 있습니다. 즉, 라이선스를 걸어놓은 구성 요소 10개를 사용중이라면 10개의 lic 파일들이 exe 파일과 동일한 폴더에 배포되어야 한다는 약간의 불편함 정도가 있는 것입니다.<br /> <br /> 바로 이런 문제를 해결하기 위해 lc.exe를 사용합니다. lc.exe를 이용하면 라이선스 정보를 '하나의 파일에 여러개 정의하는 것'이 가능하고, 게다가 그렇게 정의된 파일을 어셈블리 내의 리소스로 포함하는 것이 가능합니다. 즉, 배포할 때 lic 파일들이 전혀 필요없고 오로지 exe 파일 하나만을 복사하는 것으로 끝낼 수 있다는 장점이 있습니다.<br /> <br /> lc.exe 실행 방법을 알아보기 위해 MSDN 도움말을 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > License Compiler (Lc.exe) ; <a target='_tab' href='https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-2.0/ha0k3c9f(v=vs.80)'>https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-2.0/ha0k3c9f(v=vs.80)</a> </pre> <br /> /complist 옵션에 주는 파일(ConsoleApplication1Lic.txt)의 내용을 다음과 같이 구성하도록 설명하고 있는데요. (바로 이 파일 내에 여러 개의 구성 요소를 지정해 주는 것이 가능합니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > CommercialLibrary.LicFileLicensedClass1, CommercialLibrary.dll </pre> <br /> 그리고, 위의 파일에 들어가는 구성요소에 대한 lic 파일(이 예제에서는 CommercialLibrary.LicFileLicensedClass1.lic)이 exe 파일과 같은 폴더에 있어야 합니다.<br /> <br /> 애석하게도 그렇게 모든 준비를 마치고, 실제로 실행해 보면 다음과 같은 식으로 LC0003 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > D:\...[생략]...\bin\Debug><b style='COLOR: blue'>lc /target:ConsoleApplication1.exe /complist:ConsoleApplication1Lic.txt /i:CommercialLibrary.DLL</b> Microsoft (R) .NET License Compiler [Microsoft .Net Framework, Version 4.0.30319.225] Copyright (c) Microsoft Corporation. All rights reserved. Processing complist 'ConsoleApplication1Lic.txt'... ConsoleApplication1Lic.txt (1) : <b style='COLOR: blue'>error LC0003 : Unable to resolve type 'CommercialLibrary.LicFileLicensedClass1, Commerc ialLibrary.DLL'</b> </pre> <br /> 이거 원인 찾느라고 엄청난 시간을 소비했는데요. ^^; 아래의 예제에 소개된 것을 보고서야 오류를 바로 잡을 수 있었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > .NET Licensing ; <a target='_tab' href='http://windowsforms.net/articles/Licensing.aspx'>http://windowsforms.net/articles/Licensing.aspx</a> </pre> <br /> 즉, ConsoleApplication1Lic.txt 파일의 내용에서 DLL 확장자를 지정해서는 안되는 것이었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > CommercialLibrary.LicFileLicensedClass1, <b style='COLOR: blue'>CommercialLibrary</b> </pre> <br /> 아래는 실행 결과입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > D:\...[생략]...\bin\Debug><b style='COLOR: blue'>lc /target:ConsoleApplication1.exe /complist:ConsoleApplication1Lic.txt /i:CommercialLibrary.DLL</b> Microsoft (R) .NET License Compiler [Microsoft .Net Framework, Version 4.0.30319.225] Copyright (c) Microsoft Corporation. All rights reserved. Processing complist 'ConsoleApplication1Lic.txt'... System.ComponentModel.LicFileLicenseProvider+LicFileLicense Creating Licenses file <b style='COLOR: blue'>consoleapplication1.exe.licenses</b>... </pre> <br /> 이렇게 생성된 "consoleapplication1.exe.licenses" 파일은 닷넷 어셈블리에 '리소스' 자원으로 포함될 수 있습니다. 하지만, 이렇게 되면 빌드 절차가 복잡해지기 때문에 사실 이런 유형으로는 거의 사용되질 않고 있습니다.<br /> <br /> MSbuild에서는 이런 작업을 간단하게 할 수 있도록 프로젝트에 licx라는 특별한 확장자를 가진 파일이 있다면 그것을 '/complist'에 지정되는 파일이라고 여기고 자동으로 lc.exe 컴파일러를 호출하여 .licenses 파일을 생성하고 어셈블리의 리소스로 포함까지 시켜줍니다.<br /> <br /> 실제로 LicFileLicenseProvider를 기준으로 테스트를 원한다면, 다음과 같은 식으로 솔루션을 구성해 주면 됩니다.<br /> <br /> <img alt='license_manager_compiler_1.png' src='/SysWebRes/bbs/license_manager_compiler_1.png' /><br /> <br /> 즉, 사용하려는 응용 프로그램(ConsoleApplication1.exe)측에서 licx 파일을 추가하고 내용은 다음과 같이 구성합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > CommercialLibrary.LicFileLicensedClass1, CommercialLibrary </pre> <br /> 위에서 lc.exe 컴파일을 명령행으로 사용하는 방법을 설명하면서 언급했지만, lc.exe는 /complist 옵션에 지정될 파일 뿐만 아니라, 원래의 구성요소에 대한 lic 파일들이 필요하므로, 라이브러리(CommercialLibrary.dll) 측에서는 CommercialLibrary.LicFileLicensedClass1.lic 파일의 "Copy to output Directory" 속성을 "Copy if newer" 설정으로 해두시면 '편리합니다.' (물론, 배포시에는 lic 파일들은 없어도 됩니다.)<br /> <br /> 결국, 빌드된 ConsoleApplication1.exe 파일을 .NET Reflector로 확인해 보면 다음과 같이 명령행에서 lc.exe를 실행했을 때 처럼 "consoleapplication1.exe.licenses 리소스 파일이 들어있는 것을 확인할 수 있습니다.<br /> <br /> <img alt='license_manager_compiler_2.png' src='/SysWebRes/bbs/license_manager_compiler_2.png' /><br /> <br /> LicenseProvider와 lc.exe에 대해서 이 정도 알아봤으니, 이제 자신만의 라이선스 체계를 만들어서 LicFileLicenseProvider를 확장하고 싶어질 텐데요. 소스 코드를 구현하기 전에 아래의 글들 중에서 자신이 생각하고 있던 것이 있다면,... ^^ 그대로 가져다 쓰는 것도 좋겠지요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > C#: LicenseManager (and Other uses): Get a Mobile Devices Unique ID ; http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/1962/C-LicenseManager-and-Other-uses-Get-a-Mobile-Devices-Unique-ID.aspx C#: Developing a LicenseProvider/License: Getting the Motherboard ID. ; http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/1963/C-Developing-a-LicenseProvider-License-Getting-the-Motherboard-ID.aspx C#: Developing a LicenseProvider/License: Getting the Manufacturer’s UID. ; http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/1964/C-Developing-a-LicenseProvider-License-Getting-the-Manufacturer-rsquo-s-UID.aspx C#: Developing a LicenseProvider/License: Getting the CPU’s ID. ; http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/1965/C-Developing-a-LicenseProvider-License-Getting-the-CPU-rsquo-s-ID.aspx </pre> <br /> 참고로, <a target='_tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=595&boardid=331301885'>첨부한 파일은 제가 테스트한 프로젝트 소스</a>입니다.<br /> <br /><br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1915
(왼쪽의 숫자를 입력해야 합니다.)