engineering/System Eng.2009. 11. 10. 11:26

Runas

Allows a user to run specific tools and programs with different permissions than the user's current logon provides.

Syntax

runas [{/profile|/noprofile}] [/env] [/netonly] [/smartcard] [/showtrustlevels] [/trustlevel/user:UserAccountName program

Parameters

/profile Loads the user's profile. /profile is the default.

/no profile Specifies that the user's profile is not to be loaded. This allows the application to load more quickly, but it can also cause a malfunction in some applications.

/env Specifies that the current network environment be used instead of the user's local environment.

/netonly Indicates that the user information specified is for remote access only.

/smartcard Indicates whether the credentials are to be supplied from a smartcard.

/showtrustlevels Lists the /trustlevel options.

/trustlevel Specifies the level of authorization at which the application is to run. Use /showtrustlevels to see the trust levels available.

/user:UserAccountName Specifies the name of the user account under which to run the program. The user account format should be user@domain or Domain\User.

program Specifies the program or command to run using the account specified in /user.

/? Displays help at the command prompt.

Remarks

It is good practice for administrators to use an account with restrictive permissions to perform routine, nonadministrative tasks, and to use an account with broader permissions only when performing specific administrative tasks. To accomplish this without logging off and back on, log on with a regular user account, and then use therunas command to run the tools that require the broader permissions.

For examples of the use of the runas command, see Related Topics.

The use of runas is not restricted to administrator accounts, although that is the most common use. Any user with multiple accounts can use runas to run a program, MMC console, or Control Panel item with alternate credentials.

If you want to use the Administrator account on your computer, for the /user: parameter, type one of the following:

/user:AdministratorAccountName@ComputerName

/user:ComputerName\AdministratorAccountName

If you want to use this command as a domain administrator, type one of the following:

/user:AdministratorAccountName@DomainName

/user:DomainName\AdministratorAccountName

With the runas command, you can run programs (*.exe), saved MMC consoles (*.msc), shortcuts to programs and saved MMC consoles, and Control Panel items. You can run them as an administrator while you are logged on to your computer as a member of another group, such as the Users or Power Users group.

You can use the runas command start any program, MMC console, or Control Panel item. As long as you provide the appropriate user account and password information, the user account has the ability to log on to the computer, and the program, MMC console, or Control Panel item is available on the system and to the user account.

With the runas command, you can administer a server in another forest (the computer from which you run a tool and the server you administer are in different domains).

If you try to start a program, MMC console, or Control Panel item from a network location using runas, it might fail because the credentials used to connect to the network share are different from the credentials used to start the program. The latter credentials may not be able to gain access to the same network share.

Some items, such as the Printers folder and desktop items, are opened indirectly and cannot be started with the runas command.

If the runas command fails, the Secondary Logon service might not be running or the user account you are using might not be valid. To check the status of theSecondary Logon service, in Computer Management, click Services and Applications, and then click Services. To test the user account, try logging on to the appropriate domain using the account.

Examples

To start an instance of the command prompt as an administrator on the local computer, type:

runas /user:localmachinename\administrator cmd 

When prompted, type the administrator password.

To start an instance of the Computer Management snap-in using a domain administrator account called companydomain\domainadmin, type:

runas /user:companydomain\domainadmin "mmc %windir%\system32\compmgmt.msc" 

When prompted, type the account password.

To start an instance of Notepad using a domain administrator account called user in a domain called domain.microsoft.com, type:

runas /user:user@domain.microsoft.com "notepad my_file.txt" 

When prompted, type the account password.

To start an instance of a command prompt window, saved MMC console, Control Panel item, or program that will administer a server in another forest, type:

runas /netonly /user:domain\username "command" 

domain\username must be a user with sufficient permissions to administer the server. When prompted, type the account password.

Formatting legend

Format Meaning

Italic

Information that the user must supply

Bold

Elements that the user must type exactly as shown

Ellipsis (...)

Parameter that can be repeated several times in a command line

Between brackets ([])

Optional items

Between braces ({}); choices separated by pipe (|). Example: {even|odd}

Set of choices from which the user must choose only one

Courier font

Code or program output

Cmd

Command-line reference A-Z

Create a shortcut using runas command parameters


Posted by theYoungman
engineering/System Eng.2009. 4. 13. 15:42

http://blog.naver.com/pointer98?Redirect=Log&logNo=150036254254

전처리 지시어는 컴파일 직전에 처리된다.

 

#include

ex> #include <stdio.h>

이 지시어는 헤더 파일을 지시어가 들어가 있는 위치에 헤더파일을 포함시키는 것이다. < >괄호를 사용하면 표준 헤더 파일 디렉토리에서 지정한 파일을 찾는다. 같은 폴더일 경우에는 " "괄호를 사용한다. 물론 <>, ""의경우 어떤 것을 사용해도 상관은 없다 해당 폴더를 검색해서 해당 파일이 없다면 다른 폴더도 검색하기 때문이다.

 

#define

ex> #define NUM 1

(치환전) int Arr[NUM]; -> (치환후) int Arr[1];

이 지시어는 거의 치환의 의미로 사용됩니다. 위의 NUM을 컴파일하기전에 전처리기는 1로 대체한다. NUM이 어디에 있든 찾아내서 1로 바꾼다.

 

ex> #define TEXT "전처리 지시어"

(치환전) printf("%s", TEXT); -> (치환후) printf("%s", "전처리 지시어");

또한 정수형과 같이 문자열로도 치환이 가능하다.

 

ex> #define MAX

#ifdef MAX

  //MAX가 define되어 있다면 해당 코드가 컴파일 된다.

#else

  //MAX가 define되어 있지 않다면 해당 코드가 컴파일 된다.

#endif

또한 MAX로 정의는 하지만 대치시키지는 않도록 할수도 있다. 이것은 #ifdef ~ #elif ~ #else ~ #endif 문과 같이 사용되면 상당히 유용하게 사용된다. 이런것을 조건부 컴파일이라 한다.

 

#undef

ex>

#undef MAX

//이 아래 부터서는 MAX는 정의 되어 있지 않게 된다.

#ifdef MAX

  //MAX가 undef 되어 코드를 컴파일하지 않는다.

#else

  //MAX가 undef 되어 코드를 컴파일 한다.

#endif

이 지시어는 define으로 정의된 것을 해제하는 것으로 해당 코드 아래 부터서는 MAX의 정의가 되어 있지 않은 것으로 간주 한다.

 

ex>

#define SIZE 100
i = SIZE;

#undef SIZE
#define SIZE 200
j = SIZE;

또한 Define으로 정의한 것을 다시 정의하면 컴파일 에러를 일의킨다. 이때 사용하는 것이 undef이다. 위와 같이 사용하면 컴파일 에러는 나지 않는다.

 

#if, #else, #endif

ex>

#if 0

  //if 가 0 이기 때문에 이 코드는 컴파일 되지 않는다.

#else

  //if 가 0 이기 때문에 이 코드는 컴파일 된다.

#endif

이 지시어는 일반 적인 if문과 동일 방식으로 동작한다.

 

#if 0

  //대용량 코드

#endif

또한 대용량코드를 주석 처리를 하지 않고 한번에 컴파일에서 삭제가 가능하다는 것이다.

 

#ifdef, #elif

ex>

#ifdef MAX1

  //MAX1 이 정의 되어 있다면 이곳의 코드를 컴파일 한다.

#elif MAX2

  //MAX1 이 정의 되어 있지않고 MAX2가 정의 되어 있다면 이곳의 코드를 컴파일 한다.

#else

  //MAX1 과 MAX2 가 정의 되어 있지 않다면 이곳의 코드를 컴파일 한다.

#endif

이 지시어는 MAX1 과 MAX2가 정의(Define)되었는지 체크하고 그에 해당하는 코드를 컴파일하게 된다.

 

#ifndef

ex>

#ifndef FILENAME_H

#define FILENAME_H

  //코드

#endif

이 지시어는 ifdef와 반대로 해당 수식어(FILENAME_H)가 정의 되어 있지 않다면 참으로  #endif 까지의 코드를 컴파일 하게 된다.

또한 이것은 헤더 파일이 중복되어 선언 되지 않도록 할때 자주 사용 되는 방식이다.

 

#error

ex>

#if !defined(__cplusplus)

#error C++ compiler required.

#endif

이 지시어는  전처리기가 해당 코드를 실행하게 되면 에러 메시지를 출력시키고 컴파일 작업을 하지 않도록 만든다.

 

#line

ex>

x = 1;                       //3번 라인

#line 100 "main.c"     //4번 라인

y = 1;                      //100번 라인

이 지시어는 사용자를 위한 문장이기 보다는 컴파일러 자체를 위한 프리프로세서문이다. 실제 컴파일 에러가나면 line을 거치면서 5번 라인이 아니라 100라인에서 에러가 난것으로 나타난다.

 

기타 전처리기 사용방법

매크로 함수(Macro function)

매크로 함수도 전처리기로 사용할 수 있다. 다만 디버깅이 힘들어 많이 사용되지 않는다.

ex> 

#define CUBE(x) ((x)*(x)*(x))

(치환전) y = CUBE(x);  -> (치환후) y = (x) * (x) * (x);

 

매크로 함수를 사용한다면 ()를 남발하는 습관을 키워야 한다.

ex>

#define CUBE(x) (x*x*x)

(치환전) y = CUBE(3+4);  ->  (치환후) y = (3+4 * 3+4 * 3+4);

위와 같은 경우 우리가 생각한 값은 나오지 않는다.

 C++ 사용자는 매크로 함수보다는 template이나 inline 함수를 사용해야 한다.

 

문자열 조작

ex>

#define SAY(x) printf(#x)

(치환전) SAY(Hello, world!);  ->  (치환후) printf(“Hello, world!”);

위와 같이 식별자 앞에 # 를 붙이게 되면 자동으로 “x” 와 같이 “”로 둘러 싸 준다.

 

문자열 결합 

 ex>

#define Print(x) Print ## x

(치환전) Print(One)  ->  (치환후) PrintOne

(치환전) Print(Two)  ->  (치환후) PrintTwo

## 는 두 개의 문자열을 결합해 준다. 위와 같이 사용하면 PrintOne 이라는 문자열로 대치되고 Print(Two) PrintTwo 라는 문자열로 대치된다.

 

assert() 

 ex>

#ifndef DEBUG

  #define ASSERT(x)

#else

  #define ASSERT(x) \

       if ( ! (x) ) \

       { \

             printf(#x); \

             printf(“ is NULL on line %d in file %s”, __LINE__, __FILE__); \

       }

#endif

대부분의 컴파일러는 ASSERT() 매크로를 가지고 있다. 

DEBUG 정의에 따라 디버그때만 코드가 생성되고 릴리즈시에는 코드가 생성되지 않게 할 수 있는 것이다.

또한 여러 줄이 필요할 때는 \ 가 사용되었다는 것에 유의하자.

 

ex> /* VC++6.0의 asert() */

#define _ASSERT(expr) \
        do { if (!(expr) && \
                (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, NULL))) \  //Debug 정보를 출력
             _CrtDbgBreak(); } while (0)  //자동으로 Debug Break를 잡아 준다. 이것 만으로도 유용하게 사용이 가능하다.

 

내장 매크로

ex>

printf(“ is NULL on line %d in file %s”, __LINE__, __FILE__);

컴파일 시에 컴파일러가 미리 정의하고 있는 매크로들 이다. 

매크로명

타입

설명

__DATE__

문자열

컴파일하는 날짜

__TIME__

문자열

컴파일하는 시간

__LINE__

정수

컴파일하고 있는 번호

__FILE__

문자열

현재 컴파일 하고 있는 파일의 이름

__TIMESTAMP__

문자열

소스 파일의 최종 변경 날짜와 시간

 ex>

printf("%d\n", __LINE__);  //컴파일시의 해당라인 출력 - 1234

printf("%s\n", __FILE__);  //컴파일시의 해당파일Path 출력 - c:\main.c

printf("%s\n", __DATE__);  //컴파일시의 날짜 출력 - Jan 1 2009 / 월.일.년

printf("%s\n", __TIME__);  //컴파일시의 시간을 출력 - 15:31:17 / 24시간:분:초

printf("%s\n", __TIMESTAMP__);  //컴파일시의 날짜와 시간을 출력 - Mon Jan 1 15:31:17 2009 / 요일.월.일.24시간:분:초.년

 

Posted by theYoungman
engineering/System Eng.2009. 4. 13. 15:41
Posted by theYoungman
engineering/System Eng.2009. 4. 13. 15:40
Posted by theYoungman
engineering/System Eng.2009. 4. 13. 15:39

ntohl

http://synch3d.com/winsock/ntohl.html

ntohl 함수는 32-비트에 대한 TCP/IP 네트웍 바이트 오더를 호스트 바이트 오더로 변환합니다. (빅-인디언을 리틀-인디언으로 변환)

u_long ntohl (
     u_long
netlong
);

 

Parameters

netlong
[입력] TCP/IP 네트웍 바이트 오더인 32-비트 정수입니다.

 

Remarks

ntohl 함수는 TCP/IP 네트웍 바이트 오더인 32-비트 정수를 입력으로 호스트 바이트 오더인 32-비트 정수를 리턴하는 함수입니다.

 

Return Values

ntohl 함수는 항상 호스트 바이트 오더 값을 리턴합니다. 만약 netlong 매개변수가 이미 호스트 바이트 오더라면, 아무런 연산도 일어나지 않습니다.

 

QuickInfo

Windows NT : 사용가능
Windows : 사용가능
Windows CE : 버젼 1.0 그리고 그이후의 버젼에서 사용가능
Header :
          Win16/32 : winsock.h
          Win32-II : winsock2.h
Import Library :
          Win16 : winsock.lib  
          Win32 : wsock32.lib  
          Win32-II : ws2_32.lib

See Also

overview, htonl, htons, ntohs, WSAHtonl, WSAHtons, WSANtohl, WSANtohs


Posted by theYoungman
engineering/System Eng.2008. 10. 28. 12:11
출처 : http://newtype.pe.kr/388


Sun 솔라리스 에서 Route 테이블 조회 / 추가 / 삭제 방법

- route 조회
netstat -r


- default Gateway 지정
route add default 192.168.10.1


- 특정 IP(61.211.7.4)에 대한 Gateway 지정
route add 61.211.7.4 192.168.10.1


- class 전체에 대한 Gateway 지정
route add net 61.211.7.0 192.168.10.1


- route 삭제
route delete 61.211.7.4 192.168.10.1
route delete net 61.211.7.0 192.168.10.1




Posted by theYoungman
engineering/System Eng.2007. 3. 9. 09:47


출처 - http://kin.naver.com/knowhow/entry.php?d1id=3&dir_id=3&eid=DV7BINcdSKfXO5Pt8AqguM5pDM4QXkwq&qb=bnNpcyBmaWxlIMb3x9Q=




NSIS 스크립트 예제>

=========================================================================================

;NSIS Modern User Interface
;Eocs (굴단::Nuke팀::헌터)
;Written by Eocs (=Arian2u,4u=SJWannabe=DeadlyAngel)

;★★★--------------------------------
;Include Modern UI
  !include "MUI.nsh" ; ◀ Modern UI 의 헤더파일입니다.

                            ; (Modern UI 는 최근의 윈도에서 사용되는 마법사와 같은 형태의

                            인터페이스를 갖추고 있습니다.)

;★★★--------------------------------
;General

;Name and file
  Name "Nuke UI Ver 0.7 베타" ; ◀ 셋업 실행시 상단에 나타날 프로그램 명칭입니다.
  OutFile "Nuke_Setup.exe" ; ◀ 셋업파일명을 지정해줍니다.

;Get installation folder from registry if available
  InstallDirRegKey HKCU "Software\Nuke UI Beta" "" ; ◀ 레지스트리에 등록합니다.

;★★★--------------------------------
;Interface Settings
  !define MUI_ABORTWARNING

;★★★--------------------------------
;Pages
!insertmacro MUI_PAGE_LICENSE $(myLicenseData) ; ◀ 아래의 A) LicenseData와 맞물려

                                                                            한글 txt 파일을 읽어들입니다.
  !insertmacro MUI_PAGE_COMPONENTS
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES
  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES

