본문 바로가기
Information

MFC 윈도우 프로그래밍: 쉽고 빠르게 시작하기

by 127safymsfkasf 2025. 6. 1.

 

더 자세한 내용은 아래 참고 하세요~

 

더 자세한 자료 바로보기

 

MFC 윈도우 프로그래밍: 쉽고 빠르게 시작하기

 


목차

  1. MFC, 왜 배워야 할까요?
  2. MFC 개발 환경 설정: 첫걸음
  3. MFC 애플리케이션 기본 구조 이해하기
  4. 주요 컨트롤 다루기: UI 구축의 핵심
  5. 이벤트 처리: 사용자 상호작용 구현하기
  6. 대화 상자 프로그래밍: 복잡한 UI 구현
  7. 문서/뷰 아키텍처: 데이터와 UI의 분리
  8. MFC 디버깅: 문제 해결의 필수 과정
  9. 더 나아가기: 고급 MFC 기법

MFC, 왜 배워야 할까요?

MFC(Microsoft Foundation Class Library)는 마이크로소프트 윈도우 운영체제에서 동작하는 애플리케이션을 개발하기 위한 C++ 클래스 라이브러리입니다. 초보자에게는 다소 복잡하게 느껴질 수 있지만, 윈도우 API를 직접 다루는 것보다 훨씬 추상화되어 있어 개발 생산성을 크게 높여줍니다. MFC를 배우는 것은 단순히 윈도우 프로그램을 만드는 것을 넘어, 객체 지향 프로그래밍의 실제 적용 사례를 학습하고, 윈도우 운영체제의 동작 원리를 이해하는 데 큰 도움이 됩니다. 특히, 기존에 구축된 많은 레거시 시스템들이 MFC로 개발되어 있기 때문에, 관련 분야로 진출하려는 개발자에게는 필수적인 기술이라고 할 수 있습니다. 또한, 안정성과 성능이 검증되어 있어 여전히 많은 기업에서 사용되고 있으며, 윈도우 시스템과 깊이 연동되는 애플리케이션을 개발하는 데 매우 효과적입니다. MFC는 다양한 윈도우 컨트롤과 기능을 객체 형태로 제공하여 개발자가 복잡한 윈도우 메시지 처리나 핸들링을 직접 구현할 필요 없이 직관적으로 애플리케이션을 만들 수 있도록 돕습니다. 이는 개발 시간을 단축하고 코드의 가독성을 높이는 데 기여합니다.


MFC 개발 환경 설정: 첫걸음

MFC 프로그래밍을 시작하기 위해서는 Visual Studio 설치가 필수적입니다. Visual Studio는 마이크로소프트에서 제공하는 통합 개발 환경(IDE)으로, MFC 개발에 필요한 모든 도구와 라이브러리를 포함하고 있습니다. Visual Studio 설치 시에는 반드시 "C++를 사용한 데스크톱 개발" 워크로드를 선택해야 합니다. 이 워크로드에는 MFC 관련 구성 요소가 포함되어 있으므로, 이를 누락하면 MFC 프로젝트를 생성할 수 없습니다. 설치가 완료되면, Visual Studio를 실행하고 "새 프로젝트 만들기"를 선택합니다. 프로젝트 템플릿 목록에서 "MFC 앱"을 검색하여 선택한 후, 프로젝트 이름과 저장 경로를 지정하고 다음 단계를 진행합니다. MFC 앱 마법사는 애플리케이션의 종류(단일 문서, 다중 문서, 대화 상자 기반 등)와 사용할 기능(도킹 창, 리본 메뉴 등)을 설정할 수 있는 옵션을 제공합니다. 처음에는 가장 간단한 "대화 상자 기반" 애플리케이션을 선택하는 것이 학습에 용이합니다. 이 과정을 통해 기본적인 MFC 프로젝트 구조가 자동으로 생성되며, 개발자는 복잡한 초기 설정 없이 바로 코드 작성에 집중할 수 있습니다.


MFC 애플리케이션 기본 구조 이해하기

