2010년 4월 27일 화요일
메인프레임에서 활성화된 차일드 프래임 얻어오기
우선 메인MDI프레임이 CMainFrame 이라고 하면요
CFrameWnd* frame = GetActiveFrame();
// 차일드 프레임이 없을경우엔 frame은 GetActiveFrame은 자신의 주소를 반환합니다.
// 만약 frame이 this가 다르다면 frame 은 자식윈도우 중의 엑티브된 프레임의 주소겠죠.
if( frame == this ) return;
CWnd* wnd = frame->GetWindow(GW_HWNDFIRST);
// wnd는 여러개의 ChildFrame 중의 가장 첫번째의 포인터입니다.
while( wnd )
{
wnd = wnd->GetWindow( GW_HWNDNEXT );
// 모든 ChildWindow들의 포인터를 받을 수 있습니다.
}
//그럼 위에서 wnd를 가지고 차일드 프레임의 포인터로 변환을 시도합니다.
//DYNAMIC_DOWNCAST 또는 STATIC_DOWNCAST를 이용합니다.
CChildFrame* child = DYNAMIC_DOWNCAST(CChildFrame, wnd);
// wnd가 CChildFrame 클래스이어야만 child로 제대로 변환이 됩니다.
child->do(); // 그냥 써주시면 됩니다.
wxWidgets 설치
- MinGW(Automated MinGW Installer) 설치: 설치 옵션에서 MinGW base tools, g++ compiler, MinGW Make 선택
- GDB 설치 (설치 폴더는 MinGW가 설치되어 있는 폴더로)
- PATH 환경변수에 MinGW의 bin 폴더 추가
C:\MinGW\bin
C:\MinGW\mingw32\bin - wxWidgets 설치(wxMSW-Setup.exe)
- WXWIN 환경변수 등록(불필요하다면 생각한다면 생략)
set WXWIN=C:\wxWidgets-2.8.7 - wxWidgets 빌드 (debug 버전과 release 버전을 모두 빌드할 필요가 있음)
(* %WXWIN%\lib\gcc_dll 폴더에 라이브러리(.a) 파일들과 DLL 파일들이 생성된다. 이름 뒤에 'd'가 붙어 있는 것들이 debug 버전으로 빌드한 것들이다. *)cd %WXWIN%\build\msw
mingw32-make -f makefile.gcc MONOLITHIC=1 SHARED=1 UNICODE=1 BUILD=release clean
mingw32-make -f makefile.gcc MONOLITHIC=1 SHARED=1 UNICODE=1 BUILD=release
mingw32-make -f makefile.gcc MONOLITHIC=1 SHARED=1 UNICODE=1 BUILD=debug clean
mingw32-make -f makefile.gcc MONOLITHIC=1 SHARED=1 UNICODE=1 BUILD=debug
- wxWidgets의 include 폴더에서 setup.h 파일 생성
cd %WXWIN%\include\wx
ren setup_redirect.h setup.h - Code::Blocks 설치(1.0rc2)
- 7-Zip 설치 (이미 설치되어 있다면 통과)
- Code::Blocks Forum에서 최신 Nightly Build를 받아 Code::Blocks 폴더에 설치: CB_20071224_rev4750_win32.7z, wxmsw28u_gcc_cb_wx287.7z
- Code::Blocks를 위한 기존 wxWidgets DLL 삭제: wxmsw26_gcc_cb.dll
2. Code::Blocks에서 테스트 프로그램 빌드
- 프로젝트 빌드 위저드('File>New>Project...')에서 'wxWidgets project'를 선택해서 새 wsWidgets 프로젝트 생성
- wxWidgets 폴더 위치 지정 (예를 들어 'C:\wxWidgets-2.8.7')
- 'wxWidgets Library Settings'에서 다음 옵션 선택
- Use wxWidgets DLL
- Enable unicode
- Use wxWidgets DLL
- wxWidgets 폴더 위치 지정 (예를 들어 'C:\wxWidgets-2.8.7')
- 프로젝트 빌드 옵션('Project>Build Options')의 'Linker settings'에서 링크 라이브러리 목록 수정 (다음 예는 Release 빌드의 경우이고, Debug 빌드에 대해서도 같은 방식으로 수정한다.)
- libwxmsw28u_core.a를 libwxmsw28u.a로 수정
- libwxbase28u.a 제거
- libwxmsw28u_core.a를 libwxmsw28u.a로 수정
- 프로젝트 빌드 ('Build>Build')
- 빌드한 테스트 프로그램 실행 ('Build>Run')
(* 참고로 Code::Blocks 밖에서 실행하려면 %WXWIN%\lib\gcc_dll 폴더에 있는 wxmsw28u_gcc_custom.dll 파일을 .exe 파일과 같은 폴더에 복사하거나 C:\Windows\System32\ 폴더에 복사한다. *)
3. 참고 도서
4. 참고 URL
- Code::Blocks - The Open Source, Cross-platform, Free C/C++ IDE
- MinGW - Minimalist GNU for Windows
- wxWidgets - Cross-Platform GUI Library
- wxWidgets 2.8 (latest stable) Online Manual
- Class Reference
- Blog
- Forum
- Mailing List Archives
- Screen Shots(Applications & Samples)
- Tutorials
- Wiki
- wxWidgets 2.8 (latest stable) Online Manual
- MinGW, wxWidget, Code:Blocks를 이용한 C/C++ IDE 환경 구축
- Codeblocks에서 wxWidget을 사용하여 GUI프로그램 만들기 (Ubuntu)
- Codeblocks에서 wxWidget을 사용하여 GUI프로그램 만들기 (Windows)
백업의 종류
일요일 전체백업을 받은 후 월요일부터는 변경된 내용만 별도의 파일에 보관합니다.
업데이트 백업의 특징은 변경된 내용이 동일한 파일에 (예: _001.ZIA) 저장됩니다.
장점 : 저장 공간을 최소화할 수 있습니다.
단점 : 가장 최근에 백업한 날짜, 또는 전체백업 받은 날짜로만 복구가 가능합니다.
예를 들어 목요일까지 업데이트 백업을 받았다면,
월요일,화요일,수요일로는 복구가 불가능하고,
목요일 또는 일요일로 복구가 가능합니다.

