안녕하세요. 저번에 공지한대로 이번 포스팅에서는 콘솔창을 띄우지 않고 프로그래밍을 해보겠습니다.

visual stdio를 열어 프로젝트를 만듭니다.

win32 응용 프로그램을 만들기 위해 Win32 프로젝트를 선택하여 프로젝트를 만듭니다.

만들 프로그램을 windows 응용 프로그램으로 선택하고 빈 프로젝트를 체크해 준 다음 마침을 누릅시다. 가끔 사람들이 빈 프로젝트가 뭐냐고 물으시는 분 들이 있는데 말 그대로 비어있는 프로젝트를 뜻합니다.

빈 프로젝트를 체크해제하고 만들 시 visual stdio에서 지정한 기본 main 함수가 미리 적혀있는 것을 볼 수 있습니다.

아래는 빈 프로젝트를 체크해제하고 만든 프로젝트입니다.

보시다시피 상당한 지식을 요구하는 코드가 자동으로 적혀있는 것을 볼 수 있습니다. 즉 전문가용 옵션입니다. 우리는 전문가가 아니니까 그냥 빈 프로젝트 옵션을 사용합시다.

프로젝트를 만드셨으면 소스를 만듭시다.

c언어로 작성해야하니 c++ 파일을 선택하시고 소스파일의 확장자를 c로 맞춥시다.

여기까지 하셨으면 이제 소스를 작성할 차례입니다. 미리 제가 작성한 소스를 한 번 봅시다.

네 소스코드는 콘솔프로그래밍과 별 차이가 없습니다. 하지만

main부분이 상당히 다르다는 것을 느낄 수 있습니다. 

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

이번 포스팅의 핵심부분입니다. 하나씩 살펴봅시다.

*WINAPI WinMain

WINAPI란 windows api를 뜻합니다. 즉 windows에서 사용하는 api라는 뜻입니다.

여기서 api가 무엇인고하니 api는 Application Programming Interface의 약자를 뜻합니다.

해석하면 응용프로그램 프로그래밍 인터페이스를 뜻하는데 인터페이스가 두 장치 간의 상호작용을 위한 매개체를 뜻하므로 풀이하면

응용프로그램을 프로그래밍하기 위한 매개체를 뜻합니다. 쉽게 말하면 응용프로그램을 만들기 쉽게 해주는 규격 같은 것입니다.

즉 winapi는 윈도우에서 응용프로그램을 프로그래밍할 때 도움을 주는 인터페이스를 의미합니다.

정리하면 WINAPI WinMain이란 WINAPI 호출규약인 WinMain함수를 선언하였다. 라고 보시면 됩니다. 일반 콘솔 프로그래밍에서는 컴파일러가 main함수를 찾는 것이 비해 응용 프로그래밍에서는 컴파일러가 WinMain함수를 찾습니다. 그러므로 WinMain함수를 선언해 주었습니다.

이러한 WinMain은 인자를 다음과 같이 받습니다.

보시게 되면 제가 WINAPI를 넣었던 자리에 CALLBACK라고 적혀있는 것을 볼 수 있습니다. 사실 이자리는 함수호출규약을 정하는 자리입니다. 

함수호출규약이 무엇이냐면 함수를 호출할 때 스택을 정리하는 규약을 정해놓은 것입니다. 일반적으로 __cdecl와 __stdcall가 있는데 일반 콘솔 프로그래밍에서 함수를 호출 할 경우에는 __cdecl를 쓰지만 응용프로그래밍을 할 경우에는 __stdcall 방식을 씁니다. 좀더 자세히 알아보기 위해 실습을 해 봅시다.

WinDef.h를 작성하시고 문서를 열어봅시다. WinDef 헤더파일은 여러 자료형을 정의해 놓은 문서입니다.

문서를 찾아보면 위와 같이 정의되 있는 곳을 찾을 수 있습니다.

MSDN의 CALLBACK과 제가 작성한 WINAPI의 정의된 값을 보면 __stdcall라고 정의되어있습니다. 즉 함수호출규약을 뜻합니다.

즉 CALLBACK 자리에는 CALLBACK이 와도 되고 WINAPI도 와도 되고 __stdcall이 와도 된다는 것입니다. 

그러면 꼭 함수 호출 규약을 적어야 하나? 라는 의문이 들 수 있습니다. 실험 결과 규약을 적지 않아도 프로그램이 정상적으로 실행되는 것을 볼 수 있었습니다. 하지만 밑의 결과를 보면

WinMain의 호출규약은 __stdcall이어야 한다고 경고가 나옵니다.(에러 아닙니다)

그래서 저는 저 자리에 WINAPI를 적어주었습니다.

이제 인자들을 차례대로 살펴 봅시다.

hInstance

자료형이 HINSTANCE입니다. HINSTANCE는 핸들 인스턴스의 약자이며 쉽게 말하면 프로그램 자체의 주소라고 보시면 됩니다. HWND가 프로그램 내의 윈도창의 번호라고 한다면 HINSTANCE는 프로그램의 번호라고 보시면 됩니다.

hPrevInstance

자료형이 HINSTANCE입니다. 즉 프로그램 자체의 주소를 받는다는 것은 앞의 인자와 동일하나 이 인자는 이 프로그램의 주소가 아닌 앞에 실행된 프로그램의 주소를 받습니다. 그런데 이 인자는 16비트 환경일 때 사용한 인자이며 현재 32비트 환경에서는 사용되지 않습니다. 그래서 기본적으로 NULL값이 인자로 들어갑니다.

*lpCmdLine

자료형이 LPSTR인 이 인수는 이 프로그램의 이름 혹은 경로를 유니코드체계로 받습니다.

*nCmdShow

자료형이 INT인 이 인수는 윈도우가 표시되는 방법을 정수형으로 받습니다.

자 여기까지가 WinMain의 설명입니다. 기본적으로 WinMain를 사용할 시에는 저 4개의 인자를 적어주어야 합니다.

추가로 덧붙이자면 위의 인자이름들은 가독성을 위해 MSDN에서 정해놓은 인자이므로 굳이 인자이름을 똑같이 적을 필요는 없습니다.

자료형만 맞추고 인자 이름이 예약어가 아니라면 정상적으로 실행이 됩니다.

자 이제 소스설명이 끝났으니 한번 실행 해 봅시다.

콘솔창이 뜨지 않는 것으로 보아 정상적으로 실행됐음을 알 수 있습니다.

다음 포스팅은 이렇게 제작한 프로그램을 리버싱하는 것을 올리겠습니다. 참고로 리버싱 카테고리에 올릴 예정입니다.

이상으로 포스팅을 마치겠습니다.





Posted by englishmath
,