기존 Application이나 Patch등은 별다른 조건 없이 설치 진행이 되었기 때문에, 설치 프로그램의 기본값만으로도 충분하게 패키지화 했다. 하지만, 이번에는 본격적으로 End-User를 향한 제품을 패키지 하는 작업이기 때문에, 그렇게 단순하고 쉽게 패키징을 할 수 없었다.

물론 아래의 처리 방법들은 현재까지 패키징을 하면서 받았던 각종 정보와 설정 값들일 뿐, 원하는 형태로 성공적인 패키지 한 것은 아니다.

단순하게나마 패키지를 할 때 도움이 될 것 같아 기록에 남긴다.

1. NSIS ( Nullsoft Scriptable Install System )

Nullsoft에서 제작한 Installer System 프로그램. 100%에 가깝게 스크립트기반이며, 스크립트로 처리가 불가능한 경우 DLL 등을 이용하여 외부 모듈을 통해 플러그인의 개념처럼  추가할 수 있다. 하지만, 아직 그 부분까지는 접근조차 하지 못했으며, 특히 매 버전마다 변경점 마다 스크립트 수정 작업의 부하가 너무 커서 제작 중 도중에 포기하였다.하지만, 단순하고 직관적으로 패키지를 말때는 상당히 도움이 될 것 같다.

준비물.

  1. NSIS( Nullsoft Scriptable Install System) 컴파일러.
    제일 중요한 부분. 이 제품은 Open Source 라이센스를 따르며 무료로 배포되고 있다.
    http://nsis.sourceforge.net/Main_Page
    에서 Download 부분을 통해 다운 받을 수 있다.
  2. HM NIS Edit
    NSIS의 동작은 모두 Script를 컴파일 한 뒤, 나온 결과물로 동작한다. 즉 Script 파일과 실제 배포할 파일들만 있으면 간단하게 만들 수 있다. 진짜 “메모장” 하나 열고 그 안에서 Text 파일로 된 Script 파일을 구성한 뒤, 컴파일 하면 된다. 하지만, 이제 처음 NSIS를 돌려보시거나, NSIS 개념을 막 잡아가는 초보(필자도 포함)에게는 버겁기 그지 없다. 이를 그나마 많이 편하게 제공하는 UI가 바로 HM NIS Edit 프로그램.
    이 역시 무료이며, 불편함이 없지않아 있지만, 그 작은 불편을 뛰어 넘는 다양한 기능들이 NSIS를 조금은 더 쉽게 다가게 해준다.
    해당하는 프로그램은
    http://hmne.sourceforge.net/
    에서 볼 수 있으며, 다운로드 받아 설치하면 된다.

 

개념을 익히기 좋은 사이트들.

사실 NSIS 는 개념익히는데 상당히 어렵다. 물론 MSI 작성 방법보다는 조금은 더 직관적이고 단순하다. 그러나 작은 개념조차 익히기 어려운 건 사실이며, 대부분의 설명 사이트들은 영어로 되어 있다. 그래도 국내에서 NSIS로 삽질하시던 많은 프로그래머들이 있고 그들의 흔적을 잘만 찾아 댕겨도 의외의 많은 정보들을 얻을 수 있다.

  1. Kipple 사이트
    꿀뷰(HoneyView)라는 이미지 뷰어 프로그램으로 유명세를 타고 있던 분. 이 분이 만든 제품들의 패키지를 NSIS로 했으며, 그에 따라 다양한 기능등를 자체적으로 구성했다. 그래서 그 속에서 묻어 나오는 각종 팁들이나 예제들을 제공한다. 특히 예제로 담은 nsissample.zip 파일은 받드시 받고 그 안의 스크립트 내용을 잘 확인해보록 한다.
    http://www.kippler.com/doc/nsis/
  2. 게으른 엔지니어가 사는법 ~~~~ 사이트.
    NSIS 에는 몇가지 UI가 있는데, 과거 Winamp 시절에 사용한 classic 방법 부터 현재는 MUI2 라는 방식까지 여러가지가 존재한다. 필자의 경우 Windows Installer 3.1 UI랑 비슷하게 나오게 하는 MUI2를 주로 사용하는데 간혹 관련 예제들을 Google에서 찾으면 classic 시절에 짰던 방법으로 많이 나온다. 그래서 이래저래 방황을 많이 했는데, 아래의 사이트에서 많은 도움을 얻었다.
    http://www.cipher.pe.kr/tt/cipher/154?category=6
  3. 그 외..
    http://innara.springnote.com/pages/3828755
    http://jgh0721.tistory.com/category/프로그래밍/NSIS

 

구성 순서.

1. 기본 도구 설치 준비.

제일 먼저 NSIS 컴파일러와 HS NIS Edit를 설치한다.
이 두가지는 반드시 설치해서 진행하도록 한다.

2. 작업 폴더 준비.

인스톨러를 준비하기 위한 적절한 폴더를 하나 마련한다.
보통 이 폴더에 배포하기 위해 필요한 내용도 적절하게 보관하여 정리하도록 한다.
실행에 필요한 각종 내용들 (.NET 기준으로 bin\Debug 혹은 bin\Release 같은 폴더)을 담은 폴더와,
기타 부가적으로 필요한 내용들 ( 인스톨러 커스터마이징을 위한 이미지나 아이콘 등)을 담은 폴더,
그리고 별도로 복사할 때 사용되는 잡스러운 내용을 담은 폴더를 나누어 정리한다.

folderlists

3. 설정 파일 생성 혹은 템플릿 이용.

HM NIS Edit에서 새로 만들기를 하면, 마법사를 이용하여 기본적인 NSIS용 설정파일을 하나 만들어준다. 하지만, 이 방법으로 만들게 되면 결과물이 거의 완전 영어판으로 나오기 때문에,영어 알레르기가 있으신 분은 무척 애매해지는 경우가 발생할 수 있다.
이 경우에는 앞서 언급한 Kipple 님의 홈페이지에서 NSIS 예제를 다운로드 받는 것이다.
그 파일을 그대로 활용해도 된다.  물론 바로 받아와서 사용하려고 하면 컴파일할 때 오류가 발생하는데,
NSIS를 Kipple님이 수정한 버전으로 교체하거나, 아니면 설정 파일에서 오류나는 부분을 주석 처리해도 된다.
여기서는 Kipple님의 설정파일을 기준으로 설명한다.

4. 설치 파일 설정하기.

My_CopyFile 라는 함수를 찾는다. Ctrl + F를 눌러 저 Text로 찾으면 된다.
다른 부분은 그대로 두면 되고, SeachOutPath와 File 이라는 명령어가 있는 부분을 대거 수정한다.

filelist1

