리소스 풀어 헤치기
by 신영진(YoungJin Shin), codewiz at gmail.com, @codemaru, http://www.jiniya.net

디버그뷰나 프로세스 익스플로러같은 프로그램을 보면 실행 파일 하나로 구성되어 있는데 프로그램을 실행하면 드라이버를 로딩하는 것을 볼 수 있습니다. 어떻게 하는 걸까요? 답은 간단한데요. 해당 드라이버 파일을 리소스에 포함시켜 놓고 런타임에 풀어서 사용하는 방식입니다. 리소스에 추가하는 방법은 간단합니다. Visual Studio 리소스 뷰에서 오른쪽 클릭하시고 임포트 하시면 됩니다. sys 파일 같은건 안보이시죠. *.*로 필터링한다음 추가하시면 됩니다. 그러면 어떤 타입을 추가할지 물어볼텐데요. 아무렇게나 이름을 지어 주시면 됩니다. Binary 이런 식으로요. 자 그렇다면 이제 이렇게 추가된 리소스 파일을 런타임에 어떻게 조작하는지를 알아보도록 합시다.

조작하는 API는 소 심플합니다. FindResource, LoadResource, SizeOfResource, LockResource라는 API가 사용됩니다. 각각의 함수 사용 방법을 알아보도록 합시다.

  1. HRSRC FindResource(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType);  

FindResource 함수입니다. 이 함수는 우리가 분리해 내려고 하는 리소스를 찾는데 사용됩니다. hModule에는 리소스를 찾을 DLL의 모듈 핸들을 넣어주면 됩니다. NULL을 전달하면 현재 프로세스의 실행 파일 모듈에서 찾습니다. lpName에는 리소스 이름을 전달합니다. MAKEINTRESOURCE를 사용해서 리소스 ID를 문자열로 변환한 것을 대입해 주면 됩니다. 리소스 ID가 IDR_BINARY1이라면 MAKEINTRESOURCE(IDR_BINARY1)을 전달하면 되겠죠. lpType에는 리소스 타입을 넣어줍니다. 리소스 타입이 Binary라면 “Binary”를 전달하면 됩니다. 이렇게 넣어주면 리소스를 찾아서 해당 리소스의 핸들을 넘겨줍니다. 실패하면 NULL이 리턴되겠죠.

  1. DWORD SizeofResource(HMODULE hModule, HRSRC hResInfo);  

러소스의 크기를 구할 때 사용하는 함수입니다. hModule에는 모듈 핸들을 hResInfo에는 FindResource를 통해서 찾은 리소스 핸들을 넣어줍니다. 성공한 경우에는 리소스 크기를, 실패한 경우에는 0을 리턴합니다.

  1. HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);  

리소스를 로드하는 함수입니다. hModule에는 모듈 핸들을 hResInfo에는 FindResource로 찾은 리소스 핸들을 전달하면 되겠습니다. 해당 리소스의 포인터가 리턴됩니다.

  1. LPVOID LockResource(HGLOBAL hResData);  

마지막 함수입니다. LoadResource 한 메모리의 실제 포인터를 반환합니다. hResData에는 LoadResource에서 반환한 포인터를 넣어줍니다. 그럼 실제 포인터가 리턴됩니다.

종합해서 함수 하나로 만들어 봅시다. GetResourceInfo라는 함수입니다. module에서 type, name의 리소스를 찾아서 해당 리소스의 포인터를 data에 크기를 rsize에 있는지 없는지를 리턴 값으로 리턴해 주는 함수입니다.

  1. BOOL WINAPI GetResourceInfo(HMODULE module   
  2.                             , LPCTSTR type   
  3.                             , LPCTSTR name   
  4.                             , PVOID *data   
  5.                             , SIZE_T *rsize)   
  6. {   
  7.     DWORD size;   
  8.     HGLOBAL mem;   
  9.     PVOID ptr;   
  10.     HRSRC src;   
  11.   
  12.     src = FindResourceW(module, name, type);   
  13.     if(!src)   
  14.         return FALSE;   
  15.   
  16.     size = SizeofResource(module, src);   
  17.     if(!size)   
  18.         return FALSE;   
  19.   
  20.     mem = LoadResource(module, src);   
  21.     if(!mem)   
  22.         return FALSE;   
  23.   
  24.     ptr = LockResource(mem);   
  25.     if(!ptr)   
  26.         return FALSE;   
  27.   
  28.     __try  
  29.     {   
  30.         if(data)   
  31.             *data = ptr;   
  32.   
  33.         if(rsize)   
  34.             *rsize = size;   
  35.     }   
  36.     __except(EXCEPTION_EXECUTE_HANDLER)   
  37.     {   
  38.         return FALSE;   
  39.     }   
  40.   
  41.     return TRUE;   
  42. }  

