본문 바로가기

TIPS/API(Win32)

[TIPS] 9th 20160801

9번째 강좌정리입니다.



API 실습(2)


윈도우는 옛날에 양보에 의한 멀티태스킹을 했다. 이게 메세지 방식인데, 호환성 때문에 지금도 메세지 방식을 사용하는 것이다.


메세지에 대해 더 얘기하자면


GetMessage는 반환값이 0이여야 while문이 종료된다. WM_QUIT 메세지가 들어와야 GetMessage함수가 0을 반환한다. 

WM_QUIT은 시스템이 넣어주는 경우도 있고, 다른 어플리케이션이 넣는 경우도 있고, 내가직접 넣는 경우도 있다.


지난번 실습까지가 기본 골격이였다. 기본 골격에서 배경색, 화살표, 아이콘, 좌표, 캡션명 등을 바꿀 수 있었다.


윈도우 자체에서 해주는 것이 많다. 클라이언트 부분만은 사용자가 정하는데 그때 사용하는 것이 lpfnWndPro 함수포인터이다.


지난 첫번째 API실습 때 


wc.lpfnWndProc = WndProc;


WndProc라고 등록만 하고 아직 만들지 않았다. 이제 WndProc을 만들어보자.



LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)




WM_LBUTTONDWON에서 F1 누르면  wParam에 들어가는 걸 볼 수 있다. 비트단위로 표시됨. lParam에는 상위 16비트에 x, 하위 16비트에는 y. (좌표는 우리가 아는 y와는 반대이다.)


h_dc에서 펜을 빨간색으로 바꿀 때 주의해야한다.

지역변수로 펜과 브러시를 만들어 사용 후 원래대로 바꾸지 않고 종료해버리면 펜과 브러시가 사라져서 문제가 생긴다. 

(기본적으로 검정펜과 흰색 브러쉬임.)



<DC> (운영체제 입장에서는 구조체..)


|HEPN |------>PEN<-------------HPEN or HGDIOBJ 기존에 쓰던 펜을 다른 변수가 가리키고 있도록 함.(백업)

|HBRUSH |------>BRUSH

|HFONT |

PEN"Red"바꾸면 이걸 가리킴.


이렇게 DC라는 개념은 그리기에 사용하는 모든 인자를 다 가지고 있어서 다 따로 놀지 않고 하나로 줄일 수 있다는 장점이 있다.

(실제로는 나중에 더 좋은 그래픽함수는 개별적으로 암시하도록 함. 요즘 기계는 그게 더 효과적이라서...)





LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 


변수명 함수명은 바꿔도 됨. 

CALLBACK: 스택프레임

첫번째 인자 : 어떤 메세지가 발생했는지 알려주기 위해 윈도우 핸들이 넘어감.

두번째 인자 : u:unsigned 왼쪽마우스, 오른쪽 마우스, 등등

세번재 네번째 : 윈도우 메세지 타입(어떤 종류의 메세지인지)이외 32비트의 추가 정보가 두개 더 붙는데 하나는 wparameter, long parameter

WM_Lbouttendown : 왼쪽마우스클릭. 이러한 입력과 함께 키보드 알트키 등을 눌렀을 때 그 키보드값이 들어가있다. 외울 필요는 없음. 도움말에서 제공. MFC경우에는 전혀 필요없음.


if (uMsg == WM_DESTROY) {


창의 x버튼을 누르면 실행되는 것. 즉, "이제 윈도우가 파괴될 것이다. 파괴 전 무엇을 할 것인가 적어라. " 거부 불가능!!


PostQuitMessage(0);}


비동기방식. post하고 그냥 나옴. 메세지루프를 빠져나오면서 정상적인 윈도우 종료가 가능하다,

}