설치 결과물를 잘 고민하도록 하자. 만일 아래와 같은 형태로 구성하고 싶은 경우라고 가정을 하자.
filelist2

Program Files 밑에 Easy Connect 라면, 일단 그 부분은 그대로 두고,
그 폴더 안에 복사될 파일들을 File 이라는 명령을 사용해 넣도록 하자.
지금 설치될 파일은 모두 Binaries 폴더에 있으니 그 경로의 파일들을 나열하면 된다.

File ".\Binary\bin\Debug\\DevExpress.XtraTreeList.v10.1.xml"
File ".\Binary\bin\Debug\\DevExpress.XtraTreeList.v10.1.dll"
File ".\Binary\bin\Debug\DevExpress.XtraRichEdit.v10.1.xml"
File ".\Binary\bin\Debug\DevExpress.XtraRichEdit.v10.1.dll"
File ".\Binary\bin\Debug\DevExpress.XtraPivotGrid.v10.1.xml"
…………

자 다음은 Cur 부분. 일단 File 이 쭉 나열된 목록들 맨 끝에 다음과 같은 줄을 넣는다.

SetOutPath "$INSTDIR\Cur"

그리고 Cur 폴더에 들어갈 파일들을 위의 FILE 처럼 쭉 아래로 나열한다.

원리는 간단하다 SetOutPath 라는 것을 이용해 폴더를 구축한다. 여기서 시작점이 바로 "$INSTDIR"이 된다.
그 하위에는 당연히 \ 가 붙고 그 하위에 폴더를 만들면 된다.

5. 조건 별로 설치되어야 할 파일 설정.

지금 배포할 응용 프로그램은 .NET Framework 2.0 을 기반으로 구성되어 있다.
그러므로 반드시 미리 .NET Framework 2.0이 설치되어 있어야 하는데, 이를 체크한 뒤에 해당하는 프로그램이 설치되어 있지 않으면 설치해야 할 것이다.
아래의 코드로직을 설명하기 전에, 찾는 방법을 간단하게 설명하면 아래와 같다.

  1. 레지스트리에서 HKey_Local_Machine\SOFTWARE\Microsoft\.NETFramework 부분의 키를 따라들어간다.
  2. 키 안에 값들 중 InstallRoot 라는 항목을 열어 본다.
  3. 그 안의 값에 맨 뒤에 .NET 버전을 붙여본다.
    보통 .NET 2.0 이 설치되어 있다면 "C:\Windows\Microsoft.NET\Framework\2.0.50727" 라는 폴더가 있고, 그 안에 파일들이 있다.
  4. 위의 경로에 파일이 있는지 확인한다.

위의 단계에서 1 부분에서 오류가 있다면, 즉 레지스트리에 값이 없다면 .NET Framework가 설치되어 있지 않다는 의미. 그러므로 .NET Framework 2.0 을 그냥 설치하면 된다. 만일 이 부분이 있다면 .NET Framework 가 설치된 폴더에 파일들이 있는지 확인한다. ( Windows 설치 폴더가 생뚱 맞은데일 수도 있다. - E:\Windows 등등 ). 만일 파일들이 없다면 다른 .NET Framework 는 설치되어 있지만, 2.0은 설치되어 있지 않다는 것이다.

이런 로직으로 찾아보도록 한다.

제일 먼저 .NET Framework 가 설치되어 있는지 아닌지 여부를 저장하기 위한 전역 변수를 하나 설정한다.

Var IsHadNetFramework20

이 변수에 "t"가 들어 있으면 설치되어 있는것이고, 비어 있으면 설치되지 않은 것으로 정한다.

그리고 난 뒤, 체크하는 로직을 위한 Function을 만든다.

Function CheckAlreayInstalledSolutions

    ; .NET Framework 2.0 설치 여부 체크
   ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\.NETFramework" "InstallRoot"
   StrCpy $IsHadNetFramework20 ""
   StrCmp $R0 "" notFound foundIt

   foundIt:
           IfFileExists "$R0\v2.0.50727\*.*" VersionFound notFound
   VersionFound :
           StrCpy $IsHadNetFramework20 "t"
   notFound:


FunctionEnd

함수는 Function {이름} 으로 시작해서 FunctionEnd 로 끝난다.
그 안에 필요한 로직을 넣으면 된다.

일단 한 줄 씩 끄집어 보도록 하자. 

함수의 맨처음 줄은 ";" 가 맨 앞에 붙어 있는데, 주석이다. "#" 을 써도 된다.

ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\.NETFramework" "InstallRoot"

ReadRegStr은 특정 레지스트리 에서 값을 가져오는 것이다.
HKLM은 HKey Local Manchine을 기준으로 "SOFTWARE\Microsoft\.NETFramework" 에서 "InstallRoot" 라는 곳에서 문자열을 읽어온다. 이렇게 읽어온 문자열은 $R0 이라는 임시변수에 저장한다는 것이다.

StrCpy $IsHadNetFramework20 ""

별다른 의미는 없고 전역 변수로 설정한 변수를 초기화 하는 것이다. 그를 위해서 StrCpy라는 명령을 썼는데, 다른게 아니고 바로 문자열 복사같은 것이다. "" 를 복사했으니 완전 빈 변수가 되었다고 보면 된다.

StrCmp $R0 "" notFound foundIt

이 부분 부터 암호화의 느낌을 받은 문장. 다른 의미는 아니고 $R0 과 "" 를 비교한다는 것이다.
그 결과에 따라서 만일 같으면 notFound로 같지 않으면 foundIt 으로 이동한다는 의미.
굳이 Basic 스타일로 번역하면..

if $R0 == "" 
Then 
  Goto notFound
Else
  Goto foundIt

이 NSIS의 스크립트에는 IF라는 개념이 없는데 그와 유사한 로직으로 사용하는 것이 바로 이 StrCmp.
이 것을 활용하는 것으로 보면 된다.

foundIt:

암호화에 일조하는 부분인데, 바로 라벨이다. 즉 goto 해서 이동할 라벨을 의미하는 것.

   IfFileExists "$R0\v2.0.50727\*.*" VersionFound notFound

왠지 IF 스러운 내용인데, 이 If 는 여러가지로 활용가능한 If 가 아니라, 오로지 파일이 있는지 여부를 확인하기 위한 로직이다. .NET 2.0 파일들이 있는지 확인한다. 만일 파일들이 있다면 VerisonFound로 goto 하고 없다면 notFound 로 goto 한다.

위의 로직에서는 Check 하는 것이므로, 이젠 설치하는 로직을 만들도록 하자.

Function InstallNETFramework20