2. 증가분(Incremental) 백업
일요일에 전체백업을 받은 후 월요일부터 변경된 내용은 백업을 실행할 때마다
별도의 파일(_001.ZIA, _002,ZIA, _003.ZIA ...) 에 보관됩니다.
장점 : 저장공간을 줄이면서, 백업받은 날짜별로 복구가 가능합니다.
단점 : 백업/복구할 때 모든 순차 파일이 필요합니다.
예를 들어 목요일로 복구하기 위해서는
전체백업 + 001 + 002 + 003 + 004 파일이 모두 필요합니다.
또한 모든 순차 파일을 비교하면서 백업/복구가 진행되기 때문에
순차 파일이 많아질수록 다른 백업 방법에 비해 시간이 오래 걸릴 수 있습니다.

3. 변경분(Differential) 백업
일요일에 전체백업을 받은 후 월요일부터 변경된 내용은 백업을 실행할 때마다
별도의 파일(_001.ZIA, _002,ZIA, _003.ZIA ...) 에 보관됩니다.
증가분(Incremental) 백업과의 차이점은,
변경된 내용에 대한 비교 대상이 바로 이전 백업본이 아니라
항상 "전체백업" 이라는 점입니다.
장점 : 백업받은 날짜별로 복구가 가능하며,
전체백업 + 해당 날짜 백업본 만 있으면 복구가 가능합니다.
예를 들어 목요일로 복구를 하려면,
전체백업 + 004 백업본만 있으면 복구를 할 수 있습니다.
단점 : 세가지 백업 방법 중에 저장공간을 가장 많이 차지합니다.