여기까지만 설명하고 마칠까 하는데 아마 똑똑한 분들이라면 먼가 찜찜한 기분이 드실 거예요. 화장실가서 볼 일 보고 뭔가 정리하지 않고 나온 느낌이겠죠. 실컷 로딩하고 락하고 했는데 그것들을 해제하는 작업에 대해서는 하나도 설명하지 않았으니 말입니다. UnlockResource, FreeResource와 같은 함수들이 있긴 한데, 그것들은 사용하지 않아도 됩니다. 왜냐하면 여기서 사용하는 리소스 핸들을 구하고 하는 함수들은 로드된 모듈에서 포인터를 참조해 오는 일이거든요. 여러분이 획득한 모든 포인터 내지는 리소스는 hModule이 FreeLibrary 되는 시점에 같이 사라집니다. 따라서 별도로 해제할 필요가 없는 셈이죠. 참고로 그래도 나는 해제하겠다고 UnlockResource, FreeResource를 호출한들 실제 해당 함수에서 하는 일은 return 밖에는 없답니다.

Posted by 모과이IT
,

 
BOOL SHGetSpecialFolderPath(
  HWND hwndOwner,
  LPTSTR lpszPath,
  int nFolder,
  BOOL fCreate
);


 HWND hwndOwner,
 만약 다이얼로그 박스나 메세지 박스에 보여주려고 할때 넘겨 줘야 하는 Owner window 핸들
 
  LPTSTR lpszPath,
 특수 폴더의 드라이브와 경로를 받을 char 버퍼

  int nFolder,
  알고자 하는 특수 폴더의 CSIDL의 상수 값, 만약 가상 폴더값이 입력되었다면 이 함수는 실패 할 것이다. 

  BOOL fCreate 
 만약 기존의 특수 폴더가 존재하지 않는다면 폴더를 생성할 것인지 아닌지를 설정, 이 값이 0이 아닌 값이라면 폴더는 생성될것이다. 하지만 0이라면 폴더는 생성되지 않는다.

   

사용 예)

 TCHAR szSpecialPath[MAX_PATH] = {0};
    SHGetSpecialFolderPath(NULL, szSpecialPath, CSIDL_WINDOWS, FALSE);


  nFolder  상수 값

  CSIDL_FLAG_CREATE
  CSIDL_ADMINTOOLS
  CSIDL_ALTSTARTUP
  CSIDL_APPDATA
  CSIDL_BITBUCKET
  CSIDL_COMMON_ADMINTOOLS
  CSIDL_COMMON_ALTSTARTUP    
  CSIDL_COMMON_APPDATA  
  CSIDL_COMMON_DESKTOPDIRECTORY    
  CSIDL_COMMON_DOCUMENTS    
  CSIDL_COMMON_FAVORITES    
  CSIDL_COMMON_PROGRAMS    
  CSIDL_COMMON_STARTMENU    
  CSIDL_COMMON_STARTUP
  CSIDL_COMMON_TEMPLATES    
  CSIDL_CONTROLS    
  CSIDL_COOKIES  
  CSIDL_DESKTOP
  CSIDL_DESKTOPDIRECTORY  
  CSIDL_DRIVES  
  CSIDL_FAVORITES    
  CSIDL_FONTS    
  CSIDL_HISTORY     CSIDL_INTERNET  
  CSIDL_INTERNET_CACHE  
  CSIDL_LOCAL_APPDATA  
  CSIDL_MYMUSIC    
  CSIDL_MYPICTURES  
  CSIDL_NETHOOD  
  CSIDL_NETWORK
  CSIDL_PERSONAL  
  CSIDL_PRINTERS  
  CSIDL_PRINTHOOD  
  CSIDL_PROFILE  
  CSIDL_PROGRAM_FILES    
  CSIDL_PROGRAM_FILES_COMMON  
  CSIDL_PROGRAMS  
  CSIDL_RECENT     CSIDL_SENDTO  
  CSIDL_STARTMENU  
  CSIDL_STARTUP  
  CSIDL_SYSTEM  
  CSIDL_TEMPLATES  
  CSIDL_WINDOWS

Posted by 모과이IT
,

