1-1 Win32 API 프로그래밍
윈도우 응용 프로그램 종류 ┌ Console 어플리케이션
└ GUI 어플리케이션
CRT main 함수
컴파일러가 최초로 실행하는 함수는 CRT main 함수이다.
CRT main 함수에서는 ① 전역 변수 객체의 생성자를 호출
[code]class FirstClass
{
public:
FirstClass() { printf("FirstClass 생성자\n"); };
}
FirstClass fc;
void main()
{
printf("테스트\n");
}[/code]
FirstClass 생성자
테스트
② C 또는 C++ 언어의 전역 변수(__로 시작)를 초기화
따라서 main 이후에는 이 변수를 사용 가능하다.
③ 힙 메모리 초기화
- 메모리 할당 malloc 함수 - ANSI 표준 C/C++을 위해 구현된 함수로 - 내부에서는 윈도우즈의 힙 할당 함수인 HeapAlloc 함수를 호출한다. HeapAlloc 을 위해서는 사전에 HeapCreate 함수를 호출해야하는데 이를 CRT main에서 해준다.
Visual Studio .NET의 컴파일러의 경우, 다음과 같은 이름으로 CRT main 함수가 구현되어있다.
어플리케이션 종류 |
문자 집합 |
CRT main |
어플리케이션 시작 함수 |
콘솔 | ANSI | mainCRTStartup | main |
UNICODE | wmainCRTStartup | wmain | |
GUI | ANSI | WinMainCRTStartup | WinMain |
UNICODE | wWinMainCRTStartup | wWinMain |
CRT main 함수 지정
프로젝트 속성 > 링커 > 시스템 > 하위 시스템 을 'Windows' 또는 '콘솔' 로 변경
문자 집합 지정
프로젝트 속성 > 일반 > 문자 집합
1-2 Win32 GUI 프로그래밍
WinMain 함수 원형
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow);
Win95 이전: 동일 어플리케이션이 두번 실행되면 '실행 코드'(중복)는 한번만 로드하고 전역 변수 메모리 블록은 프로세스 단위로 할당한다.
인스턴스 핸들 = 프로세스별 전역 변수 메모리 블록의 주소
모듈 핸들 = 실행 코드가 로드된 주소
Win95 이후: 프로세스(어플리케이션) 실행시마다 실행 코드도 프로세스 단위로 다시 로드
인스턴스 핸들 = 모듈 핸들
WinMain 함수의 기본 골격
WinMain의 역할은 1) 메인 윈도우 생성 2) 메시지 루프 처리
윈도우 메시지 발생 → 시스템 메시지 큐(OS가 관리) → 해당 어플리케이션 메시지 큐로 전달 → 어플리케이션에서 처리
메시지 큐를 통하지 않고 바로 윈도우 프로시저가 호출되는 경우도 있다.
1) Win32 API 호출에 의해 바로 윈도우 프로시저가 실행
ex:) CreateWindow 호출시 WM_CREATE 메시지는 메시지 큐에 들어가지 않고 바로 윈도우 프로시저 실행
2) 운영체제가 일 수행을 위해 바로 윈도우 프로시저로 메시지를 보내는 경우(운영체제가 GetMessage를 호출)
ex:) 운영체제가 윈도우를 움직여도 되는지 WM_MOVING 메시지를 어플리케이션에 보내는 예
GUI 기본 코드 [more..]
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASSEX wcex;
HWND hWnd = NULL;
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.cbClsExtra = 0; // 윈도우 클래스를 위한 추가 데이터 영역(bytes)
wcex.cbWndExtra = 0; // 생성할 윈도우를 위한 추가 데이터 영역(bytes)
// SetWindowLong, GetWindowLong
wcex.lpszClassName = "class_byhou";
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION);
wcex.hIcon = LoadIcon(NULL, IDC_ARROW);
wcex.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
wcex.lpfnWndProc = WndProc;
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcex.hInstance = hInstance;
RegisterClassEx(&wcex);
hWnd = CreateWindow(wcex.lpszClassName, wcex.lpszMenuName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, WINSIZE_WIDTH, WINSIZE_HEIGHT, NULL, NULL, hInstance, NULL);
if ( !hWnd ){
MessageBox(NULL, "CreateWindow failed!", "MSG", MB_OK);
return 0;
}
else
{
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
}
/*--- 메시지 처리 루프 ---*/
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while( msg.message != WM_QUIT )
{
if( GetMessage( &msg, NULL, 0, 0 ) ) // 메시지 큐에서 메시지를 읽고 삭제
{
// GetMessage 결과 메시지 큐에 메시지가 있으면 ..
TranslateMessage( &msg ); // 키보드 이벤트 처리
DispatchMessage( &msg ); // 메시지를 발송(WndProc 호출)
}
else
{
// GetMessage에서 메시지 큐에 메시지가 없을 경우 제어권을 OS에 반환하고 대기모드
// = 비선점형 멀티태스킹(Non-Preemptive Multitasking)
}
}
return (int)msg.wParam;
}
// CALLBACK : 어플리케이션이 직접 호출하는 함수가 아니라
운영체제로부터 호출되는 함수라는 의미
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int wmId, wmEvent;
switch(msg){
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
break;
// 윈도우 운영체제는 윈도우의 일부가 사라진 경우 윈도우의 그림을 저장하지 않고 대신 지워진 영역에 대해 '무효화 영역'을 설정하고 그 부분이 다시 나타날 경우 WM_PAINT 메시지를 발생시킨다.
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
// DC는 어플리케이션마다 독립적으로 생성되며 어플리케이션간에 공유되지 않는다.
// DC 생성 - 파괴
// BeginPaint - EndPaint : WM_PAINT 메시지에서 사용. 무효화 영역에 대한 DC 생성 및
// 무효화 영역을 유효화시키는 일도 한다.
// GetDC - ReleaseDC : WM_PAINT 이외의 메시지에서 사용.
// GetMessage는 메시지 큐에 메시지가 있으면 TRUE를 리턴. 단, WM_QUIT 메시지일 경우 FALSE 리턴(=종료)
// WM_DESTROY 처리 부분이 없으면 종료가 안된다.
case WM_DESTROY: // 메인 윈도우가 닫히는 시점
PostQuitMessage(0); // WM_QUIT 메시지를 발생시킨다.
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam); // 위에서 처리하지 않은 메시지에 대해서는 기본 처리
}[/CODE]
1-3 핸들
핸들이 뭐지?
: (개념적접근)윈도우가 관리중인 실제 객체의 포인터 테이블의 인덱스값
User 객체(=Window, Cursor, Caret) 핸들 : 시스템 전역적, 다른 어플리케이션에서 값을 얻어와 사용해도 무방.
GDI 객체 (=DC, Pen, Brush, Font, Bitmap, Palette, Region)핸들 : 프로세스 지역적
Kernel 객체 핸들(=Process, Thread, File, Sync)
1-4 유니코드
유니코드란?
그럼 어떻게 유니코드를 사용하지?
Win32 API의 유니코드 지원
1-5 함수 호출 규약
_ _cdecl
_ _stdcall
_ _fastcall