; .NET Framework 2.0이 설치되어 있지 않으면 설치
   StrCmp $IsHadNetFramework20 "t" DoInstllDotNet PassInstall
   DoInstllDotNet:
       DetailPrint "Install .NET Framework 2.0"
       ExecWait '".\AddonPackage\installdotnet.cmd"' $1
       SetRebootFlag true
       Sleep 20000
    PassInstall:

FunctionEnd

위에서 언급안된 부분을 설명하도록 한다.
DoInstallDotNet 이라는 라벨이 있는 부분을 보도록 한다.

DetailPrint "Install .NET Framework 2.0"

다른 의미는 없고 인스톨 설명 줄에 "Install .NET Framework 2.0"를 출력하는 것 뿐이다. 설치 화면 중에 지금 무엇이 설치되고 있는지 설명을 출력되는 창에 보이는 문구라고 보면 된다.

ExecWait '".\AddonPackage\installdotnet.cmd"' $1

이 부분이 중요한데, '".\AddonPackage\installdotnet.cmd"' 라는 문자을 Shell을 써서 실행한다는 의미이다. 단 실행은 하는데, 단지 실행이 완전히 종료될 때까지 대기를 하겠다는 의미이다. 그리고 최종적으로 실행 결과를 $1에 출력하겠다는 것이다. 기다릴 필요가 없는 경우에는 Exec 를 쓰면 된다.

SetRebootFlag true

일종의 옵션인데, 설치 후 맨 마지막에 Reboot 하겠다는 의미이다. 종종 설치 프로그램에서도 특정 프로그램을 설치한 뒤 자동으로 재시작하는 경우를 많이 보는데, 바로 그럴 때 사용하는 옵션이다. 만일 .NET을 설치하지 않는 경우에는 Reboot를 할 필요가 없으니, 설치할 때만 이 옵션을 true로 설정하는 것이다.

Sleep 20000

설치 중에 다른 프로그램을 설치하게 되면 HDD의 Access Time이라는 것이 있어서, 약간의 대기가 필요할 수 있다.
여기서는 20초 정도로 설정했다. 1/1000 초이므로 1000이 1초. 즉 20초 대기라는 의미.

 

일단 설치되어 있는지 여부를 체크하는 함수와 그 체크한 결과 값을 기준으로 설치하는 로직을 담은 함수를 제작했다.
이제 이 함수를 호출하는 로직을 넣어보도록 한다.

먼저 체크.

설치하기 전에 맨 처음 부분에서 실행한다.
윈도우의 EventHandler 같은 기능들을 제공하는데, 그 중 인스톨러 시작할 때 걸리는 함수는 이것이다.

Function .onInit
     ………
FunctionEnd

저 함수 안에 다음과 같음 문장을 넣는다.

Call CheckAlreayInstalledSolutions

 

이제 마지막으로 남은 것은 설치하는 함수.
설치할 때 넣어주거나, 아예 시작할 때 넣어도 된다. 여기서는 설치할 때 넣을 수 있도록,
앞서 보여준 My_CopyFile  라는 함수 안에다가 다음과 같은 문장을 넣는다.

Call InstallNETFramework20

 

6.사용자 정의 화면 넣기.

사용자 정의 페이지를 넣으려면 MUI2 에서 제공하는 페이지 적용하는 방법부터 확인해야 한다.

pages

대략 보면 알겠지만, "!insertmacro" 라는 키워드를 이용해 MUI_PAGE_ 로 시작하는 페이지들을 나열한다.
바로 원하는 페이지를 넣는 방법이다. 이 방법은 MUI2 에서 만들어진 화면을 끼워넣는 것으로써,
저 넣는 순서를 바꾸면 실제 나오는 화면이 순서도 바뀌게 된다. 그리고 뒤쪽에 MUI_UPAGE는 언인스톨 할 때 보여주는 페이지들이다.

사용자 정의 화면을 만드는 방법은 다음과 같다.

  1. UI를 표시하는 ini 파일을 생성한다.
    물론 텍스트 파일 편집기로 ini 파일을 만들어도 되지만, HM NIS Edit 도구를 써서 만들도록 한다.
    만드는 방법은 파일(F) -> 인스톨 옵션 파일 만들기 를 선택한다. 그러면 다음과 같은 UI 도구가 나오는데,
    원하는 형태의 UI를 구성한다.
    custompage1
    적당한 UI를 넣고 설정을 한 뒤, 저장하면 ini 파일이 만들어진다.
  2. 만들어진 ini 파일을  스크립트 파일 내에서 등록해줘야 한다.
    먼저 스크립트 소스의 상단에 다음과 같은 줄을 포함한다.

    ReserveFile ".\qlmscr.ini"

  3. .onInit 함수 - 초기화 함수 - 에 다음과 같은 줄을 넣는다.

    !insertmacro INSTALLOPTIONS_EXTRACT_AS ".\qlmscr.ini" "qlmscr.ini"

    ini 파일의 내용을 미리 분석해서 이름을 정해 놓는 것이다. 즉 .\qlmscr.ini 라는 의미는 스크립트가 담긴 폴더위치의 qlmscr.ini를 분석한 뒤 이제 이름을 "qlmscr.ini" 로 하겠다는 것이다. 이제 이 화면에 대한 아이디는 바로 "qlmscr.ini" 가 되는 것이다.

    사실 ini 파일은 NSIS 가 설치된 폴더 아래에 있는 Plugin에 복사해서 사용하는게 일반적인 것 같다.
    하지만, ini 파일을 영구히 다른데서 쓸 예정이 아니라면, 스크립트 파일이 있는 위치에 ini 파일을 위치시켜 놓고, 위와 같은 줄을 포함해 놓으면 좋다.
  4. 위 쪽에 페이지 순서를 넣는 부분 처럼 Page custom 부분을 만들어 넣는다.
    여기서 Page custom을 만들 때 뒷부분에 다음과 같은 항목들이 들어가야 된다.
    Page custom {페이지생성용 함수} {페이지내 입력값 확인용 함수}

    예를 들면 이렇게 넣는다.

    Page custom CreateCheckUserInfo ValidateCheckUserInfo

    위와 같이 만들었으면 CreateCheckUserInfo 라는 함수와 ValidateCheckUserInfo 라는 함수도 덩달아 만든다.
  5. 생성용 함수로 들어가 다음과 같은 줄을 포함시킨다.

    !insertmacro MUI_HEADER_TEXT 'User Information' 'Input your information and serial key for authorizing this application'
    !insertmacro INSTALLOPTIONS_DISPLAY "qlmscr.ini"

    MUI_HEADER_TEXT 라는 것을 !insertmacro 해서 넣었는데, 이 부분이 현재 사용자 정의로 만든 창의 제목줄과 설명 줄 내용을 넣는 부분이다. 적당한 제목과 설명을 넣으면 된다.

    다음에 있는 INSTALLOPTIONS_DISPLY "qlmscr.ini" 부분은 qlmscr.ini 라고 정의된 사용자 정의 화면을 띄우는 작업이다. qlmscr.ini 는 앞서 .onInit 함수 안에서 설정한 그 이름이다. 즉 화면 아이디 같은 것. 즉 저 화면을 띄우겠다는 의미가 되는 것이다.

    만일 화면 안의 특정 요소들에서 값을 빼와야 되는 경우가 있다. 예를 들어 문자열을 입력받을 때 사용되는 텍스트 박스 같은 것이 있다면, 그 ID와 변수를 연결한다. 이 때 사용되는 문구가 다음과 같은 것이다.

    !insertmacro INSTALLOPTIONS_WRITE "qlmscr.ini" "Field 1" "State" "$UserName"

    번역하자면, "qlmscr.ini" 화면에 있는 "Field 1" 라는 컨트롤에서 속성 값 중, "State" 부분의 속성값을 $UserName 이라는 변수에 넣는다는 것이다. 이 때 주의할 점은 모든 값들 정보에 " " 가 들어간다.

    예를 들면 아래와 같은 모습이 되는 것이다.
    !insertmacro INSTALLOPTIONS_WRITE "qlmscr.ini" "Field 1" "State" "$UserName"
    !insertmacro INSTALLOPTIONS_WRITE "qlmscr.ini" "Field 2" "State" "$UserCompany"

 

