반응형

안녕하세요. 애드소프트 입니다.

 

저번 포스팅에서 갑자스럽게 윈도우 프로그래밍에 꽂혀서 코딩을 해보았는데 개념이 생각이 나지 않아 

다시 되세김 하고자 포스팅을 시작해 볼까 합니다.

 

MFC의 기본적인 클레스대한 이해를 돕고자한 포스팅이며 개인적인 지식이며, 잘 못된 내용이 포함되어 있을 수 있습니다.

 

기본적인 클레스

 

CWinApp - 앱 자체를 의미 합니다.

#include "resource.h"       // 주 기호입니다.


// CHelloWorldApp:
// 이 클래스의 구현에 대해서는 HelloWorld.cpp을(를) 참조하세요.
//

class CHelloWorldApp : public CWinAppEx
{
	public:
		CHelloWorldApp() noexcept;
    
    ...
}

해더 파일을 살펴 보면 CWinApp 이라는 클레스를 상속 받아 만들어졌음을 알 수 있습니다.

자제적으로 UI/UX를 표시하는 기능은 없으며, 프로그램의 초기화, 종료, 실행 등의 기능이 캡슐화 되어 있습니다.

모든 앱에는 하나의 WinApp만을 상속 받아 작성되어야 합니다.

주요적인 코드를 보면 메인프레임을 생성하고 Document Template를 통해 Document, MainFrame 및 뷰 사이를 연결하는 역활을 합니다.

    InitContextMenuManager();

	InitKeyboardManager();

	InitTooltipManager();
	CMFCToolTipInfo ttParams;
	ttParams.m_bVislManagerTheme = TRUE;
	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
		RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

	// 애플리케이션의 문서 템플릿을 등록합니다.  문서 템플릿은
	//  문서, 프레임 창 및 뷰 사이의 연결 역할을 합니다.
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CHelloWorldDoc),
		RUNTIME_CLASS(CMainFrame),       // 주 SDI 프레임 창입니다.
		RUNTIME_CLASS(ListViewSample));
		
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);


	// 표준 셸 명령, DDE, 파일 열기에 대한 명령줄을 구문 분석합니다.
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);



	// 명령줄에 지정된 명령을 디스패치합니다.
	// 응용 프로그램이 /RegServer, /Register, /Unregserver 또는 /Unregister로 시작된 경우 FALSE를 반환합니다.
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// 창 하나만 초기화되었으므로 이를 표시하고 업데이트합니다.
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	// 타이틀 수정
	m_pMainWnd->SetWindowTextW(L"Hello World");

 

CFrameWnd - CMainFrame

 

MFC를 이용하여 작성한 코드는 기본적으로 프레임 윈도우를 두고 거기에 차일드 윈도우들을 붙이는 형식입니다.

화면상에 보이는 부분은 대부분 프레임 윈도상에 구현된다고 보면 됩니다. 

// MainFrm.h: CMainFrame 클래스의 인터페이스
//

#pragma once

class CMainFrame : public CFrameWndEx
{
	
	protected: // serialization에서만 만들어집니다.
		CMainFrame() noexcept;
		DECLARE_DYNCREATE(CMainFrame)
    
    ...

}

CMainFrame의 클레스의 선언부를 보면 CFrameWnd를 상속 받아 구현된것을 볼 수 있습니다.

클레스 위자드에서 메서드를 보시면 OnCreate, OnToolbarCreateNew, OnViewCustomize 등과 같이 메시지 핸들러 함수가 등록되어 있는 것을 볼 수 있습니다.

대표적인 메시지로 WM_CREATE라는 함수가 발생하였을때 OnCreate가 실행되는 것입니다.

이 메시지는 생성될때 발생하는 메시지 입니다.

이 외에도 키보드 이벤트가 발생할때 WM_COMMAND, 뷰나 프로그램이 종료할때 WM_DESTROY, 화면에 무엇인가 그려질째 WM_PAINT등의 다양한 메시지가 존재합니다.

 

