6.C++로 작성하는 윈도우 프로그램

본장에서는 지금까지 배운 C++를 이용하여 윈도우 프로그래밍을 하는 방법을 설명합니다. 본장에서 작성하는 예제는 Win32 SDK를 이용한 C++프로그램입니다.

본장에서는 C++ 로 윈도우 프로그램을 작성하는 기본적인 방법만을 제공합니다. 더욱 발전된 C++프로그래밍은 MFC편에서 자세히 다룰것입니다. 본장에서 만든 예제는 CpApiWin입니다.

1.CpApiWin의 구성형태

CpApiWind 예제에서는 두 개의 클래스를 사용합니다. 이 두 개의 클래스가 CWinApi클래스와 CMainFrame클래스입니다. CWinApi클래스는 프로그램을 총괄관리하는 클래이며 CMainFrame클래스는 출력되는 윈도우를 컨트롤 하는 클래스입니다.

CpApiWin 프로젝트를 Win32 Application으로 만듭니다. 이렇게 만든다음 5개의 파일을 프로젝트에 설정합니다. 이 5개의 파일은 다음과 같습니다.

CWinApi.h : CWinApi 클래스를 정의한 헤더

CWinApi.cpp : CWinApi 클래스의 맴버함수 내용

CMainFrame.h : CMainFrame 클래스를 정의한 헤더

CMainFrame.cpp : CMainFrame 클래스의 맴버 함수내용

(그림 1) CpApiWin 프로그램 구성

SDK로 작성한 윈도우 프로그램은 크게 두 개로 나눌수 있습니다. 하나는 윈도우 클래스를 등록하는 WinMain함수와 이것과 연결된 프로시저함수입니다. CpApiWin은 그림1과 같은 형식으로 프로그램이 작성되었습니다. WinMain에서 윈도우클래스에 정보를 등록하는 RegisterClassEx 가 실행되는 부분은 CWinApi에서 실행을 하고 CreateWindow 함수는 CMainFrame에 설정되어 있습니다. 즉 윈도우에 관계되는 내용은 모둔 CMainFrame클래스에 그리고 커널에 등록하는 부분은 CWinApi에 설정을 한것입니다. CpApiWin에서는 프로시적가 메인 프로시저 한 개만 두었습니다. 이메인 프로시저에서 메시지가 전달될 때 수행하는 부분은 CWinApi 클래스와 CMainFrame에서 둘다 처리되게 하였습니다. 예를 들어서 WM_PAINT 메시지가 발생되면 먼저 CWinApi의 OnPaint()함수가 실행된후 다시 MainFrame에 OnPaint()함수 가 실행되게 한것입니다.

C++로 프로그램을 작성할때는 이런 구조를 먼저 생각해야 합니다. 구조에 따라서 클래스의 맴버와 맴버 함수가 결정되기 때문입니다.

CWinApi 클래스

CWinApi클래스의 헤더는 다음과 같이 설정하였습니다. 이헤더를 설정하는 파일은 CWinApi.h입니다. 보통 클래스 헤더를 설정할경우에는 확장자가 h인 파일에 기록하는 것이 일반적입니다.

//CWinApi.h

//CWinApi 클래스

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

class CWinApi{

protected:

WNDCLASSEX  wndclass ; //윈도우 클래스 맴버

HINSTANCE hInstance;//윈도우 인스턴스

char *AppName;//어플리케이션 이름

int iShow;//화면 출력방법

UINT messagelist[5];//CWinApi에서 처리할 메시지 리스트

public:

//메인 윈도우 클래스

CMainFrame *m_pMainWnd;

CWinApi();//생성자

~CWinApi();//소멸자

//윈도우 인스턴스 초기화 루틴

void InitInstance(HINSTANCE hinst,char *name,int iCmdShow,

char *menuname=NULL);

//프로시저 전체 처리루틴

LRESULT Proc(HWND hwnd,UINT iMsg,WPARAM wParam,

LPARAM lParam);

//종료하기

LRESULT OnExit();

//WM_PAINT메시지가 발생시 실행하는 함수

LRESULT OnPaint(HWND hwnd,UINT iMsg,

WPARAM wparam,LPARAM lParam);

//WM_CREATE메시지가 발생시 실행하는 함수

LRESULT OnCreate(HWND hwnd,UINT iMsg,

WPARAM wParam,LPARAM lParam);

//WM_CLOSE메시지가 발생시 실행하는 함수

LRESULT OnClose(HWND hwnd,UINT iMsg,

WPARAM wParam,LPARAM lParam);

//WM_COMMAND메시지가발생시 실행하는 함수

LRESULT OnCommand(HWND hwnd,UINT iMsg,

WPARAM wParam,LPARAM lParam);

int FindMessage(UINT iMsg);//메시지가 있는가 검색

};

