본문 바로가기

TIPS/API(Win32)

[TIPS] 8th 20160728_(2)

8번째 강좌정리입니다.(2) 첫번째 실습입니다^^


1. API

Application Programming Interface

프로그램을 만드는데 도와주는 함수의 집합이라고 할 수 있다. 즉, 운영체제가 어플리케이션 개발자들에게 제공하는 함수.


2. SDK

Software Development Kit

소프트웨어를 개발하는데 필요한 모든 도구들. 비쥬얼스튜디오(VS)도 SDK에 속한다.


참고로 VS는 API와 SDK를 합한 것으로 볼 수 있다.


3. MFC

Microsoft Foundation Class 

API를 C에서 C++로 바꿔야하는데 (class로) 이러한 일을 하는 팀이 만드는 것이 MFC이다.

따라서 MFC의 경우 API보다 개발속도가 느릴 수 밖에 없고, 최신프로그램을 늦게 사용하게 된다.




우선 우리는 windows프로그램의 뼈대를 확인하는, 이해하는 정도로 API를 배우도록 한다.



실습------------------------------------------------------------------------------------------------------------------------------------------------




저장 경로에 한글이나 띄어쓰기가 없도록 한다. 특히 한글은 절대 사용하지 않는다!

솔루션용 디렉터리 만들기를 체크하는 것이 나중에 편하다.



SDL은 string함수에 대한 안정성검사이다. 체크를 한다면 _s를 붙여주어야 하기 때문에 여기서는 체크를 해제한다.



#include "stdafx.h"를 제외한 모든 코드를 삭제해준다.


먼저 handle의 개념부터 살펴보자.

운영체제는 어플리케이션으로부터의 직접적인 접근을 막아야한다. 그렇기 때문에 운영체제에게는 포인터는 위험한 존재가 된다. 운영체제 안에 있는 자원들의 주소를 직접 어플에 넘겨버리면, 운영체제가 공격당하기 쉽기 때문이다. 그렇다고 주소를 넘기지 말자니 어플리케이션을 사용할 수 없다. 따라서 이때 나온 개념이 handle이다.


직접 주소를 넘기지 않고, OS 중간에 핸들테이블을 만들어 어플이 운영체제 주소에 접근할 때 한 번 더 걸치게 한다.

그래서 직접적인 주소를 보호하도록 하는 것이다. 이때, 원래의 주소에 매칭되는 가상의 숫자가 handle이다.



그럼 코드작성을 시작해보자.


아래는 참고사항이다.


- H~~는 앞서 설명한 handle을 의미한다. 부호없는 32비트이다.


- 사용되는 명명법에는 카멜표기법(각 단어마다 대문자로 시작하는 표기법으로 옛날에 잘 사용하였다.), 헝가리안표기법(변수명 앞에 타입을 명시하는 방식)이 있다.


- lp는 롱포인트


- n은 넘버


- 문자는 1바이트의 char를 사용했는데, MS에서는 유니코드를 사용하여(UTF..) wchar 즉 wide character인 2바이트 캐릭터를 사용한다. (한글은 초성, 중성, 종성이 존재하고 총 16비트 즉 2바이트의 저장소가 필요하다. 옛날에는 각 나라별로 언어코드가 따로 있어서 프로그램 언어버전을 바꿀 때 문제가 있었다!

만일 다국어를 사용하지 않는 프로그램이라면 당연히 유니코드를 사용하는 것은 메모리가 두배이니 낭비이다. 프로젝트 속성에서 일반->문자집합->유니코드 설정안함으로 설정해준다.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)


WinMain은 우리가 C언어에서 사용하던 main함수와 같은 개념이다. 프로그램에서 우선적으로 실행되는 함수이다. 


WINAPI : 스텍프레임의 한 종류이다. 과거에는 파스칼로 적혀있었다. C는 호출자가 피호출자의 주소로 들어가는 방식이다. 즉 운영체제를 공격하는 방식이다. 하지만 파스칼은 반대이기 때문에 C언어보다 파스칼의 스택프레임이 더 안정적이였다. 이제 파스칼이 망해서..



hInstance : 프로세스의 시작 주소.(프로그램이 실행되었을 때의 고유값)


hPrevInstance : 중복실행 등을 막는데 사용하였지만 해킹의 주요 원인이 되어서 이제 사용하지 않는다.


lpCmdLine : 파일의 속성에서 실행파일(exe) 뒤에 적은 문자열이 넘어간다. 나중에 프로그램을 하다보면 많이 사용하는데, 급하게 프로그램을 수정해야하는 경우 등에 사용된다.


nCmdShow : 실행 속성에 기본창, 최소화, 최대화의 값이 넘어온다.



이제 windows에 내 어플리케이션을 등록해야 한다.


WNDCLASS wc;


어플리케이션에 대한 고유 정보들을 적어서 등록한다. wc에는 빈번하게 들어가는 요소가 들어있다.


wchar_t my_app_class_name[] = L"Tipssoft"; 


고유명칭. L은 유니코드를 적을 때 사용한다.. L을 적지 않으면 char로 인식된다. 큰따음표 안에 만약 notepad를 적으면 메모장이 실행되버린다. 따라서 유명한 명칭은 사용하지 않아야 한다.


wc.cbClsExtra = NULL;

wc.cbWndExtra = NULL;


이 두개는 우리가 쓸 일 없다. 윈도우 안에 윈도우가 존재하게 하는 그런 코드이다.


wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); 


MS는 이전 버전과의 호환이 높다는 큰 장점이 있다. (이 구조는 80년대 후반부터 쓰이던 것이다.)


면에 대한 색상은 브러쉬. 선에 대한 것은 펜을 사용한다. 내 윈도우의 배경색설정하는 코드이다.

