연습: 기존 Windows 데스크톱 애플리케이션 만들기(C++)

이 연습에서는 Visual Studio에서 기존 Windows 데스크톱 애플리케이션을 만드는 방법을 보여 줍니다. 만든 애플리케이션은 Windows API를 사용하여 창에 "Hello, Windows 데스크톱!"을 표시합니다. 이 연습에서 개발하는 코드를 패턴으로 사용하여 Windows 데스크톱 애플리케이션을 만들 수 있습니다.

Windows API(Win32 API, Windows Desktop API 및 Windows 클래식 API라고도 함)는 Windows 애플리케이션을 만들기 위한 C 언어 기반 프레임워크입니다. 수십 년 동안 Windows 애플리케이션을 만드는 데 사용되었습니다. 더 고급적이고 쉽게 프로그래밍할 수 있는 프레임워크는 Windows API를 기반으로 빌드되었습니다. 예를 들어 MFC, ATL, .NET 프레임워크입니다. C++/WinRT로 작성된 UWP 및 스토어 앱에 대한 최신 Windows 런타임 코드조차도 아래의 Windows API를 사용합니다. Windows API에 대한 자세한 내용은 Windows API Index를 참조하세요.

Important

이 문서의 끝에 있는 코드 빌드 섹션에서는 전체 코드를 보여 줍니다. 이 연습에서는 Windows 앱으로 이동하는 다양한 코드 조각을 다루지만 코드 조각에서 일부 세부 정보를 생략하여 가장 중요한 부분에 집중하기 때문에 이동하면서 코딩하지 않습니다. 전체 코드를 복사하여 마지막에 프로젝트에 붙여넣을 수 있습니다.

필수 조건

  • Microsoft Windows 7 이상 버전을 실행하는 컴퓨터. 최상의 개발 환경을 위해서는 Windows 11이 권장됩니다.

  • Visual Studio 복사본. Visual Studio를 다운로드 및 설치하는 방법에 대한 자세한 내용은 Visual Studio 설치를 참조하세요. 설치 관리자를 실행할 때 C++를 사용한 데스크톱 개발 워크로드를 선택해야 합니다. Visual Studio를 설치할 때 이 워크로드를 설치하지 않은 경우 걱정하지 마세요. 설치 관리자를 다시 실행하고 바로 설치할 수 있습니다.

    Visual Studio 설치 관리자의 C++ 워크로드를 사용한 데스크톱 개발 스크린샷: Visual C++ 도구 집합의 기능을 사용하여 클래식 Windows 기반 앱 빌드

  • Visual Studio IDE 사용에 대한 기본적인 이해입니다. 이전에 Windows 데스크톱 앱을 사용한 경우 내용을 따라갈 수 있습니다. 소개 내용을 살펴보려면 Visual Studio IDE 기능 둘러보기를 참조하세요.

  • 내용을 따라가기에 충분한 C++ 언어의 기본 사항에 대한 이해. 너무 복잡한 내용을 다루지는 않으므로 걱정하지 마세요.

Windows 데스크톱 프로젝트 만들기

다음 단계에 따라 첫 번째 Windows 데스크톱 프로젝트를 만듭니다. 이 연습의 시작 부분에 있는 메모에 따라 완성된 코드는 연습의 끝에 있는 코드 빌드 섹션에서 사용할 수 있습니다. 계속 진행하여 프로젝트를 만드는 단계를 수행하지만 전체 애플리케이션 코드가 표시될 때까지 다음 코드 섹션의 붙여넣기를 보류합니다. 가장 중요한 부분에 집중하기 위해 코드 조각에서 일부 세부 정보를 생략합니다. 전체 코드를 복사하여 마지막에 프로젝트에 붙여넣을 수 있습니다.

설명을 간소화합니다. 기본 설정된 버전의 Visual Studio에 대한 설명서를 보려면 버전 선택기 컨트롤을 사용하세요. 이 페이지의 목차 맨 위에 있습니다.

