마법사를 만드는 방법

마법사는 프로시저를 통해 사용자를 안내하는 간단하고 강력한 방법을 제공하는 속성 시트 형식입니다.

마법사는 사용자 환경을 단순화하는 열쇠 중 하나입니다. 애플리케이션 구성과 같은 복잡한 작업을 수행하고 일련의 간단한 단계로 나눌 수 있습니다. 프로세스의 각 지점에서 필요한 사항에 대한 설명을 제공하고 사용자가 선택하고 텍스트를 입력할 수 있는 컨트롤을 표시할 수 있습니다.

마법사는 실제로 속성 시트의 한 형식입니다. 속성 시트는 본질적으로 페이지 컬렉션의 컨테이너이며 각 페이지는 별도의 대화 상자입니다. 일반 속성 시트에서는 사용자가 언제든지 모든 페이지에 액세스할 수 있지만 마법사는 페이지를 시퀀스대로 표시합니다. 탭 대신 단추를 사용하여 앞뒤로 탐색합니다. 페이지가 표시되는 순서는 애플리케이션에서 제어하며 사용자 입력에 따라 수정할 수 있습니다.

마법사에는 이전 Wizard97 스타일과 Windows Vista에 도입된 Aero 스타일의 두 가지 기본 스타일이 있습니다. 그림을 보려면 속성 시트 정보를 참조하세요. (PSH_WIZARD 또는 PSH_WIZARD_LITE 플래그만 사용하는 세 번째 스타일은 헤더나 워터마크가 없는 속성 시트의 간단한 시퀀스를 나타냅니다.)

참고

마법사 컨텍스트에서 "워터마크"는 일부 페이지의 왼쪽 여백에 나타나는 비트맵입니다.

 

이 문서의 대부분에서 설명하는 내용은 버전 5.80 이상의 공용 컨트롤이 있는 시스템용 마법사를 구현한다고 가정합니다. 이전 버전의 공용 컨트롤과 함께 Wizard97 스타일을 사용하려고 하면 애플리케이션이 컴파일될 수 있지만 제대로 표시되지 않습니다. 이전 시스템에서 Wizard97 호환 마법사를 만드는 방법에 대한 설명은 이 항목 뒷부분의 이전 버전과 호환되는 마법사를 참조하세요.

알아야 하는 작업

기술

필수 구성 요소

  • C/C++
  • Windows 사용자 인터페이스 프로그래밍

지침

마법사 구현

마법사를 구현하는 것은 일반 속성 시트를 구현하는 것과 비슷합니다. 가장 기본적인 수준에서 속성 시트를 정의하는 PROPSHEETHEADER 구조체에서 다음 플래그 중 하나 또는 플래그 조합을 설정하는 문제입니다.

플래그 스타일
PSH_WIZARD 헤더나 비트맵이 없는 간단한 마법사입니다.
PSH_WIZARD_LITE PSH_WIZARD와 비슷하지만 모양이 약간 다릅니다. 예를 들어, 단추 위의 구분선은 창의 전체 너비로 설정됩니다.
PSH_WIZARD97 (선택 사항) 헤더, 헤더 비트맵 및 워터마크가 있는 Wizard97 마법사입니다.
PSH_WIZARD | PSH_AEROWIZARD Aero 마법사입니다. Aero 마법사는 워터마크나 헤더 비트맵을 사용하지 않습니다. STA(단일 스레드 아파트) 모델이 필요합니다.

 

마법사를 구현하는 기본 프로시저는 다음과 같습니다.

  1. 각 페이지에 대한 대화 상자 템플릿을 만듭니다.
  2. 각 페이지에 대해 PROPSHEETPAGE 구조체를 만들어 페이지를 정의합니다. 이 구조체는 페이지를 정의하고 대화 상자 템플릿과 비트맵 또는 기타 리소스에 대한 포인터를 포함합니다.
  3. 이전 단계에서 만든 PROPSHEETPAGE 구조체를 CreatePropertySheetPage 함수에 전달하여 페이지의 HPROPSHEETPAGE 핸들을 만듭니다.
  4. PROPSHEETHEADER 구조체를 만들어 마법사를 정의합니다.
  5. PROPSHEETHEADER 구조체를 PropertySheet 함수에 전달하여 마법사를 표시합니다.
  6. 페이지 컨트롤 및 마법사 단추의 알림 메시지를 처리하고 다른 Windows 메시징을 처리하기 위해 각 페이지에 대한 대화 상자 프로시저를 구현합니다.