CMainFrame *m_pMainWnd 는 바로 메인프레임을 관리하는 클래스형을 변수로 선언한것입니다. 보통 맴버변수는 protected에 설정하지만 때로는 public에 설정할경우도 있습니다. 본예가 그런 방법중에 하나입니다. m_pMainWnd는 단순한 형이 아니라 클래스입니다. 클래스라는 것은 그 클래스안에 또다른 함수들이 내장되어 있다는 것입니다. 그 함수들을 사용하기 위해서는 protected보다는 public에 설정하는 것이 좋기 때문입니다. InitInstance 함수의 기능은 윈도우에 클래스를 등록하는 내용을 담은것입니다. 첫 번째 인자는 윈도우 인스턴스 핸들이며 두 번째 인자는 어플리케이션 이름이며 3번째 인자는 윈도우를 출력시키는 방법 플러그입니다.4번째인자는 메뉴명인데 인자에 =NULL를 설정하면 이 인자를 사용하지 않았을경우에는 NULL로 설정된다는것입니다. 예를 들면 다음두가지 방법으로 InitInstance함수를 사용할수 있습니다.

m_pApp->InitInstance(hInstance,"CpApiWin",iCmdShow,"MENU");

m_pApp->InitInstance(hInstance,"CpApiWin",iCmdShow);

"MENU"를 설정하면 메뉴명이 설정되는것이며 이 인자가 없는 두 번째 방법을 사용하면 hMenu에는 NULL이 설정되는 형태입니다. 일반적으로 윈도우에서는 옵션과 인자가 매우 많습니다.(지금까지 프로그램을 해왔다면 피부로 느끼는 이야기 일것입니다.) 이런 인자들중에 사용이 필요없을 경우 NULL를 하는 경우가 매우 많습니다. C++로 작성할경우에는 함수자체의 인자에 =NULL이라는 값을 미리 설정하여 사용이 필요없는 인자들은 자동적으로 NULL이 설정되도록 합니다.

InitInstance 함수의내부를 보면 다음과 같습니다.

void CWinApi::InitInstance(HINSTANCE hinst,char *name,int iCmdShow,char *menuname)

{

strcpy(AppName,name);

hInstance=hinst;

wndclass.cbSize        = sizeof (wndclass) ;

wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

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 = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName  = menuname ;

wndclass.lpszClassName = AppName ;

wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;

RegisterClassEx (&wndclass) ;

iShow=iCmdShow;

}

InitInstance함수는 WinMain에서 넘겨준 iCmdShow와 hInstance값과 그리고 어플리케이션 이름은 protected에 정의된 맴버 변수에 넘겨주고 WNDCLASSEX 의 변수인 wndclass 에 정보를 설정하고 RegisterClassEx함수를 실행하여 등록을 한것입니다. 즉 InitInstance함수는 WinMain의 첫 번째 스텝을 그대로 함수화 한것입니다.  OnPaint와 OnCreate,OnCommand,OnClose등은 메시지에 의해서 실행되는 함수들입니다. 그림 1에서 설명하였듯이 메시지가 발생되면 우선 CWinApi에 있는 함수들이 실행되고 다시 CMainFrame에 설정된 함수들이 실행됩니다. 따라서 CWinApi의 On계열의 함수는 자신의 내용이 실행된후 CMainFrame 형이 m_pMainWnd의 On계열의 함수를 호출하는 방식으로 설정되어야 합니다.