일단 NSIS 로 인스톨러를 구성하면서 막혔던 부분에 대한 설명을 모두 담은 것 같다.
아직은 이 NSIS 라는 도구에 대한 학습이 부족하고, 더욱이 버젼별로 나누어 만드는 방법을 자동화 하는 방법을 아직 못찾고 있어서 현재로는 더 이상의 파악은 어려운 상태이다.

나중에 시간적인 여유가 되면 이 NSIS 라는 부분을 체크하고 인스톨러 답게 만들려고 한다.

여기까지 정리.

728x90
원본 문서 : http://www.twain.org/docs/TWAIN_2_1_Spec.pdf
Chapter 2. Technical Overview - TWAIN User Interface

응용 프로그램이 TWAIN을 이용하여 데이터를 취득할 때, 응용 프로그램을 사용하는 사람을 기준으로 바라보는 취득하기 위한 절차는 다음과 같은 세가지 측면으로 볼 수 있습니다.

Figure 2-2 Data Acquisition Process

The Application

사용자에게는 원하는 데이터를 취득하기 위해, 적절한 장치를 선택할 수 있어야 합니다. 또한 데이터 전송 준비가 완료되었을 때 그 에 맞는 신호를 받기 원합니다. 이러한 요구 사항들을 충족하기 위해 TWAIN에서는 File 메뉴와 같은 곳에 반드시 두가지 옵션을 넣도록 권고 하고 있습니다.

  • Select Source - Source 선택 : 장치를 선택하기 위한 기능
  • Acquire - 데이터 획득 : 데이터 전송 처리를 시작.

The Source Manager

사용자가 Select Source의 옵션을 선택 할 때, 응용 프로그램에서는 Source Manager에게 Select Source 대화상자를 띄우도록 요청하게 됩니다. 여기서는 현재 선택가능한 모든 장비들을 나열하고 사용자가 원하는 장비를 선택 표시될 수 있도록 합니다. 필요하면, 응용 프로그램에서 이 사용자 인터페이스를 자신의 버전에 맞게 별도 제작도 가능합니다.

The Source

모든 TWAIN 호환 Source에서는 독자적인 장비 별로 사용자 인터페이스를 제공합니다. 응용 프로그램 사용자는 Acquire 옵션을 선택할 때, Source에서 제공되는 인터페이스를 보여주게 됩니다. 물론 필요하면, 응용 프로그램에서 자신의 버전에 맞게 별도 제작도 가능합니다.

728x90

준비물.

VMWare Workstation 7.0 정품.

vmware-darwin-200

해킨토시용 MacOSX ( D:\OSX86.iPC.iDeneb.v1.4.10.5.6.Mac.OS.X.Leopard.Kalyway_10.5.2_DVD_Intel_Amd.iso 같은...파일이름은 각기 배포판 버전이나 캐리어의 규칙에 따라 달라질 수 있음 )

1. VMWare Workstation 준비.

일단, VMWare Workstation 7.0 을 설치한다. (가격이 세긴하지만, 성능은 우수한 가상 머신)
설치방법이야, 일반적인 VMWare Workstation 방법이고, 사이트에서 받은 Key를 넣는다.

그리고 vmware-darwin-200 을 설치한다. 사실 darwin for vmware 인데, 어둠의 경로나 기타 여러 해킨토시 관련 사이트를 통해 받을 수 있다. 일단 필자가 가진 darwin for vmware는 200 이라는 이름으로 적혀서 전달 받았는데, 그건 각기 받는 곳에따라 버전에 따라 조금씩 차이는 있겠지만, 적절한 경로에 맞추어 설치해주도록 한다.
일단 위의 파일의 압축이 되어 있으면 압축을 풀도록 한다.
그리고 setup.cmd 가 있는지 확인한다.
setup.cmd가 있으면 다음과 같이 명령을 넣는다.

setup.cmd install

만일 Windows Vista나 Windows 7 과 같은 버전의 윈도우를 사용 중이라면, cmd 창을 띄울 때 반드시 Administrator 권한을 가진 cmd 창을 열도록 한다.

 

2. VM 만들기.

가상 머신을 만드는 작업이다.

