자료 출처

2CPU의 가상화 게시판 : http://2cpu.co.kr/bbs/board.php?bo_table=vm
XPENology Forum : http://xpenology.com/forum/index.php
DomStation 블로그 : http://www.domstation.com/opware-bootstrap-and-open-vm-tools-installation/
Idiot's Guide to DSM 4.2 and ESXi 5.1.docx : http://depositfiles.com/files/virzefc1a

2CPU 장터를 통해 XW4600을 구하게되었고, 무사히 Esxi 5.5를 설치했다.
( 벤더 제품 중 가장 Native 하다고 생각되는 HP. 역시 큰 문제 없이 한번에 Esxi 5.5를 설치할 수 있었다.)

테스트를 위한 Windows Server를 설치하고 나니, 왠지 내부적으로 사용할만한 NAS가 필요했고,
이ㅔ XPEnology ( Synology OS를 커스텀화한 NAS 운영체제)를 설치하게 되었다.
편리한 UI 와 Extention이 가능한 추가 기능들은 매우 매력적일 수 밖에 없었기에, 자연스럽게 설치를 시작하게 되었다.

생각보다 진입점이 높아서(구축사례가 많지만, 기록물이 적은듯...) 검색어에 잘 걸리지 않아, 결국 2CPU를 통해 하나씩 접근해보았고, 그에 맞춰 성공한 사례를 기반으로 새로 하나 더 만들면서 기록해 본다.

 

1. 준비하기.