MFC 애플리케이션은 여러 클래스 간의 유기적인 상호작용으로 구성됩니다. 가장 핵심적인 클래스는 CWinApp, CFrameWnd, CView, CDocument, CDialog 등입니다.

  • CWinApp: 애플리케이션의 진입점 역할을 하며, 애플리케이션의 초기화 및 종료를 담당합니다. InitInstance() 멤버 함수에서 애플리케이션의 주요 객체들을 생성하고 초기화합니다. 모든 MFC 애플리케이션은 CWinApp을 상속받는 하나의 파생 클래스를 가집니다.
  • CFrameWnd: 메인 윈도우의 프레임을 관리하는 클래스입니다. 메뉴, 툴바, 상태 표시줄 등 윈도우의 기본적인 사용자 인터페이스 요소를 포함합니다. SDI(Single Document Interface) 애플리케이션에서는 CFrameWnd를 직접 사용하거나 파생시켜 메인 프레임을 구성하고, MDI(Multiple Document Interface) 애플리케이션에서는 CMDIFrameWndCMDIChildWnd를 사용합니다.
  • CView: 문서의 데이터를 화면에 표시하고 사용자 입력을 처리하는 역할을 합니다. 일반적으로 CDocument와 연동하여 데이터를 시각화합니다. OnDraw() 멤버 함수는 뷰의 클라이언트 영역에 그림을 그리는 역할을 합니다.
  • CDocument: 애플리케이션의 데이터를 관리하는 클래스입니다. 데이터의 로드, 저장, 변경 등의 작업을 수행합니다. Serialize() 멤버 함수를 통해 데이터를 파일로 직렬화하거나 역직렬화할 수 있습니다.
  • CDialog: 대화 상자를 나타내는 클래스입니다. 버튼, 에디트 박스, 콤보 박스 등 다양한 컨트롤을 포함하여 사용자로부터 입력을 받거나 정보를 표시하는 데 사용됩니다. 대화 상자 기반 애플리케이션에서는 CDialog를 메인 윈도우로 사용하기도 합니다.

이러한 클래스들은 서로 메시지를 주고받으며 애플리케이션의 전반적인 동작을 제어합니다. MFC는 메시지 맵(Message Map)이라는 메커니즘을 통해 윈도우 메시지와 해당 메시지를 처리할 멤버 함수를 연결합니다. 개발자는 메시지 맵에 매핑된 함수를 구현함으로써 특정 사용자 이벤트나 시스템 메시지에 반응하는 코드를 작성할 수 있습니다. 예를 들어, 버튼 클릭 시 특정 함수가 실행되도록 설정하는 것이 메시지 맵의 기본적인 활용 예시입니다.


주요 컨트롤 다루기: UI 구축의 핵심

MFC에서 사용자 인터페이스(UI)를 구축하는 핵심은 다양한 컨트롤(Control)을 활용하는 것입니다. Visual Studio의 리소스 뷰에서 대화 상자나 폼을 디자인할 때, 도구 상자(Toolbox)에서 원하는 컨트롤을 드래그 앤 드롭 방식으로 배치할 수 있습니다. 각 컨트롤은 CEdit, CButton, CListBox, CComboBox, CStatic 등 해당 컨트롤을 캡슐화하는 MFC 클래스와 연결됩니다.

  • CEdit (에디트 컨트롤): 텍스트를 입력하거나 표시하는 데 사용됩니다. GetWindowText()SetWindowText() 함수를 이용하여 텍스트를 가져오거나 설정할 수 있습니다. 다중 라인 입력, 숫자만 입력, 비밀번호 입력 등 다양한 스타일을 지정할 수 있습니다.
  • CButton (버튼 컨트롤): 클릭 이벤트를 발생시키는 기본적인 컨트롤입니다. ON_BN_CLICKED 메시지 맵 항목을 통해 클릭 이벤트를 처리합니다. 푸시 버튼, 라디오 버튼, 체크 박스 등 다양한 형태가 있습니다.
  • CListBox (리스트 박스): 항목 목록을 표시하고 사용자가 하나 또는 여러 항목을 선택할 수 있도록 합니다. AddString(), DeleteString(), GetCurSel(), GetText() 등의 함수를 사용하여 항목을 추가, 삭제하거나 선택된 항목의 정보를 얻을 수 있습니다.
  • CComboBox (콤보 박스): 에디트 컨트롤과 리스트 박스가 결합된 형태로, 텍스트 입력과 항목 선택을 동시에 제공합니다. 드롭다운 리스트 형태나 단순 콤보 박스 형태로 사용할 수 있습니다.
  • CStatic (정적 텍스트 컨트롤): 사용자 입력을 받지 않고 단순히 텍스트나 이미지를 표시하는 데 사용됩니다. 레이블이나 정보 메시지를 표시할 때 유용합니다.

