From bf35d809d40519268f36aa840cec0f4ce516623e Mon Sep 17 00:00:00 2001
From: Thuy Nguyen <thuy@macadamian.com>
Date: Sun, 19 Sep 1999 12:14:38 +0000
Subject: [PATCH] Added support for wizard property sheets.

---
 dlls/comctl32/comctl32.h  |   4 +
 dlls/comctl32/propsheet.c | 510 ++++++++++++++++++++++++++++++++++++--
 dlls/comctl32/rsrc.rc     |  14 ++
 3 files changed, 503 insertions(+), 25 deletions(-)

diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index 52b759d5c64..1c754997820 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -15,6 +15,10 @@ extern HMODULE COMCTL32_hModule;
 
 #define IDC_TABCONTROL   12320
 #define IDC_APPLY_BUTTON 12321
+#define IDC_BACK_BUTTON  12323
+#define IDC_NEXT_BUTTON  12324
+#define IDC_FINISH_BUTTON 12325
+#define IDC_SUNKEN_LINE   12326
 
 
 /* Toolbar customization dialog */
diff --git a/dlls/comctl32/propsheet.c b/dlls/comctl32/propsheet.c
index bd47aaa7de8..9858d31130e 100644
--- a/dlls/comctl32/propsheet.c
+++ b/dlls/comctl32/propsheet.c
@@ -5,8 +5,7 @@
  * Copyright 1999 Thuy Nguyen
  *
  * TODO:
- *   - Modeless mode
- *   - Wizard mode
+ *   - Tab order
  *   - Unicode property sheets
  */
 
@@ -78,7 +77,6 @@ const char * PropSheetInfoStr = "PropertySheetInfo";
 #define MAX_CAPTION_LENGTH 255
 #define MAX_TABTEXT_LENGTH 255
 
-
 /******************************************************************************
  * Prototypes
  */
@@ -99,12 +97,16 @@ static int PROPSHEET_CreatePage(HWND hwndParent, int index,
                                 BOOL showPage);
 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
+static BOOL PROPSHEET_Back(HWND hwndDlg);
+static BOOL PROPSHEET_Next(HWND hwndDlg);
+static BOOL PROPSHEET_Finish(HWND hwndDlg);
 static BOOL PROPSHEET_Apply(HWND hwndDlg);
 static void PROPSHEET_Cancel(HWND hwndDlg);
 static void PROPSHEET_Help(HWND hwndDlg);
 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
+static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
                                 int index,
@@ -121,6 +123,8 @@ static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
                                  HPROPSHEETPAGE hpage);
 static void PROPSHEET_CleanUp();
 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
+static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
+static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg);
 
 BOOL WINAPI
 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
@@ -317,9 +321,13 @@ BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
   LPVOID temp = 0;
   HRSRC hRes;
   DWORD resSize;
+  WORD resID = IDD_PROPSHEET;
+
+  if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
+    resID = IDD_WIZARD;
 
   if(!(hRes = FindResourceA(COMCTL32_hModule,
-                            MAKEINTRESOURCEA(IDD_PROPSHEET),
+                            MAKEINTRESOURCEA(resID),
                             RT_DIALOGA)))
     return FALSE;
 
@@ -397,6 +405,49 @@ static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
   return FALSE;
 }
 