먼저 XPENology 파일들은 모두 7zip으로 압축되어 있다.
7zip 부터 설치해놓자. ( http://www.7-zip.org )

다음은, Esxi용 이미지가 필요하다.
처음에는 설치용 미디어만 있으면 될 줄 알았으나, 그 방법은 직접 PC 혹은 서버에 설치할 때이였고, 실제로는 Esxi용으로 별도로 만든 이미지가 필요했다. 이 파일은 다음 경로에서 다운이 가능하다.
http://xpenology.trantor.be/esxi/

image

image

image

다운을 받으면 7zip으로 압축된 파일을 다운 받는다. 이 파일을 받아 압축을 풀면 VMDK 파일이 생기는데, 이 파일이 가상머신에서 사용될 HDD 디스크 파일이다. 일단 이 파일을 저장해 놓는다.
( 현재 여기서 사용한 파일의 파일이름은 synoboot_trantor_3810_esxi_v1.1.vmdk 이다. )

그리고, 실제 XPENology를 구동하기 위한 프로그램들을 담은 Patch 파일이 필요하다.
이 파일은 배포본을 다운 받으면 된다.

image

image

image

파일을 다운로드 해서 압축을 풀면, 두개의 파일이 나오는데, 그 중 PAT 파일이 필요하다. 이 파일도 보관하자.
( 현재 여기서 사용한 파일의 파일이름은 XPEnology_trantor_v1.0_DSM_DS3612xs_3810.pat 이다. )

마지막으로 Synology Asist 라는 프로그램을 다운 받는다.
XPENology를 설치했을때, 어디에 설치되어 있는지 부터, 최초 구성작업을 이도구를 통해서 작업할 수 있어 매우 편하다. 경로는 http://global.download.synology.com/download/Tools/SynologyAssistant/4359/Windows/SynologyAssistantSetup-4.3-4359.exe 이다.

설치용 프로그램이므로 다운받은 뒤 실행해서,  반드시 설치해 놓도록 한다.

 

 

2. VM 만들기.

이제 ESXI 서버에 접속하자. 콘솔을 통해서 업로드하고, CLI 입력들을 해서 처리할 수 있겠지만, 편한 GUI를 사용하여 작업할 수 있기 때문에, 여기서는 GUI 기반으로 설명한다. ( 사실 필자도 CLI는 잘 사용하지 못한다. )

vSphere Client를 통해 Esxi 를 접속한다.

image

서버가 표시되었을 때, 서버에서 Context Menu를 띄워 "New Virtual Manchine"으로 들어간다.

image

Configuration Type은 Custom으로 한다

image

적당한 이름을 정한다.

image

VM 파일들이 저장될 위치를 선정한다. 나중에 VM Image를 올릴 위치이므로 어디다 VM을 만들었는지 기억해 놓도록 한다.

image

가상 머신의 버전을 선택하는 화면이 나온다.
여기서는 호환성 문제가 걸리지만 않는다면, 최대한 최신 설정으로 진행한다.

image

설치할 게스트의 운영체제를 선택하는 화면이 나온다.
여기서는 Linux로 하고, 2.6.X 버전의 리눅스를 사용한다고 체크한다.

image

CPU 설정은 취향대로 하면 된다.
다만, 다양한 기능들을 사용할 예정이면, Core 갯수를 늘리는 것도 좋다.
여기서는 1 이지만, 앞서 설정했던 XPEnology에서는 Core를 2개로 잡았다.

image

메모리 설정하는 부분이다.
이 역시 CPU 처럼 고성능의 작업이 필요하면 용량을 늘리도록 한다.
다만, 굳이 1G 이상을 안잡아도 생각보다 성능이 훌륭하게 나오는 편이다.
image

네트워크 설정 화면이 나온다.
각자 ESXI가 구성된 형태에 따라 알아서 잡도록 한다.

image

SCSI 컨트롤러 선택화면이 나온다.
Synology가 연결되는 형태의 SCSI 컨트롤러로 바로 잡히려면, 맨 아래 쪽에 있는 VMWare Paravirtual을 선택하도록 한다. 다른 옵션들로 연결이 잘 안되는 것 같다. ( XPENology에 해당 컨트롤러 드라이버가 없는 듯 싶다. )

image

저장소로 사용할 디스크를 생성한다.
실제적으로 XPENology 프로그램 및 저장장소로 사용될 공간을 잡는다.
여기서는 적당히 120G로 설정했다. 이 설정은 VM 설정으로도 추가적으로 잡을 수 있으므로, 적당히 잡도록 한다.

image

image

image

이제 Summary가 나왔으면 Finish를 누르도록 한다.

image

 

3. VM 구성

자 기본틀은 완성되었다. 이제 기본으로 제공한 VM을 이용해 XPEnonlogy를 구축하기 위한 작업을 한다.

먼저 앞서 다운 받은 vmdk 파일을 저 VM이 위치한 폴더에 업로드한다.
이를 위해서는 Brower DataStore를 띄워야 한다. 이 위치 정보는 앞서 VM을 생성할 때의 위치에 해당하는 저장소를 열도록 한다.

image

Datastore Browser를 띄웠으면 해당 폴더를 열도록 한다.

image

이제 아까의 VMDK 파일을 업로드 한다.

image

업로드가 완료되었으면 이제는 해당 VM의 Edit Setings 메뉴를 띄워 Properties 창을 띄운다.

image

VM 의 Properties 창이 떴으면 Hardware 탭에 있는 Add 버튼을 클릭하고, 새로 뜬 창에서
Hard Drive를 선택하도록 한다.

image

이제 업로드한 HDD를 연결한다. "Use an exsisting virtual disk"를 선택한다.

image

자 이제 업로드한 파일을 선택하고 Open을 한다.

image

IDE 0:0 로 되어있는지 확인하고 넘어간다.

image

완료 처리한다.

image

 

4.XPENology 설치

이제 XPENonlogy를 위한 VM 작업은 다 끝났다. 이제 VM을 실행하도록 한다.
실행하면서 Console 창을 띄워보면 뭐라 뭐라 Linux 부팅이 되고 최종적으로 "Diskstation login:" 이라는 문구로 끝날 것이다.

image

만일 띄우지 못했다면, Booting 순서 문제일 수 있으니, 재부팅을 한 뒤, 바이오스에 진입(F2 로 들어감)하여, 부팅 순서가 SCSI 보다 IDE HDD가 먼저 나올 수 있도록 한다. ( 부팅이 한순간이므로 부팅되자 마자 매우 빠른 F2 연타가 필요할 수 있다. )

image

이제 XPESynology를 구성하도록 한다. 이를 위해서 앞서 설치한 Synology Assist를 사용한다.
Synology Assist 프로그램을 실행한다.

그러면 자동적으로 설치된 XPENology를 볼 수 있다.
(만일 볼 수 없다면, 같은 네트워크 대역에 있는지 확인하고, 해당 XPENology VM이 제대로 떴는지 등을 확인하도록 한다. 예를 들면 Synology Assist가 실행되는 PC의 IP는 192.168.0.101 인데, XPENology의 IP는 192.168.102.8 인 경우 192.168.0.X 와 192.168.102.X는 서로 대역이 다르므로 직접 연결하여 찾지 못한다. 단순하게 말하자면, 같은 공유기 내에 있어야 된다는 의미.)

image

자, 연결된 개체서 Context Menu를 띄워 설치를 클릭한다.

image

이제 설정 마법사가 뜬다.
설치 파일 경로를 입력해달라는 위치에, 앞서 다운 받은 PAT 파일을 연결한다.

image

PAT를 정상적으로 연결했으면, 이제는 서버 정보를 입력한다.
여기서는 admin의 암호를 설정하고, 서버 이름등을 설정하면 된다.
admin 암호만 입력해도 된다. ( 서버이름의 기본값이 DiskStation 이다. )

image

SHR 볼륨 생성에 대한 체크가 된 상태로 하면 경고 창이 뜨는데, "확인" 누르고 진행하도록 한다.

이제 네트워크 설정을 한다. 가급적이면 IP를 고정해서 설정하도록 한다.
그래야 접근할 때 쉽기 때문이다.

image

그러면 설치 진행 화면이 나오는데, 큰 문제가 없으면 체크가 다 표시되면서 종료 버튼이 나오는데,
그 버튼을 클릭하면 된다.

image

 

5. VM Tools 설치.

사실 여기까지만 오면 완료되긴 했지만, 문제는 Esxi 서버에서 이 XPENology 서버를 끄질 못한다. 즉 직접 XPEnology를 콘솔로 접근하던가 해서 강제로 꺼야 된다는 말. 전원 자체를 내리는 Power Off는 되지만, Shutdown이 안된다는 의미이다.

그래서 ESXI에서 Shutdown Guest 제어가 되려면 VM Tools를 설치해야 한다. 문제는 ESXI에서 제공하는 VM Tools를 설치하기가 쉽지 않은데다가, 이 XPENology와 호환이 안된다. 그래서 다른 방식으로 진행해야 한다.

먼저 Putty 같은 telent 접속 프로그램이 필요하다. ( http://www.chiark.greenend.org.uk/~sgtatham/putty/ 설치용 프로그램이 아니므로 실행 파일만 받아서 실행하면 된다. )

실행하면 주소 창이 뜨는데, 그 안에 XPEnology의 주소를 입력한다. ( 앞서 XPENology 설치할 때의 IP 주소)

image

인증서 부분의 Warning이 뜨는데, Yes를 눌러 진행한다.

image

그러면 콘솔 접속 화면이 뜨는데, ID는 root 로, 암호는 앞서 만든 admin의 암호를 넣는다.

image

이제 명령 창과 함께 명령어들을 잘 입력하면 된다.

  1. 먼저 temp 디렉토리로 이동한다.
    cd /volume1/@tmp
  2. bootstrap 을 다운로드 받는다.
    wget  http://ipkg.nslu2-linux.org/feeds/optware/syno-i686/cross/unstable/syno-i686-bootstrap_1.2-7_i686.xsh
  3. 다운 받은 bootstrap 파일을 실행 파일로 만든다.
    chmod +x syno-i686-bootstrap_1.2-7_i686.xsh
  4. .xsh 파일을 실행한다.
    sh syno-i686-bootstrap_1.2-7_i686.xsh
  5. 이제 실행했던 스크립트 파일을 삭제한다.
    rm syno-i686-bootstrap_1.2-7_i686.xsh
  6. PATH의 경로를 변경하는 작업을 한다. 이를 위하 vi를 띄운다.
    vi /root/.profile
  7. vi에서 다음과 같이 입력하여 PATH의 문자열을 바꾼다.
    :%s/PATH=/PATH=$PATH:/
  8. vi에서 다음과 같이 입력하여 저장하고 닫는다
    :wq!
  9. 재부팅한다.
    reboot
  10. 재부팅이 완료되었으면, 다시 putty를 실행해서 다시 로그인해서 연결한다.
  11. 이제 ipkg를 이용해 내부 패키지를 정리한다.
    ipkg update
    ipkg upgrade
  12. 다시 temp 디렉토리로 이동한다.
    cd /volume1/@tmp
  13. open vm tools를 다운 받는다.
    wget http://users.skynet.be/synology/i686/syno_vmware_kernel_mod_x86_64_3.2.30.zip
  14. 다운 받은 파일의 압축을 해제한다.
    unzip syno_vmware_kernel_mod_x86_64_3.2.30.zip
  15. 압축이 풀린 경로로 들어간다.
    cd syno_vmware_kernel_mod_x86_64_3.2.30
  16. sh용 파일을 실행 가능하게 만든다.
    chmod +x S37vmware.sh
  17. sh용 실행한다.
    sh S37vmware.sh start
  18. 이제 Tools의 실제 동작하는 파일들을 설치한다.
    ipkg install http://users.skynet.be/synology/i686/open-vm-tools_9.2.3-1031360-1_i686.ipk
  19. vmtools가 자동으로 실행될 수 있도록 구성 준비한다.
    cd /opt/etc/init.d/
  20. 자동 스크립트를 다운 받는다.
    wget http://www.domstation.com/wp-content/uploads/2014/01/S22open-vm-tools-v1.1.zip
  21. 스크립트의 압축을 푼다.
    unzip S22open-vm-tools-v1.1.zip
  22. 스크립트를 실행 가능하도록 만들어 준다.
    chmod +x S22open-vm-tools.sh
  23. 다운 받은 zip 파일은 삭제하고 reboot를 한다.
    rm S22open-vm-tools-v1.1.zip
    reboot

명령 줄을 입력할 내용을 쭉 나열해서 그렇지, 사실 별 내용은 없다. 이제 root 되고 난 뒤, 완전히 부팅되었으면, Esxi 관리도구에서 해당 VM을 종료해본다. 이제는 제대로 종료가 되는 것을 확인할 수 있다.

 

정리.

사실 모든 정보는 준비되어 있었고, 자료도 있었지만, 여기저기에 단편적으로 나뉘어 있는데다가, 대부분 영어권 자료다 보니 쉬이 적용을 못하고 있었다. 하지만, 막상 해보니 큰 어려운은 없었던것 같다.

나중에 2~3T 짜리 HDD가 들어오면 용량을 넉넉히 붙여서 내 개인 저장 장소로 활용해보도록 해야 겠다.

728x90

Windows 7에서는 기존에 설정된 네트워크와 IP 주소, 게이트웨이, 넷마스크 등의 값을 기반으로, 네트워크가 틀려지면 해당 네트워크에 대한 프로파일을 생성한다.

아마도 아무 의미없이 지나가겠지만, 새로운 네트워크에 접속하면 아래와 같이 선택하는 화면이 뜬다.

image

그래서 집/회사/공공 장소로 나누어 각 보안 설정을 나누어 특정 대역대에 접속하면, 그에 맞게 방화벽이나, 공유 설정등을 할 수 있다. 집은 모든게 열려 있고, 회사는 특정 멀웨어들의 포트들을 막고, 공공장소는 대부분이 막힌 그런 설정을 꾸밀 수 있다.

그런데, 어느날 친구가 안드로이드 폰으로 테터링을 했더니, 너 프로파일이 무척이나 많이 생겼다는 것이였다. 개인적으로는 저 프로파일이 수십개 생겨도 컴퓨터에 별 지장도 없거니와 큰 불편함이 없기에 그냥 쓰라고 종용했다.

그러다, 문득 "왜? 없지" 라는 질문을 스스로에게 던지고, 구글 사마에 물어보니..왠걸.. 있었다.

http://answers.microsoft.com/en-us/windows/forum/windows_7-networking/how-do-i-delete-or-clear-redundant-network/07834191-708d-45f9-9ef2-e779dd930ce3

image

뭐 솰라솰라 읽을 필요는 없고, 간단히 말하지만, 네트워크 프로파일의 아이콘을 클릭한 뒤, 하이퍼 링크로 제공하는 "네트워크 위치 삭제 및 병합"을 하면 되는 작업이다.

해당 메뉴는 다음과 같은 순서로 들어간다.

1. 제어판 열기 ( 시작 메뉴의 제어판을 클릭한다 )

image

2. 네트워크와 인터넷 열기 ( 만일 아이콘 배열을 했으면 3번 항목으로 건너 뛴다)

image

3, 네트워크와 공유센터 열기

image

4. 연결된 네트워크 중 아이콘 아무거나 클릭하기 ( 집, 회사, 벤치 어느거든 상관 없음 )

image

5. 하단의 "네트워크 위치 삭제 또는 병합" 클릭하기 ( 웹의 하이퍼링크 처럼 생긴 부분 )

image

6. 이제 원하는 네트워크를 삭제하거나 병합한다.

image

 

예전에는 이거 안되는 걸로 알고 있었는데 원래 기능이 있었던 것 같다. ( 답변이 2010년인거 보면, Windows 7 발표 후 얼마 안되서 이므로... )

이거 친구에게 안된다고 박박 우겼는데 미안할 따름이다 ;;;;;

728x90

Windows PE에 대한 오해 중 하나는 무료 Windows 로 오해하시는 분들이 있는데, 사실 이 Windows는 Windows 안의 Core 부분만 추출하여 만든 일종의 Minimum Windows라고 생각하면 된다. Windows Vista 때부터 Windows 설치를 할 때, 완전히 GUI 기반으로 동작하는데, 이 부분이 Windows 설치용으로 구성한 Windows PE 이다. 그래서 보통 이 Windows PE는 H/W 오류로 인해 부팅이 안될 때 복구용으로 주로 쓰인다.

여기서는 ImageX 라는 MS에서 Ghost에 대항/대체 하기 위해 만든 HDD 이미지 캡쳐 도구를 사용하기 위한 Windows PE를 만들어 본다.

준비물

  • Windows 7 운영체제
    - Windows Vista나 Windows 8의 경우에는 그에 맞는 AIK 도구를 받아야 되는데, 여기서는 Windows 7을 기준으로 설명할 예정이므로, Windows 7 으로 정한다.
  • Windows 7용 AIK(자동 설치 키트) 설치용 CD 혹은 CD 이미지.
    - 위의 설명 대로 Windows 7이므로 Windows 7용 AIK를 받는다. (http://www.microsoft.com/ko-kr/download/details.aspx?id=5753 ) 에서 다운로드 가능하며, 혹시 찾지 못하는 경우 "Windows 7용 Windows AIK(자동 설치 키트)" 라는 검색어로 검색하면 쉽게 찾을 수 있다.
  • 공 CD
    - Windows PE로 구울 공시디.
  • D:\ 드라이브.
    - 이 부분은 굳이 필요한 것은 아니지만, 아래 예제로 제공될 도스창 명령줄의 모든 내용이 D:\ 드라이브에 맞춰져서 설명하므로, 이야기 한다. C:\ 나, E:\ 같은 다른 드라이브명이라면, 그에 맞게 알아서 수정해서 적용한다.

 

구성 방법

AIK(Automatic Installation Kit : 자동 설치 키트) 설치하기

먼저 AIK를 다운로드 받는다. 받는 위치는 (http://www.microsoft.com/ko-kr/download/details.aspx?id=5753 ) 이고, 만일 해당 링크가 깨져서 못 들어가는 경우 라면, "Windows 7용 Windows AIK(자동 설치 키트)" 라는 검색어로 검색하면 다운로드 페이지를 쉽게 찾아서 들어갈 수 있다..

대략 1.6 G 정도의 크기이기 때문에, 다운로드 받는데 약간의 시간이 소요될 수 있다.

파일이름이 KB3AIK.ISO 인데, 가상 드라이브 프로그램(Deamon , Virtual Clone Drive)으로 ISO를 연결하여 AutoRun을 실행하거나, 아예 DVD로 구워서 직접 DVD-ROM에 넣어 띄울 수도 있다.

실행하면 아래와 같은 AutoRun 화면이 뜨는데, 왼편에 위치한 메뉴 중 "Windows AIK 설치(W)"를 클릭한다.

그러면 설치용 프로그램이 동작하면서 설치가 진행된다. 계속 "다음(N)" 버튼을 눌러서 설치를 진행하고 완료시킨다. 내부적으로 특별히 선택을 가감하는 부분은 없기 때문에, 설치에 어려움을 없을 것이다.

 

Windows PE 파일 준비.

설치가 완료되었다면, 이제 Windows PE 제작용 폴더를 구성한다.

시작 -> 모든 프로그램 -> Microsoft Windows AIK 안으로 들어가 "배포 도구 명령 프롬프트" 아이콘에서 오른쪽 마우스 버튼을 클릭해 메뉴를 띄운 뒤, "관리자 모드로 실행"을 클릭한다..

그러면 도스 창이 뜨는데, 그 안에

copype.cmd x86 D:\winpe_x86

라고 입력한다.

그럼 자동으로 무언가를 열심히 복사하고 난 뒤, 최종적으로 커서는 D:\winpe_x86 폴더로 이동된다.

Windows PE에 필요한 모든 파일들이 복사가 완료되었다.

 

Windows PE 설정

사실 d:\winpe_x86\winpe.wim 파일을 d:\winpe_x86\ISO\boot\ 에 복사 한 뒤 파일 이름을 boot.wim 으로 변경하면 Windows PE 구성은 완료된다. 하지만, 이 Windows PE이미지는 진짜 부팅만 되는 버전이기 때문에, 내부적으로 약간 손을 봐줘야 한다. 안 그러면, 한글 폴더 이름이 깨져 보이거나, 잘못 동작하는 경우가 발생할 수도 있으며(Unicode 기반이기 때문에, 잘못 동작하는 경우는 거의 없지만... ) 한글 입력이 안되고, 좀 불편한 부분이 존재한다. 또 H/W 장치에 대한 접근을 제대로 할 수 없어, 진정한 복구 CD로써의 역할은 제대로 할 수 없다.

그래서 Windows PE를 제대로 쓰려면, 저 boot.wim 파일을 손봐야 한다.

먼저 d:\winpe_x86\winpe.wim 파일을 d:\winpe_x86\ISO\boot\ 에 복사 한 뒤 파일 이름을 boot.wim 으로 변경 해야 한다.

copy d:\winpe_x86\winpe.wim d:\winpe_x86\ISO\sources\boot.wim

도스 창에서 위와 같은 명령을 치면 복사와 함께 이름 변경이 된다.

그리고 난 뒤, boot.wim 파일을 열어야 된다. 이 때 압축 풀 듯이 열기는 하는데, 여기서 wim 파일을 여는 작업을 Mount 라고 해서, 적당한 디렉터리에 파일 자체를 아예 연결해버리는 것이다. 마치 하위 폴더에 압축 풀듯 바로 접근을 할 수 있다. 이 마운트 방법은 다음과 같다.

dism /Mount-Wim /WimFile:D:\winpe_x86\ISO\sources\boot.wim /index:1 /MountDir:D:\winpe_x86\Mount

그러면 D:\winpe_x86\Mount 폴더를 보면 wim 파일 내용이 그대로 보인다.

다음은 Windows PE용 추가 패키지 설치 작업이다.

먼저 한글판 구성을 위한 설정들이다.

다음 명령 줄을 한 줄 씩 실행한다. 그러면 한글에 관련된 폰트, 기본적인 파일들이 적용되고, 최종적으로 Windows PE 자체를 한글판으로 구성하게 된다.

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-fontsupport-ko-kr.cab" 

Dism /image:D:\Winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\ko-KR\lp_ko-kr.cab"

Dism /image:D:\winpe_x86\mount /Set-AllIntl:ko-KR

이제 기타 추가 도구를 설치한다. 여기서 설치하는 것은 Htmal 기반의 Application 용 도구, WMI 관련 모듈, Script 관련 모듈이다. 이 역서 다음 명령 줄을 차례 대로 실행하면 된다. 비슷한 이름으로 맨 뒤에 _ko-KR 파일은 해당 도구/모듈의 한글 리소스 내용이므로 반드시 같이 설치해야 한글로 제대로 나온다.

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-hta.cab"

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\ko-KR\winpe-hta_ko-kr.cab"

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-wmi.cab"

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\ko-KR\winpe-wmi_ko-kr.cab"

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\WinPE-Scripting.cab"

Dism /image:D:\winpe_x86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\ko-KR\WinPE-Scripting_ko-kr.cab"

마지막으로 imageX 관련된 파일 및 기타 도구들을 직접 복사해 준다.

xcopy /y "C:\Program Files\Windows AIK\Tools\x86\imagex.exe" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\intlcfg.exe" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\oscdimg.exe" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\wdsmcast.exe" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\wimmount.inf" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\wimmount.sys" "d:\winpe_x86\mount\Windows\System32\"
xcopy /y "C:\Program Files\Windows AIK\Tools\x86\WimMountInstall.exe" "d:\winpe_x86\mount\Windows\System32\"

그러면 1차적으로 Windows PE를 위한 기본적인 구성은 끝난다.

 

부팅 이미지 만들기.

CD로 굽기 위해서는 ISO 파일로 만들어야 하는데, 이를 위해서는 Mount 시킨 WIM 이미지를 해제 시키고, ISO 파일로 만드는 작업을 한다.

Unmount 방법은 다음과 같다.

Dism /unmount-Wim /MountDir:D:\winpe_x86\mount /Commit

그러면 자동으로 Unmount 된다.

만일 안된다면, D:\winpe_x86\Mount 폴더 내에 연결되어 있는 모든 프로그램들을 종료하고 다시 시도하도록 한다.

모든 것이 정리되었다면, 이제 부팅 시디를 만들기 위한 ISO 파일을 제작한다. 이 역시 명령 줄로 해결한다.

oscdimg -n -bD:\winpe_x86\etfsboot.com D:\winpe_x86\ISO D:\winpe_x86\winpe_x86.iso

그러면 최종적으로 D:\winpe_x86 위치에 winpe_x86.iso 파일이 있다.

그 파일을 CD로 구우면 된다.

 

정리 및 추가 정보

Windows PE 제작이 예전에 비해서 정말 쉬워졌다. 과거 Windows XP 시절에 생성하던 Windows PE에 비해 wim 이라는 이미지 파일이 생겨서 간단하게 적용이 된다.

만일, Windows PE로 부팅했을 때, 자동으로 실행되어야 할 내용이 있다면, Unmount 하기 전에, d:\winpe_x86\mount\Windows\System32\ 폴더에 있는 Startnet.cmd 파일을 편집하면 된다. 자동으로 실행되는 배치 파일로써, 이 안에다 넣으면 자동으로 실행되게 만들어 줄 수 있다.

네트워크 드라이버나, 저장 장치 드라이버를 추가하고 싶다면, http://technet.microsoft.com/en-us/library/cc749350%28v=ws.10%29.aspx 글을 참고하면 된다.

만일 이 Windows PE를  부팅용 USB로 만들고 싶다면, http://technet.microsoft.com/en-us/library/cc766092%28v=ws.10%29.aspx 글을 참고한다.

728x90

NTFS로 포멧된 폴더에 다양한 사용 권한을 걸어 사용하다가,
운영체제를 자주 변경하는 경우, 데이터용으로 사용한 파티션의 파일들이
알 수 없는 권한이 걸려 Access Denine이 걸리는 경우가 많다.

보통 C:\는 운영체제용으로 사용하고, D:\를 데이터로 하는데, C:\ 야 설치 중에 Format을 하니, 큰 문제가 없지만, 백업 처럼 사용하는 D:\ 드라이브에서는 어떻게 될지 모른다. 특히 공유 폴더들을 설정하거나, 개인용 폴더 설정등을 하다가 보면, 자신도 모르게 파일 권한이 변경이 되어 있고,
나중에 운영체제를 바꿔서 해당 폴더를 접근하려다 보면, 접근 불가에 빠진다.
그렇다고 속성을 열어서 이렇게 저렇게 수정해봐도 도저히 불가능한 경우에도 빠지게 된다.

이 경우 보안 속성을 어떻게든 초기화 해야 하는데, 이 경우에 처리하는 방법이다.

1. 시작 –> cmd를 검색 –> cmd를 관리자 권한으로 실행한다.

2. 권한을 바꾸려는 폴더 이름이 D:\Works 면 다음과 같이 입력한다.

icacls D:\Works /T /Q /C /RESET

만일 드라이브 전체라면, 해당 드라이브로 옮겨가서 D:\Works 대신 * 라고 넣는다.

icacls * /T /Q /C /RESET

3. 기다린다.

 

파일이 많으면 생각보다 긴 시간이 소요된다.
이렇게 바꾸면 최소한 기존에 설정된 각종 보안 설정 값들이 초기화 되서, 접근 되지 않는 경우가 많이 없어진다.

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

단순한 컨트롤인 TextBox 나 ListBox 같은 것은 그냥 쓰면 되는데, 복합 컨트롤을 만들 필요가 있는 경우 사용자 컨트롤을 만들어 사용하곤 한다. 즉 TextBox와 ListBox가 하나로 합쳐진 특수 목적 컨트롤 같은 것을 만들때다.

compositectrl1

저렇게 컨트롤 안에서 동작만 되면 문제가 없는데, 만일 외부로 이벤트를 노출 시킬 필요가 있는 경우가 있다. 위의 그림을 예로 들면 아랫쪽이 ListBox인데, ListBox의 선택이 변경되는 경우 저 통짜 컨트롤을 쓰는 곳에서 그 이벤트를 받기 위해서 구성하는 경우다.

어떻게 해야 될까 고민을 하다가 링크 하나를 발견했다. ( http://www.akadia.com/services/dotnet_user_controls.html )

만드는 방법은 간단하다. 딱 두 줄에 해당하는 내용을 넣으면 된다.

public delegate void 이벤트이름Handler();
public event 이벤트이름Handler 이벤트이름;

위와 같이 구성하면 되는데, 위의 컨트롤에서 사용한 내용은 아래와 같다.

// 컨트롤 내부 소스
public delegate void SelectChangedHander(); 
event SelectChangedHander SelectChanged;

event로 SelectChanged 라는 이름으로 하고 밖에서 연결할 때 사용하는 끈 역할을 하는 Handler를 delegate(대리자)로 선언하여 처리하는 것이다. 그러면 밖에는 이 Handler를 통해 이벤트 가입을 하는 것이다. 가입방법은 예전에도 많이 봤던 그런 형태가 된다. ( 저 이벤트를 받을 메인 프로그램에 선언하는 그 형태. )

// 컨트롤을 사용하는 메인 프로그램 소스
this.categoryCtrl.SelectChanged += new CategoryCtrl.SelectChangeHander(this.categoryCtrl_SelectChanged);

그러면 컨트롤 측에서 이벤트를 발생을 어떻게 하는 걸까?
그 역시 간단하다.

이벤트 이름을 함수로 호출하듯 하면 된다.

// 컨트롤 내부 소스 중 이벤트가 발생되는 시점
if (SelectChanged != null)
   SelectChanged();

보면 뜬금 없이 SelectChage가 null 인지 체크하는 경우가 있는데, 컨트롤이 제대로 초기화되지 않은 상황에서 호출되는 불상사를 막기 위한 안전 장치이다. 무시해도 되긴 하지만, 가급적이면 저렇게 안전장치를 거는걸 권장한다.

자,위와 같이 구성했다면, 이렇게 된다.

컨트롤내부 실행 중

-> SelectChange() 함수 호출

-> SelectChanageHandler로 연결한 모든 부분에 이벤트 발송

-> SelectChangedHandler에 인자값으로 넘긴 함수를 호출
   (위의 예제로 있는 categoryCtrl_SelecChanged() 함수 같은거)

기존에는 그냥 만들어진 이벤트를 소비하기만 했다면 자신만의 이벤트로 작업을 한다면 이런 부분을 활용해 보는 것도 나쁘지 않을 것이다.(생각해보니, 이렇게 만들 수 밖에 없기는 하다.)

728x90

+ Recent posts

728x90