log4j 라는 Apache 프로젝트가 있다. ( http://logging.apache.org/log4j )
java 내에 동작하는 각종 Log 내용을 쌓기 위한 모듈인데, 내부적으로 어떠한 설계로 구성되었는지는 살펴보지 않아, 잘은 모르지만, 성능적 저하 없이 많은 양의 Log 관리에 훌륭하게 대처 할 수 있다. 또, Log로 남겨지는 형태를 단순 Text 파일 형식에서 부터 DB 파일까지 그 대응적 능력이 우수하다.

.NET 프로그램에서도 이 강력한 log4j를 사용할 수 있는데, 그 도구가 바로 log4net 이다. ( http://logging.apache.org/log4net/ )

여기에 쓸 내용은 지금까지 Application 내에 적용하면서 진행되었던 사항들을 적용 순서 대로 나열할 예정이다. 그래서 그 순서가 log4net에 대한 기초와는 다르다. 그러다 보니, 독자가 현재 적용 중인 Project나 구성과는 사뭇 다를 수 있으며, 스스로 잘못 이해한 부분으로 인한 오류도 있다.
더욱이 Web-Base가 아닌 WinForm-Base로 제작하면서 익힌 기능이다 보니, Web 기반의 구성과 일부 차이가 발생할 수 도 있다. 이점을 이해하면서 살펴보면 좋을 것 같다. 또, 이 글 외에도 많은 log4net에 대한 예제, 구성 이야기들을 살펴볼 수 있으므로, 사뭇 달라도, 자신의 적용과 유사한 다른 글들을 찾아보기도 쉬울 것이다.

 

log4net 접근 시작

최초에는 독자적으로 log 파일을 쌓고 구성했다. 그런데, 문제는 Single Thread 기반의 Application이다 보니, 로그 쌓는데, 의외로 많은 Process Time을 잡아 먹는 문제점이 발생했다. 로그는 좀 더 Detail 하게 쌓고 싶었지만, 그 성능적 문제로 인해 log를 쌓기에 두려움까지 얻게 되었다.

그러다가, java 관련 프로젝트를 수행하면서 log4j 에 대한 접근을 좀 하고 나니, log 쌓는 작업에 대한 대치성에 대해서 고민하게 되었고, 잠시 짬을 두어 log4net을 살펴보았다.

오픈 소스다 보니, 소스 자체를 공개하고 있으며, 다양한 Platform에 대한 컴파일이 이미 되어 있어, 사실 자신이 원하는 프로젝트에 대한 Platform에 맞추어 미리 컴파일된 버전을 바로 연결해서 사용가능 하다.
http://logging.apache.org/log4net/download_log4net.cgi 에서 다운로드 페이지 내에, Binaries 중,
log4net-1.2.13-bin-newkey.zip 을 다운 받았다. 그 안을 열면 여러가지 폴더가 있는데, bin 폴더에 들어가, 자신의 .NET Framework 버전에 맞추어 들어가면, log4net.dll 이 있는데, 이 파일만 꺼내오면 된다.

이제 자신의 Project 내에 저 파일을 복사( 개인적으로는 Solution 폴더 바로 아래에 Assembly 폴더를 만들어서 그 안에 복사) 해준다.

이제 자신의 프로젝트에 참조를 건다.

참조 건 뒤에 빌드 할 때 마다 파일이 복사되서 전달 될 수 있도록 Copy Local 이 True인지도 살펴본다.
(간혹 이 부분을 누락해서, 배포할 때, DLL이 빠져서 실제 이 배포본을 받는 사람은 실행이 안되는 문제가 발생하기도 한다.)

그리고 로그를 쌓는 로직을 작성한다.

그리고 이제 소스 상에서 다음과 같이 추가한다.

여기서는 제일 만만한 Form1.cs 파일을 열고 수정한다.

최초로 열면 아래와 같은 소스이다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyTestProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

이제 이 소스를 다음과 같이 수정한다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyTestProject
{
    public partial class Form1 : Form
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public Form1()
        {
            log.Info("Form Init Start");    
            InitializeComponent();
            log.Info("Form Init End");
        }
    }
}

이제 프로젝트를 실행해보자.

분명 로그를 쌓으라고는 했으나, 로그가 쌓이지는 않는다. 당연하다.
로그를 쌓기 위한 log 개체는 만들었다.

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

하지만, 위의 개체에다 아무리 로그를 쌓으라고 해도 어디다가 어떻게 쌓아야 될지에 대한 설정이 없으므로 쌓일리 없다.
즉 로그가 모두 무시되는 상황. 이를 위해서 설정을 해주어야 한다.

 

이 설정 방법은 크게 두 가지가 있는데, 하나는 정적인 방법이고, 다른 하나는 동적인 방법이다.

그 방법이 아래와 같다.

 

로그 쌓기 설정 그 방법 1.

구글을 통해 이런 저런 설정 관련 예제를 받으면 대부분은 .config 파일에다 그 설정을 넣는 방법을 제공한다.
즉 응용 프로그램 프로젝트의 경우 App.config 파일이 그 해당 파일인데 응용 프로그램 프로젝트를 최초로 만들 때는 없는 경우가 많다. 그 경우 새 항목을 추가해서 새로 만들어 주도록 한다.

이제 App.config 파일을 열어보면, 설정을 위한 XML 파일이 열린다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration?> 
</configuration?>

이 안을 다음과 같이 설정한다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration?> 
  <configsections?>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /?>
  </configsections?>
  <log4net?>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender"?>
      <file value="example.log" /?>
      <appendtofile value="true" /?>
      <maximumfilesize value="100KB" /?>
      <maxsizerollbackups value="2" /?>
      <layout type="log4net.Layout.PatternLayout"?>
        <conversionpattern value="%level %thread %logger - %message%newline" /?>
      </layout?>
    </appender?>
    <!-- Set root logger level to DEBUG and its only appender to A1 --?>
    <root?>
      <level value="INFO" /?>
      <appender-ref ref="RollingFile" /?>
    </root?>
  </log4net?>
</configuration?>

그리고 Properties 폴더를 열고, AssemblyInfo.cs 파일을 연다.

이제 맨 아래 줄에다가, 다음 줄을 삽입한다.

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

앞에서 로그 쌓는 로직이 정상적으로 작성되어 있다면, 이제 다시 프로젝트를 실행해보자.

실행 한 뒤에 Build 결과물 폴더를 열어보면 example.log 라는 파일이 생성되는데 그 안에 보면,

Form Init Start와 Form Init End가 보일 것이다.

설정이야 어쨌던 로그가 쌓인다.

 

로그 쌓기 그 방법 2

대부분의 경우는 위의 경우에 다 처리 될 수 있다. (상세 설정은 추가적인 검색을 하면 상세한 설정이 가능하다.)
그런데, 이런 저런 프로젝트에 적용하다가 보니, 이 로그 설정을 동적으로 설정해야 할 경우가 발생했다.

즉 app.config를 이용해서 설정하는 방식으로는 그 설정 내용을 마음대로 주무르기가 무척 힘들다는 사실이다.
예를 들면 로그 파일의 이름이나, 경로 같은 경우다. 경로가 딱 정해진 위치라면 상관 없지만, 프로그램이 실행된 뒤, 동적으로 변경되어야 하는 경우라면 이야기가 많이 달라진다.

예를 들면 Application 관련 설정이 다른 위치에 저장되고, 설정 창을 통해 로그 파일의 위치가 변경되는 경우라면 어떻게 할 것인가? 그럼 매번 app.config를 변경해서 재실행해야 할까?

이런 저런 생각에 동적(코드상)으로 변경하는 방식을 찾아보았고, 그 방법을 정리해 보았다.

 

먼저 동적인 방법으로 설정을 하기 위해서는 log 개체에 대한 구성체계를 가져와야 한다.

	log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
	hierarchy.Configured = true;

 

이제 모든 설정은 hierarchy를 통해서 진행되게 된다.

먼저 제일 중요한 로직이 어디다가 어떻게 쌓을지에 대해서다.
log4net 에서 제공되는 쌓는 방식은 19가지 정도 되지만, 위의 예제도 그렇듯이, 파일로 제공하는 형태로 구성할 예정이다. 방법 1과 동일한 방식으로 쌓으려면 아래와 같은 로직을 통해 쌓는 방식에 대한 클래스를 생성한다.

	log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
	rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
	rollingAppender.AppendToFile = true;
	rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
	rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
	rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
	log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
	rollingAppender.Layout = layout;

여기에 있는 RollongFileAppender는 log 내용을 파일로 쌓는 역할을 제공하는 모듈이다.
이 모듈에 대한 개체를 생성했으면, 이제는 hierarchy에 붙이도록 한다.

	hierarchy.Root.AddAppender(rollingAppender);
	rollingAppender.ActivateOptions();

이제 로그를 쌓는 레벨을 설정한다.

hierarchy.Root.Level = log4net.Core.Level.All;

이 로직을 로그가 쌓이기 전에 한번 실행 할 수 있도록 구성하면 된다. 다음 코드는 위의 부분 부분을 모두 합친 부분이다.

	log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
	hierarchy.Configured = true;

	log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
	rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
	rollingAppender.AppendToFile = true;
	rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
	rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
	rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
	log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
	rollingAppender.Layout = layout;

	hierarchy.Root.AddAppender(rollingAppender);
	rollingAppender.ActivateOptions();
	
	hierarchy.Root.Level = log4net.Core.Level.All;

프로그램 제일 먼저 시작하는 로직에 추가하면 된다. 대개의 경우에는 program.cs 파일내 추가해주면 된다.

        static void Main()
        {
            #region 로그 설정
            log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
            hierarchy.Configured = true;

            log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
            rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
            rollingAppender.AppendToFile = true;
            rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
            rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
            rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
            log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
            rollingAppender.Layout = layout;

            hierarchy.Root.AddAppender(rollingAppender);
            rollingAppender.ActivateOptions();
	
            hierarchy.Root.Level = log4net.Core.Level.All;
            #endregion


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

이제 app.config 없이도 log가 쌓이게 된다.

 

정리

이 포스트의 목적은 바로 이 2번째 방법에 따른 방식을 소개하기 위한 글이다.

log4net의 기능의 강력함은 동작 중에 무시할 만큼의 리소스를 소모하면서 강력하게 로그를 쌓는 방식에 있을 것이다. 더욱이 자동으로 파일로 떨구기도 하고, 데이터베이스에 쌓을 수도 있기 때문에, 활용도에서도 우수하다.

개인적으로 현재 프로젝트를 모두 이 log4net 으로 전환하고, 쌓이는 로그를 WinTail(http://www.baremetalsoft.com/wintail/)  이라는 프로그램을 통해서 살펴보고 있다. 동작 중에 발생되는 각종 값에 대한 감시 및 데이터 체크는 모두 이를 통해서 하고 있다. 동적으로 프로그램을 실행하면서 디버깅을 할 때 의외로 편하다.

닷넷 프로그램으로 로깅을 남기는 작업을 해보고 있다면 한번 시도해보심이?

728x90


nexusupdater_exe.zip

NexusUpdater_src.zip

usb_driver.zip


앞서 "넥서스 S 젤리빈 순정롬 설치하기" 라는 글을 썼습니다.. 

별 다른 글은 아니고, 구글 펌웨어 다운로드 페이지에서 다운 받은 순정롬을 간단(?)하게 업데이트 하는 방법인데, 문제는 그 안에 배치 파일이 .sh 파일로 된 Unix 기반의 파일이라는 사실입니다. 
( 요즘 나오는 젤리빈용 업데이트 롬 파일안에는 .bat 파일이 있어서, 윈도우 에서도 실행 할 수 있습니다 ).

그리고 fastboot 과 같은 도구 같은 경우 안드로이드 SDK에서 뽑아내야 하는데, 그 작업도 이해가 안되는 경우 전혀 손도 못대고, 손댈 수 있다고 해도, 해당 도구만 다운 받기가 생각보다 어렵습니다.

또, 매번 페이지 접속해서 해당 압축 파일 받고, 압축 풀고, 배치 파일 실행하고 하는 그 일련의 작업도 귀찮긴 매한가지 였죠. ( 역시 이런 건 컴퓨터가....)

그래서 그냥 만들었습니다. ㅋ

프로그램 전체는 Visual Studio 2010 기반으로 해서 .NET Framework 2.0 기반으로 만들어져 있으며,
내부적으로 압축을 풀기 위해 ICSharpCode.SharpZipLib 라이브러리를 ( http://www.icsharpcode.net/opensource/sharpziplib )를 가져다 썼습니다.

주의 사항

0. USB 드라이버가 반드시 설치되어 있어야 합니다.

아래 댓글의 숭숭구리님께서 언급해주신 USB 드라이버 <- 이거 해결해 주셔야 합니다.

Nexus의 전원을 끈채로 연결 한 뒤에, 켤 때, 전원 + 볼륨 상 을 눌러 주셔야 합니다.
그러면 알 수 없는 장치로 인식되는 경우 Driver를 설치해 주셔야 합니다.

설치하는 방법은 http://mynexusone.tistory.com/1 에 방문하시면 쉽게 찾아보실 수 있습니다.
여기서는 Windows 7 x64 버전을 기준으로 간단하게 설명 드리겠습니다.

먼저, 상단에 위치한 usb_driver.zip 을 다운 받으시고 적당한 곳에 압축을 푸세요.
( http://www.hind.pe.kr/attachment/cfile28.uf@26341B4D51C122EA118B7D.zip )

이미 장치가 연결되어 있으면 하단 트레이에서 장치 연결 아이콘을 찾으세요.

아이콘 위에서 오른쪽 버튼을 누르면 메뉴가 뜨는데, 굵은색 표시가 된 부분을 클릭하세요.

그러면 장치 관리자가 뜨는데, 드라이버가 제대로 설치되어있지 않으면 Android 1.0 이런식으로 잡혀 있을 겁니다.

해당 아이콘에서 오른쪽 버튼을 눌러 속성에 들어가시기 바랍니다.

속성 창에서 상단에 있는 "하드웨어" 탭을 클릭하세요. 그리고 하단에 있는 속성 버튼을 클릭하세요.


그러면 드라이버에 대한 상세 창이 뜨는데, 하단에 있는 "설정 변경" 버튼을 한번 누르세요.


그러면 드라이버 업데이트 버튼이 활성화 됩니다.

이제 드라이버 업데이트 버튼을 클릭하세요.

드라이버를 찾는 방법에 대한 옵션을 선택하는 창이 뜨는데, "내 컴퓨터에서 드라이버 소프트웨어 찾기"를 선택하세요. 자동 검색을 하게 되면 윈도우즈 업데이트 사이트까지 뒤지는데, 의외로 시간이 너무 걸립니다.


경로를 묻는 창이 뜨는데, 직접 장치를 선택하겠다는 항목을 클릭하세요..

이제 장치 종류가 나오는 창에서 모든 장치 보기를 선택하세요.

드라이버 목록 창에서 이번에는 "디스크에서 찾기" 버튼을 클릭하세요.

이제 드라이버 파일 찾기 창이 뜨면 "찾기" 버튼을 클릭합니다.

아까 압축을 푼 드라이버 파일 위치까지 가면 android_winusb.inf 파일이 보이는데 그것을 선택합니다.

그리고 선택하고 나와서 확인 버튼을 클릭하면 다음과 같은 창이 뜹니다.

맨 위에 있는 Android ADB Interface를 선택하고 다음을 클릭합니다.

설치가 진행되면 이 드라이버가 올바른 드라이버인지 여부를 묻는 창이 뜨는데, 그냥 "네"를 선택하세요.
그리고 중간에 드라이버 확인이 또 들어가는데, "설치" 버튼을 클릭해주세요.

설치가 완료되면 이제 정상적으로 이 프로그램을 사용하실 수 있습니다.


1. Nexus S 에서만 테스트되었습니다.

애석하게도 필자는 이 프로그램을 만들 때 Nexus S로만 했습니다. 즉, Nexus Galaxy, Nexus 7 으로는 전~혀 테스트 안되어 있습니다. 테스트 가능하신 용자분들이 계시면 해보시고, 이상이 발견했을 때 저에게 말씀해주시면 업데이트 하도록 하겠습니다.

2. 휴대폰 내부가 완전 초기화 됩니다.

이거 중요한데요, 이 업데이트 방법을 취하면 기계가 완전히 초기화 됩니다. 진짜 완벽하게!
마치 공장에서 나온듯 깔끔하게 지워져서 초기화 됩니다. 만일 자신의 휴대폰에 중요한 자료가 있거나, 미처 백업해본적이 없는 경우 시도하지 마십시요... 커펌 올리다 벽돌 되거나 했으면 모르겠지만, 잘 사용하는 휴대폰을 가지고 단순히 업그레이드/다운 그레이드 한다고 설치하시면 나중에 피눈물 나옵니다. ( 미처 업로드 못한 사진 등등, 친구와 연인과 대화했던 목록들 등등. )

3. 롬 파일 다운 위치는 내 문서의 NexusUpdate 라는 폴더 입니다.

롭 업데이트 하기 전에 내 문서의 위치를 기준으로 용량이 얼마나 남았는지 확인하시고 진행하시기 바랍니다. 보통 롬 하나가 100~200 메가 안팎이고, 이것을 압축을 풀고 준비하게 되면 보통 3~500 메가 정도의 여유 공간이 있어야 합니다. 요즘은 대부분 테라 사이즈의 용량의 하드를 가지고 계셔서 큰 문제가 없을지 모르겠지만, 간혹 용량이 무척 부족하신 분들이 있습니다. 넉넉히 500메가 정도의 공간을 확보하시고 진행하시기 바랍니다.

꼭 내 문서 위치 입니다. ( 다른 위치를 잡으려 했으나, 윈도우 보안 문제등이 걸리는 경우 알 수 없는 오류들이 너무 많아서 다른 위치 설정은 안됩니다. ㅋ )

4. 인터넷과 연결되어야 합니다.

여기서 사용되는 모든 자료는 인터넷을 통해 받아옵니다.

먼저 ROM 파일 목록은 https://developers.google.com/android/nexus/images?hl=ko-KR 에서 직접 페이지를 읽어서 정리해서 표출 합니다. 그래서 만일 해당 페이지를 열 수 없는 경우에는 이 프로그램도 사용할 수 없습니다. 또한 페이지가 리뉴얼 되서 해당 내용을 추출하지 못하는 경우에도 사용할 수 없습니다. ( 만일 페이지 내용을 분석하지 못하는 경우 다시 업데이트를 해야 합니다. )

그리고 fastboot 과 같은 도구는 제 홈페이지 ( http://www.hind.pe.kr/attachment/cfile1.uf@031B7843507F91551911D4.zip )에서 다운로드 합니다. 만일 홈페이지 접속을 못해서 도구를 다운 받지 못하면 역시 이 프로그램을 사용할 수 없습니다;;;;

5. ROM 파일을 너무 많이 다운 받지는 마세요.

ROM 파일을 다운 받아 놓으면, 이 프로그램을 실행할 때, 해당 파일이 원본인지 여부를 확인하기 위해 Check-Sum이라는 작업을 합니다. 이 경우 모든 ROM 파일에 대해서 검사를 하게 되는데, 이게 은근 시간을 잡아 먹습니다. ( 100~200 메가 짜리 파일을 일일히 열어 모두 합산을 한 뒤, 값을 얻어오는 작업이다 보니... )

내문서\NexusUpdate 폴더 안에서 불필요한 롬 파일들과 하위 폴더들은 모두 삭제하시고 진행하세요.

 

사용법

먼저 프로그램을 실행하면 다음과 같은 화면이 뜹니다.

콤보 박스가 두개 있는데, 하나는 제품별 필터 기능이고 두번째는 그 제품에 속한 롬들을 나타납니다. 현재 펌웨어 다운로드 페이지에 가면 아래와 같은 제품들만 제공한다. 그래서 아래와 같은 화면이 뜹니다. 업데이트할 폰의 제품명을 선택하시면 됩니다.

해당 제품을 선택하면 그에 한정된 롬들 목록을 보여줍니다..

아래의 그림은 Nexus S 목록인데, Nexus S 제품이나 지역별 롬들이 모두 표시됩니다. (우리나라에서 출시된 Nexus S의 경우 4G와 850Mhz version은 없으므로, 반드시 Korean Version 이나 Worldwide version을 사용하셔야 합니다.)

적절한 제품과 롬을 선택했으면 이제 해당 제품의 롬을 다운 받습니다.

다운 받는 법은 제품 목록 밑에 위치한 다운로드 버튼을 누르면 됩니다.

그러면 자동으로 펌웨어 페이지에서 다운로드를 하고, 압축까지 푼다. 진행 정보는 아래의 로그 창에 찍힙니다.

어설픈 마법사 화면이지만, 다운로드와 압축 풀기가 정상적으로 끝나면
업데이트를 하기 위한 다이얼로그가 자동으로 뜹니다.
맨 처음에는 fastboot 화면으로 들어가도록 요청하는 화면입니다.

여기서 fastboot 화면이란, Nexus 폰의 일종의 관리 화면으로 굳이 컴퓨터로 말하자면 BIOS 설정 화면 같은 것입니다. 넥서스 S를 기준으로 보면 볼륨 UP 버튼을 누른 상태로 전원을 켜면 나오게 됩니다. ( 다른 제품은 모르겠습니다 ^^)

Fastboot 화면에 들어온 것을 확인했다면 '다음'을 클릭하세요.

다음 화면은 Lock을 푸는 화면입니다. 보통 별도 펌웨어 작업을 해본적이 없다면 대개의 폰에는 Lock이 걸려 있습니다. 이것을 해제해야 fastboot을 이용한 펌웨어 업데이트가 가능합니다. Unlock을 하려면, "Yes"를 선택해야 하는데, 터치는 안되고, 볼륨 조절 버튼을 눌러서 "Yes"를 선택한 뒤에 전원 버튼을 눌러주면 Unlock이 됩니다.

만일 Lock이 걸려 있지 않으면 이 화면이 잠깐 보였다가 다음 업데이트 화면이 뜰겁니다.

자 그럼 이제 모든 업데이트 준비는 완료되었습니다.

'다음' 버튼을 누르고 휴대폰을 보면서 업데이트가 잘 되고 있는지만 가만히 보시면 됩니다.
(이 때 가급적이면 다른 동작은 자제하시기 바랍니다. 심심하시다고 웹 브라우징 하거나 게임 하시거나 이러면 업데이트가 실패할 수 있습니다. )

보통 업데이트 내용은 휴대폰 맨 아래 쪽에 영어로 된 글이 보이는데, 그 내용에 변화가 있으면 됩니다. 업데이트 중에는 자동으로 휴대폰이 껐다 켜집니다.

마지막으로 Lock 하는 화면이 나옵니다.
보통 위의 업데이트 과정을 거치면 자동으로 업데이트한 버전으로 부팅이 완료되기 때문에, 자동으로 Lock을 거는 것은 어렵습니다. 그러므로 수동으로 다시 fastboot 화면으로 들어가야 합니다.

물론 unlock 상태에서 계속 사용할 예정이면 무시하셔도 무방합니다.

휴대폰을 재부팅 한뒤, 앞에서 제시한 내용 처럼 Fastboot 화면을 띄웁니다.
FastBoot 화면이 떴으면 '다음'버튼을 누르면 됩니다. 그러면 자동으로 Lock을 걸고 휴대폰을 Reset 합니다.

이제 프로그램 종료하시면 됩니다.

 

정리

정상적인 상황에서의 사용은 큰 문제가 없을 것입니다.
하지만, 모든 사람이 똑같은 환경에서 사용하리라 생각되지는 않습니다.
Windows XP에서 실행하시는 분, Vista에서 실행하시는 분, 심지어는 8에서 실행하실 수도 있겠죠.
x86이면 모르겠지만, x64의 경우도 있을 것이며, USB 2.0 이 아닌 1.0 혹은 3.0일 수도 있습니다.

애석하게도 각 케이스별로 모두 테스트한 프로그램은 아니기 때문에, 오류가 발생할 수 있습니다.

오류가 발생했다면, 내 문서\NexusUpdate 폴더 안에 .Log 파일이 있는데, 그 파일을 저에게 알려주시면 됩니다. 그 내용을 비밀 댓글을 통해서 알려주시면 됩니다.

개발된 모든 소스와 프로그램은 Open 되었으며 여기서 다운로드 받으실 수 있습니다.
(나중에 Source는 네이버 오픈 소스 사이트에 올릴 예정입니다. )

728x90

지금까지 해온 웹 프로그래밍은 ASP.NET 2.0 기반으로 해왔기 때문에, 이 지식을 기반으로 Java에 매핑하기 시작했다. 사실 지금까지 ASP.NET 2.0 형태로 Web Form을 구성하면서, 외부에 노출되지 않은 내부 기능들에 많이 답답해 왔던 것도 사실이다.


그런데, 이번 Java기반 웹 프로그래밍을 하면서 이 ASP.NET이 많은 부분에 있어 프로그래머에게 편의를 주고 있다는 점을 알게되었다. ( 물론 Java 기반의 웹 프로그래밍을 전부 파악하고 하는 말은 아니다. 분명 Java에서도 다양한 기능들이 있기 때문에, 쉽게 처리할 수 있는 방법은 있을 것이다. )


일단 ASP.NET 2.0 으로 넘어가면서 웹 페이지 디자인 코드 부분과 코드 부분이 명확하게 나뉘게 되었다. 그래서 실제적인 .NET 코드들은 코드 부분이 담기는 페이지에 담기고, HTML 부분은 ASP 부분에만 담기게 되었다. 그 사이를 IIS와 .NET 엔진에서 알아서 붙여 진행하였다. ( 이 부분은 대부분의 웹 프로그래밍 환경에서는 최악의 문제점으로 알고 있다. 디자인과 코드가 뒤엉키다 보면 유지보수가 너무 어렵다. )


더 결정적인 부분.

사실 Form에서 데이터를 전달할 때, Ghost 페이지라는 것을 만들어 사용했다. 즉, Form에서 입력된 데이터를 DB에 저장하거나, 그 데이터를 기반으로 특정 값을 찾는 작업을 하려고 할 때, 사용자에게 보여주지는 않는 페이지를 Form의 Action으로 등록하여 처리하는 것이다. 


이 때, Servlet과 JSP에서는 이렇게 처리한다.

JSP에는 실제 사용자에게 값을 입력 받을 때 사용되는 Form(혹은 결과값을 보여주는 Form)으로 제공되고, Servlet은 이 Form에서 만들어진 값을 받아 처리하게 되는 일종의 Ghost 페이지처럼 동작하도록 하는 것이다.


즉, 입력 Form(JSP) –> Servlet –> Form(JSP).


합리적이긴 하지만, ASP.NET 2.0 기반 프로그래머 입장에서는 순간 헤매기 십상일 듯 싶었다.

게다가 Servlet 이라는게 사실 Web Server와 직접 연동하여 동작하는 작업을 구성하는 것이기 때문에 왠지 접근하기가 쉽지 않은(.NET 에서는 이 부분의 로직을 모두 숨겨서 알아서 처리해 줬기 때문이다. )부분이라, 망설임이 지대로다.


지금 Google Apps Engine 코드들을 하나씩 까면서 차근 차근 따라가보고 있다.

뭐랄까 새록새록 한 기분?

728x90

옛날 자료들, .NET 1.0 시절에서 부터 내려온 자료들을 근간으로 하나씩 하나씩 체크하면서 진행했습니다. 그런데 생각보다 의외의 요소들이 너무 많아 헷갈려 포기 할 즈음 간신히 성공했습니다.

성공했던 내용을 기반으로 지금까지 제가 판단했던 각종 정보들을 정리해보도록 하겠습니다.
현재 이 작업은 .NET 2.0 기반으로 Visual Studio 2005를 기준으로 작성하고 테스트 되었습니다.
(아직 Visual Studio 2008에서는 해보지는 않았지만… 잘 되리라 그냥 막연히 짐작합니다. 2003 버전은,
외국에 많은 사례들이 있으므로 한번 찬찬히 보시면 금방 하실 수 있을 것입니다. )
그리고 구현 언어는 C# 입니다.

1. 프로젝트 생성

먼저 프로젝트 생성입니다. 사실 대부분의 다른 사이트들의 예제를 보게 되면 Class Library 기반으로 시작하게 끔 유도하곤 합니다. 그런데, 생각보다 설정하거나 구성해야 되는 부분이 너무 많아 무언가 노가다 하는 기분이 들더군요. 그러다가 찾은 프로젝트 형식이 바로 “Windows Control Library”  였습니다.

이 프로젝트를 생성하려면 File –> New –> Project 라는 메뉴에 들어가시면 아래와 같은 화면이 뜨는데 그 중, Windows Control Library를 선택하시면 됩니다.

2. 클래스 설정.

ActiveX로 보여줄 컨트롤에 해당하는 클래스를 열도록 합니다. 보통 기본적으로 UserControl1 이라는 이름의 클래스가 만들어지는데, 바로 이 부분을 수정하게 될 것입니다. 더블 클릭하면 디자인 모드로 넘어가므로, 코드 보기로 들어가 주시기 바랍니다.

 

2.1 using 추가하기

맨처음 해주셔야 할 작업은 using을 걸어주시는 작업이 됩니다. Active X 설정을 위해 약간의 Assembly 및 COM 처리를 해야 하는 부분이 있기 때문입니다. using 해야 할 항목은 다음과 같습니다.

using System.Runtime.InteropServices; // 동적으로 컴파일러 관련 옵션을 업데이트하는 값을 넣기 위한 부분
using System.Reflection; // 현재 어셈블리 정보를 동적으로 가져오기 위한 부분
using Microsoft.Win32; // Registry에 정보를 업데이트 하기 위한 부분

일단 위의 3가지만 들어가면 지금 부터 업데이트 하는 부분은 큰 문제 없이 들어갈 것입니다.

2.2 ActiveX로 노출될 컨트롤 Class 옵션 적용

다음은 Class에 옵션을 설정하는 작업입니다.

먼저 제일 처음에 보이는 클래스 위쪽에 다음 3가지를 추가하여 주시기 바랍니다. 물론 프로젝트의 속성 값을 수정하여 대입되는 값들도 있기는 하지만, 혹시나 모르니 그냥 넣어주시면 좋을 듯 싶습니다.

[Guid("20F0F02D-044C-4013-AFAE-F2241D95FDA3")]
[ComVisible(true)]
[ProgId("HindNo1.TestAX")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public partial class UserControl1 : UserControl
{
      ………

대충 보시면 아시겠지만, [ ] 안에 들어가는 값이 바로 코드에 직접 박아서 명시적으로 설정하는 작업입니다.

맨 먼저 Guid 부분은 이 컨트롤의 고유한 ID 입니다. CLSID 같은 것으로 Active X 마다 각자 고유한 ID를 갖는데, 바로 그 ID를 의미합니다. 프로젝트 옵션에 있는 Assembly 옵션에도 이 비스무리한 값이 있는 것 같지만, 일단 저렇게 명시적으로 해주세요.( 전 VS 잘 몰라서, 장담드리기가 힘들어 가급적 그냥 제가 말씀 드린 방법대로 해보세요. )

두 번째에 있는 ComVisible 부분은 이 Control을 COM으로 노출 시키는 작업을 할 것인지 말 것인지를 결정하는 부분입니다. ActiveX도 어찌보면 COM의 일종이기 때문에, 반드시 COM 노출이 되어줘야 합니다. 이 역시 Project 속성의 Assembly 옵션에서 변경할 수 있긴 합니다.

세 번째 ProId 부분은 보통 VB 스크립트에서 쓰는 CreateObject(“xxxx.xxx”)의 xxxx.xxx 부분을 의미합니다. 일단 알기 쉽게 쓰는 것도 중요하지만, 가급적 특이하게 적어주시는 것이 좋습니다. Guid야 겹칠 일이 거의 전무하지만, 이 이름은 혹여나 겹칠 수 있으니깐, 조심조심 쓰시기 바랍니다. 문장이 길다 싶으면 “.” 으로 구분하여 표시해주시면 됩니다.

네 번째 ClassInterface(….) 부분은, COM(즉 ActiveX)가 외부에 노출되는 각종 Interface의 유형을 결정하는 부분입니다. 자세한 원리는 저도 잘 모르겠구요, COM에 대한 기초적인 지식이 필요할 것 같습니다. 일단 AutoDual로 하면 대부분의 인터페이스를 커버한다고 하더군요. 뭐 보안이나 성능상의 문제로 제한적으로 설정할 수 있는데, 이 역시 천천히 자습하시거나 내용을 찾아 설정해주시면 좋겠습니다.

2.3 컨트롤 등록 시 자동으로 실행되어야 할 사항

일단 위의 설명을 쭉 읽어보시고 만일 전혀 이해가 안되거나 도리어 헷갈린다 싶으면 위의 내용을 그대로 쓰세요. 그리고 난뒤에, Guid 와 ProgId 안의 값만 적절하게 변경해주시면 됩니다. (Guid는 Guid를 새로 생성해서 새롭게 넣으시고, ProgId는 겹치지 않게 적당한 문자열을 나열해주시면 됩니다. – 영어, 숫자, 마침표로만 – )

이제 이 Control이 등록될 때 몇 가지 Registry에 등록해야 되는데, 이 작업을 수행하기 위한 함수 두 개를 추가해 주시기 바랍니다.

///    <summary>
///    Register the class as a    control    and    set    it's CodeBase entry
///    </summary>
///    <param name="key">The registry key of the control</param>
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
    // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open the CLSID\{guid} key for write access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

    // And create    the    'Control' key -    this allows    it to show up in
    // the ActiveX control container
    RegistryKey ctrl = k.CreateSubKey("Control");
    ctrl.Close();

    // Next create the CodeBase entry    - needed if    not    string named and GACced.
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
    inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
    inprocServer32.Close();

    // Finally close the main    key
    k.Close();
    MessageBox.Show(key + " 's registered");
}

///    <summary>
///    Called to unregister the control
///    </summary>
///    <param name="key">Tke registry key</param>
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open    HKCR\CLSID\{guid} for write    access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

    // Delete the 'Control'    key, but don't throw an    exception if it    does not exist
    k.DeleteSubKey("Control", false);

    // Next    open up    InprocServer32
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);

    // And delete the CodeBase key,    again not throwing if missing
    k.DeleteSubKey("CodeBase", false);

    // Finally close the main key
    k.Close();
}

각 함수는 이 컨트롤을 해당 PC내에 등록할 때 자동으로 불려지는 함수입니다. RegisterClass(..) 함수는 등록될 때, UnregisterClass(..) 함수는 등록을 해제 될 때 자동으로 불리며, 각 함수의 내용은 마치 Active X처럼 필수적인 정보들을 Registry에 적어 추가하게 됩니다.

2.4 프로젝트 설정

자 마지막으로 설정해야 하는 부분은 프로젝트 설정 부분입니다.

솔루션 탐색기에서 해당 프로젝트에서 오른쪽 클릭을 하셔서 Context Menu를 띄우세요. 그리고 “속성”에 들어가시기 바랍니다.

속성 창에 들어가서 제일 먼저 응용 프로그램 탭을 선택한 뒤에 “어셈블리 정보를 클릭합니다.”

 

어셈블리 정보 창이 떴으면 맨 아래쪽에 있는 어셈블리를 COM에 노출을 선택해주시기 바랍니다.
그리고 어셈블리 버전 안에 "*" 표시가 있으면 반드시 지워주시기 바랍니다!!!!! - ( 가장 중요. 만일 * 가 들어가 있으면 계속 버전이 자동 갱신 되기 때문에, 알 수 없는 오류를 계속 뱉어 낼 수 있습니다. )

Update ( for pjyoung 님 ) - 2010.09.13.

현재 포스트 내용만으로는 regasm 으로 이 Active X 에 등록하려는데 문제가 있더군요.
만일 위의 내용만으로 등록하려고 하면 아래의 메시지가 뜹니다.

D:\MyData\Documents\Visual Studio 2010\Projects\ActiveXTest\ActiveXTest\bin\Debu
g>C:\windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase ActiveXTest
.dll
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.4927
Copyright (C) Microsoft Corporation 1998-2004.  All rights reserved.

RegAsm : warning RA0000 : Registering an unsigned assembly with /codebase can ca
use your assembly to interfere with other applications that may be installed on
the same computer. The /codebase switch is intended to be used only with signed
assemblies. Please give your assembly a strong name and re-register it.
RegAsm : error RA0000 : An error occurred while writing the registration informa
tion to the registry. You must have administrative credentials to perform this t
ask.  Contact your system administrator for assistance

만일 한글판이면 한글판 나름 메시지가 뜨겟는데요.. 일단, 위의 내용을 간단히 언급하자면, 2가지 오류가 있는 것입니다. 하나는 일종의 경고로써, (warning RA0000). 만든 ActiveX 내에 강력한 이름의 서명이 없다는 것입니다. 이게 없다면 뭐 다른 컴퓨터에서 안된다는 의미 같은데.. 경고라고 할지라도, 일단 해결해야 겠죠. 두번째는 Windows Vista, 7 에서만 발생하는 오류인데.. 도스 창을 띄울때 관리자 권한으로 해서 넣으라는 의미입니다.
아래의 내용은 그 부분을 해결하기 위한 내용을 정리햇습니다.

  1. codebase로 등록하려면, 최소한 dll 내에 인증서가 들어가야 된다는 것입니다. 물론 파는 제품이라면, 상업용 인증서가 들어가야 겠지만, 테스트용도라면, 개인 인증서를 직접 만들어 넣을 수 있습니다.
    인증서를 넣는 방법은 아래와 같습니다.
    1. 프로젝트를 솔루션에서 연 뒤, 프로젝트 속성에 들어갑니다.
    2. 프로젝트 속성이 열리면, 왼편에 나열된 탭들 중 Signing (한글로는 아마 '서명' 정도 일거입니다.) 탭을 클릭하시고, 열리는 내용 중 Sign the assembly( 한글로는 아마 '어셈블리 내에 서명' 이겠죠)를 체크합니다.
    3. 다음은 안에 열린 Choose a strong name key file: 에서 아래의 콤보 박스 내용 중,  New… 를 선택합니다.
    4. 그러면 새로운 다이얼로그가 뜨는데, 이 창이 바로 새로운 개인 인증서 하나 멋대로 만드는 것입니다.
      (외부에서 쓰기에는 좀 많이 부족하지만, 프로그램 돌리는 인증서로는 적당합니다.)
      Key file name 에다가 적당한 이름을 넣고.. 암호 부분은 넣어도 되고 안넣어도 됩니다.
      (넣으면 코드도 보호를 하는 것 같습니다만.. 뭐.. 귀찮으면 안넣어도 됩니다. 전 그냥 버릇처럼 넣습니다.). 다 넣었으면 OK를 클릭해서 닫습니다.
    5. 그러면 Assembly 내에 String name key로 위에서 넣은 이름대로 들어갔음을 확인합니다.
      그리고 컴파일을 다시 해주세요.
  2. 두번째 등장한 오류는 관리자 권한 문제입니다. 제 PC 가 Windows 7 이므로 Windows 7 중심으로 갑니다.
    Windows XP 라면 아주 특이하게 사용하시는 분(관리자 권한이 아닌 사용자 권한으로 동작시키는 분들)이 아닌 이상 발생되는 오류는 아닐 겁니다.
    1. 시작 을 클릭하고 검색창에 cmd 입력한 뒤, cmd에서 오른쪽 버튼을 눌러 관리자 권한으로 실행을 합니다.
    2. 그리고 열린 도스창에서 작업을 시작합니다. ( 3. 컴파일 그리고 배포 부분 )

3. 컴파일 그리고 배포.

네 이제 컴파일을 해주시기 바랍니다. 오탈자의 문제가 없다면 큰 문제 없이 컴파일이 될 것입니다. 컴파일이 완료되면, 이제 명령창(cmd) 창을 띄우세요.(시작 –> 실행 –> cmd 입력 )

그리고 다음 명령을 넣어주시기 바랍니다.

C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm /codebase “어셈블리파일”

“어셈블리파일” 이라는 부분은 지금 컴파일 된 DLL 파일의 전체 경로를 의미합니다.

예를 들자면…

"E:\Prj\ExposingDotNetControls_src\Home\Prisoner\bin\Debug\Prisoner.dll"

과 같은 스타일로 하시면 됩니다.

예전 C++이나 VB로 만든 ActiveX는 보통 regsvr32로 등록하고 해제했지만, 이제 .NET 기반으로 만든 ActiveX 는 이 regasm 이라는 도구로 하셔야 합니다. .NET Framework 2.0 을 설치하셨다면 위의 경로와 같은 위치에 regasm이 있을 것입니다.

정상적으로 등록되면 등록한 GUID 값과 함께 해서 조그만한 다이얼로그가 뜨게 됩니다.

4. 테스트

뭐 Object 태그로 Html 소스 안에 직접 박아서 테스트를 할 줄 아시는 분은 Html 소스를 만들어 하실 수 있을 것이고, 아니면 Visual Studio의 C++ 관련도구를 설치하신 분은 tstcon32.exe 라는 프로그램을 실행해서 테스트 해보실 수 있을 것입니다.

HTML 코드를 아래와 같이 넣어보아서 IE를 띄워봅니다.

<HTML><BODY>
<OBJECT id="myX"  CLASSID="CLSID:20F0F02D-044C-4013-AFAE-F2241D95FDA3" width="560" height="480"> 
</OBJECT>
</BODY></HTML>

당연히 뜨는 노란색 바가 보이는데, 그것을 클릭해서 진행해주시면… 아래 처럼 만든 모양 대로 뜹니다.



5. 정리.

사실 VC++로 만드는 Active X 보다는 배포하기가 조금은 까탈스럽습니다. 이 Active X를 돌릴 클라이언트 PC내에 .NET Framework가 설치되어 있어야 겠죠. 게다가 개발 편의로 따지만 SmartClient가 훨 좋습니다 ^^;  하지만 .NET의 개발 편의성과 당장 ActiveX가 필요한 상황에서는 좋을 해결점이 될 수 있으리라 생각됩니다.

pjyoung 님의 질의 내용을 근간으로 다시 프로젝트를 생성하면서 일부 업데이트를 했습니다.
최종 된 상태에서 정리하다 보니, 일부 내용을 Skip 해서 오해의 소지가 다분 있었으리라 생각이 듭니다.
(최소한 진행을 재점검해서 실행은 했습니다.)

PS. 첨부한 파일은 이 글을 재 테스트하기 위해서 만든 프로젝트를 압축한 내용입니다.
애석하게도 Visual Studio 2010 용으로 되어 있어, 예전 Visual Studio로는 솔루션과 프로젝트 파일을 제대로 활용할 수 없을 것입니다. 새로 프로젝트를 만들어서 파일만 가져다가 재 생성해야 할지도 모르겠네요.
그래도 모르니 일단 업로드를 해봅니다.

728x90

+ Recent posts

728x90