1. WIN32 VS WIN64

(1) 64 비트와 32 비트

- 한번에 CPU 가 송수신할 수 있는 데이터 크기와 한번에 처리할 수 있는 데이터 크기를 기준으로 32 비트와 64 비트 컴퓨터를 구분짓는다.

 

(2) 주소값의 크기

- 주소값의 크기는 크면 클수록 좋다. 메모리 공간의 활용이 크만큼 커지기 때문이다. 그러나 주소값의 크기를 무한정 늘릴수는 없는데 왜냐하면 컴퓨터에서 한번에 전송되고 처리되는 데이터의 크기에 따라 주소값의 크기는 종속되기 때문이다. 따라서 32 비트 컴퓨터에서 주소값은 32 비트 (4바이트) 로 표현되며, 64 비트 컴퓨터에서는 64 비트 (8바이트) 로 표현된다.

2. 프로그램 구현 관점에서의 WIN32 VS WIN64

- 마이크로소프트에서는 64 비트 기반의 운영체제를 내놓으면서도 32 비트 시스템과의 호환성을 중시하였다. 그로 인해 프로그래밍 스타일에 대한 가이드를 제시하고 있는데, 이것을 따르는 것이 바로 64 비트 기반 프로그래밍 스타일의 기본이다.

(1) LLP64 VS LP64

- 지금까지 우리는 int, long, 포인터 모두 4바이트로 표현된다고 알고 있었다. 이것은 32 비트 환경에서 WIndows 가 기본자료형과 포인터를 표현하는 방식이다. 그러나 64 비트 컴퓨터에서는 다음과 같이 표현한다.

- LLP64 : Windows 에서 LLP64 라는 데이터 표현 모델은 int, long 은 그대로 4바이트로 표현하고 포인터만 8바이트로 표현한다. 따라서 32 비트 시스템과의 호환성을 중시한 모델이라고 말한다.

- LP64 : UNIX 에서는 LP64 모델을 취하는데, Windows 의 LLP64 모델과 차이가 나는 부분은 long 또한 8바이트로 표현한다는 점이다.

 

(2) 64 비트와 32 비트 공존의 문제점

- 64 비트 시스템에서는 포인터가 지니고 있는 주소값을 4 바이트 정수형으로 형 변환해서는 안된다.

 

(3) Windows 스타일 자료형

- 다른 시스템으로의 이식성을 고려한다면 기본 자료형을 사용하거나 프로젝트의 성격 및 특성에 맞게 새로운 이름으로 자료형을 정의하는 것이 좋은 방법이다. 다만 Windows 기반에서의 실행만 고려한다면, 마이크로소프트에서 정의하고 있는 자료형을 사용하는 것도 좋은 선택이 될 수 있다.

- 다음은 마이크로소프트에서 정의하고 있는 많은 양의 자료형 중에서 ANSI 기본 자료형에 대응하는 일부를 보여준다. (첨부표 참고) 이미 앞에서도 문자열 관련 자료형을 몇몇 소개하였다. (TCHAR, LPTSTR, LPCTSTR)

- 위 표를 보면 WIN64 로 넘어가면서, 새로운 자료형 (끝이 32, 64 로 끝나는) 이 상당수 추가되었음을 알 수 있는데, 이는 WIN32 와 WIN64 에서 시스템에 상관없이 동일한 의미를 지니는 자료형을 표현하기 위한 것이다. ~32 형태의 자료형은 시스템에 상관없이 32비트로 표현되고, ~64 형태의 자료형은 시스템에 상관없이 64비트로 표현된다.

* Microsoft C/C++ 에서는 정수 타입으로 크기를 지정해서 선언하는 것이 가능하다. __int(n) 의 형태로 8, 16, 32, 64 를 지정해서 변수를 선언할 수 있다. 즉, __int8, __int16, __int32, __int64 와 같은 타입 선언이 가능하다. 이들은 각각 ANSI 표준의 char, short, int 에 해당한다. 다만 __int64 는 ANSI 표준에 존재하지 않는, Microsoft C/C++ 에만 존재하는 자료형이다. 그러나 기본 자료형과 마찬가지로 사칙연산이 가능하다는 아주 멋진 특성을 지닌다.

- WIN64 로 이전하면서 등장한 자료형들을 사용할 경우, 변수 선언 시 할당된 바이트 수를 정확하고도 쉽게 파악할 수 있어서 도움은 되지만, 그렇다고 WIN32 시절에 정의된 자료형이 WIN64 환경에서 쓸모가 없어진 것은 아니다.

 