+/******************************************************************************
+ *            PROPSHEET_IsTooSmallWizard
+ *
+ * Verify that the default property sheet is big enough.
+ */
+static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
+{
+  RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
+  HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
+
+  GetClientRect(hwndDlg, &rcSheetClient);
+  GetWindowRect(hwndDlg, &rcSheetRect);
+  GetWindowRect(hwndLine, &rcLine);
+
+  /* Remove the space below the sunken line */
+  rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
+
+  /* Remove the buffer zone all around the edge */
+  rcSheetClient.bottom -= (padding.y * 2);
+  rcSheetClient.right -= (padding.x * 2);
+
+  /*
+   * Biggest page size.
+   */
+  rcPage.left   = psInfo->x;
+  rcPage.top    = psInfo->y;
+  rcPage.right  = psInfo->width;
+  rcPage.bottom = psInfo->height;
+
+  MapDialogRect(hwndDlg, &rcPage);
+  TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
+        rcPage.right, rcPage.bottom);
+
+  if (rcPage.right > rcSheetClient.right)
+    return TRUE;
+
+  if (rcPage.bottom > rcSheetClient.bottom)
+    return TRUE;
+
+  return FALSE;
+}
+
 /******************************************************************************
  *            PROPSHEET_AdjustSize
  *
@@ -454,6 +505,51 @@ static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
   return TRUE;
 }
 
+/******************************************************************************
+ *            PROPSHEET_AdjustSizeWizard
+ *
+ * Resizes the property sheet to fit the largest page.
+ */
+static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
+{
+  HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
+  HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
+  RECT rc;
+  int buttonHeight, lineHeight;
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
+
+  /* Get the height of buttons */
+  GetClientRect(hwndButton, &rc);
+  buttonHeight = rc.bottom;
+
+  GetClientRect(hwndLine, &rc);
+  lineHeight = rc.bottom;
+
+  /*
+   * Biggest page size.
+   */
+  rc.left   = psInfo->x;
+  rc.top    = psInfo->y;
+  rc.right  = psInfo->width;
+  rc.bottom = psInfo->height;
+
+  MapDialogRect(hwndDlg, &rc);
+
+  TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
+
+  /* Make room */
+  rc.right += (padding.x * 2);
+  rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
+
+  /*
+   * Resize the property sheet.
+   */
+  SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
+               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  return TRUE;
+}
+
 /******************************************************************************
  *            PROPSHEET_AdjustButtons
  *
@@ -549,6 +645,112 @@ static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
   return TRUE;
 }
 
+/******************************************************************************
+ *            PROPSHEET_AdjustButtonsWizard
+ *
+ * Adjusts the buttons' positions.
+ */
+static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
+                                          PropSheetInfo* psInfo)
+{
+  HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
+  HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
+  RECT rcSheet;
+  int x, y;
+  int num_buttons = 3;
+  int buttonWidth, buttonHeight, lineHeight, lineWidth;
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
+
+  if (psInfo->hasHelp)
+    num_buttons++;
+
+  /*
+   * Obtain the size of the buttons.
+   */
+  GetClientRect(hwndButton, &rcSheet);
+  buttonWidth = rcSheet.right;
+  buttonHeight = rcSheet.bottom;
+
+  GetClientRect(hwndLine, &rcSheet);
+  lineHeight = rcSheet.bottom;
+
+  /*
+   * Get the size of the property sheet.
+   */
+  GetClientRect(hwndParent, &rcSheet);
+
+  /*
+   * All buttons will be at this y coordinate.
+   */
+  y = rcSheet.bottom - (padding.y + buttonHeight);
+
+  /*
+   * Position the Next and the Finish buttons.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
+
+  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  ShowWindow(hwndButton, SW_HIDE);
+
+  /*
+   * Position the Back button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
+
+  x -= buttonWidth;
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  /*
+   * Position the Cancel button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDCANCEL);
+
+  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  /*
+   * Position Help button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDHELP);
+
+  if (psInfo->hasHelp)
+  {
+    x = rcSheet.right - (padding.x + buttonWidth);
+
+    SetWindowPos(hwndButton, 0, x, y, 0, 0,
+                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+  }
+  else
+    ShowWindow(hwndButton, SW_HIDE);
+
+  /*
+   * Position and resize the sunken line.
+   */
+  x = padding.x;
+  y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
+
+  GetClientRect(hwndParent, &rcSheet);
+  lineWidth = rcSheet.right - (padding.x * 2);
+
+  SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
+               SWP_NOZORDER | SWP_NOACTIVATE);
+
+  return TRUE;
+}
+
 /******************************************************************************
  *            PROPSHEET_GetPaddingInfo
  *
@@ -574,6 +776,53 @@ static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
   return padding;
 }
 
+/******************************************************************************
+ *            PROPSHEET_GetPaddingInfoWizard
+ *
+ * Returns the layout information.
+ * Horizontal spacing is the distance between the Cancel and Help buttons.
+ * Vertical spacing is the distance between the line and the buttons.
+ */
+static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
+{
+  PADDING_INFO padding;
+  RECT rc;
+  HWND hwndControl;
+  POINT ptHelp, ptCancel, ptLine;
+
+  /* Help button */
+  hwndControl = GetDlgItem(hwndDlg, IDHELP);
+  GetWindowRect(hwndControl, &rc);
+
+  ptHelp.x = rc.left;
+  ptHelp.y = rc.top;
+
+  ScreenToClient(hwndDlg, &ptHelp);
+
+  /* Cancel button */
+  hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
+  GetWindowRect(hwndControl, &rc);
+
+  ptCancel.x = rc.right;
+  ptCancel.y = rc.top;
+
+  ScreenToClient(hwndDlg, &ptCancel);
+
+  /* Line */
+  hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
+  GetWindowRect(hwndControl, &rc);
+
+  ptLine.x = 0;
+  ptLine.y = rc.bottom;
+
+  ScreenToClient(hwndDlg, &ptLine);
+
+  padding.x = ptHelp.x - ptCancel.x;
+  padding.y = ptHelp.y - ptLine.y;
+
+  return padding;
+}
+
 /******************************************************************************
  *            PROPSHEET_CreateTabControl
  *
@@ -631,8 +880,8 @@ static int PROPSHEET_CreatePage(HWND hwndParent,
   HWND hwndPage;
   RECT rc;
   PropPageInfo* ppInfo = psInfo->proppage;
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
-  HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
+  PADDING_INFO padding;
+  HWND hwndAfter;
 
   TRACE("index %d\n", index);
 
@@ -686,12 +935,25 @@ static int PROPSHEET_CreatePage(HWND hwndParent,
 
   MapDialogRect(hwndParent, &rc);
 
-  /*
-   * Ask the Tab control to fit this page in.
-   */
-  SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
+  if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
+  {
+    GetWindowRect(hwndParent, &rc);
+    padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
+    hwndAfter = hwndParent;
+  }
+  else
+  {
+    /*
+     * Ask the Tab control to fit this page in.
+     */
+
+    HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
+    SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
+    padding = PROPSHEET_GetPaddingInfo(hwndParent);
+    hwndAfter = HWND_TOP;
+  }
 