각 컨트롤을 대화 상자나 폼에 배치한 후에는, 해당 컨트롤과 상호작용하기 위해 변수 연결(Associate Variable) 기능을 사용합니다. 컨트롤을 선택하고 마우스 오른쪽 버튼을 클릭하여 "변수 추가"를 선택하면, 컨트롤의 ID와 매핑되는 멤버 변수를 클래스에 추가할 수 있습니다. 이 멤버 변수를 통해 코드에서 컨트롤의 속성을 제어하거나 값을 가져올 수 있습니다. 예를 들어, CEdit 컨트롤에 연결된 CString 타입의 멤버 변수를 통해 에디트 박스의 텍스트를 쉽게 읽고 쓸 수 있습니다.


이벤트 처리: 사용자 상호작용 구현하기

MFC에서 사용자 상호작용은 이벤트 처리(Event Handling)를 통해 이루어집니다. 윈도우 운영체제는 사용자의 마우스 클릭, 키보드 입력, 윈도우 크기 변경 등 다양한 사건들을 메시지(Message) 형태로 애플리케이션에 전달합니다. MFC는 이러한 메시지를 효율적으로 처리하기 위해 메시지 맵(Message Map)이라는 메커니즘을 사용합니다.

메시지 맵은 클래스 정의 내에 선언되며, 특정 메시지 ID와 해당 메시지를 처리할 멤버 함수를 연결하는 테이블 역할을 합니다. Visual Studio의 클래스 뷰에서 특정 클래스를 선택하고 속성(Properties) 창을 열면, 해당 클래스가 처리할 수 있는 다양한 메시지 목록을 볼 수 있습니다. 예를 들어, 버튼 클릭 이벤트는 BN_CLICKED 메시지로, 윈도우 생성 이벤트는 WM_CREATE 메시지로 전달됩니다.

개발자는 처리하고자 하는 메시지를 선택한 후, 해당 메시지에 대한 메시지 핸들러(Message Handler) 함수를 추가할 수 있습니다. Visual Studio는 이 과정을 자동화해줍니다. 메시지 핸들러 함수는 특정 메시지가 발생했을 때 자동으로 호출되며, 개발자는 이 함수 안에 원하는 동작을 구현합니다. 예를 들어, "확인" 버튼이 클릭되었을 때 특정 연산을 수행하거나, "닫기" 버튼이 클릭되었을 때 애플리케이션을 종료하는 코드를 메시지 핸들러 안에 작성할 수 있습니다.

메시지 맵의 구조는 다음과 같습니다:

BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
    ON_BN_CLICKED(IDC_MY_BUTTON, &CMyDialog::OnBnClickedMyButton)
    ON_WM_PAINT()
END_MESSAGE_MAP()

위 코드에서 ON_BN_CLICKED는 버튼 클릭 메시지를 처리하겠다는 매크로이며, IDC_MY_BUTTON은 버튼 컨트롤의 ID, &CMyDialog::OnBnClickedMyButton은 해당 메시지를 처리할 멤버 함수를 의미합니다. ON_WM_PAINT()는 윈도우 그리기 메시지를 처리하는 예시입니다. 메시지 핸들러 함수는 일반적으로 afx_msg 키워드를 사용하여 선언되며, 특정 형식의 매개변수를 가집니다. MFC는 이러한 메시지 맵을 통해 윈도우 메시지를 효율적으로 디스패치하여 개발자가 메시지 루프를 직접 구현할 필요 없이 이벤트 기반 프로그래밍을 할 수 있도록 지원합니다.


대화 상자 프로그래밍: 복잡한 UI 구현