일반적인 새 가상 머신을 만드는 작업과 동일하지만, 몇가지 부분만 고려해서 만들도록 한다.

  1. 반드시 Custom(advanced) - 사용자 정의(고급) 을 선택해서 진행한다.
  2. 버전은 Workstation 6.5~7.0 에 맞춘다. 기본값이므로 그대로 둔다.
  3. 설치될 게스트 OS를 선택한다, 여기서는 반드시 Other의 FreeBSD를 선택한다.
    물론 Darwin이 x64 지원 버전이 있을 수 있는데, 그 경우에는 FreeBSD 64-Bit 를 선택한다.
    몇가지 변경이 필요할 수 있겠지만, 여기서는 FreeBSD로 할 예정이다.

  4. VM의 이름 및 저장될 위치등을 결정한다. 이름은 임의대로, 그리고 위치도, 원하는 대로 설정하도록 한다.
    (만일 C 드라이브로 설정되어 있는데, 용량이 부족할 수 있으므로 이 부분을 꼭 확인하도록 하자)
  5. 프로세스 갯수 및 코어 갯수. 프로세서야 보통 1개니 위쪽에서 1을 선택하고(시피유 2개짜리면 2를 선택하면 될듯). 듀얼 코어면 밑의 칸에서 2, 쿼드코어면 4, 구형 PC면 1을 선택하면 된다. 현재 자신의 PC에서 여유가 될법한 만큼 설정하면 된다.

  6. 메모리 사이즈. 간단하게 돌리는 정도면 512MB도 무난하지만, 개발을 하려면, 현재 가지고 있는 메모리를 고려해서 넉넉하게 잡도록 한다. 현재 필자의 PC는 거의 3G 정도인데, 그래서 2G 2048MB로 잡았다.
  7. 네트워크 설정. 지금 랜카드와 직접적으로 연결하려면 Bridge를 설정한다.만일 VM의 네트워크가 밖으로 안새게 하려면 NAT로 설정하도록 한다. 여기서는 그냥 NAT로 잡아도 무방하다. ( 즉 인터넷 공유기를 한개 더 끼어 있다고 생각하면 됨 )

  8. 다음은 HDD. HDD 동작 방식인데, 이 부분은 필자도 명확이 모르는 기능. 현재로는 권장사항이라고 적힌 부분을 선택된 채로 두도록 한다.

  9. 다음은 Virtual HDD를 새로 만들 것인지, 기존의 것을 슬것인지, 아니면 직접 물리적인 HDD와 연결할 것인지를 묻는 부분인데, 그냥 새로 만드는 것으로 한다.

  10. 그 다음 IDE 방식으로 할지, SCSI 방식으로 할지인데, 권장 방법으로 선택한다. 만일 64bit인 경우라면, 아마도 SCSI 방식이 권장으로 되어 있는데, 현재는 32Bit 여서 그런지, IDE로 설치하도록 한다.
  11. 용량은 자유롭게, 하지만, 기본 값이 8G 는 너무 작으니, 넉넉하게 잡도록 한다.

  12. 다음은 HDD 디스크 파일 이름. 그냥 VM 이름과 동일하게 잡히므로 그대로 두면 된다.
  13. 최종적으로 설치될 VM에 대한 각종 값들을 표시해주는데, 확인하고 Finish를 클릭하면 된다.
    만일 FDD 같은 쓸모없는 장치에 대한 제거는 Customize Hardware 버튼을 눌러 지우면 된다.
    단, 주의할 것은 이 가상장치를 일단 켜지 말고, 다음 작업을 해야 한다. 이를 위해서는 Power on this virtual machine after creation 의 체크를 끄도록 한다..

  14. 자 이젠 VM이 설치되어 있는 폴더로 이동하자.
    그리고 VM 파일들이 있는 위치내에서 vmx 파일을 메모장을 통해 열도록 한다.
    vmx 파일을 Drag & Drop(끌어 놓기)하면 된다.

  15. 열린 파일에서 GuestOS 라고 적힌 부분에 "Darwin10" 이라고 넣는다.
    만일 지금까지 64bit로 설정하신 분은 Darwin10-64 라고 넣도록 한다.

 

3. Mac OS X 설치하기.

VM도 준비되었고, 이제 준비해 놓은 Mac OS X 시디 이미지를 VM에 연결한다.
연결 방법은 VM의 설정(Edit virtual machine)에 들어가, 이미지를 걸어준다.
앞서 준비물로 언급한 핵킨토시용 Mac OS X면 된다.

그리고 난 뒤 장치를 켠다.그러면 맨 처음 검은 화면에 아래와 같이 표시된다.
지체없이 검은 화면 안으로 들어가 아무키나 누른다.

그럼 아래와 같은 화면으로 넘어간다. 잠시만 기다리자.

그러면 맨처음 언어 설정이 나온다. 한글로 하도록 하자.

계속을 클릭한다.(이 화면은 가지고 있는 해킨토시 이미지에 따라 다를 수 있습니다.)

해킨토시 사용에 대한 주의 사항을 일러줍니다.VM이 아닌 직접 자신의 PC에다 설치하는 경우 간혹 호환성 문제나 H/W 문제를 일으킬 소지가 다분이 있다는 조금 겁나는 경고들입니다. 그냥 동의하시구요.

이제 어디에다 설치할 것인가... 하는 부분인데, 맨처음 보면 아래와 같이 텅텅 비어 있습니다.

상단의 메뉴에서 유틸리티 -> 디스크 유틸리티를 선택합니다.

아래의 이미지 처럼, 볼륨설계에서 1개의 파티션을 선택하고, 이름에 적당한 이름을 넣고 적용을 누릅니다.

디스크 선택화면에 드디어 HDD가 보입니다. 해당 하드를 선택하고 설치를 진행하면 된다.

이제 설치 버튼을 클릭하면 자동으로 쫙 설치합니다.

4. Mac 가상 머신 설정.

이제 대부분의 단계는 완료되었다.
뭐 apple.com 계정이 기존에 있다면 최초 그 계정을 넣어주고, 없다면 계정 생성을 위한 정보들을 제공하게 된다.
뭐 자질구레한 설정 후 최후 darwin.iso를 설치하면 된다.

5. 마무리

사실 1~3 까지의 단계가 문제지, 그 이후는 Mac에 대한 기본 동작이므로 쉽게 쉽게 진행 할 수 있다.
(사용자 계정을 만드는 작업 빼고.)
현재 포스팅 내용은 대부분 직접 캡처하고 기록한 것이지만,
이 모든 내용의 단서는 "다크스타"님의 블로그를 참고(아니 완전 활용) 했다.

  1. VMware에 맥 스노우레오파드 설치하기![1]
  2. VMware에 맥 스노우레오파드 설치하기![2]

 

여튼 성공 기원 합니다 ㅋ

728x90

원본 문서 : http://www.twain.org/docs/TWAIN_2_1_Spec.pdf
Chapter 2. Technical Overview - TWAIN Architecture

TWAIN에서는 전체적으로 세가지 소프트웨어 구성요소들 통해 만들어진 데이터를 전송합니다. 응용프로그램, Source Manager, Source 이렇게 세가지가 그 중요 구성요소입니다.

이 구성요소들은 TWAIN의 아키텍처를 사용하여 서로 커뮤니케이션을 수행합니다. TWAIN 아키텍처는 ekdmarhk rkxdl 총 4가지 레이어로 되어 있습니다.

  • Application
  • Protocol
  • Acquisition
  • Device

TWAIN 소프트웨어 구성요소들이 각 계층에 어떻게 배치되는지를 아래의 그림처럼 나타낼 수 있습니다. 각 레이어는 각 섹션별로 설명을 할 예정입니다.

Application