다음은 On계열중 OnCreate함수입니다.

LRESULT CWinApi::OnCreate(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

//자신의 내용 수행을 이곳에 코딩

//메인 윈도우의 OnCreate를 호출한다.

m_pMainWnd->OnCreate(hwnd,iMsg,wParam,lParam);

return 1;

}

CpApiWin의  OnCreate에서 할 일은 사실 없습니다. 따라서 단순히 m_pMainWnd의 OnCreate함수를 호출한 것으로 끝냈습니다. 만일 OnCreate함수에서 처리해야할 일이 있다면 m_pMainWnd의 OnCreate함수를 호출하기 바로 위에 내용을 코딩해주면 됩니다.

메시지 프로시저 처리

C++로 전환할 때 가장 문제점이 바로 메시지 프로시저입니다. 메시지 프로시저는 보통 다음과 같은 switch문으로 처리되고 있습니다.

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

HDC         hdc ;

PAINTSTRUCT ps ;

switch (iMsg)

{

case WM_CREATE :

:

return 0 ;

case WM_PAINT :

:

return 0 ;

case WM_DESTROY :

:

return 0 ;

}

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

}

또한 프로시저함수는 WinMain과 같이 C언어 함수로 클래스에 등록되어 있지 않습니다. 이함수를 클래스에 등록하고자 한다면 아마 friend기능을 사용해야 할것입니다. 어떻든 등록이 된다 하여도 switch문으로 되어 있는 것을 C++의 각 함수로 분리 한다면 일반 프로시저함수를 하나두고 다음과 같은 방법을 사용한다는 것이 일반적인 생각일것입니다.

switch (iMsg)

{

case WM_CREATE :

OnCreate(...)//맴버함수 OnCreate호출

return 0 ;

case WM_PAINT :

OnPaint(...)//맴버 함수 OnPaint호출

return 0 ;

case WM_DESTROY :

OnClose(...) //맴버 함수 OnClose호출

return 0 ;

:

}

만약 메시지를 핸들링하는 내용이 200개이라면 위의 스위치 문을 이용하여 200개의 나열이 필요합니다. 보기에도 좋지 않을뿐만 아니라 메시지 처리시에 로드가 걸려 복잡한 프로그램일 경우 메시지를 놓칠 경우도 있을수 있습니다. 이럴 경우 콜백함수를 이용할수 있으나 본장에서는 조금 다르게 함수포인터를 이용하고자 합니다.

우리가 수행하고자하는 메지지 처리 함수들이 있다면 이함수들을 적재할 함수배열을 만듭니다.

LRESULT (*func[5])(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM	lParam);

위의 예는 5개의 메시지 처리를 하는 함수 배열입니다. 만약 100개의 메시지를 처리하고자 한다면 100개의 함수 배열을 만들면 되고 몇기 인지 모르다 후에 설정하고자 한다면 *func[] 형태로 설정하고 후에 크기 만큼 메모리를 할당하여 설정하여 주면 됩니다.

이함수 배열에 각함수를 등록하는 것입니다.

func[0]=onCreate;//WM_CREATE일 경우 수행하는 함수

func[1]=onPaint;//WM_PAINT일 경우 수행하는 함수

func[2]=onClose;//WM_DESTROY일 경우 수행하는 함수

func[3]=onCommand;//WM_COMMAND일 경우 수행하는 함수

이와 같이 등록한다음 만일 WM_PAINT메시지가 발생되면 단순하게 func[2]의 함수를 호출하면 됩니다. func에 설정하는 함수는 클래스 맴버 함수가 아니라 일반 C용함수인 것이 좋습니다. (이유는 계속 설명하겠습니다)

//일반 C용으로 func[0]에 설정되는 함수

LRESULT onCreate(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

//CWinApi형의 변수인 m_pApp의 OnCreate를 설정한다.

m_pApp->OnCreate(hwnd,iMsg,wParam,lParam);

return 1;

}

onCreate라는 함수는 CWinApi 클래스의 OnCreate함수를 호출하는 것으로 끝납니다. 이렇게 하기 위해서는 CWinApi클래스이 변수를 전역변수로 설정해야 합니다. CpApiWin.cpp에서는 m_pApp를 다음과 같이 정의하였습니다.