대화 상자 템플릿 만들기

마법사 페이지에는 외부 및 내부의 두 가지 기본 형식이 있습니다. 외부 페이지는 소개(환영) 및 완료 페이지입니다. 다른 모든 페이지는 내부 페이지입니다.

외부 페이지 대화 상자 템플릿

소개 페이지와 완료 페이지의 기본 레이아웃은 동일합니다. 다음 그림에서는 자리 표시자 워터마크가 있는 샘플 Wizard97 소개 페이지를 보여 줍니다.

screen shot showing a wizard page with a graphic on the left, title and body text on the right, and back, next and cancel buttons at the bottom

Wizard97 외부 페이지의 경우 대화 상자 템플릿은 317x193 대화 상자 단위입니다. 뒤로, 다음취소 단추가 포함된 맨 아래의 밴드와 캡션을 제외한 모든 마법사를 채웁니다. "워터마크" 비트맵용으로 예약된 템플릿의 왼쪽에는 컨트롤이 없어야 합니다. 워터마크가 마법사의 PROPSHEETHEADER 구조체에 지정되며 자동으로 페이지에 추가됩니다. 리소스 템플릿을 설계할 때 공간을 허용해야 합니다.

워터마크 비트맵을 만들 때 예를 들어, 사용자가 큰 시스템 글꼴을 선택하는 경우 대화 상자의 크기가 커질 수 있다는 점에 유의합니다. 다른 언어는 또한 다른 글꼴 메트릭을 갖는 경향이 있습니다. 페이지가 커지면 워터마크용으로 예약된 영역이 그에 비례하여 커집니다. 그러나 워터마크 비트맵을 변경할 수 없으며 더 큰 영역을 채우기 위해 비트맵을 늘릴 수도 없습니다. 대신, 비트맵은 예약된 영역의 왼쪽 상단에 원래 크기로 남아 있습니다. 워터마크로 덮이지 않은 더 큰 예약 영역 파트는 자동으로 비트맵의 왼쪽 상단의 픽셀 색으로 채워집니다.

서로 다른 글꼴 메트릭에 대해 서로 다른 크기의 워터마크 비트맵이 필요한 경우 가능한 두 가지 솔루션은 다음과 같습니다.

  • 마법사를 만들기 전에 글꼴 메트릭을 가져오고 적절한 크기의 워터마크 비트맵을 지정합니다.
  • 마법사를 만들 때 워터마크 비트맵을 지정하지 마세요. Wizard97은 워터마크 영역을 비워 둡니다. 그런 다음 워터마크용으로 예약된 영역에 적절한 크기의 비트맵을 그립니다.

일반 대화 상자에서와 마찬가지로 워터마크 오른쪽 영역에 컨트롤을 배치할 수 있습니다. 이 영역의 배경색은 시스템에 의해 결정되며 사용자가 작업을 취할 필요가 없습니다. 일반적으로 이 영역에 두 개의 정적 컨트롤을 배치합니다. 상단에는 제목이 있고 크고 굵은 글꼴(Wizard97의 경우 12포인트 Verdana Bold)을 사용합니다. 다른 하나는 설명 텍스트용으로 표준 대화 상자 글꼴을 사용합니다.

소개 페이지와 완료 페이지의 주요 차이점은 마법사 단추와 정적 컨트롤의 텍스트입니다. 소개 페이지에는 일반적으로 다음뒤로 단추가 있으며 다음 단추만 사용하도록 설정되어 있습니다. 완료 페이지에는 뒤로 단추가 사용하도록 설정되어 있고 다음 단추는 마침 단추로 바꿔졌습니다.

참고

Aero 마법사에서 뒤로 단추는 캡션 표시줄의 화살표 단추로 바꿔집니다.

 