;★★★--------------------------------
;Languages
!define EUL_RUL "를"       ;한글 (을)(를) 처리 ; ◀ 한글 (을)(를)처리를 수정해줍니다.
!insertmacro MUI_LANGUAGE "Korean" ; ◀ 기본 언어를 한글로 설정합니다.

;Reserve Files
  !insertmacro MUI_RESERVEFILE_LANGDLL

LicenseLangString myLicenseData ${LANG_KOREAN} "${NSISDIR}\Docs\Modern UI\License_NukeUI_KR.txt"
LicenseData $(myLicenseData) ; ◀ A) LicenseLangString과 함께 사용하여 라이센스

                                             정보를 한글 파일로 사용할 수 있도록 합니다.

;★★★--------------------------------
;함수 내에서만 실행되는 것들 처리
Function .onInit         ;onInit
;WOW가 설치된 경로 가져오기
ReadRegStr $INSTDIR HKEY_LOCAL_MACHINE "SOFTWARE\Blizzard Entertainment\World of Warcraft" "InstallPath" ; ◀ 레지스트리의 값을 읽어서 $INSTDIR에 저장합니다.
;중복실행 방지
  System::Call 'kernel32::CreateMutexA(i 0, i 0, t "NukeUI_Beta_0.7") i .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
  MessageBox MB_OK|MB_ICONEXCLAMATION "NukeUI 0.7 설치를 위한 인스톨러가 이미 실행중입니다. - Eocs (굴단::Nuke팀::헌터) -" ; ◀ Mutex를 만들어 중복실행을 방지합니다.
  Abort
FunctionEnd

;★★★--------------------------------
;Default installation folder
InstallDir $INSTDIR ; ◀ 기본 설정 경로를 지정합니다.

;★★★--------------------------------
;Installer Sections - 필수 애드온 (UnitFrame 관련, Raid 관련, Sct, SpellAllert 등...)
Section "!필수(공통) 기능" GR_COMMON ; ◀ !가 들어간 Section의 문자열은 굵게 나타납니다.
SectionIn RO ; ◀ 필수 선택으로 Read Only

  ; Write the installation path into the registry
  WriteRegStr HKLM SOFTWARE\NukeUI "Install_Dir" "$INSTDIR" ; ◀ 인스톨 경로를 레지스트리에

                                                                                          등록합니다.

  ; Write the uninstall keys for Windows

  ; ◀ 아래의 4줄은 Uninstall 정보를 레지스트리에 등록합니다.
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NukeUI" "DisplayName" "Nuke UI Ver 0.7 베타"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NukeUI" "UninstallString" '"$INSTDIR\Uninstall_NukeUI.exe"'
  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NukeUI" "NoModify" 1
  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NukeUI" "NoRepair" 1
WriteUninstaller "$INSTDIR\Uninstall_NukeUI.exe"

;Start Menu Shortcuts ; ◀ 프로그램 그룹에 등록하고, 언인스톨의 바로가기 아이콘을 만듭니다.
  CreateDirectory "$SMPROGRAMS\Nuke UI Ver 0.7 베타"
  CreateShortCut "$SMPROGRAMS\Nuke UI Ver 0.7 베타\Nuke UI 언인스톨(제거).lnk" "$INSTDIR\Uninstall_NukeUI.exe" "" "$INSTDIR\Uninstall_NukeUI.exe" 0

;Remove And Create Directory
  RMDir /r "$INSTDIR\Interface" ; Interface(AddOns) 폴더 삭제 ; ◀ /r 옵션은 하위폴더를 포함
RMDir /r "$INSTDIR\WTF" ; WTF(Account) 폴더 삭제
CreateDirectory "$INSTDIR\Interface"  ; Interface(AddOns) 폴더 생
CreateDirectory "$INSTDIR\WTF"    ; WTF(Account) 폴더 생성

;필수(공통) 애드온 설치
SetOutPath "$INSTDIR\Interface\AddOns\!ImprovedErrorFrame"
File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\!ImprovedErrorFrame\" ; ◀ /r 옵션으로 모두 포함
SetOutPath "$INSTDIR\Interface\AddOns\!StopTheSpam"
;이하 생략 합니다.

;.

;.

;.


;WTF\Account 폴더에 설정 파일 설치
SetOutPath "$INSTDIR\WTF\Account\계정이름입력"
File /r "..\..\..\..\Account(NukeUI 0.7배포)\계정이름입력\"
SectionEnd

;★★★--------------------------------
;Installer Sections - 타이탄 패널과 플러그인
SectionGroup /e "타이탄 패널" GR_TITAN ; ◀ /e 옵션은 Expand입니다. 옵션을 확장시킵니다.
Section "타이탄 기본" SecTitan
 SectionIn RO
 SetOutPath "$INSTDIR\Interface\AddOns\Titan"
 File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\Titan\"
 SetOutPath "$INSTDIR\Interface\AddOns\TitanAmmo"
 File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\TitanAmmo\"
 SetOutPath "$INSTDIR\Interface\AddOns\TitanBag"
 File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\TitanBag\"
 SetOutPath "$INSTDIR\Interface\AddOns\TitanClock"
 File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\TitanClock\"
 ;이하 생략합니다.

  ;.

  ;.

  ;.
SectionEnd
SectionGroup "타이탄 추가" GR_T_PLUGIN
Section "경험치표시" SecTitanXPStatus
  SectionIn RO
  SetOutPath "$INSTDIR\Interface\AddOns\TitanXPStatus"
  File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\TitanXPStatus\"
 SectionEnd
 Section /o "어그로경고" SecTitanAggro
  SetOutPath "$INSTDIR\Interface\AddOns\TitanAggro"
  File /r "..\..\..\..\AddOns(NukeUI 0.7배포)\TitanAggro\"
 SectionEnd
 ;이하 생략합니다.

  ;.

  ;.

  ;.
SectionGroupEnd
SectionGroupEnd ; ◀ SectionGroup내에 여러 Section과 하위 SectionGroup이 있습니다.

;★★★--------------------------------

; 이하 SectionGroup과 Section들 생략합니다.

;.

;.

;.


;★★★--------------------------------
;Descriptions

  ;Language strings ; ◀ 각 섹션그룹과 섹션의 설명(툴팁) 문자열을 지정합니다.
LangString DESC_GR_COMMON ${LANG_KOREAN} "Nuke UI Ver 0.7 베타의 공통 라이브러리 입니다.(필수)"
LangString DESC_GR_TITAN ${LANG_KOREAN} "타이탄 패널입니다. WOW 화면 상하단에 유용한 기능들을 제공합니다. (필수+선택)"
LangString DESC_GR_T_PLUGIN ${LANG_KOREAN} "타이탄 패널용 플러그인 입니다. 컴퓨터 사양을 고려하여 목적에 따라 설치하시기바랍니다. (선택)"
LangString DESC_SecTitanXPStatus ${LANG_KOREAN} "Titan Panel을 경험치바 형식으로 보이게하고 경험치 정보를 표시합니다. (필수)"
LangString DESC_SecTitanAggro ${LANG_KOREAN} "어그로 대상을 탐지하고 알려주는 기능을 제공합니다. (선택)"
  ;이하 생략합니다.

  ;.

  ;.

  ;.


  ;Assign language strings to sections  ; ◀ 지정한 설명(툴팁) 문자열을 나타내도록 합니다.
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
 !insertmacro MUI_DESCRIPTION_TEXT ${GR_COMMON} $(DESC_GR_COMMON)
 !insertmacro MUI_DESCRIPTION_TEXT ${GR_T_PLUGIN} $(DESC_GR_T_PLUGIN)
 !insertmacro MUI_DESCRIPTION_TEXT ${SecTitan} $(DESC_SecTitan)
 !insertmacro MUI_DESCRIPTION_TEXT ${SecTitanXPStatus} $(DESC_SecTitanXPStatus)
  ;이하 생략합니다.

 ;.

  ;.

 ;.

;★★★--------------------------------
;Uninstaller Section

Section "Uninstall"

  ; Remove registry keys  ; ◀ 레지스트리에서 정보를 삭제합니다.
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NukeUI"
  DeleteRegKey HKLM SOFTWARE\NukeUI

  ; Remove files and uninstaller
  Delete $INSTDIR\Uninstall_NukeUI.exe ; ◀ 언인스톨용 exe 삭제

  ; Remove shortcuts
  Delete "$SMPROGRAMS\Nuke UI Ver 0.7 베타\*.*"

  ; Remove directories used for shortcuts
  RMDir "$SMPROGRAMS\Nuke UI Ver 0.7 베타" ; ◀ 시작 프로그램에 등록된 것들 삭제

; Remove WOW Inferace And WTF Folder
  RMDir /r "$INSTDIR\Interface" ; Interface(AddOns) 폴더 삭제 ; ◀ /r 옵션으로 모두 삭제
RMDir /r "$INSTDIR\WTF" ; WTF(Account) 폴더 삭제 ; ◀ /r 옵션으로 모두 삭제

SectionEnd

=========================================================================================

※ 중요하다고 생각되는 부분만 설명 추가로 주석을 달았습니다.

   위 내용만으로 충분히 샘플 스크립트 역할을 하리라고 보는데요 ^^;

   NSIS 설치 후, 제공하는 NSIS Examples Directory 폴더의 내용들과

   http://nsis.sourceforge.net/ 의 자료들을 통해서 많은 부분 알 수 있었습니다.

   http://jgh0721.egloos.com/ 헬마님의 자료도 많은 도움이 되었습니다.

   이 자리를 빌어 감사드립니다. ^^;

   HELP, CHM과 위의 내용들로 기본 부분은 충분히 이해할 수 있으리라 생각합니다.

※ 이상 미흡하지만, WOW 애드온 배포본 제작할 때 NSIS로 스크립트를 작성하면서

   기초적인 NSIS 스크립트에 대한 이해를 돕기위해 작성한 글이었습니다.

Posted by theYoungman
engineering/System Eng.2007. 3. 7. 09:19


출처 : http://www.kipple.pe.kr/doc/nsis/



NSIS : NSIS 소개와 패치/샘플
정보
패치파일
  • 받기 : NSIS2X_PATCH.EXE(245KB) (설치파일)
  • 패치 파일 저작권 정보 : 무료 프로그램/소스 포함(zlib license)
  • 버전 : NSIS 2.x용 한글 패치
  • 날자 : 2006/04/16
  • 주의 : NSIS 2.x를 먼저 설치한후 설치하여야 합니다.