CWinApi *m_pApp;

또한 위의 내용이 설정된 CWinApi.cpp에서는 위의 변수와 연결되기 위해서 extern으로 다음과 같이 설정하였습니다.

extern CWinApi *m_pApp;

이렇게 설정된 m_pApp를 C함수에서 호출하는 것입니다.

func배열에 등록되어 있는 함수가 어떤 메시지일때 수행되는가를 설정하기 위해서 CWinApi에는 메시지 정보를 가지고 있는 배열 UINT messagelist[5]를 설정하였고 이곳에 다음과 같이 메시지를 넣었습니다.

messagelist[0]=WM_CREATE;

messagelist[1]=WM_PAINT;

messagelist[2]=WM_DESTROY;

messagelist[3]=WM_COMMAND;

만일 메시지가 들어왔을 경우 먼저 messgelist에 현재의 메시지가 있는가를 확인하고 있다면 func의 해당 배열 함수를 호출하고 없을경우에는 DefWindowProc를 호출하는 방식을 택하면 편리하게 메시지를 처리할수 있습니다.

예를 들어서 WM_PAINT메시지가 날아오면 면저 messgelist배열을 검색하여 1번이라는 값을 얻고 func[1]를 실행시키면 됩니다. 만일 WM_LBUTTONDOWN이라는 메시지가 발생되었을때는 messagelist배열에는 없기 때문에 그냥 DefWindowProc를 호출하면 됩니다.

다음은 메시지를 이용하여 현재 messagelist에 메시지가 있으면 번호를 메시지가 없으면 음수값을 리턴하는 FindMessage 함수입니다.

int CWinApi::FindMessage(UINT iMsg)//메시지가 있나 없나를 확인

{

int i;

for(i=0;i<4;i++)

if(messagelist[i]==iMsg)//메시지가 배열에 있으면

return i;//해당번호를 리턴

return -1;.//없으면 -1를 리턴

}

Proc함수는 FindMessage를 실행시켜서 메시지가 배열에 있으면 func함수를 호출하고 배열에 없으면 DefWindowProc를 호출합니다. 이함수는 다음과 같습니다.

LRESULT CWinApi::Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

int num;

//메시지를 찾고

num=FindMessage(iMsg);

if(num>0)//메시지가 배열에 있으면

{

//func함수 호출

func[num](hwnd,iMsg,wParam,lParam);

}

else//없으면 DefWindowProc를 수행시킨다.

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

return 1;

}

본장에서 제작한 CWinApi 클래스와 함수배열을 이용한 func는 매우 간단한 형태로 메시지를 분리한 방법입니다. 메시지 처리를 자동적으로 함수로 처리하는 방법은 좀더 다양한 방법이 제안될수 있습니다.

현재는 CWinApi만을 func 배열함수에서 호출하고 있습니다. 이것을 방법을 달리하여 메시지만 받는 함수를 CMessage라는 클래슬 만들고 이것을 CWinApi가 상속을 받게 하였다면

CWinApi: public CMessage

