반응형
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- ControlGetText
- SetControlDelay
- if
- Menu
- EnvSet
- MouseClick
- EnvMult
- autohotkey
- Threads
- 식
- ControlSend
- IfInString
- EnvDiv
- IfWinExist
- API
- SetKeyDelay
- Var:=식
- IF (식)
- Blocks
- 배열
- if(식)
- SetMouseDelay
- 함수
- DetectHiddenWindows
- SetTitleMatchMode
- EnvAdd
- SetEnv
- 식의 설명
- EnvSub
- StringGetPos
Archives
- Today
- Total
ㄴrㅎnㅂrㄹrㄱi
[강좌 3] 윈도우의 생성과 다루기 본문
반응형
[API]강좌(3)<--계속 |
먼저 저번시간에 코딩한 소스를 컴파일 해보도록 하죠. 먼저 비주얼C 4.1을 구동하세요.
비주얼C 4.1의 통합환경은 Microsoft Developer Studio라고 써있는 아이콘을 더블클릭하면 됩니다.
자 구동이 됐습니까? 그러면 먼저 File 메뉴의 New를 선택하시기 바랍니다.
그러면 어떤것을 작성할것인지 물어오는데 이때 두번째의 Project Workspace를 선택하면 또 다른 대화상자가 생성될것입니다.
우리는 API함수를 이용해서 프로그램을 만들기 때문에 왼쪽의 타입을 Application 에 맞추어 놓고 실행 파일 생성 디렉토리를 Brower버튼을 눌러 지정하면 됩니다.
지정이 됐으면 Name부분에 생성될 실행 파일이름을 지정하면 됩니다. 이때 물론 확장자는 생략하구요.
자 여기까지 됐으면 다 된거나 다름없습니다. 여기까지 작업이 프로젝트 파일 구성 준비 단계입니다. 이번에는 어떤 작업이 필요할까요?
당연히 컴파일할 파일을 이 프로젝트에 포함시켜 주어야 겠죠. 우리가 만든 프로그램 소스는 하나만 있으면 되니 위에서 코딩한 파일을 Insert메뉴의 Files into Project를 선텍해서 포함시켜 주면 됩니다. 그렇게 어렵지 않죠?
다 됐으면 이제 Build메뉴의 Build를 선택해서 컴파일하면 됩니다. 만약에 에러가 발생되면 F4키를 눌러 어디서 에러가 발생됐는지 알아낼수도 있습니다.
에러가 없으면 Build 메뉴의 Excute를 선택하면 그 프로그램이 실행됩니다.
여기까지 잘 됩니까? 그러면 생성된 윈도우를 조작해 보세요. 아주 간단한 프로그램이지만 기본적인 것은 다 되죠. 그러면 구체적으로 그 소스에 대해 알아 보겠습니다. 아차~~ 알아보기 전에 나중에 이 프로젝트 파일을 다시 불러와서 사용하고
싶으면 File 메뉴의 Open Workspace를 선택해서 열면 됩니다.
자 그러면 구체적으로 그 소스를 분석해 볼까요?
#include <windows.h>
먼저 항상 windows.h라는 헤더파일을 포함시켜 주어야 한다고 위에서 언급했을겁니다. 이것이 없으면 윈도우즈 프로그램을 만들지 못하죠.
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
윈도우 함수가 메인 함수의 뒤에 위치하기 때문에 함수원형을 선언 해준겁니다.
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
윈도우의 핸들 자료형이 HWND입니다. 이것은 CreateWindow() 함수를 사용할때 리턴되는 자료형이 HWND 이기 때문에 이 자료형이 필요하죠.
MSG msg;
MSG는 메시지 자료형입니다.
WNDCLASS WndClass;
윈도우 클래스 자료형입니다.
char szAppName[] = "This program is to create window";
생성할 윈도우의 타이틀바 제목과 클래스 이름을 이 변수로 할겁니다. 위에서 직접 컴파일 해봤다면 생성된 윈도우의 타이틀바에 위문자열이 제목으로 들어가 있음을 확인했을 겁니다.
윈도우 속성을 지정하는 과정이군요. 위에서 제가 말씀드린것을 이해한 분이라면 그렇게 어려운 부분은 없을 겁니다.
WndClass.style = NULL;
스타일은 기본값으로 합니다.
WndClass.lpfnWndProc = WndProc;
윈도우 함수를 지정하는 부분이죠.
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
잘 쓰이지 않는다고 했죠.
WndClass.hInstance = hInstance;
프로그램 인스턴스 핸들을 지정하는 부분인데이 부분은 파라미터로 넘겨온 값을 지정 하면 된다고 했을 겁니다.
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
아이콘은 기본적으로 시스템에서 제공하는 것을 사용하겠다는 뜻입니다. 생소한 함수가 하나 있죠? LoadIcon()이라는 함수인데 보통 기본적으로 첫번째 파라미터를 NULL로 지정하고 두번째 파라미터는 지정된 예약어를 가지고 윈도우에서 제공하는 아이콘을 사용할수 있습니다. 다음은 이 함수 원형과 두번째 파라미터에 들어갈수 있는 예약어에 대한 설명입니다.
HICON LoadIcon(
HINSTANCE hinst,
LPCTSTR lpszIcon
);
IDI_APPLICATION 기본적인 프로그램 아이콘
IDI_ASTERISK 아스테리크 아이콘
IDI_EXCLAMATION 느낌표 모양의 아키콘
IDI_HAND 손 모양의 아이콘
IDI_QUESTION 물름표 아이콘
만약에 유저가 그린 그림을 가지고 아이콘으로 사용하려면 첫번째 파라미터에는 프로그램의 인스턴스 핸들을 그리고 두번째 파라미터에는 그 그림의 핸들을 지정해주어서 사용하면 됩니다. 실제적으로 유저가 그린 그림을 가지고 사용하는
방법은 뒤에 가서 다시 설명드리겠습니다.
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
역시 커서 모양을 정의하는 부분인데 윈도우즈에 말하는 커서는 도스에서 말하는 커서와는 의미가 다릅니다. 도스에서 커서의 의미는 유저로 부터 입력을 받기 위해서 깜빡거리는것을 의미하지만 윈도우즈에서의 커서는 마우스 포인트를 의
미하는 것입니다. 그러면 윈도우즈에서 유저로 부터 입력을 받기 위해서 깜빡 거리는 것을 뭐라고 할까요? 좀 생소할지는 몰라도 이것을 캐럿이라고 합니다.
이 부분은 나중에 다시 설명 드리겠습니다. 하여간 마우스 포인트를 의미하는 커서의 모양을 위 LoadCursor()이라는 함수를 가지고 할수 있습니다. 역시 첫번째 파라미터를 NULL로 하고 두번째 파라미터에 예약어를 지정하여 기본
적으로 제공하는 커서를 사용할수 있습니다. 아래는 함수 원형과 예약어에 대한 설명입니다.
HCURSOR LoadCursor(
HINSTANCE hinst,
LPCTSTR lpszCursor
);
IDC_ARROW 화살표 모양의 커서
IDC_CROSS 십자가 모양의 커서
IDC_IBEAM I자 모양의 커서
IDC_WAIT 모래 시계 모양의 커서
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
윈도우의 백경색을 흰색으로 한다는 의미입니다.
HGDIOBJ GetStockObject(
int fnObject
);
위에 GetStockObject()함수의 원형이 나와 있는데 이 함수는 앞으로도 많이 나올겁니다. 이 함수가 하는 역활은 펜, 브러쉬 또는 폰트등의 핸들을 넘기는 것인데 구체적으로는 파라미터에 따라 그 내용이 달라집니다. 들어갈 파라미터와
의미는 다음과 같습니다.
BLACK_BRUSH 검정색 브러쉬
DKGRAY_BRUSH 진한 회색 브러쉬
GRAY_BRUSH 회색 브러쉬
HOLLOW_BRUSH 빈 브러쉬
LTGRAY_BRUSH 여린 회색 브러쉬
NULL_BRUSH 빈 브러쉬
WHITE_BRUSH 흰색 브러쉬
BLACK_PEN 검정색 펜
NULL_PEN 빈 펜
WHITE_PEN 흰색 펜
ANSI_FIXED_FONT 안시 고정 폰트
ANSI_VAR_FONT 안시 가변 폰트
DEVICE_DEFAULT_FONT 장치 기본 폰트
OEM_FIXED_FONT 장치 지원 폰트
SYSTEM_FONT 시스템 폰트
SYSTEM_FIXED_FONT 시스템 고정 폰트
DEFAULT_PALETTE 기본 팔레트
WndClass.lpszMenuName = NULL;
생성될 윈도우에 메뉴가 없기때문에 NULL로 지정하였습니다.
WndClass.lpszClassName = szAppName;
클래스 이름은 타이틀바 제목과 같이 했죠. 다르게 하기 귀찮아서요.
if(!RegisterClass(&WndClass)) return NULL;
이렇게 등록한 WNDCLASS구조체를 실제로 등록하는 과정입니다. 위에서 이미 다 설명 드렸을 겁니다.
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
각 파라미터의 의미는 이미 알고 있을 겁니다. 여기서 세번째 파라미터에 보면 윈도우 생성 모양을 지정해 주게 되어 있는데 잘 모르는 게 들어있군요. 여기에 들어갈수 있는 예약어와 의미는 다음과 같습니다.
WS_BORDER 윈도우의 테두리를 그려 줍니다.
WS_CAPTION 타이틀바를 가진 윈도우를 생성합니다.
WS_HSCROLL 윈도우에 수평 스크롤바를 만들어 줍니다.
WS_ICONIC 윈도우를 아이콘화합니다.
WS_MAXMIZE 윈도우를 최대화합니다.
WS_MINIMIZE 윈도우를 아이콘화합니다.
WS_OVERLAPPED 윈도우에 최대, 최소, 종료 버튼을 생성하고 WS_CAPTION|
WS_BORDER를 한것과 같은 효과를 봅니다.
WS_OVERLAPPEDWINDOW WS_OVERLAPPED|WS_SYSMENU|WS_THICKFRAME과 같은 효과를
봅니다.
WS_SYSMENU 시스템 메뉴를 갖는 윈도우를 생성합니다.
WS_THICKFRAME 굵은 경계선을 가진 윈도우를 생성합니다.
WS_VSCROLL 윈도우에 수직 스크롤바를 만들어 줍니다.
네번째에서 일곱번째 파라미터를 보면 CW_USEDEFAULT라고 되어 있는데 이것은 그냥 기본적으로 윈도우즈가 정해준 값으로 하겠다는 의미입니다.
실제로 이 부분에 유저가 숫자를 지정해주면 그 위치, 그 크기대로 윈도우가 생성됩니다.
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
실제로 윈도우를 보여주는 과정이죠. 보여지는 형식은 기본적으로 윈도우즈에서 제공하는 형태를 띕니다. nCmdShow는 윈 메인 함수의 파라미터 값중 하나라는 것을 알고 있겠죠?
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
메시지 처리하는 부분이군요. 뭐 특별히 설명드릴 필요는 없는것 같군요.
return msg.wParam;
}
자 이번에는 실제적으로 메시지를 처리하기 위한 윈도우 함수부분입니다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
윈도우즈 프로그램은 메시지 프로그램이라고 해도 과언이 아닙니다. 윈도우 함수 코딩한것을 보면 거의 switch case문이 맣죠. 메시지를 구분하여 처리하기 때문에 이 방식을 많이 취하는 것입니다.
switch(mesg)
{
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
유저가 프로그램을 종료하려고 하면 WM_DESTROY 메시지가 발생되므로 이때 종료시켜야 프로그램이 종료됩니다.
VOID PostQuitMessage(
int nExitCode
);
파라미터로 0을 지정하면 프로그램이 종료됩니다.
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
그 외의 메시지는 디폴트로 처리하기 때문에 위 DefWindowProc() 함수를 사용합니다.
LRESULT DefWindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
이번 예제도 저번 예제와 크게 다른점은 없습니다. 단지 윈오우를 생성할때 모양을 다르게 생성하는 것인데 저번 시간에 잘 이해했다면 굳이 이번 예제를 따로 이해할 필요는 없습니다.
이번 예제는 생성되는 윈도우의 모양이 타이틀바만 가지고 있는 예제입니다.
hWnd = CreateWindow(
szAppName,
szAppName,
WS_VISIBLE|WS_BORDER,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
생성되는 윈도우가 타이틀바만 가지려면 우리가 처음에 알아본 WS_OVERLAPPEDWINDOW 대신에 위와 같은 속성을 주면 됩니다.
간단하네요. 아래는 전체 소스입니다. 한번 컴파일해서 실행시켜 보십시요.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_VISIBLE|WS_BORDER,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_CHAR :
case WM_KEYDOWN :
SendMessage(hWnd, WM_DESTROY, (WPARAM)0, (LPARAM)0);
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
자 이번에는 타이틀바를 다뤄보도록 하겠습니다. 타이틀바가 뭔지는 알죠?
CreateWindow()라는 함수를 이용해서 윈도우를 생성할때 파라미터중 타이틀바 제목을 지정하게 되어 있는데 현재 생성된 윈도우의 타이틀바가 무엇인지 알수 있게 해주는 함수가 있습니다.
int GetWindowText(
HWND hwnd,
LPTSTR lpsz,
int cch
);
위 함수를 이용해서 현재 타이틀바의 제목을 알아낼수 있습니다. 첫번째 파라미터는 타이틀바를 알아낼 윈도우의 핸들을 의미하고 두번째 파라미터는 알아낸 타이틀바의 제목을 저장할 버퍼를 의미합니다. 마지막 세번째 파라미터는 버퍼의
최대 크기를 의미하죠.
타이틀바의 제목을 알아내는 함수가 있으니 지정하는 함수도 당연히 있겠죠?
BOOL SetWindowText(
HWND hwnd,
LPCTSTR lpsz
);
위 함수를 이용해서 타이틀바의 제목을 새로 지정할수 있습니다. 두번째 파라미터에 새로 지정할 윈도우 타이틀바 제목을 써주면 됩니다.
자 그러면 이 두함수를 이용한 간단한 예제를 보도록 하겠습니다. 이번 예제는 윈도우가 생성될때 타이틀바의 제목을 바꿔주고 유저가 Enter키를 치면 현재 타이틀바를 출력해주는 예제입니다. 그럼 예제를 볼까요?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
char szTitle[] = "Title is changed !!!";
char szGetTitle[80];
switch(mesg)
{
case WM_CREATE :
SetWindowText(hWnd, szTitle);
return FALSE;
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
GetWindowText(hWnd, szGetTitle, 80);
MessageBox(hWnd, szGetTitle, "", MB_OK);
}
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
자 그러면 구체적으로 알아볼까요? 못보던 것들도 보이는군요. 그런데 잘 보면 알겠지만윈 메인 함수부분은 예전 예제랑 다른점이 하나도 없습니다.
그렇죠? 그러면 윈도우 함수 부분만 봅시다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
char szTitle[] = "Title is changed !!!";
새 타이틀바 제목을 위 문자열로하기 위해서 정의해 준겁니다.
char szGetTitle[80];
현재 타이틀바 제목을 읽어와서 저장하기 위해서 위 변수를 선언했습니다.
switch(mesg)
{
case WM_CREATE :
SetWindowText(hWnd, szTitle);
return FALSE;
못보던 메시지가 있네요. WM_CREATE라는 메시지는 윈도우가 처음 생성될 때 발생하는 메시지입니다. 대부분 변수를 초기화 하는 작업은 이 부분에서 해주죠. 위 구문을 해석하자면 윈도우가 생성될때 바로 윈도우의 제목을 바꾼다는 의미가 되겠습니다. 별로 어렵지 않죠?
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
GetWindowText(hWnd, szGetTitle, 80);
MessageBox(hWnd, szGetTitle, "", MB_OK);
}
return FALSE;
역시 못보던 메시지로 WM_KEYDOWN 이라는 메시지가 나왔습니다. 이 메시지는 특수키가 입력되었을때 발생하는 메시지입니다. 특수키는 어떤 키를 의미할까요?
F1-F12, Shift, Ctrl, Alt, Delete키등과 같은 키를 의미합니다. 어떤것인지 알겠죠? 이러한 특수키가 눌리면 WM_KEYDOWN이라는 메시지가 발생됩니다. 그러면 구체적으로 어떤키인지 어떻게 알수 있을까요? 물론 아는 방법이 있죠.
바로 부수적인 메시지가 들어간다는 wParam에 그 구체적인 값이 들어가는 것입니다. wParam의 하위워드에 그 구체적인 값이 들어가기 때문에 위 구문과 같이 사용합니다. 하여간 이부분은 입력부분에서 다시 자세히 설명 드리겠고 단지 Enter키가 눌리면 위 조건문이 참이 된다는 사실만 알고 있으면 됩니다. 조건문을 만족하면 현재 타이틀바 제목을 읽어올테고 그 다음은 또 모르는 함수네요.
int MessageBox(
HWND hwndOwner,
LPCTSTR lpszText,
LPCTSTR lpszTitle,
UINT fuStyle
);
MessageBox() 함수는 유저에게 어떤 정보를 보여주기 위한 간단한 대화상자입니다.
구체적인 사용방법은 대화상자 부분에서 다시 설명드리겠습니다. 단지 두번째 파라미터에 써준 문자열을 주제로 대화상자를 출력한다는 것입니다. 세번째 파라미터에 들어가는 문자열은 대화상자의 타이틀바 제목이 됩니다. 네번째는 버튼의 형식을 지정할수 있는데 MB_OK이라는 것은 무조건 OK버튼 하나만 생성한다는 뜻입니다. 이번 예제에서 배우려고 하는 것이 MessageBox() 함수가 아니니 이정도로만 설명을 드리죠. 하여간 현재 윈도우의 타이틀바 제목을 가지고 와서 유저에게 그 제목을 보여주는 것이죠. 직접 컴파일해서 확인해 보기 바랍니다. 그러면 MessageBox() 함수가 구체적으로 어떤것인지 알수 있을 겁니다.
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
윈도우를 종료하는 메시지가 오면 종료되겠죠.
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
이번에도 역시 윈도우를 다루는 예제인데 예제는 두개입니다.
그럼 시작해 보죠.
우리는 윈 메인 함수의 제일 앞 부분에서 어떤 작업을 하는지에 대해 이미 알고 있습니다. 어떤 작업을 합니까? 클래스 등록을 하였죠? 이중에 아마 배경색을 지정해준 부분이 있을 겁니다. 이 배경색을 프로그램상에서 바꿀수 있는 방법이 있습니다.
DWORD SetClassLong(
HWND hwnd,
int nIndex,
LONG lNewVal
);
위 함수를 이용해서 윈도우의 배경색을 바꿀수 있는데 사실 위 함수로 배경색 뿐만 아니라 커서, 아이콘, 윈도우 함수, 스타일등 윈도우 클래스에 등록한것을 전부 바꿀 수 있습니다.
첫번째 파라미터는 바꿀 윈도우의 핸들을 의미하고 두번째 파라미터는 예약어로서 이 예약어로 어떤것을 지정하느냐에 따라 해당 윈도우의 속성을 바꿀수 있습니다.
세번째 파라미터는 바꿀 새로운 값을 의미합니다. 다음은 두번째 파라미터에 들어갈 예약어와 그 의미입니다.
GCL_HBRBACKGROUND 배경생을 바꿀때 사용합니다.
GCL_HCURSOR 커서를 바꿀때 사용합니다.
GCL_HICON 아이콘을 바꿀때 사용합니다.
GCL_MENUNAME 메뉴를 바꿀때 사용합니다.
GCL_STYLE 스타일을 바꿀때 사용합니다.
GCL_WNDPROC 윈도우 함수를 바꿀때 사용합니다.
자 그러면 실제 예제를 보도록 합시다. 아래 예제는 유저가 Enter키를 쳤을때 배경색을 검정색으로 바꾸는 예제입니다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
SetClassLong(hWnd, GCL_HBRBACKGROUND,
(LONG)GetStockObject(BLACK_BRUSH));
InvalidateRect(hWnd, NULL, TRUE);
}
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
Enter키를 치면 하얀색이던 배경색이 검정색으로 바뀜을 확인할수 있을 겁니다.
한번 직접 컴파일해서 실행 시켜 보십시요. 그럼 분석을 해봅시다. 역시 윈 메인 함수는 볼 필요가 없군요. 윈도우 함수 부분만 봅시다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
Enter키가 눌리면 수행이 되도록 위 구문을 사용한 것입니다. 앞 예제와 다른점이 없죠?
SetClassLong(hWnd, GCL_HBRBACKGROUND,
(LONG)GetStockObject(BLACK_BRUSH));
배경색을 바꾸기 때문에 두번째 파라미터에 GCL_HBRBACKGROUND를 사용하였고 세번째 파라미터는 검정색을 의미하는 것입니다. 이미 다 알고 있을 겁니다.
InvalidateRect(hWnd, NULL, TRUE);
흠 .. 못보던 함수가 하나 있네요. 이 함수는 어떤 역할을 할까요? 이 함수는 윈도우를 다시 그리게 하는 역할을 합니다. 두번째 파라미터에 NULL을 지정했기 때문에 전체 윈도우를 다시 그립니다.
전체적으로 해석해 볼까요? 배경색을 바꾸고 다시 그린다. 뭐 그런 의미가 되겠네요. InvalidateRect()함수 구문을 빼고 다시 컴파일 해보시기 바랍니다. 될까?
안될까?
BOOL InvalidateRect(
HWND hwnd,
CONST RECT *lprc,
BOOL fErase
);
첫번째 파라미터는 이미 다 아실테고 두번째 파라미터는 다시 그릴 윈도우의 사각 영역의 좌표를 의미합니다.
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
RECT 구조체의 구성이 위에 잘 나와있네요. 각 사각 좌표를 의미하는 것입니다.
특별한 것은 없죠. 만약에 유저가 지정한 사각 부분만 복구하고 싶으면 직접 위 구조체 변수를 선언하여 값을 채워서 지정해 주면됩니다.
함수의 마지막 파라미터는 지정된 부분을 복구할때 배경을 지워진 상태로 하겠느냐 아니면 그렇지 않겠느냐하는 의미입니다. 말이 좀 어렵죠. 나중에 가면 다 이해 할겁니다.
}
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
이상으로 첫번째 예제 설명 끝~~~~~~~~
그러면 두번째 예제를 보도록 합시다. 두번째 예제는 전체 윈도우의 크기와 작업영역(클라이언트 영역)의 크기를 알아내는 예제입니다. 함수 두개의 사용방법만 알면 뭐 간단하죠.
BOOL GetClientRect(
HWND hwnd,
LPRECT lprc
);
위 함수로 윈도우의 작업영역의 크기를 알수 있습니다. 두번째 파라미터는 바로 위에서 알아 보았죠? 현재 윈도우의 작업영역 좌표가 두번째 파라미터에 들어가는 것 입니다.
int GetSystemMetrics(
int nIndex
);
현재 화면의 크기를 알려면 위 함수를 이용해서 할수 있는데 위 함수로 꼭 현재 화면의 해상도만을 알수 있는것은 아닙니다. 파라미터에 어떤 값이 들어가야 하는지에 따라 여러가지 크기를 얻어낼수 있습니다. 여기서 현재 화면의 크기라는 것은 유저의 윈도우즈 해상도를 의미하는 것입니다. 물론 컬러수는 빼구요.
SM_CXCURSOR 커서의 넓이를 알수 있게 해줍니다.
SM_CYCURSOR 커서의 높이를 알수 있게 해줍니다.
SM_CXFULLSCREEN 윈도우가 최대 크개일때 작업영역의 넓이를 알수 있게 해줍니다.
SM_CYFULLSCREEN 윈도우가 최대 크기일때 작업영역의 높이를 알수 있게 해줍니다.
SM_CXICON, 아이콘의 넓이를 알수 있게 해줍니다.
SM_CYICON 아이콘의 높이를 알수 있게 해줍니다.
SM_CXMIN, 윈도우의 최소 넓이를 알수 있게 해줍니다.
SM_CYMIN 윈도우의 최소 높이를 알수 있게 해줍니다.
SM_CXSCREEN, 현재 화면의 넓이를 알수 있게 해줍니다.
SM_CYSCREEN 현재 화면의 높이를 알수 있게 해줍니다.
자 그러면 실제적인 전체 소스를 보도록 합시다. 아래 예제는 윈도우가 생성될때 작업영역과 화면의 크기를 구한뒤 Enter키가 눌렸을때 그 값을 출력하는 예제입니다.
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
RECT rect;
static char szFullWindowSize[80];
static char szWindowSize[80];
switch(mesg)
{
case WM_CREATE :
GetClientRect(hWnd, &rect);
sprintf(szWindowSize, "X : %d, Y : %d", rect.right, rect.bottom);
sprintf(szFullWindowSize, "X : %d, Y : %d",
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
return FALSE;
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
MessageBox(hWnd, szWindowSize, "Window Size", MB_OK);
MessageBox(hWnd, szFullWindowSize, "Window Full Size", MB_OK);
}
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
별로 이해하기 어려운 부분은 없는것 같네요. 그렇죠?
case WM_CREATE :
GetClientRect(hWnd, &rect);
sprintf(szWindowSize, "X : %d, Y : %d", rect.right, rect.bottom);
sprintf(szFullWindowSize, "X : %d, Y : %d",
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
return FALSE;
이미 함수는 다 설명 드렸고 혹시 sprintf()라는 함수를 사용해 본적이 있습니까?
아마 printf()함수를 사용해 본 유저라면 위 함수를 잘 보면 어떤 역할을 하는지 쉽게 짐작할수 있을 겁니다. sprintf()함수의 리턴값은 첫번째 파라미터에 저장된 문자열의 길이입니다. 상당이 많이 활용하니 이 리턴값을 잘 기억하시기 바랍
니다.
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
MessageBox(hWnd, szWindowSize, "Window Size", MB_OK);
MessageBox(hWnd, szFullWindowSize, "Window Full Size", MB_OK);
}
return FALSE;
Enter키가 눌리면 그 값을 출력해 주는 것입니다.
윈도우를 제어하는 예제에 대해 알아 보겠습니다. 먼저 윈도우를 다른 크기로 원하는 곳에 위치해 놓는 예제부터 알아봅시다.
윈도우를 생성할때 CreateWindow() 함수를 사용했죠? 그 함수의 파라미터를 보면 윈도우의 생성좌표와 크기를 CW_USEDEFAULT라고 지정했을 겁니다. 이 위치와 크기를 유저가 임의로 바꿀수 있는데 이때 MoveWindow()라는 함수를 사용하면 됩니다.
BOOL MoveWindow(
HWND hwnd,
int x,
int y,
int cx,
int cy,
BOOL fRepaint
);
두번째와 세번째 파라미터가 옮길 좌표를 의미하고 네번째와 다섯번째 파라미터가 윈도우의 크기를 의미하는 것입니다. 여섯번째 파라미터는 배경을 지울것인지 판단하는 역할을 합니다. InvalidateRect()함수에서도 사용됐죠?
그럼 이 함수를 이용한 예제를 보도록 합시다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_CREATE :
MoveWindow(hWnd, 0, 0, 300, 150, TRUE);
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
위 예제는 윈도우가 생성될때 그 위치를 (0, 0)으로 크기를 300, 150으로 바꾸는 예제입니다. 뭐 그렇게 다시 설명할 부분은 없는것 같군요. 그렇죠? 너무 쉽네요.
자 이번에는 윈도우의 크기를 고정하는 예제를 보도록 합시다. 일반적으로 윈도우를 생성하면 유저가 그 크기를 임의로 마우스로 조정할수 있는데 이것을 못하게 할수 있습니다.
어떻게 못하게 하는지 알려면 우선 메시지 하나를 알아야 합니다. 유저가 윈도우의 크기나 위치를 바꾸려면 그 때에 WM_GETMINMAXINFO라는 메시지가 발생되는데 이 메시지를 처리하는 부분에 그 윈도우의 크기를 제한하는 루틴을 넣어주면 윈도우의 크기를 고정시킬수 있습니다.
그럼 먼저 소스를 보도록 합시다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_CREATE :
MoveWindow(hWnd, 100, 100, 300, 150, TRUE);
return FALSE;
case WM_GETMINMAXINFO :
((MINMAXINFO *)lParam)->ptMaxTrackSize.x = 300;
((MINMAXINFO *)lParam)->ptMaxTrackSize.y = 150;
((MINMAXINFO *)lParam)->ptMinTrackSize.x =300;
((MINMAXINFO *)lParam)->ptMinTrackSize.y = 150;
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
위 예제는 윈도우를 300, 150 크기로 생성하고 그 크기를 변경하지 못하게 하는 예제입니다. 자 그러면 실제적으로 WM_GETMINMAXINFO 메시지 처리 부분을 보도록 합시다.
case WM_GETMINMAXINFO :
((MINMAXINFO *)lParam)->ptMaxTrackSize.x = 300;
((MINMAXINFO *)lParam)->ptMaxTrackSize.y = 150;
((MINMAXINFO *)lParam)->ptMinTrackSize.x = 300;
((MINMAXINFO *)lParam)->ptMinTrackSize.y = 150;
return FALSE;
UINT형인 mesg에 주 메시지가 들어가고 wParam이나 lParam에 부수적인 메시지가 들어간다고 제일 처음부분에서 설명 드렸을 겁니다. 이 메시지를 처리할때는 위에서 보듯이 lParam이라는 메시지를 사용하는 군요.
WM_GETMINMAXINFO 메시지가 발생됐을때 MINMAXINFO라는 구조체 형식으로 lParam에 값을 채워주면 그 값에 의해서 윈도우의 크기를 제한할수 있습니다. 아래는 이 구조체의 원형입니다.
typedef struct tagMINMAXINFO { // mmi
POINT ptReserved;
POINT ptMaxSize;
POINT ptMaxPosition;
POINT ptMinTrackSize;
POINT ptMaxTrackSize;
} MINMAXINFO;
POINT 자료형은 x, y를 맴버로 가지는 구조체입니다.
우리가 위 맴버중 사용할것은 네번째, 다섯번째 맴버인데 ptMinTrackSize의 x, y 에 값을 넣어주면 윈도우의 최소 크기를 지정하게 되는 것입니다. ptMaxTrackSize 의 x,y에 값을 넣어주면 윈도우의 최대 크기이고요. 윈도우의 최소 크기와 최대
크기를 같게 만들어 주었으니 윈도우의 크기가 변하지 않겠죠? 간단하네요.
자 이번에는 윈도우의 배경색을 바꾸는 예제를 알아 보도록 합시다. 어! 이거 앞 부분에 이미 했죠? 그런데 앞부분에 한 것은 아주 단순한 색으로 윈도우의 색을 바꾼것에 불가합니다. 실제로 유저가 임의로 RGB()값으로 배경색을 바꾸려면
앞에서 배운 방법으로 는 불가능하죠. 그렇다고 앞 부분에서 배운 SetClassLong() 이라는 함수를 사용하지 않고 바꾸는 것은 아닙니다. 앞 부분에서 어느정도 했기 때문에 그렇게 크게 어려운 부분은 없을 겁니다.
우선 원하는 색깔로 배경색을 바꾸려면 SetClassLong()함수의 파라미터로 블어가는 새로운 색깔 지정부분에 맞는 형식으로 색을 만들어야 하는데 이때 CreateSolidBrush()함수를 사용합니다.
HBRUSH CreateSolidBrush(
COLORREF crColor
);
파라미터로 들어가는 색의 형식으로 브러쉬 핸들을 리턴하는 함수입니다. 자세한 것은 그래픽 부분에서 다시 언급하겠습니다. 이 함수를 이용해서 생성한 브러쉬 핸들을 사용하고 난후에는 반드시 그 핸들을 없애 주어야 합니다. 이때
DeleteObject라는 함수를 사용합니다.
BOOL DeleteObject(
HGDIOBJ hObject
);
자세한 것은 그래픽 부분에서 다룰테니 일단은 어떻게 구현했는지 봅시다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
HBRUSH hBrush;
switch(mesg)
{
case WM_CREATE :
hBrush = CreateSolidBrush(RGB(0, 0, 125));
SetClassLong(hWnd, GCL_HBRBACKGROUND, (long)hBrush);
DeleteObject(hBrush);
InvalidateRect(hWnd, NULL, FALSE);
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
위 예제는 파란색 계통의 배경색을 가진 윈도우를 생성하는 예제입니다. RGB를 어떻게 조합하는지는 다 알고 있겠죠?
RGB(0, 0, 0)은 검정색이고 RGB(255, 255, 255)은 흰색이구요. RGB(255, 0, 0)은 빨간색이 되겠고, RGB(0, 255, 0)은 녹색, RGB(0, 0, 255)는 파란색입니다.
R은 빨간색을 의미하고 G는 녹색을 B는 파란색을 의미합니다. 세 색깔을 조합해서 색을 만들면 됩니다.
case WM_CREATE :
hBrush = CreateSolidBrush(RGB(0, 0, 125));
SetClassLong(hWnd, GCL_HBRBACKGROUND, (long)hBrush);
DeleteObject(hBrush);
InvalidateRect(hWnd, NULL, FALSE);
return FALSE;
위 부분이 실제적으로 배경색을 파란색 계통으로 바꾸는 부분인데 함수 두개 추가 된것 이외는 그렇게 크게 달라진 부분은 없죠?
유저가 그린 그림을 아이콘과 커서로 사용하는 방법에 대해 알아 보겠습니다. 그림 그리는게 어렵지 구현하는것은 어렵지
않습니다.
우선 리소스 파일에 대해 알아야 합니다.
리소스 파일은 윈도우즈에서 사용하는 여러가지 자료들을 모아서 정의 해 놓은 것을 의미합니다. 메뉴나 대화상자, 또 비트맵, 아이콘등을 이곳에 정의해 놓죠. 우리가 그린 그림을 아이콘과 커서로 사용하려면 그 그림에 대한 정의를
이 곳에서 해주어야 합니다.자 그러면 먼저 우리가사용할 아이콘과 커서를 그려 봅시다.
통합 환경에서 File메뉴의 New를 선택하시기 바랍니다. 그러면 대화상자가 생성 되죠? 아래부분을 보세요. Icon File과 Cursor File이 있을 겁니다. 그것을 선택하면 그림을 그릴수 있는 상태로 환경이 바뀌는데 그곳에서 그림을 그리면 됩니
다. 다 그렸으면 원하는 파일이름으로 저장하시기 바랍니다. 저장할곳은 프로그램 파일이 있는 곳이여야 겠죠? 여기서 주의할 점이 있습니다.
컴파일을 할때 꼭 이 리소스 파일을 프로젝트 파일에 포함시켜 주어야 한다는 거죠. 추가시키는 방법은 Insert 메뉴의 Files into Project를 선택해서 하면 됩니다. 아! 한가지 또 빼먹었군요. 리소스 파일의 확장자는 rc이어야 한다는 것
입니다.
자 그럼 실제적으로 소스를 보도록 합시다.
아래는 리소스 파일의 소스(test.rc)입니다.
#include <windows.h>
MyIcon ICON "my.ico"
MyCursor CURSOR "my.cur"
아래는 프로그램 소스(test.c)입니다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to create window";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(hInstance, "MyIcon");
WndClass.hCursor = LoadCursor(hInstance, "MyCursor");
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
어때요? 정말로 아이콘과 커서가 그린 그림으로 바뀌었죠? 자 그러면 리소스 파일을 보도록 합시다.
MyIcon ICON "my.ico"
MyCursor CURSOR "my.cur"
뒤에 따옴표로 묶인것이 실제 그림 파일의 이름이 되는 것입니다.
WndClass.hIcon = LoadIcon(hInstance, "MyIcon");
WndClass.hCursor = LoadCursor(hInstance, "MyCursor");
클래스 등록부분에 위와 같은 형식으로 기입하면 됩니다. 간단하죠.
자 여기까지 해서 윈도우에 관련된 부분은 끝난것 같군요.. 다음 시간에는 입출력에 대해 알아 보겠습니다.
반응형
'API 관련 > API 강좌모음' 카테고리의 다른 글
[강좌 6] 출력부분 (0) | 2007.10.26 |
---|---|
[강좌 5] 입력부분 (0) | 2007.10.26 |
[강좌 4] 문자열 출력 (0) | 2007.10.26 |
[강좌 2] 윈도우의 생성과 다루기 (0) | 2007.10.26 |
[강좌 1] 윈도우즈 프로그램의 개요 (0) | 2007.10.26 |
Comments