(4) Polymorphic 자료형

- 포인터값 기반의 산술연산을 위해 정의된 자료형이다. 32비트 시스템과 64비트 시스템의 포인터 크기가 다르기 때문에 발생할 수 있는 문제를 해결하기 위해 등장한 자료형이다.

#if defined(_WIN64)

   typedef __int64 LONG_PTR;

   typedef unsigned __int64 ULONG_PTR;

   typedef __int64 INT_PTR;

   typedef unsigned __int64 UINT_PTR;

#else

   typedef long LONG_PTR;

   typedef unsigned long ULONG_PTR;

   typedef int INT_PTR;

   typedef unsigned int UINT_PTR;

#endif

* 매크로 _WIN64는 64비트 기반으로 프로젝트 구성시 자동적으로 삽입되는 매크로이다. 32비트 기반으로 프로젝트 구성시 마찬가지로 매크로 _WIN32 가 자동 삽입된다. 따라서 이 매크로는 시스템 환경에 따라서 조건부 컴파일 및 실행하는데 있어서 기준이 된다.

* Polymorphic 자료형을 이용하면 주소값을 64비트 환경에서는 64비트로 32비트 환경에서는 32 비트로 표현할 수 있다.

3. 오류의 확인

- Windows 시스템 함수를 호출하는 과정에서 오류가 발생하면, GetLastError 함수 호출을 통해 오류의 원인을 확인할 수 있다. 많은 수의 Windows 시스템 함수들은 오류가 발생했을 때 NULL 을 반환한다. 반환되는 NULL 값으로 오류가 발생했음을 알 수 있지만, 원인은 알 수가 없다. 오류가 발생했을 때, 이어서 바로 GetLastError 함수를 호출하면 오류의 원인에 해당하는 에러코드를 얻을 수 있다.

DWORD GetLastError(void);

- MSDN 을 참조하면 시스템 에러코드의 종류와 해당 에러코드가 의미하는 바를 알 수 있다.

- 오류 확인은 오류가 발생한 직후에 바로 한다. 에러코드는 Windows 시스템 함수가 호출 될 때마다 갱신되기 때문이다.


Posted by 모과이IT
,
Ctrl-Alt-Delete를 누르면 나타나는 작업관리자 목록에서 원하는 프로그램을 감추는 방법을 소개하겠다. 사실 방법은 매우 간단하지만 잘 알려져 있지 않은듯하다.

Win32 API 중 RegisterServiceProcess()는 커널함수가 있다. 이 함수는 MSDN에서도 문서화되어 있는 함수이지만 일반 API 함수를 사용하듯 호출할 수 없다. 아마 특별한 이유에서 헤더파일에 프로토타입을 빼놓은 듯 한데, GetProcAddress() 함수와 함수포인터를 사용해서 호출할 수 있다. 아래에 리스트된 코드를 보자.

typedef DWORD (WINAPI *LPREGSRVPROC)(DWORD, DWORD); 
void RegisterServiceProcess(DWORD dwProcessId, DWORD dwType) 
HMODULE hMod = GetModuleHandle("kernel32.dll"); 
if(hMod) 
LPREGSRVPROC pfn = (LPREGSRVPROC)GetProcAddress (
hMod, "RegisterServiceProcess"); 

if(NULL != pfn) pfn(dwProcessId, dwType); 

 
dwProcessId : 프로세스 식별자
dwType : 1이면 프로세스를 서비스모드로 등록(작업관리자에 나타나지 않음), 0이면 서비스모드 해제 

Example Borland c code:

//--------------HiddenApp.cpp--------------
#include 
#pragma hdrstop

USERES("HiddenApp.res");
USEFORM("Unit1.cpp",Form1);

typedef DWORD (WINAPI *TRegisterServiceProcess)(DWORD,DWORD);
bool registered=false;

//////////////////////////////////////////////////////////////////////////
void __fastcall reg(bool which) //true=register, false=unregister
{
  HMODULE hmod;
  TRegisterServiceProcess pReg;
  hmod = LoadLibrary("kernel32.dll");

  if (!hmod) return;
  (FARPROC)pReg = (FARPROC)::GetProcAddress(hmod,"RegisterServiceProcess");
  if (!pReg) {FreeLibrary(hmod); return;}
  else 
  {
 if (which)
 pReg(0,1); //unregister our process  
 else
 pReg(0,0);
  }
  registered = true;
  FreeLibrary(hmod);
}
//////////////////////////////////////////////////////////////////////////
WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{  
  try
  {
 reg(true);
 Application->Initialize();
 Application->CreateForm(__classid(TForm1), &Form1);
 Application->Run();
  }
  catch (Exception &exception)
  {
 Application->ShowException(&exception);
  }

  if (registered) reg(false);
  return 0;
}
//--------------eof----------------------------
Posted by 모과이IT
,