Visual Studio에서 Windows 데스크톱 프로젝트를 만들려면

  1. 주 메뉴에서 파일>새로 만들기>프로젝트를 선택하여 새 프로젝트 만들기 대화 상자를 엽니다.

  2. 대화 상자 맨 위에서 언어C++로 설정하고 플랫폼Windows로 설정하고 프로젝트 형식데스크톱으로 설정합니다.

  3. 필터링된 프로젝트 형식 목록에서 Windows 데스크톱 마법사를 선택한 후 다음을 선택합니다. 다음 페이지에서 프로젝트의 이름(예: DesktopApp)을 입력합니다.

  4. 만들기 단추를 선택하여 프로젝트를 만듭니다.

  5. 이제 Windows 데스크톱 프로젝트 대화 상자가 나타납니다. 애플리케이션 유형 드롭다운에서 데스크톱 애플리케이션(.exe)을 선택해야 합니다. Windows 애플리케이션을 만들고 있으므로 콘솔 애플리케이션을 선택하면 사용할 코드에 따라 빌드되지 않는 프로젝트가 생성됩니다. 추가 옵션에서 빈 프로젝트를 선택합니다. 확인을 선택하여 프로젝트를 만듭니다.

  6. 솔루션 탐색기에서 DesktopApp 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 새 항목을 선택합니다.

    Visual Studio 2019에서 DesktopApp Project에 새 항목을 추가하는 방법을 보여 주는 애니메이션입니다.

    이 애니메이션은 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 표시되는 메뉴에서 추가를 선택한 다음 새 항목을 선택하는 것을 보여 줍니다.

  7. 새 항목 추가 대화 상자에서 C++ 파일(.cpp)을 선택합니다. 이름 상자에 파일의 이름(예: HelloWindowsDesktop.cpp)을 입력합니다. 추가를 선택합니다.

    Visual Studio 2019의 새 항목 추가 대화 상자 스크린샷. C++ 파일(.cpp) 옵션이 선택되어 있습니다. 이름 필드는 Hello Windows Desktop.cpp로 설정됩니다.

이제 프로젝트가 만들어지고 원본 파일이 편집기에서 열립니다.

Visual Studio 2017에서 Windows 데스크톱 프로젝트를 만들려면

  1. 파일 메뉴에서 새로 만들기, 프로젝트를 차례로 선택합니다.

  2. 새 프로젝트 대화 상자의 왼쪽 창에서 설치된>Visual C++를 확장 한 다음, Windows 데스크톱을 선택합니다. 가운데 창에서 Windows 데스크톱 마법사를 선택합니다.

    이름 상자에 프로젝트의 이름(예: DesktopApp)을 입력합니다. 확인을 선택합니다.

    Visual Studio 2017의 새 프로젝트 대화 상자 스크린샷. Windows 데스크톱 마법사 항목이 선택되어 있습니다. 이름 텍스트 상자에 DesktopApp이 표시됩니다.

  3. Windows 데스크톱 프로젝트 대화 상자의 애플리케이션 종류에서 Windows 애플리케이션(.exe)을 선택합니다. 추가 옵션에서 빈 프로젝트를 선택합니다. 미리 컴파일된 헤더가 선택되지 않았는지 확인합니다. 확인을 선택하여 프로젝트를 만듭니다.

  4. 솔루션 탐색기에서 DesktopApp 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 새 항목을 선택합니다.

    Visual Studio 2017에서 DesktopApp Project에 새 항목을 추가하는 방법을 보여 주는 애니메이션입니다.

    이 애니메이션은 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고, 표시된 메뉴에서 추가를 선택한 다음, 새 항목을 선택하는 것을 보여 줍니다.

  5. 새 항목 추가 대화 상자에서 C++ 파일(.cpp)을 선택합니다. 이름 상자에 파일의 이름(예: HelloWindowsDesktop.cpp)을 입력합니다. 추가를 선택합니다.

    Visual Studio 2017의 새 항목 추가 대화 상자 스크린샷. 설치된 > Visual C++가 왼쪽에서 선택되고 C++ 파일 옵션이 강조 표시됩니다.

이제 프로젝트가 만들어지고 원본 파일이 편집기에서 열립니다.