{

메시지 처리를 하는 포인터를 다음과 같이 만들고

CMessage *p

이포인터에 링크할 클래스 포인터를 넘겨주는 함수를 다음과 같이 설정합니다.

SetMessageClass(CMessage *data)

{

p=data;

}

위와 같이 하고 메시지를 처리하고 싶은 클래스는 모두 CMessage를 상속받은 클래스로 만들면 됩니다.

CWinApi클래스와 CMainFrame클래스가 모두 CMessage클래스를 상속받았다고 가정을 하고 이번에는 CMainFrame클래스가 메시지를 처리하고 싶다면

//m_pMainWnd는 CMainFrame형의 클래스임

SetMessageClass((CMessage*)m_pMainWnd);

형태로 설정하면 func에서 호출하는 함수들은 모두 m_pMainWnd에 설정되어 있는 것입니다.

이런 개념으로 매세지를 처리하는 함수를 포인터로 넘겨주게 하여서 switch문 형태를 제거하고 분리형태로 메시지를 처리할 수가 있습니다.

CMainFrame 클래스

CMainFrame 클래스의 형태는 CMainFrame.h에 설정되어 있습니다. 이내용은 다음과 같습니다.

//CMainFrame.h

//CMainFrame 클래스

class CMainFrame{

protected:

HWND hwnd;//윈도우 핸들

char *AppName;	//어플리케이션 명

HINSTANCE hInstance;//인스턴스

MSG         msg ;//메시지 구조체

int iShow;//화면에 출력할 형태 플러그

public:

CMainFrame();//생성자

~CMainFrame();//소멸자

//윈도우 만들기 함수

int Create(char *txt,DWORD style,int x,int y,int cx,int cy);

//WM_PAINT메시지가 발생되었을때 처리하는 함수

void OnPaint(HWND hWnd,UINT iMsg,WPARAM wParam,

LPARAM lParam);

//WM_CREATE 메시지가 발생되었을때 처리하는 함수

void OnCreate(HWND hwnd,UINT iMsg,WPARAM wParam,

LPARAM lParam);

//인스턴스와 어플리케이션 이름 화면 출력 플러그 설정함수

void SetAppName(char *app,HINSTANCE hinst,int show);

};

CMainFrame 클래스에서 가장 중요한 함수가 Create입니다. 이함수에서는 기본적인 윈도우를 만들고 메시지처리를 해줍니다. 이함수의 내용은 다음과 같습니다.

int CMainFrame::Create(char *title,DWORD style,int x,int y,int cx,int cy)

{

//윈도우를 만든다.

hwnd = CreateWindow (AppName,title,style,x,y,cx,cy,

NULL,NULL,

hInstance,

NULL);

ShowWindow (hwnd, iShow) ;

UpdateWindow (hwnd) ;

//메시지 처리루틴

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

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}

쉽게 보면 WinMain에서의 두 번째 스텝에 해당하는 부분이 Create에 설정 ehldj 있습니다. Create에서 넘겨주지 않는 인자 즉 인스턴스 핸들과 AppName그리고 iShow값은  SetAppName 함수에 의해서 설정하도록 하였습니다. 이함수의 내용은 다음과 같습니다.

void CMainFrame::SetAppName(char * app,HINSTANCE hinst,int show)

{

strcpy(AppName,app);

hInstance=hinst;

iShow=show;

}

Create함수를 수행하기 이전에 SetAppName를 호출해야만 합니다. 그렇지 않고서는 인스턴스와 AppName가 제대로 설정되지 않아 Error내면서 화면에 출력되지 않을 것입니다.  CMainFrame클래스에서 나머지 On계열 함수들은 메시지 처리함수이며 이것은 CWinApi클래스에서 호출하여 실행되게 되어 있습니다.

CpApiWin.cpp

CpApiWin.cpp는 WinMain과 WndProc가 설정되어 있는 메인 파일입니다. 소스를 먼저 보시고 설명을 드리겠습니다.

CWinApi *m_pApp;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

m_pApp= new CWinApi;//m_pApp설정

//인스턴스 초기화

m_pApp->InitInstance(hInstance,"CpApiWin",iCmdShow,"MENU");

//메인 프레임에 어플리케이션 이름과 인스턴스 설정

m_pApp->m_pMainWnd->SetAppName("CpApiWin",hInstance,iCmdShow);

//메인 프레임 Create함수 호출

return m_pApp->m_pMainWnd->Create("CpApiWin 예제",WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT);

}

//윈도우 프로시저

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{	//CWinApi형인 m_pApp의 프로시저 함수를 호출하면서 끝낸다

return m_pApp->Proc(hwnd,iMsg,wParam,lParam);

}

제일먼저 CWinApi형인 m_pApp라는 클래스를 만들고 이클래스의 InitInstance함수를 호출하여 초기화를 하고 m_pApp의 맴버 변수인 CMainFrame형인 m_pMainWnd의 SetAppName와 Create함수를 호출함으로써 WinMain의기능을끝냅니다. WndProc에서는 단순하게 m_pApp의 Proc를 호출함으로써끝냅니다.