대화 상자(Dialog Box)는 MFC 애플리케이션에서 사용자로부터 정보를 입력받거나 특정 메시지를 표시하는 데 가장 흔히 사용되는 UI 요소입니다. 대화 상자는 크게 모달(Modal) 대화 상자모덜리스(Modeless) 대화 상자로 나눌 수 있습니다.

  • 모달 대화 상자: 대화 상자가 닫히기 전까지는 부모 윈도우와의 상호작용을 차단합니다. 즉, 대화 상자가 떠 있는 동안에는 부모 윈도우의 다른 컨트롤을 조작할 수 없습니다. 사용자에게 반드시 응답해야 하는 중요한 정보를 전달하거나 필수적인 입력을 받을 때 사용됩니다. DoModal() 함수를 호출하여 모달 대화 상자를 띄웁니다. 함수 호출 후, 대화 상자가 닫힐 때까지 프로그램 흐름이 멈추게 됩니다.
  • 모덜리스 대화 상자: 대화 상자가 떠 있는 동안에도 부모 윈도우와 계속 상호작용할 수 있습니다. 찾기/바꾸기 대화 상자처럼 사용자가 다른 작업을 하면서도 대화 상자의 기능을 사용할 수 있도록 할 때 유용합니다. Create() 함수를 호출하여 모덜리스 대화 상자를 생성하고, ShowWindow() 함수를 통해 화면에 표시합니다. 모덜리스 대화 상자는 생성된 후에도 프로그램 흐름이 계속됩니다.

Visual Studio의 리소스 편집기에서 대화 상자 템플릿을 생성한 후, 원하는 컨트롤들을 배치하여 디자인합니다. 각 컨트롤에는 고유한 컨트롤 ID가 부여되며, 이 ID를 통해 코드에서 컨트롤을 식별하고 접근할 수 있습니다. 대화 상자에 컨트롤을 배치한 후에는, 클래스 마법사(Class Wizard)를 사용하여 대화 상자 클래스와 컨트롤에 대한 멤버 변수 및 메시지 핸들러를 편리하게 추가할 수 있습니다. 예를 들어, 확인(OK) 버튼의 BN_CLICKED 메시지에 대한 핸들러를 추가하여 OnOK() 함수를 오버라이드하고, 취소(Cancel) 버튼에 대해서는 OnCancel() 함수를 오버라이드하여 대화 상자가 닫힐 때의 동작을 제어할 수 있습니다. OnInitDialog() 함수는 대화 상자가 초기화될 때 호출되므로, 여기에 초기값 설정이나 컨트롤 초기화 코드를 작성합니다. UpdateData(FALSE)는 컨트롤의 값을 멤버 변수로 업데이트하고, UpdateData(TRUE)는 멤버 변수의 값을 컨트롤에 반영하는 데 사용됩니다.


문서/뷰 아키텍처: 데이터와 UI의 분리

MFC의 문서/뷰 아키텍처(Document/View Architecture)는 애플리케이션의 데이터를 관리하는 부분(문서)과 데이터를 화면에 표시하는 부분(뷰)을 분리하여 설계하는 강력한 디자인 패턴입니다. 이는 코드의 재사용성을 높이고 유지보수를 용이하게 하며, 여러 뷰에서 동일한 문서를 공유할 수 있도록 합니다.

  • CDocument: 애플리케이션의 핵심 데이터를 캡슐화합니다. 파일 열기, 저장, 데이터 수정 등 데이터와 관련된 모든 로직은 CDocument 파생 클래스에 구현됩니다. 예를 들어, 그림판 애플리케이션에서는 그림 데이터(점, 선, 도형 정보)가 문서 객체에 저장될 수 있습니다. Serialize() 멤버 함수는 문서의 데이터를 파일로 직렬화하거나 파일에서 역직렬화하는 데 사용됩니다. UpdateAllViews() 함수는 문서의 데이터가 변경되었을 때 연결된 모든 뷰에 데이터 변경을 알리는 역할을 합니다.
  • CView: CDocument에 저장된 데이터를 화면에 시각적으로 표현합니다. 사용자로부터의 입력을 처리하고, 필요에 따라 문서의 데이터를 변경하도록 요청합니다. 예를 들어, 그림판 애플리케이션에서는 뷰 객체가 문서에 저장된 그림 데이터를 화면에 그려주고, 사용자의 마우스 클릭이나 드래그 이벤트를 처리하여 그림 데이터를 수정하는 기능을 제공합니다. OnDraw() 멤버 함수는 뷰의 클라이언트 영역에 그림을 그리는 역할을 하며, 문서 객체로부터 데이터를 가져와 화면에 그립니다. 뷰는 또한 OnUpdate() 함수를 통해 문서의 변경 사항을 통보받고, 화면을 다시 그릴지 여부를 결정합니다.