Visual Studio 2015에서 Windows 데스크톱 프로젝트를 만들려면

  1. 파일 메뉴에서 새로 만들기, 프로젝트를 차례로 선택합니다.

  2. 새 프로젝트 대화 상자에서 설치된>템플릿>Visual C++를 펼친 다음 Win32를 선택합니다. 가운데 창에서 Win32 프로젝트를 선택합니다.

    이름 상자에 프로젝트의 이름(예: DesktopApp)을 입력합니다. 확인을 선택합니다.

    Visual Studio 2015에 설치된 > 템플릿 > Visual C++ > Win32가 선택된 새 프로젝트 대화 상자, Win32 프로젝트 옵션이 강조 표시되고 이름 텍스트 상자에 DesktopApp이 입력된 스크린샷.

  3. Win32 애플리케이션 마법사개요페이지에서 다음을 선택합니다.

    Win32 애플리케이션 마법사 개요 페이지에서 DesktopApp을 만듭니다.

  4. 애플리케이션 설정 페이지의 애플리케이션 종류 아래에서 Windows 애플리케이션을 선택합니다. 추가 옵션에서 미리 컴파일된 헤더의 선택을 취소한 다음 빈 프로젝트를 선택합니다. 마침을 선택하여 프로젝트를 만듭니다.

  5. 솔루션 탐색기에서 DesktopApp 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 새 항목을 선택합니다.

    Visual Studio 2015에서 DesktopApp Project에 새 항목을 추가하는 방법을 보여 주는 애니메이션입니다.

    이 애니메이션은 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 표시되는 메뉴에서 추가를 선택한 다음 새 항목을 선택하는 것을 보여 줍니다.

  6. 새 항목 추가 대화 상자에서 C++ 파일(.cpp)을 선택합니다. 이름 상자에 파일의 이름(예: HelloWindowsDesktop.cpp)을 입력합니다. 추가를 선택합니다.

    설치된 > Visual C++가 선택되고 C++ 파일 옵션이 강조 표시된 Visual Studio 2015의 새 항목 추가 대화 상자의 스크린샷.

이제 프로젝트가 만들어지고 원본 파일이 편집기에서 열립니다.

코드

다음으로 Visual Studio에서 Windows 데스크톱 애플리케이션에 대한 코드를 만드는 방법을 알아봅니다.