결국 메인은 매우 짧습니다. 그이유는 모든 처리가 CWinApi와 CMainFrame에서 수행되고 메인 은 단순하게 CWinApi와 CMainFrame클래스의 변수를 만들고 몇 개의 설정함수를 호출하는것이기 때문입니다.

CpApiWin 프로그램 소스

//CWinApi.h

//CWinApi 클래스

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

class CWinApi{

protected:

WNDCLASSEX  wndclass ;

HINSTANCE hInstance;

char *AppName;

int iShow;

UINT messagelist[5];

public:

int FindMessage(UINT iMsg);

CWinApi();

~CWinApi();

LRESULT Proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

LRESULT OnExit();

CMainFrame *m_pMainWnd;

LRESULT OnPaint(HWND hwnd,UINT iMsg,WPARAM wparam,LPARAM lParam);

LRESULT OnCreate(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

LRESULT OnClose(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

LRESULT OnCommand(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

void InitInstance(HINSTANCE hinst,char *name,int iCmdShow,char *menuname=NULL);

void AddFrame(char *winname);

};

///////////////////////////////////////

//CWinApi.cpp

//CWinApi 클래스 함수

#include <windows.h>

#include "CMainFrame.h"

#include "CWinApi.h"

#include "resource.h"

//메시지 처리 함수 배열

static  LRESULT (*func[5])(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

extern CWinApi *m_pApp;

//func배열에 설정할 C함수

LRESULT onCreate(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

m_pApp->OnCreate(hwnd,iMsg,wParam,lParam);

return 1;

}

LRESULT onPaint(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

m_pApp->OnPaint(hwnd,iMsg,wparam,lParam);

return 1;

}

LRESULT onCommand(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

return m_pApp->OnCommand(hwnd, iMsg, wparam, lParam);

}

LRESULT onClose(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

return m_pApp->OnCommand(hwnd, iMsg, wparam, lParam);

}

//func 배열

//////////////////////////////////////////////

CWinApi::CWinApi()

{

AppName= new char[80];

m_pMainWnd= new CMainFrame;

func[0]=onCreate;

func[1]=onPaint;

func[2]=onClose;

func[3]=onCommand;

messagelist[0]=WM_CREATE;

messagelist[1]=WM_PAINT;

messagelist[2]=WM_DESTROY;

messagelist[3]=WM_COMMAND;

}

CWinApi::~CWinApi()

{

delete AppName;

delete m_pMainWnd;

}

void CWinApi::InitInstance(HINSTANCE hinst,char *name,int iCmdShow,char *menuname)

{

strcpy(AppName,name);

hInstance=hinst;

wndclass.cbSize        = sizeof (wndclass) ;

wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

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 = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName  = menuname ;

wndclass.lpszClassName = AppName ;

wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;

RegisterClassEx (&wndclass) ;

iShow=iCmdShow;

}

LRESULT CWinApi::OnCreate(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

m_pMainWnd->OnCreate(hwnd,iMsg,wParam,lParam);

return 1;

}

LRESULT CWinApi::OnPaint(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

m_pMainWnd->OnPaint(hwnd,iMsg,wparam,lParam);

return 1;

}

LRESULT CWinApi::OnCommand(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

switch(LOWORD(wparam))

{

case ID_EXIT:

OnExit();

return 1;

}

return 0;

}

LRESULT CWinApi::OnClose(HWND hwnd, UINT iMsg, WPARAM wparam, LPARAM lParam)

{

PostQuitMessage (0) ;

return 1;

}

LRESULT CWinApi::OnExit()

{

PostQuitMessage (0) ;

return 1;

}

LRESULT CWinApi::Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

int num;

num=FindMessage(iMsg);

if(num>0)

{

func[num](hwnd,iMsg,wParam,lParam);

}

else

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

return 1;

}

int CWinApi::FindMessage(UINT iMsg)

{

int i;

for(i=0;i<4;i++)

if(messagelist[i]==iMsg)

return i;

return -1;

}

//CMainFrame.h

//CMainFrame클래스

class CMainFrame{

protected:

HWND hwnd;

char *AppName;

HINSTANCE hInstance;

MSG         msg ;

int iShow;

public:

void OnPaint(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

void OnCreate(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);

void SetAppName(char *app,HINSTANCE hinst,int show);

CMainFrame();

~CMainFrame();

int Create(char *txt,DWORD style,int x,int y,int cx,int cy);

};

///////////////////////////////////////////////////////

//CMainFrame.cpp

//CMainFrame 클래스

#include <windows.h>

#include "CMainFrame.h"

CMainFrame::CMainFrame()

{

AppName= new char[80];

}

CMainFrame::~CMainFrame()

{

delete AppName;

}

int CMainFrame::Create(char *title,DWORD style,int x,int y,int cx,int cy)

{

hwnd = CreateWindow (AppName,title,style,x,y,cx,cy,

NULL,NULL,

hInstance,

NULL);

ShowWindow (hwnd, iShow) ;

UpdateWindow (hwnd) ;

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

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}

void CMainFrame::SetAppName(char * app,HINSTANCE hinst,int show)

{

strcpy(AppName,app);

hInstance=hinst;

iShow=show;

}

void CMainFrame::OnCreate(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

return;

}

void CMainFrame::OnPaint(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

HDC         hdc ;

PAINTSTRUCT ps ;

hdc = BeginPaint (hWnd, &ps) ;

EndPaint (hWnd, &ps) ;

return;

}

//C++로 만드는 Api Window

//CpApiWin.c

#include <windows.h>

#include "CMainFrame.h"

#include "CWinApi.h"

#include "resource.h"

CWinApi *m_pApp;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

m_pApp= new CWinApi;

m_pApp->InitInstance(hInstance,"CpApiWin",iCmdShow,"MENU");

m_pApp->m_pMainWnd->SetAppName("CpApiWin",hInstance,iCmdShow);

return m_pApp->m_pMainWnd->Create("CpApiWin 예제",WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT);

}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

return m_pApp->Proc(hwnd,iMsg,wParam,lParam);

}

C++문법을 마치며

본장의 내용은 조금 복잡한 것 같아서 이해하기 힘든 분들도 있을지 모르겠습니다. 만약 그렇다 하더라도 너무 걱정을 하지 않으셨으면 합니다. 본장의 목적은 C++를 이용하여 윈도우 프로그래밍을 어떻게 하는가에 대한 간단한 소개이며 MFC구조를 이해하기 위한 형태입니다. 이부분에 대해서 약간만 이해하고 MFC로 넘어가셔도 됩니다.

본편으로 C++언어에 문법에 대한 설명을 마칩니다. 보통 일반 C++책보다 매우 작은 분량으로 이루어 졌을것입니다. 또한 설명하지 않은 부분들도 있습니다. 그러나 걱정을 하실 필요는 없습니다. C++에 대해서 설명한 일반 서는 모든 OS와 모든환경에서 프로그래밍하는 전체 내용을 다루었으며 본책에서는 윈도우 프로그래밍을 목표로 다루었기 때문에 작은 것입니다. 예를 들어서 영어회화가 주목적인 사람이 타임즈의 사설을 공부하고 문법책을 공부하며 세익스피어의 소설을 읽는다면 이것은 방법이 틀린것입니다. 영어회화가 목적이면 말하는 방법을 위해서 회화책을 중점으로 음성테이프나 비디오를 이용하여 공부를 해야 합니다. 영어공부라고 한다면 모든 것을 포함하는 형태이고 회화라는 접근하고자 한다면 분야가 작아집니다. 그리고 그분야를 집중적으로 공부해서 말하기와 듣기가 늘어나면 자동적으로 읽기도 늘어나고 그리고 쓰기도 후에 증가됩니다. 책을 읽는게 목적이라면 또 접근 방법이 다르게 됩니다. 프로그래밍도 같습니다. C++를 이용하여 윈도우 프로그램밍을 한다면 그 접근방법으로 가는것입니다. 이렇게 접근하여 윈도우 프로그래밍을 마스터한다면 C++언어에 대한 전반적인것도 마스터 할수 있는것입니다.