메시지 처리는 Win32API의 메시지 처리를 보시면 좀더 수월하게 이해 할 수 있으리라 생각합니다.

HINSTANCE hinst; 
HWND hwndMain; 
 
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpszCmdLine, int nCmdShow) 
{ 
    MSG msg;
    BOOL bRet; 
    WNDCLASS wc; 
    UNREFERENCED_PARAMETER(lpszCmdLine); 
 
    // Register the window class for the main window. 
 
    if (!hPrevInstance) 
    { 
        wc.style = 0; 
        wc.lpfnWndProc = (WNDPROC) WndProc; 
        wc.cbClsExtra = 0; 
        wc.cbWndExtra = 0; 
        wc.hInstance = hInstance; 
        wc.hIcon = LoadIcon((HINSTANCE) NULL, 
            IDI_APPLICATION); 
        wc.hCursor = LoadCursor((HINSTANCE) NULL, 
            IDC_ARROW); 
        wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
        wc.lpszMenuName =  "MainMenu"; 
        wc.lpszClassName = "MainWndClass"; 
 
        if (!RegisterClass(&wc)) 
            return FALSE; 
    } 
 
    hinst = hInstance;  // save instance handle 
 
    // Create the main window. 
 
    hwndMain = CreateWindow("MainWndClass", "Sample", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
        CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, 
        (HMENU) NULL, hinst, (LPVOID) NULL); 
 
    // If the main window cannot be created, terminate 
    // the application. 
 
    if (!hwndMain) 
        return FALSE; 
 
    // Show the window and paint its contents. 
 
    ShowWindow(hwndMain, nCmdShow); 
    UpdateWindow(hwndMain); 
 
    // Start the message loop. 
 
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    } 
 
    // Return the exit code to the system. 
 
    return msg.wParam; 
} 

위 코드는 Win32API를 사용하여 앱을 생성할때 사용되는 코드입니다.

 

 

이 코드 중에서 다음 코드가 메시지를 처리할때 사용하는 코드로 보시면 됩니다.

    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    } 

윈도우 메시지 큐에 메시지가 쌓으면 하나씩 빼내어 처리하는 FIFO 방식입니다.

 

MFC에서는 메시지가 발생할때 특정 기능을 추가하기 위해서는 가상함수 중 PreTranslateMessage를 통해 메시지를 후킹할 수 있으며, 다른 방법으로는 가상함수 중 WindowProc을 통해서도 가능합니다.

프레임 윈도우가 하는 역활은 툴바, 스테이터스바, 메뉴, 뷰 등과 같이 메시지가 발생할때 처리하는 역활을 합니다.

 

CWnd - 모든 윈도우는 CWnd상속 받아 생성된다.

 

CMainFrame도 CFrameWnd를 상속받아 생성된거 같지만 끝까지 따라가보면 CWnd를 상속 받아 생성 된것을 알 수 있습니다. 

따라서 CWnd 객체에 대해서 자세히 이해할 필요가 있습니다. 물론 더 상위에 대한 클레스에 대해 이해를 한다면 좋겠지만 현재 수준에서 상위 클래스를 이해하기도 어려울 뿐더라 아직은 윈도우에 대한 이해가 더 중요하므로 이부분을 중점적으로 이해 하는게 좋을 것으로 생각됩니다.

 

위에서 설명했듯이 Win32API 또한 윈도우 프로그래밍이기 때문에 둘 다 다뤄보면 일맥 상통하는 부분을 많이 찾을 수 있을 것입니다. 두개의 공통된 부분을 보면 많은 이해력이 생길 수 있으며, Win32코드로 MFC를 채울때도 존재합니다.

 

이번 포스팅은 MFC의 기본 클래스에 대해 알아보았습니다.

 

감사합니다.

 

반응형

+ Recent posts