문서/뷰 아키텍처는 특히 데이터 지향적인 애플리케이션에 적합합니다. 예를 들어, 워드 프로세서, 스프레드시트, 그래픽 편집기 등은 모두 문서/뷰 아키텍처의 좋은 예시가 됩니다. 이 아키텍처를 통해 개발자는 데이터 관리 로직과 UI 표시 로직을 명확하게 분리하여 각 부분을 독립적으로 개발하고 테스트할 수 있습니다. 또한, 하나의 문서에 대해 여러 가지 다른 뷰(예: 표 뷰, 차트 뷰)를 제공하거나, MDI(Multiple Document Interface) 애플리케이션에서 여러 문서 인스턴스를 관리하는 데 효과적입니다. MFC 애플리케이션 마법사를 통해 SDI 또는 MDI 애플리케이션을 생성하면, 문서/뷰 아키텍처의 기본 골격이 자동으로 생성되어 개발자가 복잡한 초기 설정을 직접 할 필요 없이 바로 개발에 착수할 수 있습니다.


MFC 디버깅: 문제 해결의 필수 과정

MFC 애플리케이션 개발 과정에서 발생하는 오류를 찾아내고 수정하는 디버깅(Debugging)은 필수적인 과정입니다. Visual Studio는 강력한 디버깅 기능을 제공하여 개발자가 효율적으로 문제를 해결할 수 있도록 돕습니다.

  • 중단점(Breakpoint) 설정: 특정 코드 라인에서 프로그램 실행을 일시 중지하고 싶을 때 사용합니다. 코드 라인 번호 옆을 클릭하거나 F9 키를 눌러 중단점을 설정할 수 있습니다. 프로그램이 중단점에서 멈추면, 해당 시점의 변수 값, 메모리 상태, 호출 스택 등을 확인할 수 있습니다.
  • 단계별 실행(Step-by-step Execution): 프로그램이 중단점에서 멈춘 후, 다음 코드 라인으로 한 단계씩 실행하면서 프로그램의 흐름을 추적할 수 있습니다.
    • F10 (프로시저 단위 실행): 함수 내부로 진입하지 않고 함수 전체를 한 단계로 실행합니다.
    • F11 (한 단계씩 코드 실행): 함수 내부로 진입하여 함수 내부의 코드를 한 단계씩 실행합니다.
    • Shift+F11 (프로시저 나가기): 현재 함수 실행을 완료하고 호출 지점으로 돌아갑니다.
  • 변수 확인: 디버깅 중에는 조사식(Watch) 창, 자동(Autos) 창, 지역(Locals) 창 등을 통해 변수의 현재 값을 실시간으로 확인할 수 있습니다. 이를 통해 변수에 예상치 못한 값이 할당되거나 변경되는 시점을 찾아낼 수 있습니다.
  • 호출 스택(Call Stack): 현재 함수가 어떤 함수에 의해 호출되었는지, 즉 함수 호출의 경로를 보여줍니다. 이를 통해 프로그램의 흐름을 역추적하여 오류의 근원지를 찾아낼 수 있습니다.
  • 출력 창(Output Window): 디버깅 메시지, 오류 메시지, 경고 메시지 등이 표시됩니다. OutputDebugString() 함수를 사용하여 개발자가 직접 디버깅 메시지를 출력할 수도 있습니다.
  • 메모리 뷰(Memory View): 특정 메모리 주소의 내용을 직접 확인하여 메모리 관련 문제를 분석할 때 유용합니다. 포인터 오류나 메모리 누수 등을 파악하는 데 도움이 됩니다.

효과적인 디버깅을 위해서는 문제 발생 시점을 정확히 파악하고, 관련된 코드 영역에 중단점을 설정한 후, 단계별 실행을 통해 변수 값의 변화를 주의 깊게 관찰해야 합니다. 또한, 오류 메시지나 경고 메시지를 무시하지 않고 면밀히 분석하는 것이 중요합니다. MFC 애플리케이션은 윈도우 메시지 처리와 객체 간의 상호작용이 복잡하게 얽혀 있기 때문에, 디버깅 도구를 적극적으로 활용하여 프로그램의 내부 동작을 이해하는 것이 문제 해결에 큰 도움이 됩니다.