-  SetWindowPos(hwndPage, HWND_TOP,
+  SetWindowPos(hwndPage, hwndAfter,
                rc.left + padding.x,
                rc.top + padding.y,
                0, 0, SWP_NOSIZE);
@@ -741,6 +1003,91 @@ static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
   return TRUE;
 }
 
+/******************************************************************************
+ *            PROPSHEET_Back
+ */
+static BOOL PROPSHEET_Back(HWND hwndDlg)
+{
+  BOOL res;
+  NMHDR hdr;
+  HWND hwndPage;
+  HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  hdr.code = PSN_WIZBACK;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) == -1)
+    return FALSE;
+
+  res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
+
+  /* if we went to page 0, disable Back button */
+  if (res && (psInfo->active_page == 0))
+    EnableWindow(hwndBack, FALSE);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Next
+ */
+static BOOL PROPSHEET_Next(HWND hwndDlg)
+{
+  NMHDR hdr;
+  HWND hwndPage;
+  LRESULT msgResult = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  hdr.code = PSN_WIZNEXT;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
+
+  TRACE("msg result %ld\n", msgResult);
+
+  if (msgResult == -1)
+    return FALSE;
+
+  PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Finish
+ */
+static BOOL PROPSHEET_Finish(HWND hwndDlg)
+{
+  NMHDR hdr;
+  HWND hwndPage;
+  LRESULT msgResult = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  hdr.code = PSN_WIZFINISH;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
+
+  TRACE("msg result %ld\n", msgResult);
+
+  if (msgResult != 0)
+    return FALSE;
+
+  if (psInfo->isModeless)
+    psInfo->active_page = -1;
+  else
+    EndDialog(hwndDlg, TRUE);
+
+  return TRUE;
+}
+
 /******************************************************************************
  *            PROPSHEET_Apply
  */
@@ -894,19 +1241,19 @@ static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
       SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
       break;
     case PSBTN_BACK:
-      FIXME("Wizard mode not implemented.\n");
+      PROPSHEET_Back(hwndDlg);
       break;
     case PSBTN_CANCEL:
       SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
       break;
     case PSBTN_FINISH:
-      FIXME("Wizard mode not implemented.\n");
+      PROPSHEET_Finish(hwndDlg);
       break;
     case PSBTN_HELP:
       SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
       break;
     case PSBTN_NEXT:
-      FIXME("Wizard mode not implemented.\n");
+      PROPSHEET_Next(hwndDlg);
       break;
     case PSBTN_OK:
       SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
@@ -1008,6 +1355,30 @@ static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
     SetWindowTextA(hwndDlg, lpszText);
 }
 
+/******************************************************************************
+ *            PROPSHEET_SetFinishTextA
+ */
+static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
+{
+  HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+
+  /* Set text, show and enable the Finish button */
+  SetWindowTextA(hwndButton, lpszText);
+  ShowWindow(hwndButton, SW_SHOW);
+  EnableWindow(hwndButton, TRUE);
+
+  /* Make it default pushbutton */
+  SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
+
+  /* Hide Back button */
+  hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
+  ShowWindow(hwndButton, SW_HIDE);
+
+  /* Hide Next button */
+  hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
+  ShowWindow(hwndButton, SW_HIDE);
+}
+
 /******************************************************************************
  *            PROPSHEET_QuerySiblings
  */
@@ -1185,6 +1556,62 @@ static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
   return FALSE;
 }
 