사용자의 소프트웨어 응용프로그램 자체가 실행되는 부분이 바로 이 계층입니다.

TWAIN 에서는 사용자 인터페이스에 대한 가이드라인을 제공합니다. TWAIN기능들을 사용자들이 어떻게 접근해야 하는지 특정 Source를 어떻게 선택하는지와 같은 방법들을 응용 프로그램 개발자들에게 제시하게 됩니다.

TWAIN에서는 응용 프로그램을 어떻게 구현하는지는 전혀 고려되어있지 않습니다. 단지 응용 프로그램에서 사용하게 될 각종 응용 프로그램 내부 간의 통신 스키마에 대해 쉽게 접근 할 수 있도록 도와주는 것입니다.

Protocol.

Protocol 이란 일종의 "언어"로써 TWAIN에서 사용되는 각종 문법 같은 것으로 생각하면 됩니다. 데이터 송수신에 필요한 정확한 명령들과 통신 규약들을 정해 놓은 것입니다.

Protocol 계층에는 다음과 같은 내용이 포함되어 있습니다.

  • 응용 프로그램과 TWAIN 간에 인터페이스를 제공하는 응용 프로그램 소프트웨어의 일부분.
  • TWAIN에서 제공하는 TWAIN Source Manager
  • Source Manager에서 명령을 받고, 데이터와 결과 코드를 돌려주는 Source 장비에 포함된 소프트웨어

Protocol 계층에 대한 더 자세한 내용들은 "Communication Between the Element of TWAIN" ( Page 2-5 ) 를 참조하세요.

Acquisition

Acquisition(취득) 장치는 물리적(스캐너 혹은 디지털 카메라 같은)일 수도 있고, 논리적(이미지 데이터베이스 같은)일 수도 있습니다. 이 계층에서 가장 중요한 위치에서 Source 라고 불리는 취득 동작을 제어하는 소프트웨어 요소들로 되어 있습니다.

Source에서는 응용 프로그램에게 데이터를 전송합니다. Source와 응용 프로그램 상에서 합의를 본 형식과 전송 방법을 사용하여 전송하게 됩니다.

Source는 항상 Source 장치들을 제어하기 위한 내장된 사용자 인터페이스들을 제공합니다. 물론 필요한 경우에 응용 프로그램에서 이들 기능들을 추가적으로 덧붙여 자신만의 사용자 인터페이스를 제공할 수 있습니다.

Device

이 부분은 전통적인 저 수준의 장지 드라이버 레벨을 의미합니다. 여기서는 장치 별로 제공되는 H/W 레벨의 명령과 지시들을 전달하는 것으로 각 제조사 별로 제공된 드라이버에 특화되어 있습니다. 응용 프로그램에서는 단지 TWAIN을 사용을 하면 되고 , 이 장치 드라이버를 별도로 탑재하지 않아도 됩니다. 이 부분은 모두 Source에서 담당하게 됩니다.

TWAIN에서는 Device 계층에 대한 모든 사항들이 고려되어 있지는 않습니다. 단지 Source에서 응용 프로그램이 직접 Device 계층을 접근하지 않도록 숨겨놓았습니다. Source는 TWAIN 동작과 Source의 사용자 인터페이스 사이에서 조율을 하게 됩니다. 이를 통해 사용자가 직접 장비에 접근하지 않고도 원하는 기능을 수행할 수 있도록 내부적으로 적절한 명령들을 내리게 되는 것입니다.

NOTE : Protocol 계층은 응용 프로그램 과 Source들 사이에서 정확한 통신을 할 수 있도록 사려깊으며 엄격하게 정의되어 있습니다. 이 문서안의 정보들은 Protocol 과 Acquisition 계층에 대해 주안점을 두고 작성되었습니다.

728x90

출처 : 이선우 과장님.

.NET 응용 프로그램에 app.config 라는 설정을 넣는 부분이 있다.(ASP.NET의 web.config과 유사). 응용 프로그램이 최초 실행될때 기본적으로 설정할 때 사용되는 값들인데, 이 부분을 직접 Text로 열어 편집하곤 했다.

appsettings_view
이 부분을 직접 편집하는 것도 방법이겠지만, Resource 편집하듯 설정하는 방법이 있다.
솔루션 목록에서 윈도우 응용 프로그램 프로젝트 위에서 속성을 클릭하면 응용 프로그램 속성창이 뜨는데,
그 중 Settings 탭에 위치한 항목이 바로 그것이다.

property_settings

그런데 저 Type을 보면 알겠지만, .NET에서 제공되는 형만 존재한다.
만일 enum 형태로 사용자가 만든 별도의 형이 있다면? 그것을 사용하는 방법이 있다면?

바로 그것이다.예를 들어보자.만일 다음과 같은 enum이 존재한다면..

enums_example

TestType 이라는 형태로 저 Settings에 표현하려면??

물론 위와 같은 TestType을 먼저 선언한다.
그리고 난 뒤, 아까 Settings 에 들어가도록 한다. 그리고 Type 부분의 콤보 박스를 클릭한다.

settings_types

클릭하게 되면 여기서 사용가능한 Type들이 나열된다. 그러나 우리가 원하는 Type은 없다.
이제 맨 아래쪽에 있는 Browse... 를 선택하도록 한다.
이제 Select a Type 이라는 항목을 볼 수 있다. 여기서 아까 선언했던 enum을 찾도록 한다.
selectappsettingtype
찾았으면 선택한 뒤 OK를 클릭한다.

그리고 원하는 값을 선택한 뒤, 저장한다.
selectsettingsvalues

 

자! 그런데 여기서 문제 그 하나.

먼저 위에서 처럼 enum을 선언했는데, browse를 해도 그 enum을 찾을 수 없는 경우.
이 부분 때문에 이선우 과장님이 이리저리 헤매다가 그 차이점을 밝혔다.
즉 저 enum 선언은 반드시 app.config에 걸리는 응용 프로그램 외에 설정해야 된다는 것이다.
다시 말해 만일 app.config가 TestApp 라는 응용 프로그램에 존재한다면, Class Library 프로젝트를 별도로 만들어
그 안에서 선언해야 된다는 것이다.

correcteddefine

지금 필자가 구현한 코드 부분을 예로 든다면, 실제 실행되는 응용 프로그램이 TwainGui. 즉 app.config는 저 안에 있다. 하지만, enum은 별도의 Class Library 프로젝트인 TwainLib 라는 위치에 있다. 그것을 선언한 것.

저렇게 만들어 컴파일이 정상적으로 된다면, TwainGui에서 참조를 걸어 놓으면 위의 예제처럼 Browse 할 때 저 enum을 볼 수 있다.

 

이걸로 땡일까? 부부~ 이제 그 문제 2.