구버전용
  • 받기 : NSIS206P.EXE(235KB) NSIS205P.EXE(238KB) NSIS 2.01용, 2004/10/05(230KB) (설치파일)
    예제 파일
    • 예제 파일 : nsissample.zip(53KB)
    • 예제 파일 저작권 정보 : 무료 프로그램/소스 포함(zlib license)
    • 날자 : 2004/10/05
    • 주의 : NSIS 2.x 와 위의 한글 패치가 설치되어 있어야 합니다.
    관련 페이지
    문서 정보
    • 문서위치 : http://www.kipple.pe.kr/doc/nsis/
    • 2004/10/06 : 최초 작성
    • 2004/10/08 : 질문과답 추가
    • 2005/03/06 : NSIS 2.05 용으로 맞추어서 자잘한 업데이트, AlwaysOnTop 플러그인 추가
    • 2005/04/03 : NSIS 2.06 으로 업데이트
    • 2006/04/16 : NSIS 2.x 모든 버전용으로 업데이트, nsis의 컴파일방법이 복잡해져서 이제 수정된 lang.h 와 makensis.exe는 제공되지 않고, 그냥 수정된 플러그인만 제공됩니다. 따라서 NSIS2.X 전 버전에 설치해서 사용하여도 문제가 없습니다.
    NSIS 소개

    NSIS 는 Nullsoft Scriptable Install System의 약자로, Winamp를 만든 NullSoft에서 Winamp용 설치프로그램을 만들기 위해서 제작되었다가, 나중에 오픈소스 형태(zlib 라이센스)로 공개된 설치프로그램 입니다. 물론 사용에 아무런 제한이 없으며 상업적으로 사용하여도 됩니다.


  • NSIS 를 다른 설치 프로그램과 비교하였을때 눈에 띄는 장점을 정리하자면...

    작은 크기

    설치파일의 오버헤드가 단지 50kb 정도 밖에 나지 않습니다. 단순히 압축 프로그램으로 압축한 파일과 비교하였을때 설치파일의 크기가 50kb 정도만 더 크다는 의미입니다. 프로그램을 배포할때 굳이 크기 때문에 zip 으로 묶어서 배포할 이유가 없어집니다.

    최고의 압축율

    NSIS 는 기본적으로 zip/bzip2/lzma압축 방식을 지원합니다. 여기서 주목할만한 점은 lzma를 지원한다는 것인데, lzma는 7-zip으로 알려진 압축방식으로 현존하는 방식중 최고의 압축율을 자랑하는 압축방식 입니다. 개인적으로 테스트해본 결과 zip 에 비해서 보통 30% 이상 파일의 크기가 줄어들며, winrar 의 solid 압축과 비교해도 더 좋은 압축율을 보여줬습니다. 이런 압축방식을 설치파일에 사용하게 되면 다른 설치프로그램 보다 월등하게 작은 크기의 설치파일을 만들어 낼 수 있습니다.

    스크립트 지원

    그다지 보기 좋지는 않지만, 강력한 자체 스크립트를 지원합니다. 별도의 플러그인을 만들어서 설치 스크립트에서 호출하는 것도 가능합니다. 다른 간단한 GUI 방식의 설치프로그램은 이러한 기능을 지원하지 않습니다.

    다국어 지원

    NSIS 2.0 에서는 다국어 버전을 지원해서 설치파일 하나로 여러가지 언어를 지원하는게 가능합니다만... 꽤 사용하기 복잡합니다.

    기타

    이것 이외에도 홈페이지에는 여러가지 장점이 나열되어 있지만, 작은 크기 만으로도 선택의 이유로 충분할듯 합니다.


    하지만 NSIS 에도 몇가지 단점이 있습니다.

    스크립트를 배워야 한다

    세상에 공짜가 없기때문에 스크립트를 배워야 합니다. HM NIS EDIT 같은 스크립트 생성 및 편집툴을 별도로 쓸 수도 있습니다만, 이것보다는 아래에 소개될 예제 소스를 변경하여서 사용하는 방식을 추천 합니다.
    ( 초기 스크립트 생성은 편한듯 보이지만, 설치파일의 유지보수에 그다지 적합치 않습니다. )

    한글처리의 문제

    NSIS 는 다국어 문제를 거의 완벽하게 지원하지만, 프로그램 설치시 을/를 이라던가 이/가 문제가 발생합니다. 이외에 다이알로그의 LDU 문제로 MODERN UI 사용시 이미지가 늘어져 보이는 문제도 발생합니다. 이 문서에서 제공하는 패치 파일과 샘플 파일은 이에 대한 해결 방법을 제공합니다.

    NSIS 예제 파일

    NSIS 의 예제 파일과 각각의 부분에 대해서 설명합니다. 이 예제 파일은 반드시 위에 있는 NSIS 패치를 설치하여야만 정상적으로 사용이 가능합니다.




    테스트 하기

    예제 파일의 압축을 풀고 __make.bat 파일을 실행하면



    NOTEPADSETUP.EXE 라는 예제 설치 파일이 생성됩니다. 이제 이 설치파일로 메모장을 설치하고, 제거하는걸 테스트 할 수 있습니다.







    기본 설정 : 언어 종속

    다국어 처리를 위해서 분리된 부분이다. 한글로 적는다.







    한글 특화

    한글처리 (을/를, 이/가 문제) 를 위해서 설정하는 부분이다. 자신의 프로그램에 맞게 이/가 를 설정한다. 반드시, 패치가 설치되어 있어야 정상 작동한다.






    기본 설정 : 언어 비종속

    설치에 관련되 화면에 보이지 않는 기본적인 정보를 설정한다. 가급적 영어로 적도록 한다. ( 설치 폴더와 같은 부분들.. )






    파일 복사

    설치시 파일을 복사하는 부분이다. 마찬가지로 Function un.My_Uninstall 부분에는 파일을 삭제하는 코드가 들어가야 한다.






    기타

    나머지는 소스의 주석 참고.

    NSIS 패치

    이 파일은 NSIS 를 좀더 편하게 쓰기 위해서 이것저것 패치한 파일입니다.
    특히 한글의 을/를,이/가 처리를 위해서 일부 파일이 수정되었고, 이 문서의 예제 파일은 이 문제를 해결하기위한 방법을 보여줍니다.
    패치파일을 설치하면, 기존에 설치된 NSIS 를 자동으로 패치하며, 패치파일의 소스는 NSIS\_patch_ 폴더에 같이 복사됩니다.
    다음은 패치되는 내용을 정리한 것입니다.

    advsplash.c

    • advsplash.c : 밀레니엄 계열에서 이상작동 버그 수정
    • advsplash.dll : 수정된후 컴파일된 플러그인

    lang.h

    • ※2006/04/16 수정, 이제 수정된 lang.h makensis.exe 는 제공되지 않음.
    • lang.h : exehead 에 있는 파일. 설치 파일 손상시 오류 메시지를 영어 + 한글로 나오도록 수정
    • makensis.exe : 수정된후 컴파일된 실행 파일



    NSISAutoSetupPlugin

    • NSISAutoSetupPlugin\ : /A 옵션으로 자동으로 설치될수 있도록 해주는 플러그인
    • NSISAutoSetupPlugin.dll : 컴파일된 플러그인

    win-k.bmp

    • win-k.bmp : "${NSISDIR}\Contrib\Graphics\header\win-k.bmp" 에 위치, 기존의 win.bmp 는 한글 윈도우에서 늘어나 보이므로, 대신 이 파일을 사용하면 늘어나 보이지 않는다.
    • 이런 방식으로 사용한다.

    !define MUI_HEADERIMAGE ; HEADER 비트맵 보일까 말까 여부.
    !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\header\win-k.bmp"



    레지스트리 변경

    • .nsi 파일을 더블클릭하면 메모장으로 편집되는 대신 makensis 로 바로 컴파일 되도록 수정
    • 컴파일후 /PAUSE 옵션으로 화면에 결과를 볼수 있도록 수정
    • NSIS가 있는 폴더를 PATH 환경변수에 추가해서 makensis 를 바로 실행 가능하도록 수정

    한글 문제 해결

    • 한글 문제를 해결하기 위해서 Korean-eul.nlf, Korean-rul.nlf 가 추가되었고, Korean.nsh 가 수정되었음.
    • 사용법은 이 문서의 "한글 특화" 부분 참고

    질문과 답

    실행중인 프로그램 종료시키기

    새버전의 프로그램을 설치할때나, 프로그램을 제거할때 기존의 프로그램이 실행중이면 이 프로그램을 종료할 필요가 생깁니다. 이때 프로그램을 죽이거나(Kill) 종료(Close) 시킬수가 있는데, 이 문서의 예제에서는 다음과 같은 방법을 사용합니다.

    ; 함수 선언부
    ;
    ;----------------------------------------------------------------------------------------
    ; 프로그램의 클래스를 이용하여서 프로그램이 실행중인지 체크하고, 종료시킨다.
    ; 호출전 Push 로 꼭 함수 이름을 보내줘야 한다.
    Function CheckAndCloseApp 
    Pop    $R0                    ; GET WINDOW CLASS NAME
    loop1: 
       FindWindow $R1 "$R0"
       IntCmp $R1 0 done1
       SendMessage $R1 16 0 0 ; WM_CLOSE
       SendMessage $R1 2 0 0  ; WM_DESTROY
       Sleep 3000
       FindWindow $R1 "$R0"
       IntCmp $R1 0 done1
       MessageBox MB_OK "$(TXT_NAME)${I_KA} $(TXT_STILLRUN_EXIT_PROGRAM)"
       goto loop1
    done1:
    FunctionEnd
    --------------------------------------------------------------------------------
    ; 사용할때는 
    Push "Notepad"
    Call CheckAndCloseApp 

    이 방법은 윈도우의 클래스(Class) 명을 가지고 윈도우의 핸들을 찾아서 종료메시지(WM_CLOSE) 를 보내는 방식을 사용한다.
    윈도우의 클래스는 윈도우의 속성과 관련된 부분이다. 예를 들자면 버튼 윈도우의 클래스명은 "Button" 이다. 어떠한 프로그램의 클래스명을 알고 싶다면 SPY++ 라는 프로그램으로 확인이 가능하다. 메모장의 클래스 이름은 스파이로 확인한 결과 "Notepad" 이였다.

    만일 프로그램이 MFC 로 작성되어서 윈도우의 클래스가 Afx:xxxx 와 같이 매번 바뀐다면 FindWindow 함수에서 클래스명 대신 타이틀을 이용해서 검색하는것도 가능하다. (하지만 타이틀도 매번 바뀐다면? OTL)

    OS 의 종류에 따라서 다른 프로그램 설치하기

    레지스트리의 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion 항목을 검사해서 NT계열(NT/2000/XP/2003) 계열인지 아닌지(95/98/ME) 확인이 가능하다.
    다음은 꿀뷰에서 유니코드 버전과 아스키 버전을 설치할때 사용하고 있는 스크립트의 예제 이다.


    ReadRegStr $R0 HKLM  "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
    IfErrors NotNT
    File /oname=HoneyView.exe HoneyViewU.exe 
    goto NEXT
    NotNT:
    File HoneyView.exe
    NEXT:

    Posted by theYoungman
    engineering/System Eng.2007. 3. 6. 19:40
    출처 : http://www.cipher.pe.kr/tt/cipher/107



    NSIS 로 인스톨러를 만들면 각각의 페이지를 만드는 것이다. 각 페이지가 모여서 전체적인 인스톨 프로그램을 구성하게 된다. 주로 많이 접하는 페이지가 라이센스 동의에 대한 페이지나 인스톨할 디렉토리 선택등을 알 수 있다. 물론 사용자 구성/작성 페이지를 추가 할 수도 있다. 스크립트를 사용해서 이런 페이지의 순서를 변경할 수도 있으며, 특정한 정보를 제공할때 한 페이지에만 머무르도록 할 수도 있다.

    페이지에 관련된 기본적인 명령어는 Page, UninstPage 이다. 첫번째 명령어는 페이지를 인스톨 프로그램에 추가하는 것이고, 두번째는 언인스톨 프로그램에 페이지를 추가하는 것이다. 또 다른 명령어로는 PageEx 가 있다. Ex가 의미하는바가 Extension을 의미하는 것이므로 Page 명령어 보다 더 자세하게 셋팅을 할 경우 사용하는 명령어 이다.

    1. 페이지 순서

    페이지 순서는 스크립트에서 Page, UninstPage, PageEx 가 나타나는 순서대로 페이지가 실제로 보여지게 된다. 예를 들어

    1. Page license
    2. Page components
    3. Page directory
    4. Page instfiles
    5. UninstPage uninstConfirm
    6. UnistPage instfiles


    위의 코드를 이해해 보자면, 인스톨 프로그램에서 제일 먼저 라이센스 관련된 페이지, 컴포넌트 선택하는 페이지, 인스톨 디렉토리 선택 페이지, 마지막으로 인스톨 로그를 보여주는 페이지를 보여 주라는 얘기이다. 그리고 언인스톨 프로그램에서 처음에는 언인스톨 할건지 확인하는 페이지를 보여 주고, 마지막으로 언인스톨 되는 파일에 대한 로그를 보여 주라는 얘기이다.

    NSIS 스크립트에서 예전 버전과의 호환성 때문에 Page 명령어가 없을 경우 license, components, directory, instfiles등이 자동으로 포함된다. 물론 각 페이지를 만들기 위한 정보가 제공될 경우 이다. license의 경우 LicenseText와 LicenseData가 지정되어 있어야 하며, directory 페이지의 경우 DirText가 지정되어 있어야 하는 등을 말한다.

    2. 페이지 옵션

    각 페이지는 페이지를 포함하기 위한 각각의 정보를 필요로 한다.

    License page

    1. LicenseText [text [button_text] ]

    - text에 적히는 내용이 페이지 위쪽에 라이센스 아이콘 옆에 적히는 글이다. [button_text] 의 경우 라이센스 동의 시에 누르는 "I Agree" 대신에 쓰여질 글을 적는 부분이다.
    1. LicenseData (txt|rtf)

    - 라이센스에 사용할 파일을 표시한다. 이 데이타가 없는 경우 라이센스 페이지는 표시되지 않는다. 만약 각 언어마다 다른 라이센스 파일을 추가 하고자 할때는 LicenseLangString 을 이용한다. LicenseLangString은 다중 언어 설명에서 더 자세하게 설명하겠다.
    1. LicenseForceSelection (checkbox [accept_text] | radiobuttons [accept_text] [decline_text] | <b>off</b>)

    - 라이센스에 동의하겠다는 라디오 버튼이나 체크 박스를 표시하여서 선택하지 않으면 "next" 버튼을 활성화 시키지 않는 옵션이다.

    단순히 설명만 보면 잘 모를 수도 있으니 아래와 같은 스크립트를 작성하여서 컴파일하여 실행시켜 보자. 아래 그림과 같이 창이 나오게 된다. Page에 대한 내용을 적어 주지 않아도 디폴트로 라이센스 페이지가 가장 먼저 나오므로 아래와 같이 된다. 아래 코드를 보면 위에 설명한 내용이 어떤 내용을 말하는지 이해가 될것이다. LicenseForceSelection 에서 "위 라이센스에 동의 합니다"와 같이 사용자가 글을 직접 쓸 수도 있고, "" 라고 쓰면 디폴트 값이 쓰여지게 된다. 하나 생각할 것은 license.dat 파일에서 http로 주소를 적으면 자동으로 하이퍼링크가 걸려서 라이센스 파일에서 보여 준다는 것이다.

    1. # set the name of the installer
    2. outfile "pages.exe"
    3. # set license data file
    4. LicenseText "라이센스 동의해 주세요~~~ " "동의"
    5. LicenseData ".\license.txt"
    6. LicenseForceSelection checkbox "위 라이센스에 동의 합니다."
    7. # create a default section.
    8. section
    9. sectionEnd

    사용자 삽입 이미지



    Component selection page
    1. ComponentText [text [subtext] [subtext2]]

    - 컴포넌트 페이지에 쓰여지는 디폴트 글을 바꾸는 옵션이다.
      text : 인스톨 아이콘 옆에 쓰여지는 글 이다. 일종의 제목 글로 생각하면 되겠다.
      subtext : 인스톨 타입 선택 옆에 쓰여지는 글이다.
      subtext2 : 인스톨 타입 아래에 쓰여지는 글이다.
    여기에 쓰이는 텍스트는 변수 형태로 미리 써서 포함 시킬 수도 있다. 이해 하기가 어려우니 위에 쓴 코드를 확장해서 아래와 같이 만들어서 사용해 보자. 컴포넌트는 Section의 개념이 포함되므로 일단 여기서는 어떻게 쓰는지만 보고 Section의 내용을 보고 전체적으로 다시 만들어 보자.

    1. # set the name of the installer
    2. outfile "pages.exe"
    3. LicenseText "라이센스 동의해 주세요~~~ " "동의"
    4. # set license data file
    5. LicenseData ".\license.txt"
    6. LicenseForceSelection checkbox "위 라이센스에 동의 합니다."
    7. ComponentText "필요한 컴포넌트를 인스톨 합니다." \
    8.               "내부적인 소제목입니다." "인스톨 하는 설명을 자세하게 여기에 씁니다."
    9. # create a default section.
    10. section
    11. sectionEnd
    12. section "Component1"
    13.         MessageBox MB_OK "You select component1"
    14. SectionEnd
    15. Section "Component2"
    16.         MessageBox MB_OK "You select component2"
    17. SectionEnd

    사용자 삽입 이미지

    위의 코드와 실행했을때 나오는 화면을 보면 각각이 어떤 역활을 하는지 충분히 이해 할 수 있을 것이다.


    Directory selection page

    1. DirText [text] [subtext] [browse_button_text] [browse_dlg_text]

    - 인스톨할 디렉토리를 선택하는 페이지를 포함할 경우 그 디렉토를 셋팅하는 페이지에 대한 옵션을 줄 수 있다.
      text : 인스톨 아이콘 옆에 쓰여지는 제목이라고 볼 수 있다.
      subtext : 디렉토리 선택 페이지에 보여지는 글이다.
      browse_button_text : 다른 디렉토리를 선택할때 클릭하는 버튼에 적히는 텍스트 이다.
      browse_dlg_text : 다른 디렉토리를 선택하기 위해 버튼을 클릭한 후 나온 다이얼로그에 적히는 글이다.
    디폴트 값을 이용하고자 할 경우에는 "" 로 자리를 차지하면 되겠다. 글을 보면 좀 이해하기가 힘들겠지만, 코드와 함께 실행된 화면을 보면 이해할 거라고 생각한다.

    1. # set the name of the installer
    2. outfile "pages.exe"
    3. LicenseText "라이센스 동의해 주세요~~~ " "동의"
    4. # set license data file
    5. LicenseData ".\license.txt"
    6. LicenseForceSelection checkbox "위 라이센스에 동의 합니다."
    7. ComponentText "필요한 컴포넌트를 인스톨 합니다." \
    8.               "내부적인 소제목입니다." "인스톨 하는 설명을 자세하게 여기에 씁니다."
    9. DirText "인스톨 할 디렉토리 선택 창입니다." "본 프로그램을 인스톨 할 디렉토리를 선택해 주십시오." \
    10.         "클릭해줘!" "디렉토리 선택하는 다이얼로그 설명입니다."
    11. # create a default section.
    12. section
    13. sectionEnd
    14. section "Component1"
    15.         MessageBox MB_OK "You select component1"
    16. SectionEnd
    17. Section "Component2"
    18.         MessageBox MB_OK "You select component2"
    19. SectionEnd


    위 스크립트를 컴파일하고 실행한 후, 라이센스를 동의하고 컴포넌트 선택하고 나면 아래와 같이 디렉토리 선택하는 윈도우가 나오고, "클릭해줘!" 라는 버튼을 클릭하면 실제로 디렉토리를 선택할 수 있는 창이 나온다. 위 코드에서 사용한 문자열과 실제로 어떻게 화면에 출력되는지 확인을 해보면 되겠다.
    사용자 삽입 이미지


    1. DirVar user_var

    - 일반적으로 디렉토리를 선택할 경우에 $INSTDIR에 그 값이 저장된다. 만약 사용자가 선택한 폴더와 디폴트 폴더 모두 사용하고자 하면 이 명령어를 써서 사용자가 선택한 변수에 선택한 디렉토리를 저장할 수 있게 된다. 이 명령어는 반드시 PageEx 내에서만 사용해야 한다. 예제는 밑에 있는 한 가지 옵션을 더 보고 동시에 셋팅한 예제를 보겠다.

    1. DirVerify auto|leave

    - 이 명령어는 기본적으로 사용하지 않아도 auto로 셋팅되어 있다. 이 옵션은 인스톨 할 디렉토리가 제대로 되어 있지 않던가, 디스크에 프로그램을 인스톨 할 여유 공간이 없을 경우 next 버튼이 활성화되지 않게 된다. 하지만 이 명령어를 사용해서 leave로 하게 되면 이러한 체크에 상관없이 항상 next 버튼이 활성화 되게 된다. 일반적으로는 사용할 필요가 없는 그런 옵션이다.

    아래 예제 코드를 살펴 보자. 이제 코드가 좀 복잡해 진것 처럼 보이지만, 앞의 코드를 약간 수정한 내용이다. 먼저 봐야 할 부분이 19째 줄부터 보면 PageEx~PageExEnd 가 있다. DirVar의 기능을 보여 주기 전에 먼저 보여 줄것이 있어서 코드 자체를 주석 처리해 놓았다. 6번째 줄을 보면 InstallDir 명령어가 있는데, 이 명령어는 $INSTDIR에 문자열을 포함시키는 역할을 한다. 디폴트로 여기로 인스톨 하겠다는 디렉토리를 정하는 명령어 이다. 아래의 코드를 실행 시키면 인스톨 디렉토리를 선택하는 부분에 6번째 줄에 있는 디렉토리로 디폴트 값이 저장되게 된다. 디렉토리 페이지에서 이 디폴트 값을 보여 주는 역할을 한다. 아래 그림과 같이 나오게 된다. PageEx 명령어를 쓰게 되면 디폴트로 license 페이지부터 보여 주던 것을 더 이상 보여 주지 않고 directory 페이지만 보여 주므로 명시적으로 라이센스부터 끝까지 페이지를 보여 주기 위해서 17번째 줄에서 22번째 줄까지 직접 page 를 삽입했다. 앞에서 봤듯이 이 페이지의 순서는 적혀 있는 순서이므로 나중에 순서를 바꾸어서 한번 테스트 해보기 바란다.
    1. # set the name of the installer
    2. outfile "pages.exe"
    3. Var ANOTHER_DIR
    4. InstallDir "$PROGRAMFILES\testing"
    5. LicenseText "라이센스 동의해 주세요~~~ " "동의"
    6. # set license data file
    7. LicenseData ".\license.txt"
    8. LicenseForceSelection checkbox "위 라이센스에 동의 합니다."
    9. ComponentText "필요한 컴포넌트를 인스톨 합니다." \
    10.               "내부적인 소제목입니다." "인스톨 하는 설명을 자세하게 여기에 씁니다."
    11. DirText "인스톨 할 디렉토리 선택 창입니다." "본 프로그램을 인스톨 할 디렉토리를 선택해 주십시오." \
    12.         "클릭해줘!" "디렉토리 선택하는 다이얼로그 설명입니다."
    13. Page License
    14. Page Components
    15. PageEx directory
    16. #       DirVar $ANOTHER_DIR
    17. PageExEnd
    18. Page instfiles
    19. # create a default section.
    20. section
    21. MessageBox MB_OK "$INSTDIR" # , $ANOTHER_DIR"
    22. sectionEnd
    23. section "Component1"
    24.         MessageBox MB_OK "You select component1"
    25. SectionEnd
    26. Section "Component2"
    27.         MessageBox MB_OK "You select component2"
    28. SectionEnd


    사용자 삽입 이미지


    DirVar 의 기능을 보기 위해서 먼저 아래 코드에서 20번째줄에 있는 주석 표시를 지우고, 28번째 줄을 [code type=nsis]MessageBox MB_OK "$INSTDIR, $ANOTHER_DIR"[/CODE] 로 변경해 보자. 실행시키면 directory 페이지에 디폴트 값이 나오지 않는 것을 알 수 있을 것이다. 그리고 디렉토리를 아무거나 선택해 보면 창에 적히는 것이 선택한 디렉토리\testing 으로 나오는 것을 알 수 있을 것이다. 그리고 "Install" 버튼을 클릭해 보면 아래 그림과 같이 $INSTDIR과 $ANOTHER_DIR 모두 다른 값을 가짐을 알 수 있다.
    사용자 삽입 이미지

    여기서 문제는 디렉토리 페이지에 디폴트 값이 표시 되지 않는 것인데, 이는 DirVar로 선택한 $ANOTHER_DIR가 초기 값을 아무것도 안 가지기 때문이다. 여기에 디폴트 값을 뭔가 주면 되겠다. 어떻게 하면 되는지 한번 고민해 보기 바란다. 간단하게 $ANOTHER_DIR의 초기화를 PageEx~PageExEnd 안에 두면 되지 않겠느냐고 생각할 수도 있지만, PageEx~PageExEnd 안에는 StrCpy 명령어를 쓸 수 없다.

    1. function .onInit
    2.        StrCpy $ANOTHER_DIR "$WINDIR"
    3. functionEnd


    위 코드를 그 위에 있는 코드 23번째줄에 삽입하고 실행하면 원하는 데로 되는 것을 알 수 있을 것이다. function에 대해서는 아직 배우지 않았으므로 여기서는 .onInit 에서 필요한 초기화를 해주면 된다는 것만 알고 넘어 가자.

    1. DetailsButtonText [text]

    DetailsButtonText는 위에 전체 코드 중에서 22번째 줄에 있는 Page instfiles 대신에 아래 코드로 변경하고 컴파일을 하면 아래 창 처럼 버튼에 적히는 글의 내용이 달라 진다.
    1. CompletedText [text]

    CompletedText는 인스톨이 끝났을 경우 "Completed" 라는 것 말고 다른 말을 적을 때 사용한다.

    1. PageEx instfiles
    2.        DetailsButtonText "자세히 보여줘~~"
    3.        CompletedText "끝났당~~"
    4. PageExEnd

    사용자 삽입 이미지

    위에 있는 DetailsButtonText와 CompletedText는 모두 언인스톨 창에서도 사용할 수 있다. 또 한 DirVar도 마찬가지로 언인스톨시에 사용할 수 있다.

    페이지 옵션으로 마지막으로 남은것은 UninstallText가 남아 있다. 이 옵션은 나중에 언인스톨러를 공부할 때 실제로 보도록 하겠다.
    Posted by theYoungman
    engineering/System Eng.2007. 2. 26. 10:47

    =============================================
            배열과 포인터는 전혀 다르다 # 1


                     - 프롤로그 -

                    13 Dec, 2002
                 Written by Un-Wook
    =============================================



    - 차례 -

    1. 서문
    2. 주제
    3. 문제의 제기 1
    4. 문제의 제기 2
    6. 윈도우 이야기
    7. DOS vs WINDOW
    8. 마치며


    -----------------------------
    1. 서문
    -----------------------------

    안녕하세요.
    그동안 제가 이 게시판에서 글을 여러편 올렸었는데
    강좌로서는 이번이 3번째 강좌가 되었네요..
    되도록 부담없고 읽기 쉽게 자세히 풀어서 쓰는 것을 목표로 여기까지 달려왔는데..
    읽는 분의 입장에서는 어떨지 모르겠어요..
    지금까지.. 많지는 않지만 격려해 주신분들에게 너무 감사드리고..
    이번에도 최선을 다해서 작성해보겠습니다.
    언제나 그랫듯이 제딴에는 최대한 읽기 편하게 쓸 것이구요..  ㅋㅋㅋ
    분량도 언제나 그랫듯이 좀 나갈꺼구요..
    분량이 많아도.. 말은 다 쉬운말입니다.. 쉽게 쓰려면 분량 많아지는거는 어쩔수가 없는거 가타여..
    내용상 문제가 있다면 지적해 주십시오. 오타 같은 것도 찾아 주시면 수정합니다.
    지난번 강좌는 비트에 대한 강좌였고, 이번 강좌는 거기서 영역을 조금 넓힌 메모리에 대한 강좌입니다.
    읽으시는 분이 최소한 포인터의 의미와 용도를 이해하고 있다 가정하고..
    그럼 시작하겠습니다.




    -------------------------------------
    2. 주제
    -------------------------------------

    배열과 포인터가 같다고 생각하시나요?..

    전혀 다릅니다..

    그리고 강좌의 제목은 배열이 어쩌고 포인터가 어쩌고 지만..

    제가 써보고 싶은 내용은 메모리의 기본 개념을 잡아보는 것입니다.

    본론으로 들어가기 전에 이것저것 기반지식을 먼저 간략하게 설명해 드려리구 합니다.

    프로세스에 대해서 좀 설명을 하고..

    스택과 힙의 의미를 설명해 나가다가

    궁극적으로 배열과 포인터의 차이점을 비교하여 설명할 계획입니다.

    아마 주로 스택에 대해서 다루게 될것 같습니다..

    되도록이면 저번에 연재 해드렸던 비트강좌를 먼저 이해하고 난 뒤에 읽어주셨으면 좋겠네요..

    그 강좌에서 설명했던 용어들을 여기서 다시 설명하진 않으려구요..^^




    -------------------------------------
    3. 문제의 제기 1
    -------------------------------------

    아래의 코드를 봐 주세요

       char    *pTest= "01ABC";
       char    cTest[]= "01ABC";

    이 두 라인의 차이점이 무엇이라고 생각되세요?

    문자열을 다룰때 저렇게 하는 것이라고 생각하신다면.. 제 글을 꼭 끝까지 읽어보세요..

    pTest[2] 도 'A' 이고 cTest[2] 도 'A' 입니다..

    strlen() 을 이용하여 검사해보면 똑같은 5 라는 값이 넘어옵니다.

    pTest 란 것과 cTest 라는 이 두변수가 똑같은 사이즈로 할당되어 있는 것 일까요?

    그렇다면 이것이 실제로 같은 동작을 하는 것일까요?




    아래와 같은 코드는 프로그램시 왜 서로 결과가 다를까요.. 하나는 에러가 나고.. 하나는 에러가 안납니다.

       strcpy(pTest, "안녕");   // 에러 남
       strcpy(cTest, "안녕");   // 에러 안남




    이 차이점을 지금 이해하지 않으신다면..

    앞으로 많은 난관을 부딪치게 되실태고... 그러한 과정에서 이해하셔야 할 것입니다.

    지금 조급하게 결론을 내려보자면..

    배열변수의 데이터는 스택이라는 메모리영역에 잡히기 때문입니다.




    -------------------------------------
    4. 문제의 제기 2
    -------------------------------------

    아래 코드는 pTest 와 cTest 변수에, 담긴 값과 그 변수들이 메모리에 어느위치에 확보되어 있는가 얻어오는 코드입니다.

       char    *pTest= "01ABC";
       char    cTest[]= "01ABC";

       printf("pTest : %08x %08x \n", pTest, &pTest);
       printf("cTest : %08x %08x \n", cTest, &cTest);

    결과는 다음과 같이 출력됩니다.

       pTest : 0040705c 0012ff78
       cTest : 0012ff7c 0012ff7c

    모두가 한번쯤 생각해 봤을만한 코드라고 생각되는데요..


    ..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:

    +*보충설명*+

    안 읽으셔두 됨..

    & 연산자는 비트연산에서는 and 를 의미하지만

    일반 변수 앞에다가 붙혀주면 그 변수가 런타임시 위치하게되는 메모리 주소를 수치로 반환해 줍니다.

    어드래스 오퍼레이터라고 부릅니다. 모두 아시는 내용이지만, 노파심에 설명해 보았습니다.

    (키워드 & 는 3가지의 의미가 있습니다. Address of operator / Bit operator / Refference operator)

    ..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:..:+:


    cTest 의 경우 조금 특이하지 않나요?..

    cTest 의 메모리의 위치와.. cTest 에 담겨있는 값이랑 서로 동일하다는게 말이죠..

    앞으로.. 이런 것들을 풀어보려고 합니다.




    -------------------------------------
    5. 윈도우 이야기
    -------------------------------------

    포인터와 관련된 메모리 강좌에서 소단원 주제가 "윈도우 이야기" 이라서 좀 의야해 하실것 같습니다만..

    다 연관이 되어있고, 미리 설명해야 나중의 설명이 편하기 때문에 꺼내보는 이야기 입니당..




    우리가 요즘 사용하는 OS는 대부분이 윈도우즈 95, 98, ME, 2000, NT 일 것입니다..

    겜방에 가보나, 시골 친척집에 놀러가보거나.. 요즘 개인용 컴퓨터 봐보면 하나같이 IBM 계열 컴터에다가

    "윈도우" 라는 OS 가 설치되어 있습니다.

    이 윈도우라는 OS를 WIN32 Platform 이라고 합니다..

    플랫폼은 그런의미 입니다.

    어떤 장치에서 무엇인가를 구현할수 있게 해주기 위해

    기반을 제공해주는 시스템을 플랫폼이라고 해요..

    WIN32 플랫폼은 32비트 방식으로 메모리를 다루며, 멀티태스킹이란 것도 지원해주지요..




    과거 MS-DOS 플랫폼에선 컴터의 기본메모리를 응용프로그램이 직접 관리해야 했습니다.

    곧.. 프로그래머가 물리적인 메모리를 직접 관리한다는 의미 입니다.

    실제 메모리의 제한이 걸리는 것도 염두해두어야 했고, 메모리라는 것 때문에 영 골치아플때가 많았지요..

    ( 확장메모리 서비스를 이용하여 보다 많은 메모리를 사용할 수 있긴 했지만 것두 그냥그냥 쉽지는 않습니다.. )




    MS-DOS 는 16 비트 플랫폼 입니다. 16 비트 레지스터를 가지고 메모리 주소를 포인팅하기 때문에

    한번에 최대 65535 Byte 이상의 메모리를 포인팅 할수가 없습니다.

    한번에 표현가능한수치가 65535 이라 640KB 의 기본메모리를 선형으로 접근할수가 없었다는 말입니당..

    생각해 보세요.. 65535 밖에 표현이 안되는데.. 655360 나 되는 물리적 메모리 주소를 담을수가 없잖아요... ㅋㅋㅋ

    지금 시대의 분들이 본다면 참 기이한 방식이라고 생각할 수도 있지만

    그당시에는 이 문제를 해결하기 위하여 "세그먼트:오프셋" 이라는 방식으로 65535의 한계를 뛰어넘어

    640kb 의 메모리를 접근하였습니다.

    메모리 구간을 세그먼트로 나누고.. 여기서의 오프셋은.. 세그먼트를 기준으로 상대적인 메로리 주소값을 나타냅니당..

    (Watcom C++ 와 같은 32 비트 컴파일러도 있긴 했습니다.)

    하지만 지금 생각하시는대루 "세그먼트:오프셋" 방식은 무지 불편했지요..

    일딴 연속해서 65535 바이트 이상은 할당 못하는 꼴이니까요..

    도스때 프로그래밍을 시작하려 했었던 입문자 입장에서는 이해도 잘 안되고 이해하고싶지도 않지요..




    이제 시대는 흘러흘러 WIN32 가 발표 되었습니다.

    현재 대부분의 개인용 컴퓨터의 OS가 미국의 코쟁이들이 만들어 놓은 "윈도우" 라는 것이고

    어플리케이션을 제작해야만 하는 우리들은..

    당연히 OS시장에서 주도권을 잡고있는 WIN32 플랫폼용으로 저작물을 출시하려고 합니다.

    우리는 알게모르게 WIN32 의 덕을 좀 많이 보고 있어요

    화려한 그래픽 인터페이스 환경에서 비주얼틱하게 프로그래밍을 하며..

    더이상 세그먼트:오프셋 이란 것으로 골머리 썩을 필요도 없어지게 되었습니다.

    32 비트 로는 40 억까지 수치가 표현 가능합니다..
    (이것을 이해 못하시면.. 제가 지난번에 올렸던 비트 강좌를 참조 해 보시구요..)

    40 억은.. 약 4 GB 입니다.

    WIN32 라는 플랫폼은 32비트로 메모리를 포인팅하기 때문에..

    논리적으로 4GB 까지 메모리를 억세스 할수 있다는 이야기에요..

    참으로 황당할정도로 방대하지 않을수가 없는 수치입니당..




    -------------------------------------
    6. DOS vs WINDOW
    -------------------------------------

    제가 세월의 저편으로 사라진 MS-DOS 이야기를 많이 꺼냈는데.. 그 이유는

    윈도우에서 비주얼씨로 프로그래밍하는 것이.. 프로그래밍의 모든 면이 아니라는 것을 말씀 드리고 싶었고..

    요즘에는 윈도우부터 프로그래밍을 시작하신 분들이 많아서 그런지..

    비주얼틱한 면으로 익숙해지신 분들이 많은 것 같기 때문입니다.




    툴이라는 것에만 익숙해지게 되면... 언제나 종속적이되고.. 표현범위 또한 한정적일 수 밖에 없습니다.

    프로그래밍은 기초와 기본원리가 중요하다고 생각합니다.

    제가 잠깐 재직했던 회사의 상사님께서도 언제나 강조하셨던 말씀이구요.

    지금까지의 제 강좌가 최신 기술쪽 보다는 기초와 원리 위주인 이유도..

    이런 부분을 데브피아 식구들과 토론해 보기 위해서 입니다.




    -------------------------------------
    7. 마치며
    -------------------------------------

    음.. 이번에는 한번에 씨리즈를 다 안올리고.. 한편 작성이 완료될때마다 그때 그때 올릴 생각입니다.

    첫회에서는 제 강좌의 방향에 대해서 주로 설명해 드렸고..

    그 첫 단추로는.. 윈도우에 대한 이야기를.. 메모리의 관점에서 이야기 해 보았습니다..

    과연.. 읽는 입장에서 얼마나 유익하게 받아드릴지는 걱정되네요..

    다음편에선 가상메모리와 프로세스이야기를 잠깐 해보고 스택에 대한 이야기를 할 계획입니다.

    모두 좋은하루 보내시고

    행복하시길 바랍니다.

    수고하셨고

    끝까지 읽어주셔서 감사합니다.




    마침.

    18:36  3 Dec, 2002

    Written by Un-Wook




    =============================================

            배열과 포인터는 전혀 다르다 # 2

               - 가상메모리와 프로세스 -


                    13 Dec, 2002

                 Written by Un-Wook

    =============================================




    - 차례 -

    1. 서문
    2. 메모리의 한계
    3. 프로그램의 시작과 끝
    4. 마치며


    -----------------------------
    1. 서문
    -----------------------------

    요즘 날씨가 많이 쌀쌀합니다. 전 감기 안걸렸었는데 순전히 담배 때문에 감기 걸린것 같네요.

    담배를 줄여야 하는데 참 걱정이네요..

    코딩하려고 키보드 잡으면

    혹은 스타크래프트 플레이할 때 절정에 다다렀다가 거의 이겨갈때 쯤...

    저도 모르게.. 검지 손가락과 중지손가락 사이에 껴있는 담배 한개피를 발견합니다.

    님들아 담배는 건강에 무지 해로우니까 담배 줄이도록 노력하시고

    자 그럼 2 회 강좌를 시작해 보겠습니다.

    이번 편에서는 프로그램이 실행되는 원리를 이야기해 보려는게 목표입니다.




    -------------------------------------
    2. 메모리의 한계
    -------------------------------------

    메모리는 참 중요한 것입니다.. 프로그램이라는 것이 메모리를 통하여 모든것을 구현하거든요..

    프로그램 자체도 실행될때는 메모리에 로드되어 있는 것이고, 변수들도 죄다 메모리에 있는것이고

    심지어.. 우리가 밥 지을때 사용하는 전기 밥통도 메모리가 있습니다.




    1회 강좌에서 WIN32 는 32비트 레지스터로 메모리를 포인팅하며..

    그 수치는 4 GB 까지 가능하다고 설명했습니다..

    약 10년전에 1MB 에 4만원에 거래되던 시절이 있었습니다.

    메모리를 32 메가를 작창하려면 메모리 값만 돈 백은 됐고.. 갑부집 아들의 돈지랄이죠..

    보통 PC에서는 4 MB 를 장착했어요.

    메모리 가격이 지금은 256 MB 가 보통 10만원 정도 하나요?

    시대가 좋아져서 2002 년도의 보급형 PC 는 대부분 256 MB 를 장착하고 있습니다..

    그런데 WIN32 란 것은 메모리를 4GB 까지 논리적으로 억세스 한다니..

    게다가 OS 에서 사용되는 전체 메모리가 4GB 가 아니라..

    어플리케이션 하나를 새로 띄울때마다 4GB 가 할당됩니다..

    뭔가 어불성설 같은데..

    알고보면 그안에는 숨겨진 트릭이 잇습니다.

    "가상메모리 시스템"라는 것인데요..

    프로그래머 아니신 분들도 WIN32가 가상메모리를 사용한 다는 것을 익히 들으셔서 아실 것입니다.

    제가 이 강좌에서 가상메모리를 설명하려는건 아니고.. 그냥 훑어보는 것입니다.




    WIN32 에서는 어플리케이션 하나당.. 4GB 의 고유의 메모리 영역이 확보됩니다.

    근데 실은 말이 4GB 이지.. 가상메모리라는게 돌아가요..

    메모리 사용되는 구간만 페이지로 나눠서

    실제 메모리와 보조 장치 사이에서 페이징이 돌아가요..

    그 보조장치는.. 하드디스크이구요..

    보통 하드디스크에 스왑파일이라고.. 들어보셨지요?.. 이것이 가상메모리를 처리하기 위한 파일입니다..

    윈도95/98 에서는 win386.swp 인것 같았는데 NT 버전쪽에서는 모르겠네여..

    메모리는 전기적 성질로 비트를 기록하고, 디스크는 자기적 성질로 비트를 저장합니다.

    둘다 어쨋거나 데이터의 근본은 비트입니다.

    그렇기에 이런 동작이 가능한 것이구요..




    가상메모리 시스템이 실제 물리적인 메모리의 내용을 하드디스크로 보관해 두는 것을 "페이지 아웃"

    디스크의 내용을 메모리로 옮기는 것을 "페이지 인" 이라고 하는데

    용어는 모르셔도 되고.. 암튼..




    컴푸터에 메모리가 256MB 달려있어도.. 여러분이 작성하는 어플리케이션은

    가상메모리 방식으로 보조장치와의 페이징을 통하여

    4GB 라는 논리적인 메모리 영역을 사용할 수 있다는 것을 알아두셔욤.

    각각의 모든 어플리케이션이 실행될때 4GB 씩 할당되고..

    우리는 프로그래밍할때 가상메모리고 나발이고 생각 할 필요 없이

    그냥 WIN32 에서 메모리는 선형으로 무한정 사용할 수가 있다고 생각하십시오..

    선형이라는 말은 메모리의 주소가 0x00000000 부터 0xFFFFFFFF 까지

    쭈욱 이어졌다고 생각할 수 있다는 것을 의미입니다. 4GB 란 수치는 실로 어마어마한 수치입니다.

    여러분의 어플리케이션은 0x00000000 부터 0xFFFFFFFF 까지 4GB 라는 메모리를 접근할 수 있습니다.




    그렇다고 너무 좋아하진 마세요..

    가상메모리는 제어판에서 사용량의 한계를 두기도 하고.. 하드디스크 모잘라면 뻑납니다.

    게다가 속도도 좀 느려요..

    비트강좌에서 강조 했던거 번복하자면.. 프로그램은 메모리를 최적으로 사용해야 멋진 프로그램입니다.




    그래도 프로그래밍할때 물리적인 메모리를 직접 관리하지 않도록 처리해주는 WIN32의 가상메모리 시스템은

    프로그래머들에게는 아주 큰 메리트로 작용됩니다.




    -------------------------------------
    3. 프로그램의 시작과 끝
    -------------------------------------

    앞으로 스택과 힙을 설명해야 하는데..

    "프로세스" 이야기도 잠깐 설명하고 넘어가야 할것 같네요..

    프로세스라는 말을 많이 들어보셨을꺼에요..

    프로세스와 프로세서를 혼동하지 마세요.. 프로세서는 CPU 말하는 거고..

    프로세스는 좀 다릅니다..




    프로세스가 머냐믄.. 복잡하게 설명 안하겟습니다..

    그냥 프로그램 하나가 실행될때 확보되는 4GB 의 메모리 공간이 프로세스 입니다.

    이 4GB 라는 공간은 논리적인 사이즈입니다. 가상메모리 시스템이 돌아가니까요.




    하나의 프로그램이 시작하는 것은 하나의 프로세스가 생성되는 것입니다.

    이 프로세스에는 EXE 이미지가 고대로 로드됩니다.

    무슨말이냐면..

    하드 디스크에 비트로 기록되어있는 EXE 파일이

    프로세스에 별다른 번역이 전혀 없이 그 바이너리가 고대로 복사된다는 말입니다.

    EXE 파일을 하나의 바이너리 이미지라고 볼 수 있는 것입니다. CPU 가 실행하는 기계어코드 입니다.




    여기서부터는 조금 생소한 얘기일수도 있고.. 어려울수도 있으니..

    조금만 집중하셔서 읽어보세요.. 집중하셔서 읽어보면 다 이해가 됩니다..

    일딴 EXE 이미지가 프로세스에 로드되게 되면..

    EXE 이미지의 개개의 바이트는 모두 고유의 주소값을 가지게 되고 (모든 주소값은 바이트 단위)

    CPU 는 EXE 이미지가 시작되는 주소에서 부터 EXE 이미지의 코드를 하나씩 차례차례 실행해 나갑니다..

    그 실행중인 주소값을 "프로그램 카운트" 라고 하구요

    CPU 에는 이런것을 처리하기 위한 32비트의 "카운터 레지스터"가 있습니다..

    이 카운터 레지스터가 바로.. 프로그램의 흐름을 책임집니다..

    이 카운터 레지스터에 담긴 값은.. 바로 프로세스에서 현재 실행중인 코드 주소를 의미합니다.

    보통 이 프로그램 카운터는 실행 코드 한단위가 실행될 때마다 값이 그 증가해 나가지만..

    점프라는 것도 있습니다. 리턴이라는것도 있구요.

    카운터 레지스터에 함수가 존재하는 코드의 시작 주소가 들어가면.. 프로그램 흐름이 변형되고

    바로 함수 호출이 일어나는 것입니다.

    if 와 같은 조건문도 실은 점프가 발생합니다.




    여기 까지 읽으셨으면 프로그램이 어떻게 구동되는 것인가에 대해서도 대충은 감이 잡히실 겁니다.

    프로세스 영역은 4GB 라고 했는데.. 실행파일은 그거보다 훨씬 작지요?.

    프로세스에서 EXE이미지를 적재하고 남은 공간에다가.. 프로그램이 런타임시에(실행중일때)

    메모리를 확보하거나 반환하면서 그 공간을 이용하는 것입니다.

    정적 메모리 / 동적 메모리의 할당.. 모두 EXE 를 로드하고 남은 프로세스 영역을 사용합니다.




    이밖에도 프로세스에는 DLL 들이라거나, 메모리맵, 가상디바이스, 페이지테이블.. 등등..

    프로그램에서 사용될 모든 정보가 로드됩니다.

    CTRL+SHIFT+ESC 키 눌러보세요.

    작업관리자라고 나오죠? 다른 말로는 태스킹 메니져라고 하는 건데..

    프로세스 탭을 보시면 현재 돌아가구있는 프로세스의 모든 목록을 볼 수 있습니다.

    혹은 Spy++ 라는 유틸로 보셔두 되구요.. pview 라는 유틸도 제공됩니다.




    -------------------------------------
    4. 마치며
    -------------------------------------

    첫회 강좌를 너무 길고 어찌보면 지루할 듯한 이야기를 써서

    여러분의 관심도를 떨어트리는건 아닌지 모르겠네요..

    첫회 강좌에서 윈도우 이야기는 2회로 빼올껄 그랬어요..

    앞으론 읽기 좋게 짧막 짧막하게 나누겠습니다.

    2회에서는 가상메모리와 프로세스에 대하여 주로 설명을 하였습니다..

    이제 3 회루 넘어갑니다..  3회에서 스택이 뭔가를 알아봅시다.

    3회를 읽어주시와요~

    수고하셨고

    끝까지 읽어주셔서 감사합니다.




    마침.

    20:03:15   13 Dec, 2002

    Written by Un-Wook






    =============================================
            배열과 포인터는 전혀 다르다 # 3

                     - 스택과 힙 -

                    13 Dec, 2002
                 Written by Un-Wook
    =============================================




    - 차례 -

    1. 서문
    2. 프로세스를 조금만 더 알아보자
    3. 스택이란?
    4. 힙이란?
    5. 마치며


    -----------------------------
    1. 서문
    -----------------------------

    오늘도 앉은 자리에서 연속으로 강좌를 써나갑니다 ㅡㅡ;;
    담배는 수북히 쌓여가고.. 날씨는 드럽게 추워서 창문도 못열어 놓겠네요..
    잡소리 집어치우구 3 회 시작하겠습니다..
    이제 프로세스는 감을 잡으셨을테니
    스택과 힙에대하여 이야기 해보는 것을 이번강좌의 목표로 잡지요..



    -------------------------------------
    2. 프로세스를 조금만 더 알아보자
    -------------------------------------

    기왕 2회 강좌에서 프로세스를 설명했으니.. 쬐꼼만 더 자세히 알아봅시다..
    그래야 스택과 힙의 설명이 자연스럽게 이어질 것 같아요.


    하나의 프로세스는 4GB 이지만.. 실제로 동적할당과 정적할당에 사용되는 영역은 4GB 의 반절인 2GB 입니다.
    이유는.. MS 가서 따지셔요.. MS 에서 설계한 것입니다. ㅋㅋㅋㅋ
    넝담이거.. 이유가 있어서 그렇게 설계 한 것이에요.


    사용자 삽입 이미지

                                                                             <그림 3-1>



    위 그림은 2개의 프로세스의 내부 구조를 도식화한 것 입니다.
    Inside Visual C++ 5 라는 책에서 추출했음을 밝히고...  그거 쪼금 제가 수정한겁니다..
    무단전재라면 당장 삭제하겠습니다. 근데 제 생각엔 올려도 괜찮을 것 같습니다.
    스캐너 사니까 참 좋네요 책을 스캔도 하고 ㅋㅋㅋㅋ

    암튼..
    그림과 같이 실제 응용프로그램은 하위 2GB 만 사용합니다..
    상위 2GB 는 웃기게도 모든 프로세스가 담구 있는 값이 똑같아요..
    사실은 상위 부분은 모든 프로세스에 있는 것이 아니라.. 하나만 있고, 공유를 한다는 의미이지요.

    (그렇다고 해도.. 하나의 프로세스에 선형 주소값으로 상위까지 표현이 가능합니다.)
    API호출등을 제외하고 어플리케이션이 주로 접근하는 영역은 하위 2GB 인 셈입니다..
    그림상으로는 하위 부분이 훨씬 공간이 넓어보이지만.. 상위 2GB 와 하위 2GB 의 크기는 똑같습니다.


    상위 부분은 주로 공유될 리소스라거나 공유 되는 DLL 들이 로드되고
    하위 부분에 2회강좌에서 설명해 드렸던 EXE 이미지가 로드됩니다.
    그 밖의 공간을 "스택"으로 사용하거나, 또는 "힙"이 될수도 있습니다.
    하위 부분에서 주소값이 높은 부분에다가는 DLL 들이 로드 되구요..
    우리가 중요하게 봐야할 부분은 하위 부분입니다..!!


    EXE 이미지가 프로세스에 로드되는 위치를 보면 0x00000000 부터 로드가 안되고
    0x00400000 부터 로드가 되는 것은
    0x00000000 부터 0x003FFFFF 까지는 MS-DOS 프로그램들을 에뮬레이션 하거나
    WIN32 의 구버전인 WIN16 을 돌리기위한 영역으로 예약이 되어 있기 때문입니다. (WIN98 의 경우..)
    WIN32 플랫폼 기반의 EXE 이미지는 0X00400000 부터 로드가 됩니다.



    -------------------------------------
    3. 스택이란?
    -------------------------------------

    스택을 설명하기 위해서 지금까지 이렇게 길고 긴 이야기를 진행해 왔습니다.

    지금까지의 길고 긴 이야기가.. 바로 스택을 설명하기위한.. 베이스였습니다.




    스택이란 두가지 의미로 해석될 수 있습니다..

    자료구조에서 본 스택이라는 자료구조와, 실제 프로세스에 존재하는 스택 메모리입니다..

    스택메모리는 프로세스의 어느 구간에 존재하고 있다고 말씀드렸었고,

    이번 회에서는 자료구조면에서의 스택의을 먼저 설명하고나서..

    다음 회에서 본격적으로 스택 메모리를 이야기해 보겠습니다.

    워드프로세서 필기 시험에는 스택에 대한 내용이 나오는데요.. 혹은 전산계열 학과에서 스택을 배우죠

    여기서 말하는 스택은.. 대부분 자료구조 측면에서의 스택입니다.




    그것이 무엇이냐면.. 설명하는 거보다 실생활에서 아주 끝내주게 좋은 예가 하나 있습니다.

    택시 자주 애용하시나요?..

    술마시다가 차 시간 놓쳐서 택시를 자주 타게 되지요??

    택시값 내구 나면 잔돈 거슬러 받아야되는데

    유심히 관찰해 보시면.. 모든 택시에는 동전 빼주는 간단한 장치가 있습니다.

    사용자 삽입 이미지

    <그림 3-2>                                       



    사진을 찾아보려고 했는데 찾기가 쉽지 않아서 직접 그려보았습니다.
    동전은 원통형의 공간에 들어가고.. 원통 아랫쪽엔 스프링이 달려서 동전을 밀어 내줍니다.
    택시 기사 아자씨가 차끌고 일하러 나가기전에, 그 기계에 동전을 차곡 차곡 꽂아넣습니다. (push)
    그리고 손님에게 동전 거실러 줄 때 위에서부터 동전 한개씩 빼냅니다. (pop)
    이게 스택 자료구조 입니다.
    이거 만큼 뿅가게 스택을 설명하기 좋은 예가 없다고 생각하는데 .... ㅋㅋㅋㅋ
    어떤분이 오바이트를 스택에 비유한 글을 봤는데..
    오바이트는 뱃속에서 한번 섞였다가 입밖으로 나오는거잖아요..
    발상은 기발하지만.. 오바이트는 스택이라고 볼수 없습니다.^^


    그리고 참고로 알아두세요..
    버스에 달려있는 동전교환기는.. 스택이 아니라 큐입니다.
    버스에 달려있는 동전교환기는 다 아시죠?
    원통에 동전이 차곡차곡 쌓여있고, 아랫쪽 동전부터 빠져나옵니다.


    보통 스택 자료구조를 LIFO 라구 하는걸 들어보셨나요?
    Last In First Out 입니다..
    말그대로 마지막에 저장한 데이터는 처음 얻어는 메카니즘입니다.
    처음 집어넣은 데이터는.. 잴 마지막에 얻어지구요..
    이게 컴퓨터에서는 메모리 영역 한 부분이 이런식으로 동작하고..
    그 메모리 영역을 바로..바로.. 스택이라고 부르는 것입니다.
    스택이 불리우는 영역이.. 스택이라는 자료구조 형식으로 동작한다고 봐야 맞지요.


    컴퓨터가 자동적으로 스택을 처리해주는 것은 아니고..
    다 프로그램을 통해서 스택처리가 되는 것이구요. CPU 에 스택 관련 명령이 있습니다.
    스택이라는 자료구조는 컴퓨터에서는 매우 중요한 작용을 합니다.
    스택을 생각해내지 못했다면 많은 변수의 사용이나, 함수호출은 꿈도 꾸지 못했을 것입니다.


    그리고 스택은 프로세스가 생성될때 필요한 만큼의 할당되어 집니다. (고정사이즈 입니다.)
    스택 오버플로우라던가, 스택 언더플로우를 격어보신분은 아실텐데..
    스택이 고정사이즈이기 때문에 발생하는 에러입니다.



    -------------------------------------
    6. 힙이란
    -------------------------------------

    스택메모리의 존재감에 대해선 느끼셨겠고..
    이젠 힙을 알아봅시다.
    프로세스에 EXE 이미지가 로드되고, 할당되고, 이것저것 필요한 동적 라이브러리가 로드되고
    사용되지 않는 미사용 구간이 있는 것은 분명한데..
    그 미사용 영역이 "힙"입니다.
    프로그램 짜실때.. new 라던가 malloc() 류 함수를 이용한 동적할당이란 것을 아실텐데..
    동적할당을 하게 되면.. 힙영역이 사용가능 하도록 잡히게 됩니다.


    필요한 메모리 사이즈 만큼 OS 에게 할당해달라고 부탁할수 있고..  (new)
    사용 다 했으면 다시 OS 에게 넘겨줘야합니다. (delete)

       char    *p= new char [1000];

    위와 같은 코드가 런타임시 힙영역에 메모리를 1000 바이트 할당하는 동작을 합니다.
    할당했으면.. 반환도 해줘야겠지요..  delete p;


    참고로.. 힙을 마구 할당하고 반환시키다가 보면 선형 메모리의 중간중간이 끊어지게 되는데..
    다른 말로 표현하자면, 메모리 블럭이 여러 조각으로 나뉘게 되어 비효율적이 되버리는데..
    이 것을 해결하기 위한.. "가비지 콜렉션"이라는게 있다는 것도 알아둡시다.


    -------------------------------------
    5. 마치며
    -------------------------------------

    강좌 한편 한편 작성되는 족족 게시판에 등록하려고 했는데..
    각 회마다 조율해야 점도 많고 소단원을 다른 회로 옮길 필요성도 있고..
    그래서 그냥 다 써놓고 올리는게 속편한거 같아요..
    이제 스택과 힙의가 어느정도 이해가 되시나요?
    그럼 4 회루 넘어갑니다.
    수고하셨고
    끝까지 읽어주셔서 감사합니다.



    마침.
    21:28:39   13 Dec, 2002
    Written by Un-Wook




    =============================================
            배열과 포인터는 전혀 다르다 # 4

                  - 변수와 메모리 -

                    13 Dec, 2002
                 Written by Un-Wook
    =============================================




    - 차례 -

    1. 서문
    2. 스택 내부에서의 할당과 반환
    3. 일반변수의 사용 (스택의 용도 1)
    4. 포인터 변수의 사용
    5. 함수 호출후 복귀 (스택의 용도 2)
    6. 마치며


    -----------------------------
    1. 서문
    -----------------------------

    자 이제 크라이맥스에 다다러 갑니다.

    조금만 힘 내십시오.. 저도 장시간 타이핑해서 좀 지치는데.. 힘내서 쓰겠습니다..

    이제 스택에 대해서 아셨으니, 이번 회에서는 스택이 어떻게 사용하며 그 중요성에 대해서 말해보겠습니다.

    1회에 제기했던 의문점의 실마리가 조금씩 잡혀가고 있습니다.

    4회 시작하겠습니다.




    -------------------------------------
    2. 스택 내부에서의 할당과 반환
    -------------------------------------

    스택에 대해서 3회에서 설명해 드렸지요?

    프로세스 생성시에 스택은 정적으로 프로세스 공간에 할당됩니다.

    그런데 한가지 재밋는 점은..

    스택 내부에서도 할당과 반환이 이루어 진다는 것입니다.




    예를들어 스택공간이 1000 BYTE 라고 치면..

    이 스택의 상대적인 주소값은 0 ~ 999 까지 갖을 수가 있겠지요.

    이 비어있는 스택에 1바이트 값을 하나 넣어주면

    1바이트가 할당되는 것이라고 이해할 수가 있습니다.

    1바이트 값을 하나 스택에서 빼오는 것은..

    스택에서 1바이트를 반환(소멸)하는 것과 의미가 같습니다.




    이런 스택의 할당과 반환을 처리하기 위해서 CPU 에는 "스택 포인터"라는 레지스터가 있습니다.

    위의 예를 이어서.. 계속 예를들어보지요..

    1000 바이트 공간의 스택이 있다면..

    스택포인터에는 초기값으로 999 라는 값이 들어가있습니다.

    스택에 1바이트를 할당하면서 데이터를 넣어주면

    스택포인터가 999 이므로 스택의 999 번지에 데이터를 넣고..

    스택포인터는 998 로 감소 됩니다..

    또 한번 데이터를 넣어주면

    스택포인터가 현재 998 임으로.. 스택의 998 번지에 데이터를 넣고

    스택포인터는 997 로 감소됩니다..




    반대로 데이터를 하나 얻어오면

    스택포인터는 998 로 증가하고

    스택의 998 번지에 있는 데이터를 리턴해줍니다.

    또 한번 데이터를 얻어오려면

    스택포인터는 999 로 증가하고

    스택의 999 번지에 있는 데이터를 리턴해 줍니다..




    이게 스택의 실제 동작입니다.. 그.. 택시기사님들이 사용하는 동전교환기랑 동작이 같습니다.

    스택포인터란 것으로 스택이 작동하며..

    위 예에서는 1바이트씩 넣고 빼고 하는 동작을 설명했는데

    4 바이트씩 넣고 빼고 할수도 있고..

    스택 포인터를 조작하여 스택 내부에 가변적인 크기를 할당해 놓을 수도 있습니다..

    넣고 뺀다고 표현하니 먼가 점 그러네여... ㅋㅋㅋ




    참고로

    이 스택 동작을 이해하시면..

    어플리케이션에서.. Undo 와 Redo 기능을 구현할 수 있습니다.

    Undo/Redo가 저런식이거든요..

    담에 Undo/Redo 를 구현하는 강좌를 한번 써볼까 합니다.




    -------------------------------------
    3. 일반변수의 사용 (스택의 용도 1)
    -------------------------------------

    이 스택이라는 메모리 공간에는 우리가 변수로 잡아준 것들이

    위에서 설명한 방식으로 할당되고 반환됩니다.

    외부 정적 변수를 제외하고..

    보통 자동변수라고 함수 내에서 선언하는 변수들은..  스택내부에 확보됩니다..

    글구.. 고정되게 위치하는 것이 아니고...위에서 설명한 것처럼

    동적으로 스택에 확보됩니다.

       int    nTest;

    위와 같은 변수는.. 위의 코드 진입시 4바이트가 스택에 확보되고.. 그 스택메모리가 변수로 사용됩니다.

    블럭이 닫히는 지점에서 스택 포인터 값이 변경(증가)되며

    할당(확보)되어있던 부분이 소멸(반환)되구요.




    배열변수도 마찬가지 입니다.

       void MyFunc(void)
       {
           char   cTest[10];
       }

    위의 코드는.. 프로그램이 MyFunc() 로 진입시.. 스택에 10 바이트를 할당하고..

    그 할당된 스택 메모리가 변수를 담는 공간으로 이용되는 것입니다.

    (10 바이트만 할당되는 것은 아닙니다. 함수호출 자체가 스택을 사용하기 때문에
    기본적으로 확보되야할 스택에다가 덤으로 10 바이트를 할당합니다.)




    아래와 같은 코드에서는

       char    cTest[]= "01ABC";

    우선 스택에 문자열 길이만큼의 6 바이트가 할당되고

    그 스택 메모리로 "01ABC" + NULL CODE 가 복사됩니다..

    포인터의 의미를 이해하지는 분들은 제가 1회 강좌에서 제시했던 문제의 실마리를 잡으셨을 것입니다.




    그리고 보충설명을 드리자면..

    변수가 항상 스택에 할당되는 것은 아닙니다.. 하지만 대체로 스택에 할당됩니다.

    네이티브 코드를 생성하는 컴파일러의 재량에 달린 문제이거나.. 최적화 옵션이 영향을 줍니다.

    CPU 레지스터를 바로 변수 공간으로 사용되는 경우도 많습니다.




    -------------------------------------
    4. 포인터 변수의 사용
    -------------------------------------

    포인터는 중요성이 넓리 알려져 있고.. 강좌로 다루시는 분들도 많기 때문에

    특별히 제가 설명하지는 않겠습니다..




    한가지 강조하고 싶은점은.. 포인터 변수라고 특별날 것이 없다는 검니다..

    그냥 일반변수처럼.. 포인터 변수 또한.. 스택이라는 공간에 잡힙니다.

    단지 포인터 변수는, 그 변수에 담겨있는 값이.. 메모리 주소 값(수치) 라는 것 뿐이지..

    일반 변수와 다를 것이 없습니다.




    아래의 코드는 new 의 동작을 설명하는 것인데..

       char    *p= new char [1000];

    힙에다가 1000 바이트 할당을 요구하고..  할당된 메모리의 시작 지점 주소(수치)가 리턴되어

    p 라는 변수에 대입됩니다.

    p 변수 자체가 1000 바이트가 할당된게 아닌 것이죠...

    단지 1000 바이트의 힙 블럭을 할당하고, 그 블럭의 시작 주소를 p 라는 변수가 포인팅 하는 것입니다.




    char* 때문에 혼동되실지도 모르겠지만..

    WIN32 에서 char *p, short *p, int *p 등으로 선언된 모든 포인터 변수는 그 type과는 상관 없이

    모두 32비트 입니다.. (4바이트)

    32 비트 주소값을 담기 위한 변수는 그 크기가 32 비트여야 하기 때문입니다.

    MS-DOS 에서는 모든 포인터 변수는 16 비트 크기였습니다.




    요약해보면 포인터 변수는 그냥 일반 변수와 똑같고.. 사이즈는 언제나 32 비트 라는 것입니다.

    안에 담겨있는 값이 단지 주소라는 것 뿐이지요.

    변수 자체는 일반 변수처럼 스택에 할당됩니다.!!!!

    단지 C 라는 컴파일러에서 포인터 변수라는 의미를 부여하는 것입니다.




    -------------------------------------
    5. 함수 호출후 복귀 (스택의 용도 2)
    -------------------------------------

    이 소단원은 그냥 참고 하시라고 써보는 것이니..

    일딴 읽지 마시고 마지막 강좌까지 읽고 나신 다음에 읽어보세요.




    "프로그램 카운터"라는 것을 2회인가? 에서 설명을 했던것 같습니다.

    함수 호출시에는 "프로그램 카운터" 값을 스택에 일단 처박아주구 나서

    함수를 호출합니다..  

    2 회에서 설명했던 내용이기는 한데..

    호출이라는 것은 그냥 점프 입니다. 프로그램 카운트 값을 변경해주는 것이에요..

    현제 실행중인 프로세스의 EXE 이미지 주소값을 변경해 주는것이.. 함수 호출입니다..

    API 호출도 원리는 같아요..

    단 이때.. 함수를 호출하기 직전에.. 프로그램 카운트 값을 스택에 한번 박아주고 호출한다는 것입니다.

    그 호출된 함수가 종료되면(리턴되면).. CPU 는 스택에서 최근 쳐박혀진 프로그램 카운트 값을 빼오고..

    현제의 프로그램 카운트를 빼온 값으로 변경해 줍니다.




    그럼 프로그램은 함수 호출후에 다시 원래대로 카운트가 증가해 나가면서 실행되어 나가는 것입니다.

    이것이 함수호출의 원리 이고..

    프로세스의 스택메모리가 사용되는 또다른 예 입니다.




    -------------------------------------
    6. 마치며
    -------------------------------------

    이제 다 설명한 것 같네요..

    지금 까지 설명된 내용을 바탕으로 5 회에서는 1 회에서 제기했던 문제를 이야기 해보며 강좌를 마칠까 합니다.

    그럼 5 회로 넘어가겠습니다.

    끝까지 읽어주셔서 감사드리고

    수고하셨습니다.




    마침.

    22:56:32   13 Dec, 2002

    Written by Un-Wook




    =============================================

            배열과 포인터는 전혀 다르다 # 5

              - 배열과 포인터의 차이점 -


                    14 Dec, 2002

                 Written by Un-Wook

    =============================================




    - 차례 -

    1. 서문
    2. 문제의 해결 1
    3. 문제의 해결 2
    4. 포인터 연산자
    5. 정리
    6. 마치며


    -----------------------------
    1. 서문
    -----------------------------

    이제 마지막 5회 입니다.

    지금까지 설명된 내용을 바탕으로 1 회에서 제시한 문제를 풀어봅시다.

    여러분은 지금까지 1회에서의 제기된 그 문제를 설명하기 위해서

    지금까지 기반 지식들을 학습해 오셨고

    이제 그 지식들을 이용해서 해결할 때가 온 것 입니다.

    아래 내용을 읽으시기전에 제가 지금까지 설명해 드린... 프로세스, EXE 이미지, 스택, 힙 을 이해하셔야 됩니다..

    마지막 회 시작하겠습니다.




    -------------------------------------
    2. 문제의 해결 1
    -------------------------------------

       char    *pTest= "01ABC";
       char    cTest[]= "01ABC";

    이 두 라인의 차이점이 우리가 해결한 문제였지요.

    위 코드를 컴파일하여 EXE 파일을 얻으면.. EXE 파일 내부에는 "01ABC" 라는 스트링이 들어가있습니다.

    무슨말이냐믄...

    C언어로 코딩하실때.. 큰따옴표 안의 스트링은...  EXE 파일로 만들어지면.. 죄다 EXE 파일에 뒷쪽에 들어가게됩니다.

    (EXE 이미지에서 스트링은 코드부분에 들어가있지 않고 따로 존재합니다.  
    데이터 세그먼트라고 부르는 구간에 들어가있습니다.)

    여튼... "01ABC" 라는 문자열은 EXE 파일 내부에 있고.. 프로그램 실행시에는 EXE 파일 자체가 번역없이 프로세스에 로딩됩니다.

    그 로딩된 EXE 이미지의 "01ABC" 라는 문자열이 런타임시엔 상수처럼 사용되지요..




    위 코드에서 pTest는 단지 런타임시에 4 바이트 포인터 변수로서 스택에 할당되고

    단지 이 변수에는 "01ABC" 라는 스트링이 시작되는 주소를 넣는 코드입니다.

    동적할당하고는 관계가 없고

    그 pTest에 담겨진 주소는.. 프로세스에 로딩되어있는 EXE 이미지 구간 중 한부분입니다.




    그리고..

    cTest는 런타임시 스택에 6바이트가 할당되고

    프로세스의 EXE 이미지 구간에서 "01ABC" 라는 문자열을 복사해옵니다.




    결과적으로 pTest 가 포인팅하고 있는 메모리는 EXE 이미지인 것이며..

    위의 코드에서는 pTest가 포인팅 하는 메모리는 할당된 힙이 아니라, 바로 EXE 이미지의 데이터 구간중 한 곳입니다.

    위의 코드 바로 아래다가
       
       strcpy(pTest, "안녕");    // 포인터변수 pTest

    저렇게 코딩하게 되면.. 컴파일 할때는 오류가 검사되지 않으나.. (문법상으로는 오류가 없기 때문입니다.)

    런타임시에는 프로그램이 저 코드 부분에서 바로 죽어버립니다.

    pTest 가 포인팅 하고 있는 메모리는 EXE 이미지이기 때문입니다.

    EXE 이미지 구간은 오버라이트를 하면 안되죠..

    DOS 플랫폼 같았으면 프로그램이 알수없게 동작하거나.. 시스템 자체가 먹통이 되버리는 상황이 발생 되었을 일입니다.




    하지만

       strcpy(cTest, "안녕");  // 배열변수 cTest

    이런 코드는.. 런타임 오류가 발생하지 않습니다..

    이미 cTest 는 6 바이트라는 영역이 스택에 할당되어있기 때문입니다..

    그 안엔 이미 "01ABC"라는 문자열이 복사되어져 와있습니다.

    6바이트 이내로 안전하게.. 오버라이트가 가능합니다.




    그리고 참고로.. pTest 라던가 cTest 라던가하는 변수 이름은..

    네이티브 코드가 만들어질때.. 변수의 이름 자체는 의미가 없습니다..

    단지 C언어라는 고급 프로그래밍 언어에서

    소스 코드 작성하기 편리하도록 지원해주는 것일 뿐입니다.

    변수라는 것은 프로그램 런타임시 단지 주소값을 갖는 메모리의 일 부분일 뿐입니다.




    -------------------------------------
    3. 문제의 해결 2
    -------------------------------------

       char    *pTest= "01ABC";
       char    cTest[]= "01ABC";

       printf("pTest : %08x %08x \n", pTest, &pTest);
       printf("cTest : %08x %08x \n", cTest, &cTest);

       출력 결과----------

           pTest : 00407058 0012ff78
           cTest : 0012ff7c 0012ff7c

    출력결과는 코딩을 어케 했느냐와.. 시스템에 따라 달라질 수 있습니다.

    하지만 모든 시스템에서 두번째 라인에 출력되는 값 두개는 서로 동일합니다...

    왜 두개가 서로 동일한 것인가가.. 우리가 풀어볼 문제였지요..




    출력결과 pTest 를 보면

    첫번째 수치 0x00407058 은 pTest 변수에 담긴 값입니다..

    pTest에 담긴 이 값은 메모리 주소를 의미하고..

    이 메모리 주소는 프로세스에 로딩된 실제 EXE 이미지의 한부분이죠.  (위에서 설명한 말입니다.)

    두번째 강좌에서 0x00400000 부터 EXE 이미지가 로딩된다고 설명했었고..

    실제로 pTest가 포인팅하는 주소는 0X0040000 과 매우 근접한 것을 확인 하실 수가 있습니다.

    사용자 삽입 이미지




    실제로 EXE 파일 덤프해보면 0x7058 오프셋부터 "01ABC" 라는 데이터가 있는 것도 확인됩니다.


    사용자 삽입 이미지



    그리고 두번째 수치 0x0012FF78 의 경우는 pTest 라는 변수가 할당된 스택 메모리의 주소입니다.




    출력결과 cTest 를 보면.. (이것이 우리가 풀어볼 문제지요..)

    좀 특이한데...

    배열 변수는 [] 사용없이 배열 변수명만을 사용하면

    변수명 자체가 그 배열변수가 스택에 위치한 주소값을 나타냅니다.

    그 cTest 에 담겨 있는 값은 분명 "01ABC" 의 첫바이트인 '0' 이라는 값으로 봐야하지만..

    cTest 라고 코딩하면 이것은 cTest안에 담긴 값이 아니라 cTest 자신의 주소값을 의미합니다.

    결과적으로 C 로 코딩할때, char cTest[]="01ABC"; 라고 선언된 배열변수에 대하여

    cTest는 &cTest 와 의미가 같고

    둘다 &cTest[0] 을 의미하는 것 입니다..




    이것이 배열이 포인터와는 다른 점입니다.

    달라도 전혀 다른 것이지요.

    포인터변수는 자신에게 담긴 값으로.. 다른 메모리를 포인팅 해주지만

    배열변수는 스택에 메모리 배열이 할당되고, 변수명 자체가 자신의 주소값을 의미합니다.

    이해를 돕고자 그림을 하나 그려보았습니다..

    사용자 삽입 이미지





    이제 좀 응용해서 설명해 보겠습니다.

    (pTest + 2) 은 메모리에서 'A'가 담긴 주소값을 의미하고 (0x0042206C + 2) --> 32비트 수치 메모리 주소

    pTest 라는 변수에는 주소값이 담겨있기 때문에 메모리 주소값에 2를 더해주는 것입니다.

    그래서 pTest[2] 는 *(pTest + 2)를 의미합니다.  --> 8비트 수치 char 형 'A'


    (cTest + 2) 도 메모리에서 'A'가 담긴 주소값을 의미합니다. (0x0012FF70 + 2) --> 32비트 수치 메모리 주소

    하지만 cTest 라는 변수에는 메모리 주소값이 담겨있지 않습니다. 단지 cTest 가 &cTest를 의미하는 것입니다.

    그래서 cTest[2] 의 경우에도 *(cTest + 2)를 의미하는 것이지만 --> 8비트 수치 char 형 'A'

    cTest 엔 메모리 주소값이 담겨있는게 아니라 cTest 는 &cTest 와 동격인 것입니다.




    지금까지 제가 한 말이 못미더우시면..

    비주얼 씨의 디버깅 기능중에

    프로세스 영역을 보여주는 기능이 있습니다..

    View > Debug Window > Memory

    프로그램 런타임상태에서.. 브레이크 포인트가 걸리게 하신담에

    메모리 윈도우를 열으시고.. 메모리 주소를 트래이싱해 보시면

    직접 확인해 보실 수 있습니다.




    -------------------------------------
    4. 포인터 연산자
    -------------------------------------

    이 소단원은 그냥 참고 용으로 써보는 내용입니다.

    포인터변수의 선언과 포인터 연산자는.. 서로 다릅니다..

    이미 포인터를 학습해 오시고 사용해 오시면서.. 익히 아실 것으로 압니다.




    포인터의 선언은 포인터 변수를 선언 하는 것이고

    (반복해서 설명해 드리지만.. 선언된 변수 자체는 런타임시 32비트 사이즈로 스택에 잡힙니다.

    그리고 그 변수는 주소값을 담고 있으면서, 할당된 힙블럭을 포인팅한다거나 EXE 이미지의 데이터를 포인팅하는 것입니다.)




    포인터 연산자는 어느 수치값(주소)이 의미하는 메모리주소에 담겨있는 실제 값을 얻어오거나 할때 사용하게 됩니다.

    아래 코드에서 (char*) 는 캐스팅이고... 재일 왼쪽에 붙은 별이 포인터 연산자입니다.

       char  cA= *((char*)100);

    위와 같은 코드는 메모리주소 100 에 담긴 값이 cA 라는 변수로 바로 얻어집니다. (실제 이런 코드는 사용안되지지만..)




    WIN32에서 메모리 포인터는 죄다 32 비트라고 했는데

    char *pTest; 라고 선언된것에서 이 char 타입이.. 바로 포인터연산자에 활약하는 것입니다..

    short *Test; 라고 선언한 것에 포인터 연산자를 사용하면 2 바이트 short 값으로 얻어오게 되지요..




    그리고 [] 자체도 연산자입니다. 포인터 연산자와 같은 동작을 합니다.. 명칭은 까먹엇어요.

    ㅋㅋㅋ

    언제나 드리는 말씀이지만.. 용어를 아는것 보다 원리를 아는 것이 더 중요합니다..

    사람들이 규정한 용어라는 것은.. 원리를 이해하고 있다면 그냥 사전 찾아보시믄 됩니다.




    -------------------------------------
    5. 정리
    -------------------------------------

    이처럼.. 배열과 포인터변수는 코딩상에서 사용은 서로 유사하지만..

    사실 그 내부 동작은 매우 차이가 납니다.

    이러한 차이 때문에 발생하는 문제에 대해서도 말씀드렸구요..

    우리가 의식하지 못했던..  스택이라는 것이 존재하기 때문입니다..

    이것을 이해하는 것은 자신의 스킬을 한단계 끌여 올릴 수 있는 계기가 될 것입니다.

    이강좌를 완독하셨다면..

    지금까지 코딩하실때 그냥 그냥 사용했던 포인터 변수들과 배열/ 함수호출/ 함수진입 등이

    조금은 다른 느낌으로 가슴에 와 닿으실 거라 생각됩니다.




    -------------------------------------
    6. 마치며
    -------------------------------------

    이제 막을 내릴 시간입니다.

    이번 강좌는 지금까지 써왔던 강좌와는 좀 다르게

    해결하기 위한 문제를 먼저 제시해 보고

    그 문제를 풀기 위해 필요한 지식들을 설명해 나가는 방식으로 진행해 보았습니다..

    기반 지식을 갖추게 되면 풀리는 문제이기 때문이기도 합니다.




    스택에 대해서 용어만 알고 계셨던 분이라거나.. 사전적인 의미만 알고 계셨던 분이라거나..

    여기 까지 읽으셨다면.. 감을 잡으셨을거라 생각이 됩니다..

    중요하고 기초적인 것이면서도 왠만해서는 잘 안다뤄지고 있는 내용이라 써봤어요




    "배열과 포인터는 전혀 다르다" 라는 제목으로 작성된 이 강좌에는

    WIN32 플랫폼, 가상메모리, 프로세스, EXE 이미지, 프로그램 구동원리, 스택, 힙을 설명하였습니다.

    강좌 제목은 여러분의 이목을 끌어보기 위한 타이틀이였고,

    첫 회에 말씀드린 것 처럼 주로 메모리와 관련된 이야기였습니다.

    다루어진 항목은 많은데 각 항목에 대해 세밀한 부분까지는 설명드리지 못 한것 같은 생각이 들어요..

    제 딴에는 쉽게 풀어서 쓴다고 썻지만..

    모호한 설명이라거나 난해하게 표현된 부분이 있을지도 모르구요..

    글을 등록하고 난 후에도.. 발견하는 대로 수정하도록 하겠습니다.




    요즘 날씨가 갑자기 추워졌지요..

    감기걸려서 저처럼 고생하지 마시고.. 조심하세요..

    수고하셨고

    끝까지 읽어주셔서 감사드립니다.




    마침.

    00:00:00   14 Dec, 2002

    Written by Un-Wook



    Posted by theYoungman