운영체제 입장에서는 낭비를 줄이기 위해 많이 쓰는 색을 미리 만들어둔다. 이러한 자원들을 stock object라고 부른다.


wc.hCursor = LoadCursor(NULL, IDC_ARROW);


NULL : 운영체제가 제공하는 하나를 쓰겠다는 의미.


IDC_ARROW는 일반적인 커서.    wait는 테스트해보지 않는 것이 좋다. 클릭이 되지 않는다.ㅎㅎ


wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);


어플리케이션 좌측상단에 뜨는 아이콘.


wc.hInstance = hInstance; 


주민등록번호 등록하는 의미. 내가 만든게 아니라 넘어오는 값임.


wc.lpfnWndProc = WndProc; 


사용자영역(client area) 즉, 내가 만들어야 하는 부분. 여기서 WndProc은 callback함수이다. 최대화, 최소화 등등 이런건 운영체제가 제공하지만 사용자영역은 직접 설정해주어야 한다.


wc.lpszClassName = my_app_class_name; 


lpsz : long point string zero 문자열 0으로 끝난다.


wc.lpszMenuName = NULL; 


지금은 따로 메뉴 안써서 NULL썼다.


wc.style = NULL;


응용프로그램의 스타일. (창스타일 아니다.) 윈도우에서 봤을 때 기본이 아니라고 생각하는 여러가지 작업들을 사용할지 말지 결정하는는 코드이다. 일반적인 기본행위는 다 되지만 확장행위는 이와 같은 코드로 쓸지 말지 적어주어야 한다. 더블클릭, 휠 등이 확장행위이다.



이제 서류를 제출한다.


RegisterClass(&wc); 


대부분 받아들여진다. 만약 이와 같은 등록하는 방식이 아닌 새로운 어플리케이션을 탐색하여 등록되게 하는 반대의 경우에는 부하가 너무 걸리고 비효율적이기 때문에 이처럼 사용자가 직접 등록을 해주어야 한다.


HWND hWnd = CreateWindow(my_app_class_name, L"www.tipssoftware.com", WS_OVERLAPPEDWINDOW, 100, 90, 400, 350, NULL, NULL, hInstance, NULL);


CreateWindow : 눈에 보이는 것을 만들 때 사용. (윈도우클래스명칭으로 창 상단 글자이다.) 이 함수가 API이다.


WS_OVERLAPPEDWINDOW : 윈도우스타일


캡션바(흔히 타이틀바라고 부르는 상단이름.), thickframe은 굵은 프레임. WS_SYSMENU 등, 최소화 최대화 창겹치기 등등을 기본으로 적어야 하는데 이게 귀찮으니까 하나로 define해둔 것이 이 WS_OVERLAPPEDWINDOW이다.


항상 네 개의 좌표가 오는 경우에는 잘 봐야한다. 처음 네 개는 x, y좌표이다. , 그 뒤의 두개는 내가 부모윈도우기 때문에 쓰지 않는다.

그 다음은 내 고유값, 그 다음은 딱히 의미가 없다고 본다.


참고로 wnd는 창을 의미하고 wns는 windows운영체제를 의미한다.


ShowWindow(hWnd, nCmdShow); 


window를 보여달라. hWnd가 넘어간다. WinMain의 네번째인자인 nCmdShow.

참고로 무조건 최소화로 실행하게 하려면 sw_를 써준다.


UpdateWindow(hWnd);


사용자가 그리는 부분을 보여달라.


이 함수를 지워도 정상적으로 수행되지만...


윈도우즈는 화면에 그림그리는 것이 제일 덜 중요하다고 생각한다. 따라서 CPU점유율이 엄청 높을 때는 프로그램의 창이 화면에 나오질 않는다. 그렇기 때문에 처음 한 번은 이 함수를 써서 무조건 한 번은 눈에 보이도록 해야한다.


이 함수는 자주쓰면 안된다. 


예를 들어, movewindow를 for문돌려서 500번을 쓴다고 생각해보자. 윈도우의 500번의 움직임이 모두 보여질까? 아니다. 그냥 버려진다. 만일 창을 movewindow를 여러번 써서 밀려나오듯이 하고 싶으면 for문에 updateWindow를 써주어 화면에 무조건 나오게 만든다. 


real time 시스템 : 시스템이 정한 유효시간 내에 처리해주는 것

MSG msg;


이벤트(행위)에 정보가 추가된 것을 메세지라고 한다. 


윈도우즈는 메세지를 기반으로하는 운영체제이기 때문에 어플리케이션마다 우체통(메세지큐)을 달아준다.


어플들은 다 메세지큐만 바라보고 있다.


while (GetMessage(&msg, NULL, 0, 0)) {


GetMessage는 메세지큐를 계속 보고 있게 하는 명령이다. 메세지가 들어오면 그 메세지 꺼내오면서 메세지큐에 담겨있던 메세지는 사라진다.


pickmessage라는 함수는 메세지큐의 메세지를 없애지 않고 메세지를 확인만 한다.


TranslateMessage(&msg);


메세지 정보를 번역한다. 운영체제가 계산해줄 수 있는 것들(예를 들어 좌표)을 모두 계산해서 알려줌.


DispatchMessage(&msg); }


dispatch : 정해진 특정 모듈을 실행한다. 작은단위의 실행이다. 위의 우리가 정한 WndProc을 실행하는 것.



이제 WinMain함수를 닫아주면 된다.


return 0;

}



아래와 같이 기본 뼈대가 만들어진다.





정말 좋은 소스들은 API로 되어있는 경우가 많다. 따라서 알아두는 것이 좋다.




www.tipssoft.com




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

[TIPS] 9th 20160801  (0) 2016.08.06