Windows 데스크톱 애플리케이션에서 코드 실행이 시작되는 위치

  1. 모든 C 애플리케이션 및 C++ 애플리케이션에 시작 지점으로 main 함수가 있어야 하는 것처럼 든 Windows 데스크톱 애플리케이션에는 WinMain 함수가 있어야 합니다. WinMain 에는 다음 구문이 있습니다.

    int WINAPI WinMain(
       _In_ HINSTANCE hInstance,
       _In_opt_ HINSTANCE hPrevInstance,
       _In_ LPSTR     lpCmdLine,
       _In_ int       nCmdShow
    );
    

    이 함수의 반환 값 및 매개 변수에 대한 자세한 내용은 WinMain 진입점을 참조하세요.

    참고 항목

    이러한 모든 추가 단어(예: WINAPI 또는 CALLBACK 또는 HINSTANCE 또는 _In_)는 무엇인가요? 기존의 Windows API는 typedef 및 전처리기 매크로를 광범위하게 사용하여 호출 규칙, __declspec 선언 및 컴파일러 pragma와 같은 형식 및 플랫폼별 코드의 세부 정보를 추상화합니다. Visual Studio에서 IntelliSense 빠른 정보 기능을 사용하여 이러한 typedef 및 매크로가 정의하는 내용을 확인할 수 있습니다. 관심 있는 단어 위로 마우스를 가져가거나, 마우스를 선택하고 Ctrl+K, Ctrl+I를 눌러 정의가 포함된 작은 팝업 창을 만듭니다. 자세한 내용은 Using IntelliSense을 참조하세요. 매개 변수 및 반환 형식은 프로그래밍 오류를 파악하는 데 도움이 되는 SAL 주석을 사용하는 경우가 많습니다. 자세한 내용은 SAL 주석을 사용하여 C/C++ 코드 결함을 줄이는 방법을 참조하세요.

  2. Windows 데스크톱 프로그램에는 <windows.h>이(가) 필요합니다. 또한 #include <tchar.h>이(가)자주 표시됩니다. 따라서 char 또는 wchar_t(으)로 작업할 수 있는 앱을 더 쉽게 작성할 수 있습니다. 매크로가 작동하는 방식은 코드에서 TCHAR 매크로를 대신 사용하는 것입니다. 이는 프로젝트에 UNICODE 기호가 정의되어 있으면 궁극적으로 wchar_t(으)로 확인되고, 그렇지 않으면 char(으)로 확인됩니다. 항상 UNICODE를 사용하도록 설정하여 빌드하는 경우 TCHAR이(가) 필요하지 않으며 wchar_t을(를) 직접만 사용할 수 있습니다. 자세한 내용은 일반 텍스트 매핑 사용을 참조하세요. 다음 코드는 파일 맨 위에 있는 두 #include 개의 문을 보여 줍니다.

    #include <windows.h>
    #include <tchar.h>
    
  3. WinMain 함수와 함께 모든 Windows 데스크톱 응용 프로그램에는 창 프로시저 함수도 있어야 합니다. 이 함수 WndProc(이)라고 부르지만 코드에서 원하는 이름을 지정할 수 있습니다. WndProc 에는 다음 구문이 있습니다.

    LRESULT CALLBACK WndProc(
       _In_ HWND   hWnd,
       _In_ UINT   message,
       _In_ WPARAM wParam,
       _In_ LPARAM lParam
    );
    

    이 함수에서는 이벤트가 발생할 때 애플리케이션이 Windows에서 받는 메시지를 처리하는 코드를 작성합니다. 예를 들어 사용자가 애플리케이션에서 확인 단추를 선택하면 Windows에서 사용자에게 메시지를 보냅니다. 적절한 작업을 수행하는 WndProc 함수 내에 코드를 작성합니다. 이벤트를 처리라고 합니다. 애플리케이션과 관련된 이벤트만 처리합니다.

    자세한 내용은 창 프로시저를 참조하세요.