else if (uMsg == WM_LBUTTONDOWN) {

HDC h_dc = GetDC(hWnd);


handle dc : 현재 윈도우의 정보를 받아옴. 

DC : Device Context(휘발성데이터 현재 장치가 실행되는 동안만 유효.) Context는 지속성이 긴 데이터. (그림 그릴 때 많이 쓰다보니 사람들은 Display Context로 통용..) DC행위를 하면 윈도우즈는 '얘가 지금 그림그리려 하는구나' 라고 알게됨. 윈도우가 가지고 있는 DC를 받아오는 것이기 때문에 나 혼자 점유하면 안된다.

int x = GET_X_LPARAM(lParam);

int y = GET_Y_LPARAM(lParam);


lParam에 있는 X,Y값을 얻는다. (도움말에서 확인함) 


HBRUSH h_brush = CreateSolidBrush(RGB(0, 200, 255));


brush도 채울 때 다양하게 채울 수 있음. 그래서 createsolidbrush를 사용한 것이다.

HPEN h_pen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

두께, 색 (f12 누르면 뭘 쓸 수 있는지 나온다) 0을 적으면 1과 같음. 

굵기가 2가 되면 스타일이 실선으로 나와버림.

2이상 쓸 경우는 다른 함수를 사용해야한다.

RGB알파. 알파는 투명도. 알파는 8비트씩 쓰는데 8비트가 남아서 아까우니까 투명도를 넣은 것이다.

HGDIOBJ h_old_pen = SelectObject(h_dc, h_pen);

selectobject : 원래 가지고 있는 검은펜을 h_pen으로 새로 선택하겠다. 도움말 보면 반환값이 기존의 h_dc임을 확인할 수 있다.

이것을 저장해두어야 한다.


HGDIOBJ h_old_brush = SelectObject(h_dc, h_brush);


if (wParam & MK_CONTROL) {    //(control만 눌렀을 때 하고싶으면 ==으로 바꾸면 됨)

Ellipse(h_dc, x - 10, y - 10, x + 10, y + 10);     //사각형에 내접하는 원을 그림.

}

else {

Rectangle(h_dc, x - 10, y - 10, x + 10, y + 10);}


(h_dc, 10,10,100,100)은 10,10에서 100,100까지 그림을 그린다는 의미이다. 기본 테두리는 black, 기본 채우기는 white. 

즉, x,y를 넣어서 클릭한 곳에 네모를 그려 넣음.


SelectObject(h_dc, h_old_pen);


이렇게 사용 후 반환해주어야 문제가 없다.


DeleteObject(h_pen); 


펜 브러쉬 폰트 등은 GDI라고 부르는데 만들때는 구분해서 만들지만, 지울 때는 동일하게 이 명령어를 이용한다.


이것은 heap을 사용하기 때문에 문제가 생기면 내 프로그램만 문제가 생긴다.


시스템은 GDI에 할당할 수 있는 양이 정해져 있는데 특정 어플리케이션이 GDI를 너무 많이 써버리면(즉 지우지 않으면) 다른 어플리케이션이 그림을 그리다가 죽을 수 있다. 만약 deleteobject를 안하면 3~4시간 뒤에 핸들 쪽 오브젝트가 다 소모되서 '네트워크에 어쩌고'문제가 생길 수 있다.


SelectObject(h_dc, h_old_brush);

DeleteObject(h_brush);


ReleaseDC(hWnd, h_dc);    

}

받아온 DC값을 반환함. GetDC와 세트. 


return DefWindowProc(hWnd, uMsg, wParam, lParam);


처리할 필요 없는 메세지와 반드시 처리해야할 메세지가 있다. 사용자가 해야하는데 귀찮은 것들을 defult(기본)으로 처리해주는 명령이다. 이 함수는 반드시 써서 만일의 상황에 대비해야한다.



여기까지 하면 클릭시 그려진 그림이 윈도우 밖으로 나갔다 오면 사라지게 된다!


(A윈도우가 B윈도우에 가려있다가 다시 보이게 된것은 운영체제만 알 수 있음. 그래서 운영체제가 A에게 WM_PAINT 라는 정보를 줌.안하면 그냥 밖에 나갔다 들어온 것처럼 없어진 채로 있음.)



WM_PAINT는 메세지큐 밖에 다른 곳에 들어있다. 메세지 테이블의 WM_PAINT가 있는 부문에 1을 넣고 나머지를 다 처리한 뒤에 메세지 테이블의 1을 처리한다.

즉 100번을 넣어도 1번 수행될 수 있다.(flag성 메세지.)

그 전에 말했듯이 윈도우즈 운영체제는 그리는 것을 중요하게 생각하지 않는다.


만약 메세지테이블의 1을 영으로 바꾸지 않으면 함수는 계속 돌게된다. 이렇게 되면 컴퓨터가 아무것도 하지 않는데 CPU점유율이 엄청 올라가는 것을 확인할 수 있다. 컴퓨터가 좋으면 좋을수록 더 심하기 때문에 정말 주의하면서 써야한다.


GET DC, lelase DC를 해버리면 1이 0으로 바뀌지 않는다. 그런 능력이 없는 함수이기 때문에 이 함수를 WM_PAINT 처리할 때 사용하면 위 설명처럼 무한반복을 하기 때문에 주의해야한다.




'TIPS > API(Win32)' 카테고리의 다른 글

[TIPS] 8th 20160728_(2)  (0) 2016.08.06