- 윈도우 프로그램은 하나 이상의 윈도우(윈도우 단위로 구성)를 가지고 메세지 구동 방식으로 실행됩니다.

 

■ WinMain 함수 매개변수

- 윈도우 프로그램의 main 함수

 

 int APIENTRY WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,

                               int nCmdShow)

 

hInstance : 현재 실행을 시작하는 프로그램의 인스턴스 핸들

hPrevInstance : 이전에 실행된 동일 프로그램의 인스턴스 핸들

lpCmdShow : main 함수의 argv와 같은 기능  

nCmdShow : 프로그램의 윈도우가 어떤 모습으로 실행될 것인지 결정

                   옵션은 최소화 상태, 감춰진 상태, 보통 상태 등이 있음

 

※ 용어

인스턴스 : 프로그램이 실행되어 메모리에 로딩된 상태에 있을 때.

핸들 : 메모리에 로딩된 인스턴스 식별하기 위해 사용. 즉 윈도우 식별자

이외에도 윈도우 프로그래밍에서 '핸들'은 특정 메모리 블록을 식별하기 위한 포인터.

 

 

■ WinMain 함수의 구성

1. 프로그램을 초기화 한다.

2. 인스턴스를 초기화 한다.

3. 메세지 루프를 돈다.

 #include <windows.h>

 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

                                  LPSTR lpCmdLine, int nCmdShow)

 {

     // 프로그램 초기화

     if( !hPrevInstance )     // 인스턴스가 처음 생성되는 경우에만 실행

          if( !InitApplication(hInstance) )

               return FALSE ;

 

     // 인스턴스 초기화

     if( !hInitInstance(hInstance, nCmdShow ) )

          return FALSE ;

 

     // 메세지 루프

     return Run()

 } 

 

프로그램 초기화 : 프로그램의 인스턴스가 메모리에 처음 로딩될 때 수행해야 하는 초기화 작업

인스턴스 초기화 : 각각의 인스턴스가 메모리에 로딩될 때마다 수행해야 하는 초기화 작업

즉, 프로그램이 이미 실행되어 메모리에 인스턴스가 존재하면 두 번째 인스턴스가 생성될 때 프로그램 초기화 작업은 하지 않아도 된다. 인스턴스 초기화 작업만 하면 된다.

 

 

□ 프로그램 초기화 : 윈도우 클래스 등록

- Edit 컨트롤, Combo Box 컨트롤, List Box 컨트롤 등의 윈도우는 운영체제에 이미 클래스가 등록되어 있다. => 파생클래스로 상속을 받아 조작

- 그러나 우리가 만드는 윈도우는 새로운 기능을 가진 윈도우므로 이 윈도우 클래스를 운영체제에 새로 등록해 주어야 한다.

1. WNDCLASS 구조체에 값을 채움

2. RegisterClass 함수를 호출하여 윈도우 클래스 등록

 BOOL InitApplication( HINSTANCE hInstance )

 {

     WNDCALSS wc ;

     wc.style = CS_HREDRAW | CS_VERDRAW ;

     wc.lpfnWndProc = WndProc ;     // 함수 포인터

     wc.hInstance = hInstance ;

     wc.hIcon = LoadIcon( NULL, IDI_APPLICATION )

     wc.hCursor = LoadCursor( NULL, IDC_ARROW ) ;

     wc.hbrBackgroud = (HBRUSH)GetStockObject( WHITE_BRUSH ) ;

     wc.lpszMenuName = NULL ;

     wc.lpszClassName = "ExampleCalss" ;

     wc.cbClsExtra = 0 ;

     wc.cbWndExtra = 0 ;

 

     reutnr RegisterClass( &wc ) ;

 }

 