더 나아가기: 고급 MFC 기법

MFC의 기본적인 사용법을 익혔다면, 이제는 애플리케이션의 기능과 사용자 경험을 향상시킬 수 있는 고급 기법들에 도전해볼 차례입니다.

  • GDI/GDI+를 이용한 그래픽 프로그래밍: MFC는 윈도우의 그래픽 장치 인터페이스인 GDI(Graphics Device Interface)GDI+를 캡슐화하는 클래스(CDC, CPen, CBrush, CBitmap 등)를 제공합니다. 이를 통해 애플리케이션에서 직접 선, 도형, 텍스트, 이미지 등을 그리고 표시할 수 있습니다. 예를 들어, 차트 그리기, 이미지 편집, 커스텀 컨트롤 구현 등 다양한 그래픽 관련 기능을 구현할 때 필수적입니다. OnDraw() 함수나 OnPaint() 함수에서 CDC 객체를 사용하여 그림을 그립니다.
  • 데이터베이스 연동 (ODBC/DAO/OLE DB): MFC는 ODBC(Open Database Connectivity), DAO(Data Access Objects), OLE DB(Object Linking and Embedding, Database) 등 다양한 데이터베이스 연동 기술을 지원하는 클래스를 제공합니다. CDatabase, CRecordset 등의 클래스를 사용하여 데이터베이스에 연결하고, 데이터를 쿼리하거나 수정, 삭제하는 기능을 구현할 수 있습니다. 이를 통해 복잡한 데이터 관리 시스템을 구축할 수 있습니다.
  • 네트워크 프로그래밍 (WinSock): MFC는 윈도우 소켓 API(WinSock)를 캡슐화하는 CSocket, CAsyncSocket 등의 클래스를 제공하여 네트워크 통신 기능을 구현할 수 있도록 합니다. 클라이언트/서버 애플리케이션, 채팅 프로그램, 파일 전송 프로그램 등 네트워크 기반의 기능을 개발할 때 활용됩니다.
  • 멀티스레딩(Multithreading): 사용자 인터페이스가 멈추는 것을 방지하면서 동시에 여러 작업을 수행해야 할 때 멀티스레딩 기법을 사용합니다. MFC는 CWinThread 클래스를 통해 스레드를 쉽게 생성하고 관리할 수 있도록 지원합니다. 예를 들어, 시간이 오래 걸리는 연산이나 파일 다운로드 등의 작업을 백그라운드 스레드에서 처리하고, 메인 UI 스레드는 사용자 상호작용에 계속 응답하도록 구현할 수 있습니다.
  • ATL/COM 연동: MFC 애플리케이션은 ATL(Active Template Library)을 사용하여 COM(Component Object Model) 컴포넌트를 생성하거나 사용할 수 있습니다. COM은 윈도우 시스템에서 소프트웨어 컴포넌트 간의 상호 작용을 위한 표준 기술입니다. 이를 통해 다른 애플리케이션과 상호 운용성을 높이거나, 재사용 가능한 모듈을 만들 수 있습니다.
  • ActiveX 컨트롤 개발 및 사용: MFC는 ActiveX 컨트롤을 개발하거나 기존 ActiveX 컨트롤을 애플리케이션에 포함하여 사용할 수 있는 기능을 제공합니다. ActiveX 컨트롤은 웹 페이지나 다른 애플리케이션에 임베드될 수 있는 재사용 가능한 소프트웨어 컴포넌트입니다.
  • 리본 메뉴(Ribbon Menu) 및 도킹 창(Docking Pane): 최신 윈도우 애플리케이션의 UI 트렌드에 맞춰 리본 메뉴나 도킹 가능한 창(예: Visual Studio의 솔루션 탐색기)을 구현하는 것도 가능합니다. MFC는 이를 위한 클래스와 마법사를 제공하여 복잡한 UI를 쉽게 구현할 수 있도록 돕습니다.

이러한 고급 기법들을 익힘으로써 MFC를 사용하여 더욱 강력하고 효율적인 윈도우 애플리케이션을 개발할 수 있습니다. 각 기법들은 깊이 있는 학습과 실습을 요구하지만, MFC의 잠재력을 최대한 발휘하는 데 큰 도움이 될 것입니다.

 

더 자세한 내용은 아래를 참고하세요.

 

더 자세한 자료 보기