+/******************************************************************************
+ *            PROPSHEET_SetWizButtons
+ *
+ * This code will work if (and assumes that) the Next button is on top of the
+ * Finish button. ie. Finish comes after Next in the Z order.
+ * This means make sure the dialog template reflects this.
+ *
+ */
+static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
+{
+  HWND hwndButton;
+
+  TRACE("%ld\n", dwFlags);
+
+  if (dwFlags & PSWIZB_BACK)
+  {
+    hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
+    EnableWindow(hwndButton, TRUE);
+  }
+
+  if (dwFlags & PSWIZB_NEXT)
+  {
+    /* Hide the Finish button */
+    hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+    ShowWindow(hwndButton, SW_HIDE);
+
+    /* Show and enable the Next button */
+    hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
+    
+    ShowWindow(hwndButton, SW_SHOW);
+    EnableWindow(hwndButton, TRUE);
+
+    /* Set the Next button as the default pushbutton  */
+    SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
+  }
+
+  if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
+  {
+    /* Hide the Next button */
+    hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
+    ShowWindow(hwndButton, SW_HIDE);
+
+    /* Show the Finish button */
+    hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+    ShowWindow(hwndButton, SW_SHOW);
+
+    if (dwFlags & PSWIZB_FINISH)
+      EnableWindow(hwndButton, TRUE);
+    else
+      EnableWindow(hwndButton, FALSE);
+
+    /* Set the Finish button as the default pushbutton  */
+    SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
+  }
+}
+
 /******************************************************************************
  *            PROPSHEET_GetPageIndex
  *
@@ -1343,17 +1770,36 @@ PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 
       GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
 
-      PROPSHEET_CreateTabControl(hwnd, psInfo);
+      if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
+      {
+        HWND hwndBack = GetDlgItem(hwnd, IDC_BACK_BUTTON);
+
+        if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
+        {
+          PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
+          PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
+        }
 
-      if (PROPSHEET_IsTooSmall(hwnd, psInfo))
+        /* Disable Back button if we start at page 0 */
+        if (psInfo->active_page == 0)
+          EnableWindow(hwndBack, FALSE);
+      }
+      else
       {
-        PROPSHEET_AdjustSize(hwnd, psInfo);
-        PROPSHEET_AdjustButtons(hwnd, psInfo);
+        PROPSHEET_CreateTabControl(hwnd, psInfo);
+
+        if (PROPSHEET_IsTooSmall(hwnd, psInfo))
+        {
+          PROPSHEET_AdjustSize(hwnd, psInfo);
+          PROPSHEET_AdjustButtons(hwnd, psInfo);
+        }
       }
 
       ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);      
       PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
-      SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
+
+      if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
+        SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
 
       SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
 
@@ -1410,6 +1856,18 @@ PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
           break;
         }
 
+        case IDC_BACK_BUTTON:
+          PROPSHEET_Back(hwnd);
+          break;
+
+        case IDC_NEXT_BUTTON:
+          PROPSHEET_Next(hwnd);
+          break;
+
+        case IDC_FINISH_BUTTON:
+          PROPSHEET_Finish(hwnd);
+          break;
+
         case IDCANCEL:
           PROPSHEET_Cancel(hwnd);
           break;
@@ -1548,18 +2006,20 @@ PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       PROPSHEET_PressButton(hwnd, (int)wParam);
       return TRUE;
 
+    case PSM_SETFINISHTEXTA:
+      PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);        
+      return TRUE;
+
+    case PSM_SETWIZBUTTONS:
+      PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
+      return TRUE;
+
     case PSM_SETTITLEW:
         FIXME("Unimplemented msg PSM_SETTITLE32W\n");
         return 0;
-    case PSM_SETWIZBUTTONS:
-        FIXME("Unimplemented msg PSM_SETWIZBUTTONS\n");
-        return 0;
     case PSM_SETCURSELID:
         FIXME("Unimplemented msg PSM_SETCURSELID\n");
         return 0;
-    case PSM_SETFINISHTEXTA:
-        FIXME("Unimplemented msg PSM_SETFINISHTEXT32A\n");
-        return 0;
     case PSM_SETFINISHTEXTW:
         FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
         return 0;
diff --git a/dlls/comctl32/rsrc.rc b/dlls/comctl32/rsrc.rc
index 89e6dad4802..d3223fa292e 100644
--- a/dlls/comctl32/rsrc.rc
+++ b/dlls/comctl32/rsrc.rc
@@ -15,6 +15,20 @@ BEGIN
 END
 
 
+IDD_WIZARD DIALOG DISCARDABLE 0, 0, 292, 159
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CONTROL
+CAPTION "Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+  DEFPUSHBUTTON "Finish",  IDC_FINISH_BUTTON,121,138,50,14
+  DEFPUSHBUTTON "&Next >", IDC_NEXT_BUTTON,121,138,50,14
+  PUSHBUTTON    "< &Back", IDC_BACK_BUTTON,71,138,50,14
+  PUSHBUTTON    "Cancel",  IDCANCEL,178,138,50,14
+  PUSHBUTTON    "Help",    IDHELP,235,138,50,14
+  LTEXT         "",        IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
+END
+
+
 IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "Customize Toolbar"
-- 
GitLab