사용자 정의된 이 특수한 Type에 대한 안의 값을 선택하는 콤보 부분을 주목하자.
correcteddefine2 
아주 자연스럽게 나타나는데, 실제로 그럴까?

10이면 10, 100이면 100 대부분 아래와 같이 Type 목록으로 나오지 않고, 달랑 한개의 값만 표시된다.

correcteddefine3

실제로 그 안의 값을 열어보면, 마치 빈 TextBox 마냥 직접 사람이 입력하게 만든다.
말이 쉽지 실제로 그 값들이 기묘한 문자열이라면 찾기 무리.
처리 방법은 매우 간단하다. 일단 위의 값을 그대로 저장한 상태로 컴파일을 완료한다.
그리고 Visual Studio을 껏다가 다시켠다. 그리고 프로젝트 Reload.

즉 프로젝트를 Reload 함으로써 Reset이 되어야 올바른 값 목록이 나온다는 것이다.

일단 여기까지!

728x90

.NET Application에서 외부 이벤트를 끌어들이는 방법을 설명하고자 한다.

사실 Windows Event에서는 Managed 환경에서 제공되는 한정된 이벤트 처리를 의외로 간단하다. 하지만, Win32 기반의 외부 응용 프로그램에서 제공되는 커스텀 이벤트 처리에 대해서는 어찌되어야 할지 명확히 알지 못하는 경우가 많다. 이 부분을 언급하려고 한다.

먼저 .NET의 응용 프로그램은 Application 이라는 개체를 자체적으로 가지고 있게 된다. Static 기반으로 되어 있어, From을 띄우거나, 메시지를 가져오고 메시지를 보내는 등 어떻게 보면 OS 처럼 최하위단을 제어하고 움직이는 중요한 부분이다. 바로 이 부분을 활용하여 외부의 이벤트를 끌어오는 것이다.

이 작업을 수행하려면, 외부 이벤트를 수신하는 Windows 개체에 IMessageFilter 라는 인터페이스가 필요하다.
이 인터페이스는 System.Windows.Forms 라는 네임스페이스 상에 존재한다.

제일 먼저 이 인터페이스를 상속 받게 한다.
imessagefilter_init

그 다음은 해당 Windows 소스 내에 IMessageFilter 에 대한 구현을 구성한다.

imessagefilter_createmethod

즉 저 PerFilterMessage 라는 부분에서 실제적인 처리를 시도하게 된다.

Message 객체는 다음과 같이 구성되어 있다.

  • HWnd : 윈도우 Handle 주소값.
  • Msg : Windows 기반 메시지 ID
  • WParam : Windows 메시지와 같이 나온 값 - Word (unsigned int) 단위의 값
  • LParam : Windows 메시지와 같이 나온 값 - Long (unsinged Long) 단위의 값

Windows API 프로그래밍을 해본적이 있다면 바로 직감이 오겠지만...
바로 저 PerFilterMessage가 PumpMessage를 의미하는 것이고,
Message 객체는 Windows 메시지로 처리할 때 쓰는 모든 값이다.

이제 필요한 메시지를 직접적으로 처리해 주면 되는 것이다.

728x90

.NET을 이용해서 C++/C 로 만든 Windows DLL들을 호출하는 방법이 있다.

그 방법은 DllImport 라고 하는 System.Runtime.InteropServices 네임스페이스의 프로퍼티 클래스를 사용하면된다.

간단한 사용예는 아래와 같다.

[DllImport("twainDSM.dll")]
private static extern TwRC DSMSetParent( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, ref IntPtr refptr );

DllImport 에 원하는 DLL을 선언하고, static extern 메소드에 걸어주면 된다.
만일 입출력이 겸해지는 파라미터 인 경우 [In,Out] 을 사용하면 되고, 입력이면 그대로 [in]을 쓰면 된다.

그런데, 하나의 DLL 함수에 여러가지 형태로 정의하고 싶은 경우가 있다.
입력값이 미묘하게 틀린경우 그에 맞추기만 하면 되는 경우다.

예를 들면 TWAIN에서 제공하는 DLL 함수 중 DSM_Entry 라는 함수가 있다.

TW_UINT16 FAR PASCAL DSM_Entry( pTW_IDENTITY pOrigin,
                                  pTW_IDENTITY pDest,
                                  uint    DG,
                                  uint    DAT,
                                  uint    MSG,
                                 (void**)    pData);

그 형태는 위와 같다. 즉 첫번째 두번째 파라미터는 규격화 된 것이지만, 맨 마지막 같은 경우에는 특정한 형태가 없는 값이다. 또, 두번째 파라미터가 null 인 경우도 있을 것이다. 호출하는 방법에 따라 그 방법이 다양한데, 이것을 C#에서는 아래와 같이 표현 할 수 있다.

[DllImport("twainDSM.dll", EntryPoint="#1")]
private static extern TwRC DSM_Entry1( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, ref IntPtr refptr );

[DllImport("twainDSM.dll", EntryPoint="#1")]
private static extern TwRC DSM_Entry2( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwIdentity idds );

[DllImport("twainDSM.dll", EntryPoint="#1")]
private static extern TwRC DSM_Entry3( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwStatus dsmstat );

위의 첫번째 예에서 달라진 것은 EntryPoint를 명시한 것이다. 즉 DLL에서 제공하는 첫번째 메소드를 쓴다는 것이다. 함수 이름이야 뭐가 되든간에, 무조건 DLL에서 제공하는 첫번째 함수를 쓴다는 것이다. 파라미터도 최대한 DSM_Entry의 함수를 그대로 따르되, 두번째 파라미터가 Null 이라면 zeroptr에 IntPtr.Zero를 넣는 것이다. 그리고 맨 마지막 파라미터 같이 다양한 형태로 때려 박는 스타일일때는 그에 필요한 형을 그대로 집어넣는다. 그러면 .NET에서 DLL 함수와 연결할때, 알아서 해당 부분을 (void **)로써 제공할 뿐이라는 것이다. 다른 것들도 마찬가지로, 각 변수들의 크기만 잘 맞출 수 있다면 ( int 면 4바이트, short 이면 2바이트 등등) 그게 무슨 값이든 상관 없이 적용할 수 있다는 것이다.

Unmanaged .NET은 하면 할 수록 나름 매력이 솔솔 풍기는 기분이다.

728x90

.NET 2.0 부터 제공되는 Generic 형 Class. System.Collection.Generic 이라는 네임스페이스에 존재하는 내용이다. Collection에서는 모든 값들을 Object를 사용하기 때문에 매번 Casting 을 해야 했고, 그에 따른 성능상 문제로 인해 대안점 처럼 꺼내든 것이다. 뭐 Generic의 역사나 기타 방향성문제는 다른 문서들을 참고하시고..