WinMain 함수에 기능 추가

  1. WinMain 함수에서는 주 창에 대한 몇 가지 기본 정보를 캡처해야 합니다. 이렇게 하려면 형식 WNDCLASSEX의 구조를 입력합니다. 구조에는 응용 프로그램 아이콘, 창의 배경색, 제목 표시줄에 표시할 이름 등의 창에 대한 정보가 포함됩니다. 중요한 것은 Windows에서 앱에 보내는 메시지를 처리하는 창 프로시저에 대한 함수 포인터가 포함되어 있다는 것입니다. 다음 예제에서는 일반적인 WNDCLASSEX 구조를 보여 줍니다.

    WNDCLASSEX wcex;
    
    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(wcex.hInstance, IDI_APPLICATION);
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
    

    위 구조의 필드에 대한 자세한 내용은 WNDCLASSEX(을)를 참조하세요.

  2. WNDCLASSEX 구조가 채워지면 창과 메시지를 보내는 방법을 알 수 있도록 Windows에 등록합니다. RegisterClassEx 함수를 사용하고 창 클래스 구조를 인수로 전달합니다. 위의 유니코드에 대한 설명에 따라 TCHAR 형식을 사용하기 때문에 _T 매크로가 사용됩니다. 다음 코드는 창 클래스를 등록하는 방법을 보여줍니다.

    if (!RegisterClassEx(&wcex))
    {
       MessageBox(NULL,
          _T("Call to RegisterClassEx failed!"),
          _T("Windows Desktop Guided Tour"),
          NULL);
    
       return 1;
    }
    
  3. 다음으로 CreateWindowEx 함수를 사용하여 창을 만듭니다.

    static TCHAR szWindowClass[] = _T("DesktopApp");
    static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
    
    // The parameters to CreateWindowEx explained:
    // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application does not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindowEx(
    WS_EX_OVERLAPPEDWINDOW,
       szWindowClass,
       szTitle,
       WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT,
       500, 100,
       NULL,
       NULL,
       hInstance,
       NULL
    );
    if (!hWnd)
    {
       MessageBox(NULL,
          _T("Call to CreateWindowEx failed!"),
          _T("Windows Desktop Guided Tour"),
          NULL);
    
       return 1;
    }
    

    이 함수는 창 핸들인 HWND을(를) 반환합니다. 핸들은 포인터와 비슷합니다. Windows는 이를 사용하여 사용자가 만든 창을 추적합니다. 자세한 내용은 Windows 데이터 형식을 참조하세요.

  4. 이 시점에서 창이 만들어졌지만 여전히 Windows에 표시되도록 지시해야 합니다. 이 코드에서 수행하는 작업은 다음과 같습니다.

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
       nCmdShow);
    UpdateWindow(hWnd);
    

    표시된 창은 WndProc 함수를 아직 구현하지 않았기 때문에 빈 사각형일 뿐입니다. 애플리케이션은 Windows에서 현재 보내는 메시지를 아직 처리하지 않습니다.

  5. 메시지를 처리하기 위해 먼저 Windows에서 보내는 메시지를 수신 대기하는 메시지 루프를 추가합니다. 응용 프로그램이 메시지를 받으면 이 루프가 메시지를 처리하도록 WndProc 함수로 디스패치합니다. 메시지 루프는 다음 코드와 유사합니다.

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
    }
    
    return (int) msg.wParam;
    

    메시지 루프의 구조 및 함수에 대한 자세한 내용은 MSG, GetMessage, TranslateMessageDispatchMessage를 참조하세요.

    애플리케이션의 주 창을 만들고 Windows에서 앱을 보내는 메시지를 수신 대기하는 기본 WinMain 함수는 다음 코드와 유사합니다.

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
       WNDCLASSEX wcex;
    
       wcex.cbSize = sizeof(WNDCLASSEX);
       wcex.style          = CS_HREDRAW | CS_VREDRAW;
       wcex.lpfnWndProc    = WndProc;
       wcex.cbClsExtra     = 0;
       wcex.cbWndExtra     = 0;
       wcex.hInstance      = hInstance;
       wcex.hIcon          = LoadIcon(wcex.hInstance, IDI_APPLICATION);
       wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
       wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
       wcex.lpszMenuName   = NULL;
       wcex.lpszClassName  = szWindowClass;
       wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
    
       if (!RegisterClassEx(&wcex))
       {
          MessageBox(NULL,
             _T("Call to RegisterClassEx failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // Store instance handle in our global variable
       hInst = hInstance;
    
       // The parameters to CreateWindowEx explained:
       // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
       // szWindowClass: the name of the application
       // szTitle: the text that appears in the title bar
       // WS_OVERLAPPEDWINDOW: the type of window to create
       // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
       // 500, 100: initial size (width, length)
       // NULL: the parent of this window
       // NULL: this application dows not have a menu bar
       // hInstance: the first parameter from WinMain
       // NULL: not used in this application
       HWND hWnd = CreateWindowEx(
          WS_EX_OVERLAPPEDWINDOW,
          szWindowClass,
          szTitle,
          WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, CW_USEDEFAULT,
          500, 100,
          NULL,
          NULL,
          hInstance,
          NULL
       );
    
       if (!hWnd)
       {
          MessageBox(NULL,
             _T("Call to CreateWindow failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // The parameters to ShowWindow explained:
       // hWnd: the value returned from CreateWindow
       // nCmdShow: the fourth parameter from WinMain
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       // Main message loop:
       MSG msg;
       while (GetMessage(&msg, NULL, 0, 0))
       {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
    
       return (int) msg.wParam;
    }
    

WndProc 함수의 메시지 처리

  1. 애플리케이션이 수신하는 메시지를 처리하려면 WndProc 함수에서 switch 문을 구현합니다.

    처리해야 할 중요한 메시지는 WM_PAINT 입니다. 애플리케이션은 표시된 창 일부를 업데이트해야 할 때 WM_PAINT 메시지를 받습니다. 이 이벤트는 사용자가 창 앞에서 창을 이동하고 다시 멀리 이동할 때 발생할 수 있습니다. 창이 처음 표시될 때 이 메시지를 수신하여 애플리케이션 UI를 표시할 수 있습니다. 애플리케이션은 Windows에서 이러한 이벤트를 보낼 때 이러한 이벤트에 대해 알아봅니다. 창이 처음 표시된 경우 창을 모두 업데이트해야 합니다.

    WM_PAINT 메시지를 처리하려면 먼저 BeginPaint을(를) 호출한 다음 모든 논리를 처리하여 창에 텍스트, 단추 및 기타 컨트롤을 배치합니다. 그런 다음 EndPaint을(를) 호출합니다. 이 애플리케이션의 경우 BeginPaint()와(과) EndPaint() 사이의 코드는 WinMain()에서 만든 창에 Hello, Windows desktop!을(를) 표시합니다. 다음 코드에서 TextOut 함수는 창의 지정된 위치에 텍스트를 표시합니다.

    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, Windows desktop!");
    
    switch (message)
    {
    case WM_PAINT:
       hdc = BeginPaint(hWnd, &ps);
    
       // Here your application is laid out.
       // For this introduction, we just print out "Hello, Windows desktop!"
       // in the top left corner.
       TextOut(hdc,
          5, 5,
          greeting, _tcslen(greeting));
       // End application-specific layout section.
    
       EndPaint(hWnd, &ps);
       break;
    }
    

    앞의 코드에서 HDC은(는) 창의 클라이언트 영역과 연결된 디바이스 컨텍스트에 대한 핸들입니다. 창에서 그릴 때 클라이언트 영역을 참조하는 데 사용합니다. BeginPaintEndPaint 함수를 사용하여 클라이언트 영역에서 그리기를 준비하고 완료합니다. BeginPaint은(는) 클라이언트 영역에서 그리기에 사용되는 디스플레이 디바이스 컨텍스트에 대한 핸들을 반환합니다. EndPaint은(는) 페인트 요청을 종료하고 디바이스 컨텍스트를 해제합니다.

  2. 애플리케이션은 일반적으로 다른 많은 메시지를 처리합니다. 예를 들어 창이 처음 생성될 때 WM_CREATE이(가) 전송되고 창이 닫힐 때 WM_DESTROY이(가) 전송됩니다. 다음 코드에서는 기본적인 전체 WndProc 함수를 보여 줍니다.

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
       PAINTSTRUCT ps;
       HDC hdc;
       TCHAR greeting[] = _T("Hello, Windows desktop!");
    
       switch (message)
       {
       case WM_PAINT:
          hdc = BeginPaint(hWnd, &ps);
    
          // Here your application is laid out.
          // For this introduction, we just print out "Hello, Windows desktop!"
          // in the top left corner.
          TextOut(hdc,
             5, 5,
             greeting, _tcslen(greeting));
          // End application specific layout section.
    
          EndPaint(hWnd, &ps);
          break;
       case WM_DESTROY:
          PostQuitMessage(0);
          break;
       default:
          return DefWindowProc(hWnd, message, wParam, lParam);
          break;
       }
    
       return 0;
    }
    

코드 빌드

약속된 대로 작업 애플리케이션에 대한 전체 코드는 다음과 같습니다.

이 예제를 빌드하려면

  1. 편집기에서 HelloWindowsDesktop.cpp의 모든 코드를 삭제합니다. 이 예제 코드를 복사하여 HelloWindowsDesktop.cpp를 붙여넣습니다.

    // HelloWindowsDesktop.cpp
    // compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c
    
    #include <windows.h>
    #include <stdlib.h>
    #include <string.h>
    #include <tchar.h>
    
    // Global variables
    
    // The main window class name.
    static TCHAR szWindowClass[] = _T("DesktopApp");
    
    // The string that appears in the application's title bar.
    static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
    
    // Stored instance handle for use in Win32 API calls such as FindResource
    HINSTANCE hInst;
    
    // Forward declarations of functions included in this code module:
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(
       _In_ HINSTANCE hInstance,
       _In_opt_ HINSTANCE hPrevInstance,
       _In_ LPSTR     lpCmdLine,
       _In_ int       nCmdShow
    )
    {
       WNDCLASSEX wcex;
    
       wcex.cbSize = sizeof(WNDCLASSEX);
       wcex.style          = CS_HREDRAW | CS_VREDRAW;
       wcex.lpfnWndProc    = WndProc;
       wcex.cbClsExtra     = 0;
       wcex.cbWndExtra     = 0;
       wcex.hInstance      = hInstance;
       wcex.hIcon          = LoadIcon(wcex.hInstance, IDI_APPLICATION);
       wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
       wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
       wcex.lpszMenuName   = NULL;
       wcex.lpszClassName  = szWindowClass;
       wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
    
       if (!RegisterClassEx(&wcex))
       {
          MessageBox(NULL,
             _T("Call to RegisterClassEx failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // Store instance handle in our global variable
       hInst = hInstance;
    
       // The parameters to CreateWindowEx explained:
       // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
       // szWindowClass: the name of the application
       // szTitle: the text that appears in the title bar
       // WS_OVERLAPPEDWINDOW: the type of window to create
       // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
       // 500, 100: initial size (width, length)
       // NULL: the parent of this window
       // NULL: this application does not have a menu bar
       // hInstance: the first parameter from WinMain
       // NULL: not used in this application
       HWND hWnd = CreateWindowEx(
          WS_EX_OVERLAPPEDWINDOW,
          szWindowClass,
          szTitle,
          WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, CW_USEDEFAULT,
          500, 100,
          NULL,
          NULL,
          hInstance,
          NULL
       );
    
       if (!hWnd)
       {
          MessageBox(NULL,
             _T("Call to CreateWindow failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // The parameters to ShowWindow explained:
       // hWnd: the value returned from CreateWindow
       // nCmdShow: the fourth parameter from WinMain
       ShowWindow(hWnd,
          nCmdShow);
       UpdateWindow(hWnd);
    
       // Main message loop:
       MSG msg;
       while (GetMessage(&msg, NULL, 0, 0))
       {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
    
       return (int) msg.wParam;
    }
    
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Processes messages for the main window.
    //
    //  WM_PAINT    - Paint the main window
    //  WM_DESTROY  - post a quit message and return
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
       PAINTSTRUCT ps;
       HDC hdc;
       TCHAR greeting[] = _T("Hello, Windows desktop!");
    
       switch (message)
       {
       case WM_PAINT:
          hdc = BeginPaint(hWnd, &ps);
    
          // Here your application is laid out.
          // For this introduction, we just print out "Hello, Windows desktop!"
          // in the top left corner.
          TextOut(hdc,
             5, 5,
             greeting, _tcslen(greeting));
          // End application-specific layout section.
    
          EndPaint(hWnd, &ps);
          break;
       case WM_DESTROY:
          PostQuitMessage(0);
          break;
       default:
          return DefWindowProc(hWnd, message, wParam, lParam);
          break;
       }
    
       return 0;
    }
    
  2. 빌드 메뉴에서 솔루션 빌드를 선택합니다. 컴파일 결과가 Visual Studio의 출력 창에 표시됩니다.

    DesktopApp 프로젝트를 빌드하는 단계를 보여 주는 애니메이션입니다.

    애니메이션은 모두 저장 단추를 클릭한 다음 주 메뉴에서 빌드 > 빌드 솔루션을 선택하는 것을 보여 줍니다.

  3. 애플리케이션을 실행하려면 F5 키를 누릅니다. "Hello, Windows 데스크톱!"이라는 텍스트가 있는 창이 나타납니다.

    실행 중인 프로젝트의 스크린샷. Windows Desktop 둘러보기 응용 프로그램 제목이 있는 창이 표시됩니다. 창의 내용은 Hello, Windows 데스크톱입니다!.

축하합니다! 기존 Windows 데스크톱 애플리케이션을 빌드했습니다.

참고 항목

Windows C++ 데스크톱 애플리케이션 형식