백업 받는 드라이브의 특징과 저장 공간에 따라서,,
세가지 백업 방법을 적절히 사용하셔야 합니다.
Win32 실행파일 구조
Win32 실행파일 구조
冊 이호동 지음, "Windows 시스템 실행파일의 구조와 원리", 한빛미디어 펴냄, 2005.5.26.
■ 기초 내용.
○ PE(Portable Executable) File format : Win32 운영체제가 탑재된 플랫폼이라면 어떤 플랫폼에서도 관계없이 실행되는 exe 또는 dll 파일. 보통 windows에서 실행파일 형식이라고 얘기하는 파일을 의미함.
○ 메모리 상에 로드된 하나의 Process = 하나의 EXE 파일 + 여러개의 관련 DLL 파일.
○ EXE와 DLL은 같은 파일 구조를 가지고 있다. 즉, PE file format이다. 여기에서는 EXE와 DLL을 'PE 파일'이라 칭하기로 한다.
○ PE 파일은 디스크에 파일형태로 존재하지만 사실 그 내용은 메모리 상에서 돌아가는 프로세스의 이미지이다. 즉, 메모리 상의 프로세스 이미지를 거의 그대로 파일 형태로 저장한 것이 PE파일이라는 것이다.
■ 메모리에서의 PE 구조
| ※ 메모리 내부의 'Win32 가상주소공간'에서의 구조 | ||
| 주소 | 내용물 | |
| 0번지 | 64KB 보호영역 | |
| Thread stack | ||
| Process Heap | ||
| 0x00400000 | .text |
↑ 이 영역을 실행파일(PE)이미지 영역이라 함. ↓ |
| .data | ||
| .rdata | ||
| .idata | ||
| .didat | ||
| .reloc | ||
| .rsrc | ||
| .tls, .debug... 기타 섹션 | ||
| ...중략... | ||
| 0x10000000 | DLL 및 .edata | DLL도 PE구조이므로 각각의 .text와 .data를 가진다. |
| ...중략... | ||
| 64KB 보호영역 | ||
| 0xFFFFFFFF ~ 0x80000000 |
상위 2GB : 커널영역 | |
■ 프로그램 관점의 메모리 구조와 PE구조
| ※ 메모리 내부의 'Win32 가상주소공간'에서의 구조 | ||
| 메모리 구조 | 메모리 주소 | PE구조 |
| Stack 영역
▶ 스택의 출입구는 SP; Stack Pointer 레지스터가 가리킨다. ▶ 지역변수, 매개변수, 함수들의 복귀주소 등이 담겨지는 곳. |
0번지에서 64KB(보호영역)만큼 지난 부분부터 시작된다. | 보통 Thread stack 이라는 명칭으로 실행시 생성된다. PE구조에서는 존재하지 않으며, 실행시 생성되는 영역이다. |
| Heap 영역
▶ new, malloc 등으로 동적인 메모리가 할당되는 영역. |
Stack 영역에 바로 이어서 0x00400000 번지 이전까지 사용된다.
(즉, 약 4MB의 용량이 일반적으로 힙으로 사용가능한 용량이다.) |
실행시에 메모리를 할당하게 되면 이 공간을 사용하게 된다. PE구조에서는 존재하지 않으며, 실행시 생성되는 영역이다. |
| 코드 영역
▶ IP; Instruction Pointer 레지스터가 가리키는 곳. |
0x00400000 번지부터 시작된다.
(실제로 PE가 시작되는 부분이다. 시작위치는 컴파일러 옵션을 사용해 변경 가능하다.) |
.text 섹션이 이곳에 맵핑된다.
("MZ"문자열부터 시작해서 모두 메모리로 카피되어 맵핑된다.) (DLL의 경우에는 .text가 0x10000000 번지에 맵핑된다.) |
| 데이타 영역
▶ 전역/정적변수, 문자열 상수 등이 저장되는 곳. |
PE구조가 계속 그대로 맵핑됨. | .data와 .rdata 섹션 등이 이곳에 맵핑된다.
(.data 섹션은 읽기/쓰기 가능한 섹션이다. 단, 메모리 상에서만 그렇다. 파일 자체에 읽기 쓰기 하는 것이 아님.) (.rdata 섹션은 readonly data 섹션, 즉 읽기 전용이다. 이 영역에는 상수로 선언된 것들과 리터럴들, 에러메시지들이 위치한다. 이 영역에 기록하려고 하면 프로그램은 예외를 발생시키며 종료되어 버린다.) (.textbss 섹션은 초기화 되지 않는 데이타를 보관하는 섹션으로 디버깅 모드에서만 생성된다. 참고로 VC++6.0 이전에는 .bss 섹션이라는 이름으로 사용되었다) |
| ... 이하 생략 ... | 이하의 구조는 윗 그림을 참고할 것. | |
■ 파일에서의 PE구조
| ※ 디스크에 있는 PE파일의 내부 구조 (여기에서의 구조체는 Win32 SDK의 WinNT.h에 모두 정의되어 있다) | ||||||
| 파일 내부 위치 | 내용물 | 설명 | ||||
| 0번지~40바이트까지 | IMAGE_DOS_HEADER 구조체 |
0x5A4D(="MZ"문자열)로 시작됨
참고로 MZ는 도스를 설계한 사람중의 한 사람인 Mark Zbikowski의 이니셜이다. | ||||
| ...... | DOS 호환 더미 | 여기까지가 도스 호환을 위한 영역임. | ||||
IMAGE_NT_HEADER 구조체 : PE파일의 정보를 나타냄. 자세한 내부 구조는 아래의 아기 표와 같음.
|
여기서부터가 진짜 PE구조의 시작. | |||||
IMAGE_SECTION_HEADER 구조체 배열 : 보통 섹션 테이블이라고 칭함. 각 섹션들(.text, .data, .edata, .idata, .reloc...)의 실제 위치 정보를 담고 있는 파일포인터의 역할을 하고 있는 구조체 배열임. 세부구조는 아래의 아기 표와 같음.
|
||||||
| 이하 section data 영역. | .text | 실행코드를 담고 있는 영역. CPU 레지스터의 명령 포인터인 ip는 이 섹션 내에 존재하는 번지 값을 담게 된다.
이하 각 섹션들은 8바이트 이하의 인식 가능한 아스키코드로 된 섹션 이름으로 시작한다. 그래서 텍스트에디터로 열어도 각 섹션의 시작위치는 파악이 가능하게 된다. | ||||
| .data | 전역 데이타들을 담고 있는 영역. | |||||
| .edata | export 함수에 대한 정보를 담고 있는 영역 | |||||
| .idata | import! 함수에 대한 정보를 담고 있는 영역 | |||||
| .reloc | ||||||
| .rsrc | 다이얼로그, 아이콘, 메뉴 등의 리소스 데이터의 내용을 담고 있는 영역. | |||||
| .tls | Thread Local Storage; 스레드 지역 저장소
각 스레드에 고유한 전역 변수 공간. 멀티스레딩 환경에서 런타임 라이브러리의 전역 변수 등을 각 스레드 사이에서 보호하기 위해 사용된다. 명시적 DLL 로딩 방식에서는 TLS가 작동하지 않는다. | |||||
| ...... | ||||||
■ 프로그램의 구동.
○ 프로그램을 실행시키면 콘솔 응용프로그램은 main()이 실행되고, GUI는 WinMain()이 실행된다.
○ main()은 간단하게 arguments만 넘겨서 실행하므로 여기에서는 WinMain()을 대상으로 그 실행과정을 살펴본다.
| int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, PSTR szCmdLine, int iCmdShow); |
○ 각 매개변수 설명
- HINSTANCE hInstance : 해당 프로그램의 인스턴스 핸들.
- 이 인스턴스는 프로세스에 속한 여러 리소스들(메뉴, 아이콘, 커서, 대화상자 등등)의 준거점이 된다. 이러한 리소스들을 로드할 때에는 언제나 이 인스턴스를 요구한다.
- 실제로 이 값은 0x00400000 으로 설정되어 있다. 즉 .text 섹션의 시작 위치를 가리키고 있는 것이다.
- PE헤더의 IMAGE_OPTIONAL_HEADER의 ImageBase 필드에 지정되어 있는 값이므로 DLL의 경우에는 0x10000000 이 된다.
- HINSTANCE hPreInst : 의미없음. Win16과 호환을 위해 남겨진 부분. 항상 "NULL".
- PSTR szCmdLine : Command-line arguments에 대한 문자열 포인터.
- int iCmdShow : 처음 실행시 윈도가 화면에 나타나는 방법.
○ WINAPI : 이것은 스택 호출방법을 설정하는 것으로 내부적으로 __stdcall (PASCAL 방식의 호출)으로 정의되어 있다(WINDEF.H에 define되어 있다).
- 인자(parameter) 개수를 가변적으로 받을 수 있고(printf처럼), 인자 스택을 함수 측(호출 받은 측)에서 해제한다.
- 즉, 인자 개수의 유연성과 빠른 스택소멸을 위한 매크로 상수이다.
- VC++에서는 파스칼 방식이 표준 호출 방식으로 되어 있다. 만약 WINAPI를 명시하지 않으면 디폴트로 __cdecl로 인식해서 C선언 방식으로 컴파일 된다. 두가지 방식 중에서 어느 것을 쓰던지 상관없지만, 일치되지 않으면 스택 포인터의 불일치로 인해 대혼란에 빠지게 된다. 그리고 이런 오류는 링크시에도 오류를 발생시켜 주므로 사전에 발견할 수 있다.
- 참고로 WINAPI 키워드를 사용하지 않으면 'C선언 방식(__cdecl)' 으로 작동된다. 즉, 호출한 측에서 스택을 제거시킨다.
- 그리고 스택 push 순서는 parameter의 왼쪽에서 오른쪽 매개변수 순서로 push 되도록 통일되어 있다. 예전에는 C선언방식의 경우 매개변수를 오른쪽에서 왼쪽으로 push, 파스칼 선언방식의 경우 왼쪽에서 오른쪽으로 차례대로 push하도록 되어 있어 차이가 있었다.
○ 실행순서
- 운영체제의 프로그램 로더는 PE의 헤더에 있는 IMAGE_OPTIONAL_HEADER 구조체의 AddressOfEntryPoint 필드를 참고해 그 주소의 코드(.text 섹션 내부에 위치)를 실행시킨다.
- AddressOfEntryPoint가 가리키는 지점에는 WinMainCRTStartup()함수가 있다. 이 함수는 WinMain()이 필요로 하는 실행환경을 만들고, 각 매개변수로 전달될 값들을 구해서 WinMain()함수를 호출한다.
- WinMain()함수는 WinMainCRTStartup()함수로 부터 넘겨받은 arguments를 이용해 프로그램 내부적인 동작을 실행한다.
- WinMain()함수의 동작이 종료되면 실행 포인터는 WinMainCRTStartup()함수로 return되고, 이 함수는 다시 WinMain()의 리턴값을 exit함수의 parameter로 넘겨준다.
- exit()함수는 여러가지 마무리 작업을 하고, Win32 ExitProcess() 함수를 호출하고 WinMain()의 리턴값을 운영체제로 넘기고 프로그램을 종료한다.
■ 리소스
○ 리소스 섹션은 PE구조에서 .rsrc 섹션 영역에 존재한다.
- 프로그램에서 *.cpp가 컴파일 되어 .obj가 되는 것처럼, 리소스는 .rc 파일이 리소스 컴파일러를 통해 .res로 만들어진다. 이후 링커를 통해 실행파일에 합쳐진다.
- 당연히 리소스 파일이 없이도 윈도 프로그램은 제작 가능하다.
- MFC를 사용하면 기본적으로 항상 몇가지의 리소스는 포함된다. Accelerator, Dialog, Icon, Menu, String table, Bitmap, Font, Cursor, Version 등등...
○ 리소스 섹션은 트리 구조로 되어 있다. leaf node에 실제 리소스가 링크되어 있다.
---------------------------------------
■ .Net의 PE 구조
○ 기존의 각 섹션 개념은 그대로 가져왔지만 구조는 크게 달라졌다.
○ 웬만한 정보는 .text 섹션으로 모두 통합되었다. 다만 그 내부에서 각 섹션 개념별로 구분되어 관리될 뿐이다.
○ 자세한 내용은 생략... (나중에 별도로 책이 나온다고 함)
resizing_dlg_sample-definer27.zip