마법사에 PSM_SETFINISHTEXT 메시지를 전송하여 마침 단추의 텍스트를 수정할 수 있습니다. 기본적으로 마침 단추에는 키보드 가속기가 포함되어 있지 않습니다. 키보드 가속기를 정의하려면 PSM_SETFINISHTEXT에 전달하는 텍스트 문자열에 앰퍼샌드를 포함합니다. 예를 들어 "&Finish"는 'F'를 키보드 가속기로 정의합니다.

내부 페이지 대화 상자 템플릿

내부 페이지는 외부 페이지와 모양이 약간 다릅니다. 다음 그림에서는 자리 표시자 헤더 비트맵이 있는 샘플 Wizard97 내부 페이지를 보여 줍니다.

screen shot of a wizard page with title and subtitle text and a graphic at the top, text in the middle, and buttons on the bottom

페이지 상단의 헤더 영역은 속성 시트에서 처리하므로 템플릿에 포함되지 않습니다. 헤더의 콘텐츠는 페이지의 PROPSHEETPAGE 구조체와 마법사의 PROPSHEETHEADER 구조체에 지정됩니다. 내부 페이지는 헤더와 단추 사이에 맞아야 하므로 Wizard97 대화 상자 템플릿은 외부 페이지용 템플릿보다 다소 작은 317x143 대화 상자 단위입니다.

다음 그림에서는 동일한 템플릿에서 만들어진 Aero 마법사를 보여 줍니다.

screen shot that differs from the previous one by having a title area at the top, and only next and cancel buttons at the bottom

마법사 페이지 정의

대화 상자 템플릿과 비트맵 및 문자열 테이블과 같은 관련 리소스를 만든 후 속성 시트 페이지를 만들 수 있습니다. 프로시저는 표준 속성 시트의 프로시저와 유사합니다. 먼저 PROPSHEETPAGE 구조체의 적절한 멤버를 채웁니다. (일부 멤버는 마법사에만 해당됩니다.) 그런 다음 CreatePropertySheetPage 함수를 호출하여 페이지의 HPROPSHEETPAGE 핸들을 만듭니다.

다음 마법사 관련 플래그는 PROPSHEETPAGE 구조체의 dwFlags 멤버에서 설정할 수 있습니다.

플래그 설명
PSP_HIDEHEADER Wizard97의 외부 페이지에 대해 이 플래그를 설정합니다. 헤더는 표시되지 않으며 워터마크가 표시될 수 있습니다.
PSP_USEHEADERTITLE 내부 페이지에 대해 이 플래그를 설정하여 Wizard97의 헤더 영역 또는 Aero 마법사의 클라이언트 영역 상단에 제목을 넣습니다.
PSP_USEHEADERSUBTITLE 내부 페이지에 대해 이 플래그를 설정하여 Wizard97의 헤더 영역에 자막을 넣습니다.

 

PSP_USEHEADERTITLE 또는 PSP_USEHEADERSUBTITLE을 설정한 경우 pszHeaderTitlepszHeaderSubtitle 멤버에 각각 제목 및 부제 텍스트를 할당합니다. PROPSHEETPAGEPROPSHEETHEADER 구조체의 멤버에 텍스트 문자열을 할당할 때 문자열 포인터를 할당하거나 MAKEINTRESOURCE 매크로를 사용하여 문자열 리소스에서 값을 할당할 수 있습니다. 문자열 리소스는 마법사 PROPSHEETHEADER 구조체의 hInstance 멤버에 지정된 모듈에서 로드됩니다.

페이지를 만들기 위해 CreatePropertySheetPage를 호출할 때 결과를 HPROPSHEETPAGE 핸들 배열의 요소에 할당합니다. 이 배열은 속성 시트를 만들 때 사용됩니다. 페이지 핸들의 배열 인덱스는 표시되는 기본 순서를 결정합니다. 페이지의 HPROPSHEETPAGE 핸들을 만든 후에는 동일한 PROPSHEETPAGE 구조체를 재사용하여 관련 멤버에 새 값을 할당하여 다음 페이지를 만들 수 있습니다.

페이지를 만드는 또 다른 방법은 각 페이지에 대해 별도의 PROPSHEETPAGE 구조체를 사용하고 구조체 배열을 만드는 것입니다. 이 배열은 속성 시트를 만들 때 HPROPSHEETPAGE 핸들 배열 대신 사용됩니다. 별도의 PROPSHEETPAGE 구조체를 사용하면 CreatePropertySheetPage를 호출할 필요가 없지만 더 많은 메모리를 사용합니다. 그렇지 않으면 두 방식 간에 큰 차이가 없습니다.