여기서는 generic에 있는 각 형태에서 제공하는 find라는 함수를 이용하는 방법을 언급하려 한다. 물론 foreach와 같은 순환문을 이용해서 직접 find 함수를 구현할 수 있지만, 최소한 내부에 구현된 find 함수의 성능이 그나마 내가 직접 짠 것 보다는 좋을 것이라는 생각에 최대한 애용하는 편이다.

이 find 함수의 기본 형은 아래와 같다.

public T Find (
	Predicate<t> match
)

 

위의 형태에 대한 정의 내용을 보면 Predicate<T> 라는 게 있는데, 바로 이 부분에 대리자 역할을 하는 함수가 필요로 한다. match 라는 의미는 자신이 찾는 값의 형태인 경우에는 true 혹은 false를 돌려달라는 의미다.

여기서 개인적으로 가진 의문은 왜 find를 저렇게 구현했을까 했던 점이다. 만일 List<int> aaa 라는 개체를 만들었다면, aaa.find(1111) 식으로 aaa.find(<T>) 형태로 제공되었으면 그냥 썼을텐데, 저런식으로 만드니 원 접근이 될 터인가.. 했다. 하지만, 정작 <T> 안의 값의 형태가 복합형이고, 그 안에 찾는 조건이 복잡한 경우라면 오히려 위의 방법은 좋은 대안 식이라고나 할까?

 

일단 MSDN에서 제공되는 예제를 먼저 보자.

using System;
using System.Collections.Generic;

public class Example
{
    public static void Main()
    {
        List<string> dinosaurs = new List<string>();

        dinosaurs.Add("Compsognathus");
        dinosaurs.Add("Amargasaurus");
        dinosaurs.Add("Oviraptor");
        dinosaurs.Add("Velociraptor");
        dinosaurs.Add("Deinonychus");
        dinosaurs.Add("Dilophosaurus");
        dinosaurs.Add("Gallimimus");
        dinosaurs.Add("Triceratops");

        Console.WriteLine("\nFind(EndsWithSaurus): {0}", 
            dinosaurs.Find(EndsWithSaurus));
    }

    // Search predicate returns true if a string ends in "saurus".
    private static bool EndsWithSaurus(String s)
    {
        if ((s.Length > 5) && 
            (s.Substring(s.Length - 6).ToLower() == "saurus"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

 

끝의 글자가 saurus 로 끝나는 명칭을 찾는 로직. 저기서 보면 Find 안에 특정 값이 들어간게 아니고, 특정 함수가 들어가 있다. 즉 값의 결과가 true/false로 떨어지는 독자적인 함수가 있으면 된다.  위의 예제는 바로 List에 담긴 내용들 중 맨 끝의 글자가 saurus가 들어 있는지 체크한 뒤 있으면 true, 없으면 false로 돌려준다.

대충 이해가 되려나 싶다.

그런데, 내가 걸린 문제는 이렇다. 위의 예제대로라면, 실제 find를 사용하는 것은 그 찾으려는 값이 밖에 있다는 사실. 만일 위의 예제대로 라면, 찾기 로직 안에 saurus 라는 값 처럼 아예 박혀 있어야 되는데, 실제로는 저 값이 외부에서 받는 값일때는 걸리게 된다.

예를 들어보자. 사용자가 검색하는 단어를 기준으로 찾는다고 하자.
입력되는 값에 따라 찾는 내용이 달라져야 되는데, 이 경우에는 위와 같은 방법을 사용하면 곤란해질 수 밖에 없다. 그렇다면?

위의 예제를 보면 함수를 넣기 위해 static private로 만들었는데, 그것을 delegate라는 대리자를 사용해서 원큐로 만드는 것이다. txtInput 이라는 Text 박스에서 입력값이 생겼을 때 찾기 명령을 실행 시키는 예제로직을 만들어보았다.

List<string> aryData = new List<string>();

public Test()
{
    aryData.Add("apple");
    aryData.Add("pineapple");
    aryData.Add("steel");
}

private void txtInput_TextChanged(object sender, EventArgs e)
{
    string sResult = aryData.Find(delegate(string s) {
        return s.Equals(txtInput.Text);
    });

    if(string.IsNullOrEmpty(sResult))
        MessageBox.Show(sResult);
}

 

대략적으로 보면 알겠지만,

Find 라는 함수 뒤에 delegate 라는 대리자를 선언하고, 그 안에 가상 함수로 들어오는 파라미터 값을 정의한다. string s 부분이 있는데, 그 부분이 바로 Find 에서 역으로 호출 될 때 들어오는 값이다. 만일 List<int> 라면 int 가 되어야 할 것이다.

그리고 최종적으로 돌려주는 값은 true, false로 나올 수 있는 값이면 된다.

그러면 실제적으로 Find의 Return 값은 찾은 값을 돌려주게 된다. 지금은 List<string> 이니 돌려주는 값은 당연히 string. 만일 int면 int가 될 것이다.

 

정리하며.

물론 사람이 만든 코드이기 때문에, 성능이 월등하리라 볼 수는 없다. 하지만, 최소한 그 분야의 대가들이며, 또 내부적인 구현 시, 순수 .NET으로 만들지 않고, 성능을 위해 억지로 Binary로 만들기도 한다. 즉 알지는 못하나, 최소한 날로 짜는 것 보다 더 나은 성능을 보여줄 수 있다는 것이다.

이런 내 함수들을 활용 방법이 의외 복잡하더라도 작정하고 사용하다 보면 지금 보다 더 나은 성능을 보장할 수 있다.

 

복합형 값용 List<T>.Find 사용방법 예제.

사람 정보 중 이름이 같은 데이터를 메시지 박스에 표현 하는 방법

class PersonData
{
    public PersonData(string sName, string sSocialNo)
    {
        _name = sName;
        _socialNo = sSocialNo;
    }

    string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }

    string _socialNo;
    public string SocialNo
    {
        get
        {
            return _socialNo;
        }
        set
        {
            _socialNo = value;
        }
    }

}

List<persondata> aryData = new List<persondata>();

public Test()
{
    aryData.Add(new PersonData("홍길동", "123444-444422"));
    aryData.Add(new PersonData("조조", "123444-444422"));
    aryData.Add(new PersonData("유비", "123444-444422"));
}

private void txtInput_TextChanged(object sender, EventArgs e)
{
    PersonData sResult = aryData.Find(delegate(PersonData p) {
        return p.Name.Equals(txtInput.Text);
    });

    if(sResult != null)
        MessageBox.Show(sResult.Name + sResult.SocialNo);
}
728x90

+ Recent posts

728x90