。WNDCLASS 구조체

 typedef struct _WNDCLASS {

     UNIT          style ;            // 윈도우 스타일

     WNDPROC lpfnWndProc ; // 윈도우 프로시저(메세지를 처리할 함수)

     int             cbClsExtra ;   // (사용하지 않음) 미래 확장을 위해 사용된 값

     int             cbWndExtra ;  // (사용하지 않음) 미래 확장을 위해 예약된 값

     HANDLE     hInstance ;    // 인스턴스 핸들

     HICON       hIcon ;           // 윈도우가 최소화 되었을 때 표시될 아이콘의 핸들

     HCURSOR  hCursor ;       // 윈도우 위로 마우스 커서가 올라갔을 때 보여질 커서의 핸들

     HBRUSH     hbrBackground ;  // 배경을 지우는데 사용할 브러시의 핸들

     LPCTSTR   lpszMenuName ;  // 이 윈도우가 소유할 메뉴

     LPCTSTR   lpszClassName ;  // 윈도우 클래스의 이름

 } WNDCLASS ;

 

 

□ 인스턴스 초기화 : 윈도우 생성

1. 핸들 정의

2. 윈도우를 생성 값을 핸들에 넘김

 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

 {

     HWND hWnd ;

     if( !(hWnd = CreateWindow("ExampleClass", "C로 만든 프로그램",     

                                           WS_OVERLAPPEDWINDOW,

                                           CW_USEDEFAULT, CW_USEDEFAULT,

                                           CW_USEDEFAULT, CW_USEDEFAULT,

                                           NULL, NULL, hInstance, NULL ) ) )

          return FALSE ;

 

     ShowWindow( hWnd, nCmdShow ) ;  // 메인 프레임 윈도우를 화면에 보이게 한다.

     UpdateWindow( hWnd ) ;                  // 메인 프레임 윈도우를 다시 그려준다.

     return TRUE ;

 }

 

。CreateWindow 함수의 매개변수

 매개변수  의미 
 lpClassNamae  프로그램 초기화 부분에서 등록한 윈도우 클래스의 이름
 lpWindowName  윈도우 타이틀 바에 출력될 문자열
 dwStyle  윈도우 스타일
 x, y, nWidth, nHeight  윈도우의 위치와 가로 세로 길이
 hWndParent  부모 윈도우의 핸들
 hMenu  메뉴의 핸들
 hInstance  인스턴스의 핸들
 lpParam  CREATESTRUCT 구조체로 지정되는 윈도우 생성에 필요한 추가 정보

 

 

□ 메세지 루프

- 프로그램에 어떤 이벤트가 발생하면 윈도우 운영체제가 이를 감지하여 프로그램의 메세지 큐에 적당한 메세지를 넣어준다.

1. 프로그램의 메세지 큐에서 메세지를 가져온다.

2. 이 메세지의 정보를 알려준다.

3. 메세지를 윈도우 프로시저에 전달한다.

 int Run()

 {

     MSG msg ;

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

     {

          TranslateMessage( &msg ) ;

          DispatchMessag( &msg ) ;

      }

      return (int)msg.wParam ;

 }

 

GetMessage 함수는 프로그램의 메세지 큐에서 메세지를 가져오는 기능을 수행합니다.

이 함수는 프로그램을 종료하라는 WM_QUIT 메세지를 가져오면 TRUE를 반환하고, 그렇지 않으면 FALSE를 반환한다. FALSE를 만나면 while문을 빠져나온다.

키보드가 눌리면 WM_KEYDOWN 메시지가, 키보드가 떼지면 WM_KEYUP 메세지가 발생한다. Translatemessage 함수는 이 메세지 조합을 이용하여 KEY_CHAR, KEY_DEADCHAR, KEY_SYSCHAR 등의 메세지를 발생하여 실제로 어떤 문자가 눌렸는지 정보를 알려준다.

DispatchMessage 함수는 이 메세지를 윈도우 프로시저에 전달한다.

 

 

□ 윈도우 프로시저 : 메세지 처리

- 윈도우 메세지를 처리하는 함수로 이 함수를 어떻게 만드냐에 따라 윈도우 기능이 결정된다.

 

 LRESIT WINAPI WndProc(HANDLE hWnd, UNIT message, WPARAM wParam,

                                     LPARAM lParam)

 {

     switch( message )

     {

          case WM_KEYDOWN :          // 키보드가 눌렸을 때의 처리

               break ;

          case WM_LBUTTONDOWN :  // 마우스 왼쪽 버튼이 클릭되었을 때

               break ;

          case WM_MOUSEMOVE :     // 마우스가 움직였을 때

               break ;

     }

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

 }

 

DefWindowProc 함수는 윈도우 운영체제가 미리 정해둔 윈도우의 기본 기능을 수행하도록 한다. 

 
Posted by 모과이IT
,