다음 예에서는 PROPSHEETPAGE 구조체에 값을 할당하여 내부 Wizard97 페이지를 정의합니다. 이 예에서 페이지의 제목, 부제 및 대화 상자 템플릿은 모두 리소스 ID로 식별됩니다. 그런 다음 CreatePropertySheetPage 함수가 호출되어 페이지의 HPROPSHEETPAGE 핸들을 만듭니다. 표시되는 두 번째 페이지이기 때문에 핸들은 인덱스 1과 함께 ahpsp 핸들 배열에 할당됩니다.

// g_hInstance is the global HINSTANCE of the application.
// IntPage1DlgProc is the dialog procedure for this page.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETPAGE psp = { sizeof(psp) };

psp.hInstance         = g_hInstance;
psp.dwFlags           = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
psp.lParam            = (LPARAM) &wizdata;
psp.pszHeaderTitle    = MAKEINTRESOURCE(IDS_TITLE1);
psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE1);
psp.pszTemplate       = MAKEINTRESOURCE(IDD_INTERIOR1);
psp.pfnDlgProc        = IntPage1DlgProc;

ahpsp[1] = CreatePropertySheetPage(&psp);

사용자 지정 페이지 데이터

페이지를 만들 때, PROPSHEETPAGE 구조체의 lParam 멤버를 사용하여 사용자 지정 데이터를 할당할 수 있습니다. 일반적으로 사용자 지정 구조체에 대한 포인터를 할당합니다.

페이지를 처음 선택하면 해당 대화 상자 프로시저가 WM_INITDIALOG 메시지를 수신합니다. 메시지의 lParam 값은 사용자 지정 데이터를 검색할 수 있는 페이지의 PROPSHEETPAGE 구조의 복사본을 가리킵니다. 그런 다음 인덱스 매개 변수로 GWL_USERDATA와 함께 SetWindowLongPtr를 사용하여 후속 메시지에서 사용하기 위해 이 데이터를 저장할 수 있습니다. 여러 페이지에 동일한 데이터에 대한 포인터가 있을 수 있으며 한 페이지에서 데이터를 변경하면 해당 대화 프로시저의 다른 페이지에서 사용할 수 있습니다.

마법사 속성 시트 정의

일반 속성 시트와 마찬가지로 PROPSHEETHEADER 구조체의 멤버를 채워 마법사의 속성 시트를 정의합니다. 이 구조체를 사용하면 마법사를 구성하는 페이지와 여러 관련 매개 변수와 함께 표시되는 기본 순서를 지정할 수 있습니다. 그런 다음 PropertySheet 함수를 호출하여 마법사를 시작합니다.

Wizard97 스타일에서 PROPSHEETHEADER 구조체의 pszCaption 멤버는 무시됩니다. 대신 마법사는 현재 페이지의 대화 상자 템플릿에 지정된 캡션을 표시합니다. 템플릿에 캡션이 없으면 이전 페이지의 캡션이 표시됩니다. 따라서 모든 페이지에 동일한 캡션을 표시하려면 소개 페이지의 템플릿에 캡션을 지정합니다.

Aero 마법사 스타일에서 대화 상자 캡션은 pszCaption에서 가져옵니다.

페이지에 대한 HPROPSHEETPAGE 핸들 배열을 만든 경우 배열을 phpage 멤버에 할당합니다. 대신 PROPSHEETPAGE 구조체의 배열을 만든 경우 배열을 ppsp 멤버에 할당하고 dwFlags 멤버에서 PSH_PROPSHEETPAGE 플래그를 설정합니다.

다음 예에서는 PROPSHEETHEADER 구조체인 psh에 값을 할당하고 PropertySheet 함수를 호출하여 마법사를 시작합니다. Wizard97 스타일 마법사에는 리소스 ID로 지정된 워터마크와 헤더 그래픽이 모두 있습니다. ahpsp 배열은 모든 HPROPSHEETPAGE 핸들을 포함하고 표시되는 기본 순서를 정의합니다.

// g_hInstance is the global HINSTANCE of the application.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETHEADER psh = { sizeof(psh) };

psh.hInstance      = g_hInstance;
psh.hwndParent     = NULL;
psh.phpage         = ahpsp;
psh.dwFlags        = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
psh.pszbmHeader    = MAKEINTRESOURCE(IDB_BANNER);
psh.nStartPage     = 0;
psh.nPages         = 4;

PropertySheet(&psh);

대화 상자 프로시저

마법사의 각 페이지에는 Windows 메시지, 특히 컨트롤과 마법사의 알림을 처리하기 위한 대화 상자 프로시저가 필요합니다. 거의 모든 마법사가 처리할 수 있어야 하는 세 가지 메시지는 WM_INITDIALOG, WM_DESTROYWM_NOTIFY입니다.

WM_NOTIFY 메시지는 페이지가 표시되기 전과 마법사의 단추를 클릭할 때 수신됩니다. 메시지의 lParam 매개 변수는 NMHDR 헤더 구조체에 대한 포인터입니다. 알림의 ID는 구조체의 code 멤버에 포함되어 있습니다. 대부분의 마법사가 처리해야 하는 네 가지 알림은 다음과 같습니다.

코드 Description
PSN_SETACTIVE 페이지가 표시되기 전에 전송됩니다.
PSN_WIZBACK 뒤로 단추를 클릭하면 전송됩니다.
PSN_WIZNEXT 다음 단추를 클릭하면 전송됩니다.
PSN_WIZFINISH 마침 단추를 클릭하면 전송됩니다.

 

WM_INITDIALOG 및 WM_DESTROY 처리

페이지가 처음으로 표시되려고 할 때 해당 대화 상자 프로시저는 WM_INITDIALOG 메시지를 받습니다. 이 메시지를 처리하면 마법사가 사용자 지정 데이터 저장 또는 글꼴 설정과 같은 필요한 초기화 작업을 수행할 수 있습니다.

속성 시트가 제거되면 WM_DESTROY 메시지가 표시됩니다. 마법사는 시스템에 의해 자동으로 제거되지만 이 메시지를 처리하면 필요한 정리 작업을 수행할 수 있습니다.

Handle PSN_SETACTIVE

페이지가 표시될 때마다 PSN_SETACTIVE 알림 코드가 전송됩니다. 페이지를 처음 방문하면 PSN_SETACTIVE가 WM_INITDIALOG 메시지를 따릅니다. 이후에 페이지를 다시 방문하면 PSN_SETACTIVE 알림만 받습니다. 이 알림은 일반적으로 페이지의 데이터를 초기화하고 적절한 단추를 사용하도록 설정하기 위해 처리됩니다.

기본적으로 마법사는 모든 단추가 사용하도록 설정된 상태로 뒤로, 다음취소 단추를 표시합니다. 단추를 사용하지 않도록 설정하거나 다음 대신 마침을 표시하려면 PSM_SETWIZBUTTONS 메시지를 보내야 합니다. 이 메시지가 전송된 후에는 새 페이지가 선택되더라도 다른 PSM_SETWIZBUTTONS 메시지에 의해 수정될 때까지 단추의 상태가 유지됩니다. 일반적으로 모든 PSN_SETACTIVE 처리기는 각 페이지의 단추 상태가 올바른지 확인하기 위해 이 메시지를 보냅니다.

언제든지 이 메시지로 단추 상태를 변경할 수 있습니다. 예를 들어, 처음에는 다음 단추를 사용하지 않도록 설정할 수 있습니다. 사용자가 필요한 모든 정보를 입력한 후 다른 PSM_SETWIZBUTTONS 메시지를 전송하여 다음 단추를 사용하도록 설정하고 사용자가 다음 페이지로 진행할 수 있도록 할 수 있습니다.

다음 코드는 PropSheet_SetWizButtons 매크로를 사용하여 내부 페이지가 표시되기 전에 뒤로다음 단추를 사용하도록 설정합니다.

case WM_NOTIFY :
    {
        LPNMHDR pnmh = (LPNMHDR)lParam;
        
        switch(pnmh->code)
        {
        
        ...
        
        case PSN_SETACTIVE :
        
            ...
            
            // This is an interior page.
            PropSheet_SetWizButtons(hwnd, PSWIZB_NEXT | PSWIZB_BACK);
            
            ...
        }
    ...
    
    }

PSN_WIZNEXT, PSNWIZBACK 및 PSN_WIZFINISH 처리

다음 또는 뒤로 단추를 클릭하면 PSN_WIZNEXT 또는 PSN_WIZBACK 알림 코드가 수신됩니다. 기본적으로 마법사는 속성 시트가 만들어질 때 정의된 순서대로 자동으로 다음 또는 이전 페이지로 이동합니다. 이러한 알림을 처리하는 일반적인 이유는 사용자가 페이지를 전환하지 못하도록 하거나 기본 페이지 순서를 재정의하는 것입니다.

사용자가 페이지를 전환하지 못하도록 하려면, 단추 알림을 처리하고 DWL_MSGRESULT 값을 –1로 설정하여 SetWindowLong 함수를 호출하고 TRUE를 반환합니다. 예를 들어 다음과 같습니다.

case PSN_WIZNEXT :

        ...
        
        // Do not go to the next page yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, -1);
        
        return TRUE;
        
        ...

표준 순서를 재정의하고 특정 페이지로 이동하려면, DWL_MSGRESULT 값을 페이지의 대화 상자 리소스 ID로 설정하여 SetWindowLong을 호출하고 TRUE를 반환합니다. 예를 들어 다음과 같습니다.

case PSN_WIZNEXT :

        ...
        
        // Go straight to the completion page.
        SetWindowLong(hwnd, DWL_MSGRESULT, IDD_FINISH);
        
        return TRUE;
        
        ...

마침 또는 취소 단추를 클릭하면 각각 PSN_WIZFINISH 또는 PSN_RESET 알림 코드를 받습니다. 이 단추 중 하나를 클릭하면 마법사가 시스템에 의해 자동으로 제거됩니다. 그러나 마법사가 제거되기 전에 정리 작업을 수행해야 하는 경우 이러한 알림을 처리할 수 있습니다. PSN_WIZFINISH 알림을 받을 때 마법사가 제거되지 않도록 하려면 DWL_MSGRESULT 값이 TRUE로 설정된 SetWindowLong을 호출하고 TRUE를 반환합니다. 예를 들어 다음과 같습니다.

case PSN_WIZFINISH :

        ...
        
        // Not finished yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
        
        return TRUE;
        
        ...

이전 버전과 호환되는 마법사

이전 섹션에서는 공용 컨트롤의 버전 5 이상이 있는 시스템에 대한 마법사를 구현한다고 가정해보겠습니다.

이전 버전의 공용 컨트롤이 있는 시스템용 마법사를 작성하는 경우 이전 섹션에서 설명한 많은 기능을 사용할 수 없습니다. Wizard97 스타일에서 사용되는 PROPSHEETHEADERPROPSHEETPAGE 구조체의 여러 멤버는 공용 컨트롤 버전 5 이상에서만 지원됩니다. 그러나 Wizard97 스타일과 유사한 모양으로 이전 버전과 호환되는 마법사를 구현하는 것은 여전히 가능합니다. 이렇게 하려면 다음을 명시적으로 구현해야 합니다.

  • 소개 및 완료 페이지의 대화 상자 템플릿에 워터마크 그래픽을 추가합니다.
  • 모든 템플릿을 같은 크기로 만듭니다. 내부 페이지에 대해 별도의 시스템 정의 헤더 영역이 없습니다.
  • 템플릿에 명시적으로 내부 페이지의 머리글 영역을 만듭니다.
  • 마법사가 크기를 변경하면 제목이나 부제목과 충돌할 수 있으므로 헤더 그래픽을 사용하지 마세요.

이전 버전과 호환되는 마법사에 대한 자세한 내용은 이전 버전과 호환되는 Wizard97을 참조하세요.

설명

Wizard97의 디자인 문제에 대한 자세한 내용은 Windows SDK의 Wizard97 사양을 참조하세요. 이 문서에는 대화 상자의 크기, 비트맵 크기 및 색, 컨트롤 배치와 같은 항목에 대한 지침이 있습니다.

속성 시트 사용

Windows 공용 컨트롤 데모(CppWindowsCommonControls)