fixed line endings on all files
[reactos.git] / reactos / lib / comctl32 / propsheet.c
index 16703f8..04ea675 100644 (file)
-/*\r
- * Property Sheets\r
- *\r
- * Copyright 1998 Francis Beaudet\r
- * Copyright 1999 Thuy Nguyen\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- *\r
- * TODO:\r
- *   - Tab order\r
- *   - Unicode property sheets\r
- */\r
-\r
-#include <stdarg.h>\r
-#include <string.h>\r
-\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "winnls.h"\r
-#include "commctrl.h"\r
-#include "prsht.h"\r
-#include "comctl32.h"\r
-\r
-#include "wine/debug.h"\r
-#include "wine/unicode.h"\r
-\r
-/******************************************************************************\r
- * Data structures\r
- */\r
-#include "pshpack2.h"\r
-\r
-typedef struct\r
-{\r
-  WORD dlgVer;\r
-  WORD signature;\r
-  DWORD helpID;\r
-  DWORD exStyle;\r
-  DWORD style;\r
-} MyDLGTEMPLATEEX;\r
-\r
-typedef struct\r
-{\r
-  DWORD helpid;\r
-  DWORD exStyle;\r
-  DWORD style;\r
-  short x;\r
-  short y;\r
-  short cx;\r
-  short cy;\r
-  DWORD id;\r
-} MyDLGITEMTEMPLATEEX;\r
-#include "poppack.h"\r
-\r
-typedef struct tagPropPageInfo\r
-{\r
-  HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */\r
-  HWND hwndPage;\r
-  BOOL isDirty;\r
-  LPCWSTR pszText;\r
-  BOOL hasHelp;\r
-  BOOL useCallback;\r
-  BOOL hasIcon;\r
-} PropPageInfo;\r
-\r
-typedef struct tagPropSheetInfo\r
-{\r
-  HWND hwnd;\r
-  PROPSHEETHEADERW ppshheader;\r
-  BOOL unicode;\r
-  LPWSTR strPropertiesFor;\r
-  int nPages;\r
-  int active_page;\r
-  BOOL isModeless;\r
-  BOOL hasHelp;\r
-  BOOL hasApply;\r
-  BOOL useCallback;\r
-  BOOL restartWindows;\r
-  BOOL rebootSystem;\r
-  BOOL activeValid;\r
-  PropPageInfo* proppage;\r
-  int x;\r
-  int y;\r
-  int width;\r
-  int height;\r
-  HIMAGELIST hImageList;\r
-} PropSheetInfo;\r
-\r
-typedef struct\r
-{\r
-  int x;\r
-  int y;\r
-} PADDING_INFO;\r
-\r
-/******************************************************************************\r
- * Defines and global variables\r
- */\r
-\r
-const WCHAR PropSheetInfoStr[] =\r
-    {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };\r
-\r
-#define PSP_INTERNAL_UNICODE 0x80000000\r
-\r
-#define MAX_CAPTION_LENGTH 255\r
-#define MAX_TABTEXT_LENGTH 255\r
-#define MAX_BUTTONTEXT_LENGTH 64\r
-\r
-#define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)\r
-\r
-/******************************************************************************\r
- * Prototypes\r
- */\r
-static int PROPSHEET_CreateDialog(PropSheetInfo* psInfo);\r
-static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);\r
-static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);\r
-static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);\r
-static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,\r
-                                       PropSheetInfo * psInfo);\r
-static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,\r
-                                       PropSheetInfo * psInfo);\r
-static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,\r
-                                      PropSheetInfo * psInfo,\r
-                                      int index);\r
-static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,\r
-                                       PropSheetInfo * psInfo);\r
-static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index,\r
-                                const PropSheetInfo * psInfo,\r
-                                LPCPROPSHEETPAGEW ppshpage);\r
-static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);\r
-static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);\r
-static BOOL PROPSHEET_Back(HWND hwndDlg);\r
-static BOOL PROPSHEET_Next(HWND hwndDlg);\r
-static BOOL PROPSHEET_Finish(HWND hwndDlg);\r
-static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);\r
-static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);\r
-static void PROPSHEET_Help(HWND hwndDlg);\r
-static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);\r
-static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);\r
-static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);\r
-static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);\r
-static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText);\r
-static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);\r
-static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);\r
-static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);\r
-static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,\r
-                                int index,\r
-                                int skipdir,\r
-                                HPROPSHEETPAGE hpage);\r
-static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id);\r
-static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,\r
-                                       WPARAM wParam, LPARAM lParam);\r
-static BOOL PROPSHEET_AddPage(HWND hwndDlg,\r
-                              HPROPSHEETPAGE hpage);\r
-\r
-static BOOL PROPSHEET_RemovePage(HWND hwndDlg,\r
-                                 int index,\r
-                                 HPROPSHEETPAGE hpage);\r
-static void PROPSHEET_CleanUp();\r
-static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);\r
-static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);\r
-static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);\r
-static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);\r
-static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);\r
-\r
-INT_PTR CALLBACK\r
-PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(propsheet);\r
-\r
-#define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}\r
-/******************************************************************************\r
- *            PROPSHEET_UnImplementedFlags\r
- *\r
- * Document use of flags we don't implement yet.\r
- */\r
-static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)\r
-{\r
-    CHAR string[256];\r
-\r
-    string[0] = '\0';\r
-\r
-  /*\r
-   * unhandled header flags:\r
-   *  PSH_DEFAULT            0x00000000\r
-   *  PSH_WIZARDHASFINISH    0x00000010\r
-   *  PSH_RTLREADING         0x00000800\r
-   *  PSH_WIZARDCONTEXTHELP  0x00001000\r
-   *  PSH_WIZARD97           0x00002000  (pre IE 5)\r
-   *  PSH_WATERMARK          0x00008000\r
-   *  PSH_USEHBMWATERMARK    0x00010000\r
-   *  PSH_USEHPLWATERMARK    0x00020000\r
-   *  PSH_STRETCHWATERMARK   0x00040000\r
-   *  PSH_HEADER             0x00080000\r
-   *  PSH_USEHBMHEADER       0x00100000\r
-   *  PSH_USEPAGELANG        0x00200000\r
-   *  PSH_WIZARD_LITE        0x00400000      also not in .h\r
-   *  PSH_WIZARD97           0x01000000  (IE 5 and above)\r
-   *  PSH_NOCONTEXTHELP      0x02000000      also not in .h\r
-   */\r
-\r
-    add_flag(PSH_WIZARDHASFINISH);\r
-    add_flag(PSH_RTLREADING);\r
-    add_flag(PSH_WIZARDCONTEXTHELP);\r
-    add_flag(PSH_WIZARD97_OLD);\r
-    add_flag(PSH_WATERMARK);\r
-    add_flag(PSH_USEHBMWATERMARK);\r
-    add_flag(PSH_USEHPLWATERMARK);\r
-    add_flag(PSH_STRETCHWATERMARK);\r
-    add_flag(PSH_HEADER);\r
-    add_flag(PSH_USEHBMHEADER);\r
-    add_flag(PSH_USEPAGELANG);\r
-    add_flag(PSH_WIZARD_LITE);\r
-    add_flag(PSH_WIZARD97_NEW);\r
-    add_flag(PSH_NOCONTEXTHELP);\r
-    if (string[0] != '\0')\r
-       FIXME("%s\n", string);\r
-}\r
-#undef add_flag\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_GetPageRect\r
- *\r
- * Retrieve rect from tab control and map into the dialog for SetWindowPos\r
- */\r
-static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg, RECT *rc)\r
-{\r
-    HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-\r
-    GetClientRect(hwndTabCtrl, rc);\r
-    SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc);\r
-    MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_FindPageByResId\r
- *\r
- * Find page index corresponding to page resource id.\r
- */\r
-INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId)\r
-{\r
-   INT i;\r
-\r
-   for (i = 0; i < psInfo->nPages; i++)\r
-   {\r
-      LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;\r
-\r
-      /* Fixme: if resource ID is a string shall we use strcmp ??? */\r
-      if (lppsp->u.pszTemplate == (LPVOID)resId)\r
-         break;\r
-   }\r
-\r
-   return i;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AtoW\r
- *\r
- * Convert ASCII to Unicode since all data is saved as Unicode.\r
- */\r
-static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr)\r
-{\r
-    INT len;\r
-\r
-    TRACE("<%s>\n", frstr);\r
-    len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0);\r
-    *tostr = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));\r
-    MultiByteToWideChar(CP_ACP, 0, frstr, -1, (LPWSTR)*tostr, len);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CollectSheetInfoA\r
- *\r
- * Collect relevant data.\r
- */\r
-static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,\r
-                                       PropSheetInfo * psInfo)\r
-{\r
-  DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));\r
-  DWORD dwFlags = lppsh->dwFlags;\r
-\r
-  psInfo->hasHelp = dwFlags & PSH_HASHELP;\r
-  psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);\r
-  psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);\r
-  psInfo->isModeless = dwFlags & PSH_MODELESS;\r
-\r
-  memcpy(&psInfo->ppshheader,lppsh,dwSize);\r
-  TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",\r
-       lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,\r
-       debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);\r
-\r
-  PROPSHEET_UnImplementedFlags(lppsh->dwFlags);\r
-\r
-  if (lppsh->dwFlags & INTRNL_ANY_WIZARD)\r
-     psInfo->ppshheader.pszCaption = NULL;\r
-  else\r
-  {\r
-     if (HIWORD(lppsh->pszCaption))\r
-     {\r
-        int len = strlen(lppsh->pszCaption);\r
-        psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );\r
-        MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len+1);\r
-        /* strcpy( (char *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); */\r
-     }\r
-  }\r
-  psInfo->nPages = lppsh->nPages;\r
-\r
-  if (dwFlags & PSH_USEPSTARTPAGE)\r
-  {\r
-    TRACE("PSH_USEPSTARTPAGE is on");\r
-    psInfo->active_page = 0;\r
-  }\r
-  else\r
-    psInfo->active_page = lppsh->u2.nStartPage;\r
-\r
-  if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)\r
-     psInfo->active_page = 0;\r
-\r
-  psInfo->restartWindows = FALSE;\r
-  psInfo->rebootSystem = FALSE;\r
-  psInfo->hImageList = 0;\r
-  psInfo->activeValid = FALSE;\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CollectSheetInfoW\r
- *\r
- * Collect relevant data.\r
- */\r
-static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,\r
-                                       PropSheetInfo * psInfo)\r
-{\r
-  DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));\r
-  DWORD dwFlags = lppsh->dwFlags;\r
-\r
-  psInfo->hasHelp = dwFlags & PSH_HASHELP;\r
-  psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);\r
-  psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);\r
-  psInfo->isModeless = dwFlags & PSH_MODELESS;\r
-\r
-  memcpy(&psInfo->ppshheader,lppsh,dwSize);\r
-  TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",\r
-      lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);\r
-\r
-  PROPSHEET_UnImplementedFlags(lppsh->dwFlags);\r
-\r
-  if (lppsh->dwFlags & INTRNL_ANY_WIZARD)\r
-     psInfo->ppshheader.pszCaption = NULL;\r
-  else\r
-  {\r
-     if (!(lppsh->dwFlags & INTRNL_ANY_WIZARD) && HIWORD(lppsh->pszCaption))\r
-     {\r
-        int len = strlenW(lppsh->pszCaption);\r
-        psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );\r
-        strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );\r
-     }\r
-  }\r
-  psInfo->nPages = lppsh->nPages;\r
-\r
-  if (dwFlags & PSH_USEPSTARTPAGE)\r
-  {\r
-    TRACE("PSH_USEPSTARTPAGE is on");\r
-    psInfo->active_page = 0;\r
-  }\r
-  else\r
-    psInfo->active_page = lppsh->u2.nStartPage;\r
-\r
-  if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)\r
-     psInfo->active_page = 0;\r
-\r
-  psInfo->restartWindows = FALSE;\r
-  psInfo->rebootSystem = FALSE;\r
-  psInfo->hImageList = 0;\r
-  psInfo->activeValid = FALSE;\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CollectPageInfo\r
- *\r
- * Collect property sheet data.\r
- * With code taken from DIALOG_ParseTemplate32.\r
- */\r
-BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,\r
-                               PropSheetInfo * psInfo,\r
-                               int index)\r
-{\r
-  DLGTEMPLATE* pTemplate;\r
-  const WORD*  p;\r
-  DWORD dwFlags;\r
-  int width, height;\r
-\r
-  TRACE("\n");\r
-  psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;\r
-  psInfo->proppage[index].hwndPage = 0;\r
-  psInfo->proppage[index].isDirty = FALSE;\r
-\r
-  /*\r
-   * Process property page flags.\r
-   */\r
-  dwFlags = lppsp->dwFlags;\r
-  psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);\r
-  psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;\r
-  psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);\r
-\r
-  /* as soon as we have a page with the help flag, set the sheet flag on */\r
-  if (psInfo->proppage[index].hasHelp)\r
-    psInfo->hasHelp = TRUE;\r
-\r
-  /*\r
-   * Process page template.\r
-   */\r
-  if (dwFlags & PSP_DLGINDIRECT)\r
-    pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;\r
-  else if(dwFlags & PSP_INTERNAL_UNICODE )\r
-  {\r
-    HRSRC hResource = FindResourceW(lppsp->hInstance,\r
-                                    lppsp->u.pszTemplate,\r
-                                    (LPWSTR)RT_DIALOG);\r
-    HGLOBAL hTemplate = LoadResource(lppsp->hInstance,\r
-                                     hResource);\r
-    pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);\r
-  }\r
-  else\r
-  {\r
-    HRSRC hResource = FindResourceA(lppsp->hInstance,\r
-                                    (LPSTR)lppsp->u.pszTemplate,\r
-                                    (LPSTR)RT_DIALOG);\r
-    HGLOBAL hTemplate = LoadResource(lppsp->hInstance,\r
-                                     hResource);\r
-    pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);\r
-  }\r
-\r
-  /*\r
-   * Extract the size of the page and the caption.\r
-   */\r
-  if (!pTemplate)\r
-      return FALSE;\r
-\r
-  p = (const WORD *)pTemplate;\r
-\r
-  if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)\r
-  {\r
-    /* DLGTEMPLATEEX (not defined in any std. header file) */\r
-\r
-    p++;       /* dlgVer    */\r
-    p++;       /* signature */\r
-    p += 2;    /* help ID   */\r
-    p += 2;    /* ext style */\r
-    p += 2;    /* style     */\r
-  }\r
-  else\r
-  {\r
-    /* DLGTEMPLATE */\r
-\r
-    p += 2;    /* style     */\r
-    p += 2;    /* ext style */\r
-  }\r
-\r
-  p++;    /* nb items */\r
-  p++;    /*   x      */\r
-  p++;    /*   y      */\r
-  width  = (WORD)*p; p++;\r
-  height = (WORD)*p; p++;\r
-\r
-  /* remember the largest width and height */\r
-  if (width > psInfo->width)\r
-    psInfo->width = width;\r
-\r
-  if (height > psInfo->height)\r
-    psInfo->height = height;\r
-\r
-  /* menu */\r
-  switch ((WORD)*p)\r
-  {\r
-    case 0x0000:\r
-      p++;\r
-      break;\r
-    case 0xffff:\r
-      p += 2;\r
-      break;\r
-    default:\r
-      p += lstrlenW( (LPCWSTR)p ) + 1;\r
-      break;\r
-  }\r
-\r
-  /* class */\r
-  switch ((WORD)*p)\r
-  {\r
-    case 0x0000:\r
-      p++;\r
-      break;\r
-    case 0xffff:\r
-      p += 2;\r
-      break;\r
-    default:\r
-      p += lstrlenW( (LPCWSTR)p ) + 1;\r
-      break;\r
-  }\r
-\r
-  /* Extract the caption */\r
-  psInfo->proppage[index].pszText = (LPCWSTR)p;\r
-  TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));\r
-  p += lstrlenW((LPCWSTR)p) + 1;\r
-\r
-  if (dwFlags & PSP_USETITLE)\r
-  {\r
-    WCHAR szTitle[256];\r
-    const WCHAR *pTitle;\r
-    static WCHAR pszNull[] = { '(','n','u','l','l',')',0 };\r
-    int len;\r
-\r
-    if ( !HIWORD( lppsp->pszTitle ) )\r
-    {\r
-      if (!LoadStringW( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,sizeof(szTitle) ))\r
-      {\r
-        pTitle = pszNull;\r
-       FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));\r
-      }\r
-      else\r
-        pTitle = szTitle;\r
-    }\r
-    else\r
-      pTitle = lppsp->pszTitle;\r
-\r
-    len = strlenW(pTitle);\r
-    psInfo->proppage[index].pszText = Alloc( (len+1)*sizeof (WCHAR) );\r
-    strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle);\r
-  }\r
-\r
-  /*\r
-   * Build the image list for icons\r
-   */\r
-  if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))\r
-  {\r
-    HICON hIcon;\r
-    int icon_cx = GetSystemMetrics(SM_CXSMICON);\r
-    int icon_cy = GetSystemMetrics(SM_CYSMICON);\r
-\r
-    if (dwFlags & PSP_USEICONID)\r
-      hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,\r
-                         icon_cx, icon_cy, LR_DEFAULTCOLOR);\r
-    else\r
-      hIcon = lppsp->u2.hIcon;\r
-\r
-    if ( hIcon )\r
-    {\r
-      if (psInfo->hImageList == 0 )\r
-       psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);\r
-\r
-      ImageList_AddIcon(psInfo->hImageList, hIcon);\r
-    }\r
-\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CreateDialog\r
- *\r
- * Creates the actual property sheet.\r
- */\r
-int PROPSHEET_CreateDialog(PropSheetInfo* psInfo)\r
-{\r
-  LRESULT ret;\r
-  LPCVOID template;\r
-  LPVOID temp = 0;\r
-  HRSRC hRes;\r
-  DWORD resSize;\r
-  WORD resID = IDD_PROPSHEET;\r
-\r
-  TRACE("\n");\r
-  if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)\r
-    resID = IDD_WIZARD;\r
-\r
-  if( psInfo->unicode )\r
-  {\r
-    if(!(hRes = FindResourceW(COMCTL32_hModule,\r
-                            MAKEINTRESOURCEW(resID),\r
-                            (LPWSTR)RT_DIALOG)))\r
-      return -1;\r
-  }\r
-  else\r
-  {\r
-    if(!(hRes = FindResourceA(COMCTL32_hModule,\r
-                            MAKEINTRESOURCEA(resID),\r
-                            (LPSTR)RT_DIALOG)))\r
-      return -1;\r
-  }\r
-\r
-  if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))\r
-    return -1;\r
-\r
-  /*\r
-   * Make a copy of the dialog template.\r
-   */\r
-  resSize = SizeofResource(COMCTL32_hModule, hRes);\r
-\r
-  temp = Alloc(resSize);\r
-\r
-  if (!temp)\r
-    return -1;\r
-\r
-  memcpy(temp, template, resSize);\r
-\r
-  if (psInfo->useCallback)\r
-    (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);\r
-\r
-  if( psInfo->unicode )\r
-  {\r
-    if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))\r
-      ret = DialogBoxIndirectParamW(psInfo->ppshheader.hInstance,\r
-                                    (LPDLGTEMPLATEW) temp,\r
-                                    psInfo->ppshheader.hwndParent,\r
-                                    PROPSHEET_DialogProc,\r
-                                    (LPARAM)psInfo);\r
-    else\r
-    {\r
-      ret = (int)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,\r
-                                            (LPDLGTEMPLATEW) temp,\r
-                                            psInfo->ppshheader.hwndParent,\r
-                                            PROPSHEET_DialogProc,\r
-                                            (LPARAM)psInfo);\r
-      if ( !ret ) ret = -1;\r
-    }\r
-  }\r
-  else\r
-  {\r
-    if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))\r
-      ret = DialogBoxIndirectParamA(psInfo->ppshheader.hInstance,\r
-                                    (LPDLGTEMPLATEA) temp,\r
-                                    psInfo->ppshheader.hwndParent,\r
-                                    PROPSHEET_DialogProc,\r
-                                    (LPARAM)psInfo);\r
-    else\r
-    {\r
-      ret = (int)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,\r
-                                            (LPDLGTEMPLATEA) temp,\r
-                                            psInfo->ppshheader.hwndParent,\r
-                                            PROPSHEET_DialogProc,\r
-                                            (LPARAM)psInfo);\r
-      if ( !ret ) ret = -1;\r
-    }\r
-  }\r
-\r
-  Free(temp);\r
-\r
-  return ret;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SizeMismatch\r
- *\r
- *     Verify that the tab control and the "largest" property sheet page dlg. template\r
- *     match in size.\r
- */\r
-static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)\r
-{\r
-  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  RECT rcOrigTab, rcPage;\r
-\r
-  /*\r
-   * Original tab size.\r
-   */\r
-  GetClientRect(hwndTabCtrl, &rcOrigTab);\r
-  TRACE("orig tab %ld %ld %ld %ld\n", rcOrigTab.left, rcOrigTab.top,\r
-        rcOrigTab.right, rcOrigTab.bottom);\r
-\r
-  /*\r
-   * Biggest page size.\r
-   */\r
-  rcPage.left   = psInfo->x;\r
-  rcPage.top    = psInfo->y;\r
-  rcPage.right  = psInfo->width;\r
-  rcPage.bottom = psInfo->height;\r
-\r
-  MapDialogRect(hwndDlg, &rcPage);\r
-  TRACE("biggest page %ld %ld %ld %ld\n", rcPage.left, rcPage.top,\r
-        rcPage.right, rcPage.bottom);\r
-\r
-  if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )\r
-    return TRUE;\r
-  if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )\r
-    return TRUE;\r
-\r
-  return FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_IsTooSmallWizard\r
- *\r
- * Verify that the default property sheet is big enough.\r
- */\r
-static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)\r
-{\r
-  RECT rcSheetRect, rcPage, rcLine, rcSheetClient;\r
-  HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);\r
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);\r
-\r
-  GetClientRect(hwndDlg, &rcSheetClient);\r
-  GetWindowRect(hwndDlg, &rcSheetRect);\r
-  GetWindowRect(hwndLine, &rcLine);\r
-\r
-  /* Remove the space below the sunken line */\r
-  rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);\r
-\r
-  /* Remove the buffer zone all around the edge */\r
-  rcSheetClient.bottom -= (padding.y * 2);\r
-  rcSheetClient.right -= (padding.x * 2);\r
-\r
-  /*\r
-   * Biggest page size.\r
-   */\r
-  rcPage.left   = psInfo->x;\r
-  rcPage.top    = psInfo->y;\r
-  rcPage.right  = psInfo->width;\r
-  rcPage.bottom = psInfo->height;\r
-\r
-  MapDialogRect(hwndDlg, &rcPage);\r
-  TRACE("biggest page %ld %ld %ld %ld\n", rcPage.left, rcPage.top,\r
-        rcPage.right, rcPage.bottom);\r
-\r
-  if (rcPage.right > rcSheetClient.right)\r
-    return TRUE;\r
-\r
-  if (rcPage.bottom > rcSheetClient.bottom)\r
-    return TRUE;\r
-\r
-  return FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AdjustSize\r
- *\r
- * Resizes the property sheet and the tab control to fit the largest page.\r
- */\r
-static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)\r
-{\r
-  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  HWND hwndButton = GetDlgItem(hwndDlg, IDOK);\r
-  RECT rc,tabRect;\r
-  int tabOffsetX, tabOffsetY, buttonHeight;\r
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);\r
-  RECT units;\r
-\r
-  /* Get the height of buttons */\r
-  GetClientRect(hwndButton, &rc);\r
-  buttonHeight = rc.bottom;\r
-\r
-  /*\r
-   * Biggest page size.\r
-   */\r
-  rc.left   = psInfo->x;\r
-  rc.top    = psInfo->y;\r
-  rc.right  = psInfo->width;\r
-  rc.bottom = psInfo->height;\r
-\r
-  MapDialogRect(hwndDlg, &rc);\r
-\r
-  /* retrieve the dialog units */\r
-  units.left = units.right = 4;\r
-  units.top = units.bottom = 8;\r
-  MapDialogRect(hwndDlg, &units);\r
-\r
-  /*\r
-   * Resize the tab control.\r
-   */\r
-  GetClientRect(hwndTabCtrl,&tabRect);\r
-\r
-  SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);\r
-\r
-  if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))\r
-  {\r
-      rc.bottom = rc.top + tabRect.bottom - tabRect.top;\r
-      psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);\r
-  }\r
-\r
-  if ((rc.right - rc.left) < (tabRect.right - tabRect.left))\r
-  {\r
-      rc.right = rc.left + tabRect.right - tabRect.left;\r
-      psInfo->width  = MulDiv((rc.right - rc.left),4,units.left);\r
-  }\r
-\r
-  SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);\r
-\r
-  tabOffsetX = -(rc.left);\r
-  tabOffsetY = -(rc.top);\r
-\r
-  rc.right -= rc.left;\r
-  rc.bottom -= rc.top;\r
-  TRACE("setting tab %08lx, rc (0,0)-(%ld,%ld)\n",\r
-        (DWORD)hwndTabCtrl, rc.right, rc.bottom);\r
-  SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,\r
-               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  GetClientRect(hwndTabCtrl, &rc);\r
-\r
-  TRACE("tab client rc %ld %ld %ld %ld\n",\r
-        rc.left, rc.top, rc.right, rc.bottom);\r
-\r
-  rc.right += ((padding.x * 2) + tabOffsetX);\r
-  rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);\r
-\r
-  /*\r
-   * Resize the property sheet.\r
-   */\r
-  TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n",\r
-        (DWORD)hwndDlg, rc.right, rc.bottom);\r
-  SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,\r
-               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AdjustSizeWizard\r
- *\r
- * Resizes the property sheet to fit the largest page.\r
- */\r
-static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)\r
-{\r
-  HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);\r
-  HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);\r
-  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  RECT rc,tabRect;\r
-  int buttonHeight, lineHeight;\r
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);\r
-  RECT units;\r
-\r
-  /* Get the height of buttons */\r
-  GetClientRect(hwndButton, &rc);\r
-  buttonHeight = rc.bottom;\r
-\r
-  GetClientRect(hwndLine, &rc);\r
-  lineHeight = rc.bottom;\r
-\r
-  /* retrieve the dialog units */\r
-  units.left = units.right = 4;\r
-  units.top = units.bottom = 8;\r
-  MapDialogRect(hwndDlg, &units);\r
-\r
-  /*\r
-   * Biggest page size.\r
-   */\r
-  rc.left   = psInfo->x;\r
-  rc.top    = psInfo->y;\r
-  rc.right  = psInfo->width;\r
-  rc.bottom = psInfo->height;\r
-\r
-  MapDialogRect(hwndDlg, &rc);\r
-\r
-  GetClientRect(hwndTabCtrl,&tabRect);\r
-\r
-  if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))\r
-  {\r
-      rc.bottom = rc.top + tabRect.bottom - tabRect.top;\r
-      psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);\r
-  }\r
-\r
-  if ((rc.right - rc.left) < (tabRect.right - tabRect.left))\r
-  {\r
-      rc.right = rc.left + tabRect.right - tabRect.left;\r
-      psInfo->width  = MulDiv((rc.right - rc.left), 4, units.left);\r
-  }\r
-\r
-  TRACE("Biggest page %ld %ld %ld %ld\n", rc.left, rc.top, rc.right, rc.bottom);\r
-  TRACE("   constants padx=%d, pady=%d, butH=%d, lH=%d\n",\r
-       padding.x, padding.y, buttonHeight, lineHeight);\r
-\r
-  /* Make room */\r
-  rc.right += (padding.x * 2);\r
-  rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);\r
-\r
-  /*\r
-   * Resize the property sheet.\r
-   */\r
-  TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n",\r
-        (DWORD)hwndDlg, rc.right, rc.bottom);\r
-  SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,\r
-               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AdjustButtons\r
- *\r
- * Adjusts the buttons' positions.\r
- */\r
-static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)\r
-{\r
-  HWND hwndButton = GetDlgItem(hwndParent, IDOK);\r
-  RECT rcSheet;\r
-  int x, y;\r
-  int num_buttons = 2;\r
-  int buttonWidth, buttonHeight;\r
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);\r
-\r
-  if (psInfo->hasApply)\r
-    num_buttons++;\r
-\r
-  if (psInfo->hasHelp)\r
-    num_buttons++;\r
-\r
-  /*\r
-   * Obtain the size of the buttons.\r
-   */\r
-  GetClientRect(hwndButton, &rcSheet);\r
-  buttonWidth = rcSheet.right;\r
-  buttonHeight = rcSheet.bottom;\r
-\r
-  /*\r
-   * Get the size of the property sheet.\r
-   */\r
-  GetClientRect(hwndParent, &rcSheet);\r
-\r
-  /*\r
-   * All buttons will be at this y coordinate.\r
-   */\r
-  y = rcSheet.bottom - (padding.y + buttonHeight);\r
-\r
-  /*\r
-   * Position OK button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDOK);\r
-\r
-  x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  /*\r
-   * Position Cancel button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDCANCEL);\r
-\r
-  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  /*\r
-   * Position Apply button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);\r
-\r
-  if (psInfo->hasApply)\r
-  {\r
-    if (psInfo->hasHelp)\r
-      x = rcSheet.right - ((padding.x + buttonWidth) * 2);\r
-    else\r
-      x = rcSheet.right - (padding.x + buttonWidth);\r
-\r
-    SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-    EnableWindow(hwndButton, FALSE);\r
-  }\r
-  else\r
-    ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  /*\r
-   * Position Help button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDHELP);\r
-\r
-  if (psInfo->hasHelp)\r
-  {\r
-    x = rcSheet.right - (padding.x + buttonWidth);\r
-\r
-    SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-  }\r
-  else\r
-    ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AdjustButtonsWizard\r
- *\r
- * Adjusts the buttons' positions.\r
- */\r
-static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,\r
-                                          PropSheetInfo* psInfo)\r
-{\r
-  HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);\r
-  HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);\r
-  RECT rcSheet;\r
-  int x, y;\r
-  int num_buttons = 3;\r
-  int buttonWidth, buttonHeight, lineHeight, lineWidth;\r
-  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);\r
-\r
-  if (psInfo->hasHelp)\r
-    num_buttons++;\r
-\r
-  /*\r
-   * Obtain the size of the buttons.\r
-   */\r
-  GetClientRect(hwndButton, &rcSheet);\r
-  buttonWidth = rcSheet.right;\r
-  buttonHeight = rcSheet.bottom;\r
-\r
-  GetClientRect(hwndLine, &rcSheet);\r
-  lineHeight = rcSheet.bottom;\r
-\r
-  /*\r
-   * Get the size of the property sheet.\r
-   */\r
-  GetClientRect(hwndParent, &rcSheet);\r
-\r
-  /*\r
-   * All buttons will be at this y coordinate.\r
-   */\r
-  y = rcSheet.bottom - (padding.y + buttonHeight);\r
-\r
-  /*\r
-   * Position the Next and the Finish buttons.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);\r
-\r
-  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  /*\r
-   * Position the Back button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);\r
-\r
-  x -= buttonWidth;\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  /*\r
-   * Position the Cancel button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDCANCEL);\r
-\r
-  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));\r
-\r
-  SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  /*\r
-   * Position Help button.\r
-   */\r
-  hwndButton = GetDlgItem(hwndParent, IDHELP);\r
-\r
-  if (psInfo->hasHelp)\r
-  {\r
-    x = rcSheet.right - (padding.x + buttonWidth);\r
-\r
-    SetWindowPos(hwndButton, 0, x, y, 0, 0,\r
-                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);\r
-  }\r
-  else\r
-    ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  /*\r
-   * Position and resize the sunken line.\r
-   */\r
-  x = padding.x;\r
-  y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);\r
-\r
-  GetClientRect(hwndParent, &rcSheet);\r
-  lineWidth = rcSheet.right - (padding.x * 2);\r
-\r
-  SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,\r
-               SWP_NOZORDER | SWP_NOACTIVATE);\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_GetPaddingInfo\r
- *\r
- * Returns the layout information.\r
- */\r
-static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)\r
-{\r
-  HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  RECT rcTab;\r
-  POINT tl;\r
-  PADDING_INFO padding;\r
-\r
-  GetWindowRect(hwndTab, &rcTab);\r
-\r
-  tl.x = rcTab.left;\r
-  tl.y = rcTab.top;\r
-\r
-  ScreenToClient(hwndDlg, &tl);\r
-\r
-  padding.x = tl.x;\r
-  padding.y = tl.y;\r
-\r
-  return padding;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_GetPaddingInfoWizard\r
- *\r
- * Returns the layout information.\r
- * Vertical spacing is the distance between the line and the buttons.\r
- * Do NOT use the Help button to gather padding information when it isn't mapped\r
- * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates\r
- * for it in this case !\r
- * FIXME: I'm not sure about any other coordinate problems with these evil\r
- * buttons. Fix it in case additional problems appear or maybe calculate\r
- * a padding in a completely different way, as this is somewhat messy.\r
- */\r
-static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*\r
- psInfo)\r
-{\r
-  PADDING_INFO padding;\r
-  RECT rc;\r
-  HWND hwndControl;\r
-  INT idButton;\r
-  POINT ptButton, ptLine;\r
-\r
-  TRACE("\n");\r
-  if (psInfo->hasHelp)\r
-  {\r
-       idButton = IDHELP;\r
-  }\r
-  else\r
-  {\r
-    if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)\r
-    {\r
-       idButton = IDC_NEXT_BUTTON;\r
-    }\r
-    else\r
-    {\r
-       /* hopefully this is ok */\r
-       idButton = IDCANCEL;\r
-    }\r
-  }\r
-\r
-  hwndControl = GetDlgItem(hwndDlg, idButton);\r
-  GetWindowRect(hwndControl, &rc);\r
-\r
-  ptButton.x = rc.left;\r
-  ptButton.y = rc.top;\r
-\r
-  ScreenToClient(hwndDlg, &ptButton);\r
-\r
-  /* Line */\r
-  hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);\r
-  GetWindowRect(hwndControl, &rc);\r
-\r
-  ptLine.x = 0;\r
-  ptLine.y = rc.bottom;\r
-\r
-  ScreenToClient(hwndDlg, &ptLine);\r
-\r
-  padding.y = ptButton.y - ptLine.y;\r
-\r
-  if (padding.y < 0)\r
-         ERR("padding negative ! Please report this !\n");\r
-\r
-  /* this is most probably not correct, but the best we have now */\r
-  padding.x = padding.y;\r
-  return padding;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CreateTabControl\r
- *\r
- * Insert the tabs in the tab control.\r
- */\r
-static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,\r
-                                       PropSheetInfo * psInfo)\r
-{\r
-  HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);\r
-  TCITEMW item;\r
-  int i, nTabs;\r
-  int iImage = 0;\r
-\r
-  TRACE("\n");\r
-  item.mask = TCIF_TEXT;\r
-  item.cchTextMax = MAX_TABTEXT_LENGTH;\r
-\r
-  nTabs = psInfo->nPages;\r
-\r
-  /*\r
-   * Set the image list for icons.\r
-   */\r
-  if (psInfo->hImageList)\r
-  {\r
-    SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);\r
-  }\r
-\r
-  for (i = 0; i < nTabs; i++)\r
-  {\r
-    if ( psInfo->proppage[i].hasIcon )\r
-    {\r
-      item.mask |= TCIF_IMAGE;\r
-      item.iImage = iImage++;\r
-    }\r
-    else\r
-    {\r
-      item.mask &= ~TCIF_IMAGE;\r
-    }\r
-\r
-    item.pszText = (LPWSTR) psInfo->proppage[i].pszText;\r
-    SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-/*\r
- * Get the size of an in-memory Template\r
- *\r
- *( Based on the code of PROPSHEET_CollectPageInfo)\r
- * See also dialog.c/DIALOG_ParseTemplate32().\r
- */\r
-\r
-static UINT GetTemplateSize(DLGTEMPLATE* pTemplate)\r
-\r
-{\r
-  const WORD*  p = (const WORD *)pTemplate;\r
-  BOOL  istemplateex = (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF);\r
-  WORD nrofitems;\r
-\r
-  if (istemplateex)\r
-  {\r
-    /* DLGTEMPLATEEX (not defined in any std. header file) */\r
-\r
-    TRACE("is DLGTEMPLATEEX\n");\r
-    p++;       /* dlgVer    */\r
-    p++;       /* signature */\r
-    p += 2;    /* help ID   */\r
-    p += 2;    /* ext style */\r
-    p += 2;    /* style     */\r
-  }\r
-  else\r
-  {\r
-    /* DLGTEMPLATE */\r
-\r
-    TRACE("is DLGTEMPLATE\n");\r
-    p += 2;    /* style     */\r
-    p += 2;    /* ext style */\r
-  }\r
-\r
-  nrofitems =   (WORD)*p; p++;    /* nb items */\r
-  p++;    /*   x      */\r
-  p++;    /*   y      */\r
-  p++;    /*   width  */\r
-  p++;    /*   height */\r
-\r
-  /* menu */\r
-  switch ((WORD)*p)\r
-  {\r
-    case 0x0000:\r
-      p++;\r
-      break;\r
-    case 0xffff:\r
-      p += 2;\r
-      break;\r
-    default:\r
-      TRACE("menu %s\n",debugstr_w((LPCWSTR)p));\r
-      p += lstrlenW( (LPCWSTR)p ) + 1;\r
-      break;\r
-  }\r
-\r
-  /* class */\r
-  switch ((WORD)*p)\r
-  {\r
-    case 0x0000:\r
-      p++;\r
-      break;\r
-    case 0xffff:\r
-      p += 2; /* 0xffff plus predefined window class ordinal value */\r
-      break;\r
-    default:\r
-      TRACE("class %s\n",debugstr_w((LPCWSTR)p));\r
-      p += lstrlenW( (LPCWSTR)p ) + 1;\r
-      break;\r
-  }\r
-\r
-  /* title */\r
-  TRACE("title %s\n",debugstr_w((LPCWSTR)p));\r
-  p += lstrlenW((LPCWSTR)p) + 1;\r
-\r
-  /* font, if DS_SETFONT set */\r
-  if ((DS_SETFONT & ((istemplateex)?  ((MyDLGTEMPLATEEX*)pTemplate)->style :\r
-                    pTemplate->style)))\r
-    {\r
-      p+=(istemplateex)?3:1;\r
-      TRACE("font %s\n",debugstr_w((LPCWSTR)p));\r
-      p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */\r
-    }\r
-\r
-  /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)\r
-   * that are following the DLGTEMPLATE(EX) data */\r
-  TRACE("%d items\n",nrofitems);\r
-  while (nrofitems > 0)\r
-    {\r
-      p = (WORD*)(((DWORD)p + 3) & ~3); /* DWORD align */\r
-      \r
-      /* skip header */\r
-      p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD);\r
-      \r
-      /* check class */\r
-      switch ((WORD)*p)\r
-       {\r
-       case 0x0000:\r
-         p++;\r
-         break;\r
-       case 0xffff:\r
-         TRACE("class ordinal 0x%08lx\n",*(DWORD*)p);\r
-         p += 2;\r
-         break;\r
-       default:\r
-         TRACE("class %s\n",debugstr_w((LPCWSTR)p));\r
-         p += lstrlenW( (LPCWSTR)p ) + 1;\r
-         break;\r
-       }\r
-\r
-      /* check title text */\r
-      switch ((WORD)*p)\r
-       {\r
-       case 0x0000:\r
-         p++;\r
-         break;\r
-       case 0xffff:\r
-         TRACE("text ordinal 0x%08lx\n",*(DWORD*)p);\r
-         p += 2;\r
-         break;\r
-       default:\r
-         TRACE("text %s\n",debugstr_w((LPCWSTR)p));\r
-         p += lstrlenW( (LPCWSTR)p ) + 1;\r
-         break;\r
-       }\r
-      p += *p + 1;    /* Skip extra data */\r
-      --nrofitems;\r
-    }\r
-  \r
-  TRACE("%p %p size 0x%08x\n",p, (WORD*)pTemplate,sizeof(WORD)*(p - (WORD*)pTemplate));\r
-  return (p - (WORD*)pTemplate)*sizeof(WORD);\r
-  \r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CreatePage\r
- *\r
- * Creates a page.\r
- */\r
-static BOOL PROPSHEET_CreatePage(HWND hwndParent,\r
-                                int index,\r
-                                const PropSheetInfo * psInfo,\r
-                                LPCPROPSHEETPAGEW ppshpage)\r
-{\r
-  DLGTEMPLATE* pTemplate;\r
-  HWND hwndPage;\r
-  RECT rc;\r
-  PropPageInfo* ppInfo = psInfo->proppage;\r
-  PADDING_INFO padding;\r
-  UINT pageWidth,pageHeight;\r
-  DWORD resSize;\r
-  LPVOID temp = NULL;\r
-\r
-  TRACE("index %d\n", index);\r
-\r
-  if (ppshpage == NULL)\r
-  {\r
-    return FALSE;\r
-  }\r
-\r
-  if (ppshpage->dwFlags & PSP_DLGINDIRECT)\r
-    {\r
-      pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;\r
-      resSize = GetTemplateSize(pTemplate);\r
-    }\r
-  else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)\r
-  {\r
-    HRSRC hResource;\r
-    HANDLE hTemplate;\r
-\r
-    hResource = FindResourceW(ppshpage->hInstance,\r
-                                    ppshpage->u.pszTemplate,\r
-                                    (LPWSTR)RT_DIALOG);\r
-    if(!hResource)\r
-       return FALSE;\r
-\r
-    resSize = SizeofResource(ppshpage->hInstance, hResource);\r
-\r
-    hTemplate = LoadResource(ppshpage->hInstance, hResource);\r
-    if(!hTemplate)\r
-       return FALSE;\r
-\r
-    pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);\r
-    /*\r
-     * Make a copy of the dialog template to make it writable\r
-     */\r
-  }\r
-  else\r
-  {\r
-    HRSRC hResource;\r
-    HANDLE hTemplate;\r
-\r
-    hResource = FindResourceA(ppshpage->hInstance,\r
-                                    (LPSTR)ppshpage->u.pszTemplate,\r
-                                    (LPSTR)RT_DIALOG);\r
-    if(!hResource)\r
-       return FALSE;\r
-\r
-    resSize = SizeofResource(ppshpage->hInstance, hResource);\r
-\r
-    hTemplate = LoadResource(ppshpage->hInstance, hResource);\r
-    if(!hTemplate)\r
-       return FALSE;\r
-\r
-    pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);\r
-    /*\r
-     * Make a copy of the dialog template to make it writable\r
-     */\r
-  }\r
-  temp = Alloc(resSize);\r
-  if (!temp)\r
-    return FALSE;\r
-  \r
-  TRACE("copying pTemplate %p into temp %p (%ld)\n", pTemplate, temp, resSize);\r
-  memcpy(temp, pTemplate, resSize);\r
-  pTemplate = temp;\r
-\r
-  if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)\r
-  {\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;\r
-    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME;\r
-  }\r
-  else\r
-  {\r
-    pTemplate->style |= WS_CHILD | DS_CONTROL;\r
-    pTemplate->style &= ~DS_MODALFRAME;\r
-    pTemplate->style &= ~WS_CAPTION;\r
-    pTemplate->style &= ~WS_SYSMENU;\r
-    pTemplate->style &= ~WS_POPUP;\r
-    pTemplate->style &= ~WS_DISABLED;\r
-    pTemplate->style &= ~WS_VISIBLE;\r
-    pTemplate->style &= ~WS_THICKFRAME;\r
-  }\r
-\r
-  if (psInfo->proppage[index].useCallback)\r
-    (*(ppshpage->pfnCallback))(hwndParent,\r
-                               PSPCB_CREATE,\r
-                               (LPPROPSHEETPAGEW)ppshpage);\r
-\r
-  if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)\r
-     hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,\r
-                                       pTemplate,\r
-                                       hwndParent,\r
-                                       ppshpage->pfnDlgProc,\r
-                                       (LPARAM)ppshpage);\r
-  else\r
-     hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,\r
-                                       pTemplate,\r
-                                       hwndParent,\r
-                                       ppshpage->pfnDlgProc,\r
-                                       (LPARAM)ppshpage);\r
-  /* Free a no more needed copy */\r
-  if(temp)\r
-      Free(temp);\r
-\r
-  ppInfo[index].hwndPage = hwndPage;\r
-\r
-  if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {\r
-      /* FIXME: This code may no longer be correct.\r
-       *        It was not for the non-wizard path.  (GLA 6/02)\r
-       */\r
-      rc.left = psInfo->x;\r
-      rc.top = psInfo->y;\r
-      rc.right = psInfo->width;\r
-      rc.bottom = psInfo->height;\r
-\r
-      MapDialogRect(hwndParent, &rc);\r
-\r
-      pageWidth = rc.right - rc.left;\r
-      pageHeight = rc.bottom - rc.top;\r
-\r
-      padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);\r
-      TRACE("setting page %08lx, rc (%ld,%ld)-(%ld,%ld) w=%d, h=%d, padx=%d, pady=%d\n",\r
-           (DWORD)hwndPage, rc.left, rc.top, rc.right, rc.bottom,\r
-           pageWidth, pageHeight, padding.x, padding.y);\r
-      SetWindowPos(hwndPage, HWND_TOP,\r
-                  rc.left + padding.x/2,\r
-                  rc.top + padding.y/2,\r
-                  pageWidth, pageHeight, 0);\r
-  }\r
-  else {\r
-      /*\r
-       * Ask the Tab control to reduce the client rectangle to that\r
-       * it has available.\r
-       */\r
-      PROPSHEET_GetPageRect(psInfo, hwndParent, &rc);\r
-      pageWidth = rc.right - rc.left;\r
-      pageHeight = rc.bottom - rc.top;\r
-      TRACE("setting page %08lx, rc (%ld,%ld)-(%ld,%ld) w=%d, h=%d\n",\r
-           (DWORD)hwndPage, rc.left, rc.top, rc.right, rc.bottom,\r
-           pageWidth, pageHeight);\r
-      SetWindowPos(hwndPage, HWND_TOP,\r
-                  rc.left, rc.top,\r
-                  pageWidth, pageHeight, 0);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_ShowPage\r
- *\r
- * Displays or creates the specified page.\r
- */\r
-static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)\r
-{\r
-  HWND hwndTabCtrl;\r
-\r
-  TRACE("active_page %d, index %d\n", psInfo->active_page, index);\r
-  if (index == psInfo->active_page)\r
-  {\r
-      if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)\r
-          SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);\r
-      return TRUE;\r
-  }\r
-\r
-  if (psInfo->proppage[index].hwndPage == 0)\r
-  {\r
-     LPCPROPSHEETPAGEW ppshpage;\r
-\r
-     ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;\r
-     PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);\r
-  }\r
-\r
-  PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,\r
-                      psInfo->proppage[index].pszText);\r
-\r
-  if (psInfo->active_page != -1)\r
-     ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);\r
-\r
-  ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);\r
-\r
-  /* Synchronize current selection with tab control\r
-   * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */\r
-  hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);\r
-\r
-  psInfo->active_page = index;\r
-  psInfo->activeValid = TRUE;\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Back\r
- */\r
-static BOOL PROPSHEET_Back(HWND hwndDlg)\r
-{\r
-  PSHNOTIFY psn;\r
-  HWND hwndPage;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-  LRESULT result;\r
-  int idx;\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return FALSE;\r
-\r
-  psn.hdr.code     = PSN_WIZBACK;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-\r
-  result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-  if (result == -1)\r
-    return FALSE;\r
-  else if (result == 0)\r
-     idx = psInfo->active_page - 1;\r
-  else\r
-     idx = PROPSHEET_FindPageByResId(psInfo, result);\r
-\r
-  if (idx >= 0 && idx < psInfo->nPages)\r
-  {\r
-     if (PROPSHEET_CanSetCurSel(hwndDlg))\r
-        PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);\r
-  }\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Next\r
- */\r
-static BOOL PROPSHEET_Next(HWND hwndDlg)\r
-{\r
-  PSHNOTIFY psn;\r
-  HWND hwndPage;\r
-  LRESULT msgResult = 0;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-  int idx;\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return FALSE;\r
-\r
-  psn.hdr.code     = PSN_WIZNEXT;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-\r
-  msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-  if (msgResult == -1)\r
-    return FALSE;\r
-  else if (msgResult == 0)\r
-     idx = psInfo->active_page + 1;\r
-  else\r
-     idx = PROPSHEET_FindPageByResId(psInfo, msgResult);\r
-\r
-  if (idx < psInfo->nPages )\r
-  {\r
-     if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)\r
-        PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Finish\r
- */\r
-static BOOL PROPSHEET_Finish(HWND hwndDlg)\r
-{\r
-  PSHNOTIFY psn;\r
-  HWND hwndPage;\r
-  LRESULT msgResult = 0;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return FALSE;\r
-\r
-  psn.hdr.code     = PSN_WIZFINISH;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-\r
-  msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-\r
-  TRACE("msg result %ld\n", msgResult);\r
-\r
-  if (msgResult != 0)\r
-    return FALSE;\r
-\r
-  if (psInfo->isModeless)\r
-    psInfo->activeValid = FALSE;\r
-  else\r
-    EndDialog(hwndDlg, TRUE);\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Apply\r
- */\r
-static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)\r
-{\r
-  int i;\r
-  HWND hwndPage;\r
-  PSHNOTIFY psn;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return FALSE;\r
-\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-\r
-  /*\r
-   * Send PSN_KILLACTIVE to the current page.\r
-   */\r
-  psn.hdr.code = PSN_KILLACTIVE;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-\r
-  if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)\r
-    return FALSE;\r
-\r
-  /*\r
-   * Send PSN_APPLY to all pages.\r
-   */\r
-  psn.hdr.code = PSN_APPLY;\r
-  psn.lParam   = lParam;\r
-\r
-  for (i = 0; i < psInfo->nPages; i++)\r
-  {\r
-    hwndPage = psInfo->proppage[i].hwndPage;\r
-    if (hwndPage)\r
-    {\r
-       switch (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))\r
-       {\r
-       case PSNRET_INVALID:\r
-           PROPSHEET_ShowPage(hwndDlg, i, psInfo);\r
-           /* fall through */\r
-       case PSNRET_INVALID_NOCHANGEPAGE:\r
-           return FALSE;\r
-       }\r
-    }\r
-  }\r
-\r
-  if(lParam)\r
-  {\r
-     psInfo->activeValid = FALSE;\r
-  }\r
-  else if(psInfo->active_page >= 0)\r
-  {\r
-     psn.hdr.code = PSN_SETACTIVE;\r
-     psn.lParam   = 0;\r
-     hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-     SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Cancel\r
- */\r
-static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)\r
-{\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-  HWND hwndPage;\r
-  PSHNOTIFY psn;\r
-  int i;\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-  psn.hdr.code     = PSN_QUERYCANCEL;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))\r
-    return;\r
-\r
-  psn.hdr.code = PSN_RESET;\r
-  psn.lParam   = lParam;\r
-\r
-  for (i = 0; i < psInfo->nPages; i++)\r
-  {\r
-    hwndPage = psInfo->proppage[i].hwndPage;\r
-\r
-    if (hwndPage)\r
-       SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-  }\r
-\r
-  if (psInfo->isModeless)\r
-  {\r
-     /* makes PSM_GETCURRENTPAGEHWND return NULL */\r
-     psInfo->activeValid = FALSE;\r
-  }\r
-  else\r
-    EndDialog(hwndDlg, FALSE);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Help\r
- */\r
-static void PROPSHEET_Help(HWND hwndDlg)\r
-{\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-  HWND hwndPage;\r
-  PSHNOTIFY psn;\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (psInfo->active_page < 0)\r
-     return;\r
-\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-  psn.hdr.code     = PSN_HELP;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_Changed\r
- */\r
-static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)\r
-{\r
-  int i;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-\r
-  TRACE("\n");\r
-  if (!psInfo) return;\r
-  /*\r
-   * Set the dirty flag of this page.\r
-   */\r
-  for (i = 0; i < psInfo->nPages; i++)\r
-  {\r
-    if (psInfo->proppage[i].hwndPage == hwndDirtyPage)\r
-      psInfo->proppage[i].isDirty = TRUE;\r
-  }\r
-\r
-  /*\r
-   * Enable the Apply button.\r
-   */\r
-  if (psInfo->hasApply)\r
-  {\r
-    HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);\r
-\r
-    EnableWindow(hwndApplyBtn, TRUE);\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_UnChanged\r
- */\r
-static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)\r
-{\r
-  int i;\r
-  BOOL noPageDirty = TRUE;\r
-  HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-\r
-  TRACE("\n");\r
-  if ( !psInfo ) return;\r
-  for (i = 0; i < psInfo->nPages; i++)\r
-  {\r
-    /* set the specified page as clean */\r
-    if (psInfo->proppage[i].hwndPage == hwndCleanPage)\r
-      psInfo->proppage[i].isDirty = FALSE;\r
-\r
-    /* look to see if there's any dirty pages */\r
-    if (psInfo->proppage[i].isDirty)\r
-      noPageDirty = FALSE;\r
-  }\r
-\r
-  /*\r
-   * Disable Apply button.\r
-   */\r
-  if (noPageDirty)\r
-    EnableWindow(hwndApplyBtn, FALSE);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_PressButton\r
- */\r
-static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)\r
-{\r
-  TRACE("buttonID %d\n", buttonID);\r
-  switch (buttonID)\r
-  {\r
-    case PSBTN_APPLYNOW:\r
-      PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);\r
-      break;\r
-    case PSBTN_BACK:\r
-      PROPSHEET_Back(hwndDlg);\r
-      break;\r
-    case PSBTN_CANCEL:\r
-      PROPSHEET_DoCommand(hwndDlg, IDCANCEL);\r
-      break;\r
-    case PSBTN_FINISH:\r
-      PROPSHEET_Finish(hwndDlg);\r
-      break;\r
-    case PSBTN_HELP:\r
-      PROPSHEET_DoCommand(hwndDlg, IDHELP);\r
-      break;\r
-    case PSBTN_NEXT:\r
-      PROPSHEET_Next(hwndDlg);\r
-      break;\r
-    case PSBTN_OK:\r
-      PROPSHEET_DoCommand(hwndDlg, IDOK);\r
-      break;\r
-    default:\r
-      FIXME("Invalid button index %d\n", buttonID);\r
-  }\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * BOOL PROPSHEET_CanSetCurSel [Internal]\r
- *\r
- * Test whether the current page can be changed by sending a PSN_KILLACTIVE\r
- *\r
- * PARAMS\r
- *     hwndDlg        [I] handle to a Dialog hWnd\r
- *\r
- * RETURNS\r
- *     TRUE if Current Selection can change\r
- *\r
- * NOTES\r
- */\r
-static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)\r
-{\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-  HWND hwndPage;\r
-  PSHNOTIFY psn;\r
-  BOOL res = FALSE;\r
-\r
-  TRACE("active_page %d\n", psInfo->active_page);\r
-  if (!psInfo)\r
-  {\r
-     res = FALSE;\r
-     goto end;\r
-  }\r
-\r
-  if (psInfo->active_page < 0)\r
-  {\r
-     res = TRUE;\r
-     goto end;\r
-  }\r
-\r
-  /*\r
-   * Notify the current page.\r
-   */\r
-  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-  psn.hdr.code     = PSN_KILLACTIVE;\r
-  psn.hdr.hwndFrom = hwndDlg;\r
-  psn.hdr.idFrom   = 0;\r
-  psn.lParam       = 0;\r
-\r
-  res = !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-\r
-end:\r
-  TRACE("<-- %d\n", res);\r
-  return res;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetCurSel\r
- */\r
-static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,\r
-                                int index,\r
-                               int skipdir,\r
-                                HPROPSHEETPAGE hpage\r
-                               )\r
-{\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);\r
-  HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);\r
-  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-\r
-  TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);\r
-  /* hpage takes precedence over index */\r
-  if (hpage != NULL)\r
-    index = PROPSHEET_GetPageIndex(hpage, psInfo);\r
-\r
-  if (index < 0 || index >= psInfo->nPages)\r
-  {\r
-    TRACE("Could not find page to select!\n");\r
-    return FALSE;\r
-  }\r
-\r
-  while (1) {\r
-    int result;\r
-    PSHNOTIFY psn;\r
-\r
-    if (hwndTabControl)\r
-       SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);\r
-\r
-    psn.hdr.code     = PSN_SETACTIVE;\r
-    psn.hdr.hwndFrom = hwndDlg;\r
-    psn.hdr.idFrom   = 0;\r
-    psn.lParam       = 0;\r
-\r
-    if (!psInfo->proppage[index].hwndPage) {\r
-      LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;\r
-      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);\r
-    }\r
-\r
-    result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);\r
-    if (!result)\r
-      break;\r
-    if (result == -1) {\r
-      index+=skipdir;\r
-      if (index < 0) {\r
-       index = 0;\r
-       FIXME("Tried to skip before first property sheet page!\n");\r
-       break;\r
-      }\r
-      if (index >= psInfo->nPages) {\r
-       FIXME("Tried to skip after last property sheet page!\n");\r
-       index = psInfo->nPages-1;\r
-       break;\r
-      }\r
-    }\r
-    else if (result != 0)\r
-    {\r
-       index = PROPSHEET_FindPageByResId(psInfo, result);\r
-       continue;\r
-    }\r
-  }\r
-  /*\r
-   * Display the new page.\r
-   */\r
-  PROPSHEET_ShowPage(hwndDlg, index, psInfo);\r
-\r
-  if (psInfo->proppage[index].hasHelp)\r
-    EnableWindow(hwndHelp, TRUE);\r
-  else\r
-    EnableWindow(hwndHelp, FALSE);\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetCurSelId\r
- *\r
- * Selects the page, specified by resource id.\r
- */\r
-static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)\r
-{\r
-      int idx;\r
-      PropSheetInfo* psInfo =\r
-          (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);\r
-\r
-      idx = PROPSHEET_FindPageByResId(psInfo, id);\r
-      if (idx < psInfo->nPages )\r
-      {\r
-          if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)\r
-              PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);\r
-      }\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetTitleA\r
- */\r
-static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)\r
-{\r
-  if(HIWORD(lpszText))\r
-  {\r
-     WCHAR szTitle[256];\r
-     MultiByteToWideChar(CP_ACP, 0, lpszText, -1,\r
-                            szTitle, sizeof(szTitle));\r
-     PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);\r
-  }\r
-  else\r
-  {\r
-     PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetTitleW\r
- */\r
-static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)\r
-{\r
-  PropSheetInfo*       psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);\r
-  WCHAR                        szTitle[256];\r
-\r
-  TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText), dwStyle);\r
-  if (HIWORD(lpszText) == 0) {\r
-    if (!LoadStringW(psInfo->ppshheader.hInstance,\r
-                     LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))\r
-      return;\r
-    lpszText = szTitle;\r
-  }\r
-  if (dwStyle & PSH_PROPTITLE)\r
-  {\r
-    WCHAR* dest;\r
-    int lentitle = strlenW(lpszText);\r
-    int lenprop  = strlenW(psInfo->strPropertiesFor);\r
-\r
-    dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));\r
-    strcpyW(dest, psInfo->strPropertiesFor);\r
-    strcatW(dest, lpszText);\r
-\r
-    SetWindowTextW(hwndDlg, dest);\r
-    Free(dest);\r
-  }\r
-  else\r
-    SetWindowTextW(hwndDlg, lpszText);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetFinishTextA\r
- */\r
-static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)\r
-{\r
-  HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);\r
-\r
-  TRACE("'%s'\n", lpszText);\r
-  /* Set text, show and enable the Finish button */\r
-  SetWindowTextA(hwndButton, lpszText);\r
-  ShowWindow(hwndButton, SW_SHOW);\r
-  EnableWindow(hwndButton, TRUE);\r
-\r
-  /* Make it default pushbutton */\r
-  SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);\r
-\r
-  /* Hide Back button */\r
-  hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);\r
-  ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  /* Hide Next button */\r
-  hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);\r
-  ShowWindow(hwndButton, SW_HIDE);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetFinishTextW\r
- */\r
-static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)\r
-{\r
-  HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);\r
-\r
-  TRACE("'%s'\n", debugstr_w(lpszText));\r
-  /* Set text, show and enable the Finish button */\r
-  SetWindowTextW(hwndButton, lpszText);\r
-  ShowWindow(hwndButton, SW_SHOW);\r
-  EnableWindow(hwndButton, TRUE);\r
-\r
-  /* Make it default pushbutton */\r
-  SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);\r
-\r
-  /* Hide Back button */\r
-  hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);\r
-  ShowWindow(hwndButton, SW_HIDE);\r
-\r
-  /* Hide Next button */\r
-  hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);\r
-  ShowWindow(hwndButton, SW_HIDE);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_QuerySiblings\r
- */\r
-static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,\r
-                                       WPARAM wParam, LPARAM lParam)\r
-{\r
-  int i = 0;\r
-  HWND hwndPage;\r
-  LRESULT msgResult = 0;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                    PropSheetInfoStr);\r
-\r
-  while ((i < psInfo->nPages) && (msgResult == 0))\r
-  {\r
-    hwndPage = psInfo->proppage[i].hwndPage;\r
-    msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);\r
-    i++;\r
-  }\r
-\r
-  return msgResult;\r
-}\r
-\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_AddPage\r
- */\r
-static BOOL PROPSHEET_AddPage(HWND hwndDlg,\r
-                              HPROPSHEETPAGE hpage)\r
-{\r
-  PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                     PropSheetInfoStr);\r
-  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  TCITEMW item;\r
-  LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;\r
-\r
-  TRACE("hpage %p\n", hpage);\r
-  /*\r
-   * Allocate and fill in a new PropPageInfo entry.\r
-   */\r
-  psInfo->proppage = (PropPageInfo*) ReAlloc(psInfo->proppage,\r
-                                                      sizeof(PropPageInfo) *\r
-                                                      (psInfo->nPages + 1));\r
-  if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))\r
-      return FALSE;\r
-\r
-  psInfo->proppage[psInfo->nPages].hpage = hpage;\r
-\r
-  if (ppsp->dwFlags & PSP_PREMATURE)\r
-  {\r
-     /* Create the page but don't show it */\r
-     PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);\r
-  }\r
-\r
-  /*\r
-   * Add a new tab to the tab control.\r
-   */\r
-  item.mask = TCIF_TEXT;\r
-  item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;\r
-  item.cchTextMax = MAX_TABTEXT_LENGTH;\r
-\r
-  if (psInfo->hImageList)\r
-  {\r
-    SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);\r
-  }\r
-\r
-  if ( psInfo->proppage[psInfo->nPages].hasIcon )\r
-  {\r
-    item.mask |= TCIF_IMAGE;\r
-    item.iImage = psInfo->nPages;\r
-  }\r
-\r
-  SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,\r
-               (LPARAM)&item);\r
-\r
-  psInfo->nPages++;\r
-\r
-  /* If it is the only page - show it */\r
-  if(psInfo->nPages == 1)\r
-     PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_RemovePage\r
- */\r
-static BOOL PROPSHEET_RemovePage(HWND hwndDlg,\r
-                                 int index,\r
-                                 HPROPSHEETPAGE hpage)\r
-{\r
-  PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,\r
-                                                     PropSheetInfoStr);\r
-  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);\r
-  PropPageInfo* oldPages;\r
-\r
-  TRACE("index %d, hpage %p\n", index, hpage);\r
-  if (!psInfo) {\r
-    return FALSE;\r
-  }\r
-  oldPages = psInfo->proppage;\r
-  /*\r
-   * hpage takes precedence over index.\r
-   */\r
-  if (hpage != 0)\r
-  {\r
-    index = PROPSHEET_GetPageIndex(hpage, psInfo);\r
-  }\r
-\r
-  /* Make sure that index is within range */\r
-  if (index < 0 || index >= psInfo->nPages)\r
-  {\r
-      TRACE("Could not find page to remove!\n");\r
-      return FALSE;\r
-  }\r
-\r
-  TRACE("total pages %d removing page %d active page %d\n",\r
-        psInfo->nPages, index, psInfo->active_page);\r
-  /*\r
-   * Check if we're removing the active page.\r
-   */\r
-  if (index == psInfo->active_page)\r
-  {\r
-    if (psInfo->nPages > 1)\r
-    {\r
-      if (index > 0)\r
-      {\r
-        /* activate previous page  */\r
-        PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);\r
-      }\r
-      else\r
-      {\r
-        /* activate the next page */\r
-        PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);\r
-        psInfo->active_page = index;\r
-      }\r
-    }\r
-    else\r
-    {\r
-      psInfo->active_page = -1;\r
-      if (!psInfo->isModeless)\r
-      {\r
-         EndDialog(hwndDlg, FALSE);\r
-         return TRUE;\r
-      }\r
-    }\r
-  }\r
-  else if (index < psInfo->active_page)\r
-    psInfo->active_page--;\r
-\r
-  /* Destroy page dialog window */\r
-  DestroyWindow(psInfo->proppage[index].hwndPage);\r
-\r
-  /* Free page resources */\r
-  if(psInfo->proppage[index].hpage)\r
-  {\r
-     PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;\r
-\r
-     if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)\r
-        HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);\r
-\r
-     DestroyPropertySheetPage(psInfo->proppage[index].hpage);\r
-  }\r
-\r
-  /* Remove the tab */\r
-  SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);\r
-\r
-  psInfo->nPages--;\r
-  psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);\r
-\r
-  if (index > 0)\r
-    memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));\r
-\r
-  if (index < psInfo->nPages)\r
-    memcpy(&psInfo->proppage[index], &oldPages[index + 1],\r
-           (psInfo->nPages - index) * sizeof(PropPageInfo));\r
-\r
-  Free(oldPages);\r
-\r
-  return FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_SetWizButtons\r
- *\r
- * This code will work if (and assumes that) the Next button is on top of the\r
- * Finish button. ie. Finish comes after Next in the Z order.\r
- * This means make sure the dialog template reflects this.\r
- *\r
- */\r
-static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)\r
-{\r
-  HWND hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);\r
-  HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);\r
-  HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);\r
-\r
-  TRACE("%ld\n", dwFlags);\r
-\r
-  EnableWindow(hwndBack, FALSE);\r
-  EnableWindow(hwndNext, FALSE);\r
-  EnableWindow(hwndFinish, FALSE);\r
-\r
-  if (dwFlags & PSWIZB_BACK)\r
-    EnableWindow(hwndBack, TRUE);\r
-\r
-  if (dwFlags & PSWIZB_NEXT)\r
-  {\r
-    /* Hide the Finish button */\r
-    ShowWindow(hwndFinish, SW_HIDE);\r
-\r
-    /* Show and enable the Next button */\r
-    ShowWindow(hwndNext, SW_SHOW);\r
-    EnableWindow(hwndNext, TRUE);\r
-\r
-    /* Set the Next button as the default pushbutton  */\r
-    SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);\r
-  }\r
-\r
-  if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))\r
-  {\r
-    /* Hide the Next button */\r
-    ShowWindow(hwndNext, SW_HIDE);\r
-\r
-    /* Show the Finish button */\r
-    ShowWindow(hwndFinish, SW_SHOW);\r
-\r
-    if (dwFlags & PSWIZB_FINISH)\r
-      EnableWindow(hwndFinish, TRUE);\r
-\r
-    /* Set the Finish button as the default pushbutton  */\r
-    SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_GetPageIndex\r
- *\r
- * Given a HPROPSHEETPAGE, returns the index of the corresponding page from\r
- * the array of PropPageInfo.\r
- */\r
-static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)\r
-{\r
-  BOOL found = FALSE;\r
-  int index = 0;\r
-\r
-  TRACE("hpage %p\n", hpage);\r
-  while ((index < psInfo->nPages) && (found == FALSE))\r
-  {\r
-    if (psInfo->proppage[index].hpage == hpage)\r
-      found = TRUE;\r
-    else\r
-      index++;\r
-  }\r
-\r
-  if (found == FALSE)\r
-    index = -1;\r
-\r
-  return index;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_CleanUp\r
- */\r
-static void PROPSHEET_CleanUp(HWND hwndDlg)\r
-{\r
-  int i;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg,\r
-                                                       PropSheetInfoStr);\r
-\r
-  TRACE("\n");\r
-  if (!psInfo) return;\r
-  if (HIWORD(psInfo->ppshheader.pszCaption))\r
-      HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);\r
-\r
-  for (i = 0; i < psInfo->nPages; i++)\r
-  {\r
-     PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;\r
-\r
-     if(psInfo->proppage[i].hwndPage)\r
-        DestroyWindow(psInfo->proppage[i].hwndPage);\r
-\r
-     if(psp)\r
-     {\r
-        if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)\r
-           HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);\r
-\r
-        DestroyPropertySheetPage(psInfo->proppage[i].hpage);\r
-     }\r
-  }\r
-\r
-  Free(psInfo->proppage);\r
-  Free(psInfo->strPropertiesFor);\r
-  ImageList_Destroy(psInfo->hImageList);\r
-\r
-  GlobalFree((HGLOBAL)psInfo);\r
-}\r
-\r
-/******************************************************************************\r
- *            PropertySheet    (COMCTL32.@)\r
- *            PropertySheetA   (COMCTL32.@)\r
- */\r
-INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)\r
-{\r
-  int bRet = 0;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,\r
-                                                       sizeof(PropSheetInfo));\r
-  UINT i, n;\r
-  BYTE* pByte;\r
-\r
-  TRACE("(%p)\n", lppsh);\r
-\r
-  PROPSHEET_CollectSheetInfoA(lppsh, psInfo);\r
-\r
-  psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *\r
-                                                    lppsh->nPages);\r
-  pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;\r
-\r
-  for (n = i = 0; i < lppsh->nPages; i++, n++)\r
-  {\r
-    if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))\r
-      psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];\r
-    else\r
-    {\r
-       psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);\r
-       pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;\r
-    }\r
-\r
-    if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,\r
-                               psInfo, n))\r
-    {\r
-       if (lppsh->dwFlags & PSH_PROPSHEETPAGE)\r
-           DestroyPropertySheetPage(psInfo->proppage[n].hpage);\r
-       n--;\r
-       psInfo->nPages--;\r
-    }\r
-  }\r
-\r
-  psInfo->unicode = FALSE;\r
-  bRet = PROPSHEET_CreateDialog(psInfo);\r
-\r
-  return bRet;\r
-}\r
-\r
-/******************************************************************************\r
- *            PropertySheetW   (COMCTL32.@)\r
- */\r
-INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)\r
-{\r
-  int bRet = 0;\r
-  PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,\r
-                                                       sizeof(PropSheetInfo));\r
-  UINT i, n;\r
-  BYTE* pByte;\r
-\r
-  TRACE("(%p)\n", lppsh);\r
-\r
-  PROPSHEET_CollectSheetInfoW(lppsh, psInfo);\r
-\r
-  psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *\r
-                                                    lppsh->nPages);\r
-  pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;\r
-\r
-  for (n = i = 0; i < lppsh->nPages; i++, n++)\r
-  {\r
-    if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))\r
-      psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];\r
-    else\r
-    {\r
-       psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);\r
-       pByte += ((LPPROPSHEETPAGEW)pByte)->dwSize;\r
-    }\r
-\r
-    if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,\r
-                               psInfo, n))\r
-    {\r
-       if (lppsh->dwFlags & PSH_PROPSHEETPAGE)\r
-           DestroyPropertySheetPage(psInfo->proppage[n].hpage);\r
-       n--;\r
-       psInfo->nPages--;\r
-    }\r
-  }\r
-\r
-  psInfo->unicode = TRUE;\r
-  bRet = PROPSHEET_CreateDialog(psInfo);\r
-\r
-  return bRet;\r
-}\r
-\r
-/******************************************************************************\r
- *            CreatePropertySheetPage    (COMCTL32.@)\r
- *            CreatePropertySheetPageA   (COMCTL32.@)\r
- */\r
-HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(\r
-                          LPCPROPSHEETPAGEA lpPropSheetPage)\r
-{\r
-  PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));\r
-\r
-  memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));\r
-\r
-  ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE;\r
-  if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )\r
-  {\r
-     int len = strlen(lpPropSheetPage->u.pszTemplate);\r
-\r
-     ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,len+1 );\r
-     strcpy( (LPSTR)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );\r
-  }\r
-  if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )\r
-  {\r
-      PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon);\r
-  }\r
-\r
-  if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))\r
-  {\r
-      PROPSHEET_AtoW(&ppsp->pszTitle, lpPropSheetPage->pszTitle);\r
-  }\r
-  else if ( !(ppsp->dwFlags & PSP_USETITLE) )\r
-      ppsp->pszTitle = NULL;\r
-\r
-  return (HPROPSHEETPAGE)ppsp;\r
-}\r
-\r
-/******************************************************************************\r
- *            CreatePropertySheetPageW   (COMCTL32.@)\r
- */\r
-HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)\r
-{\r
-  PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));\r
-\r
-  memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));\r
-\r
-  ppsp->dwFlags |= PSP_INTERNAL_UNICODE;\r
-\r
-  if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )\r
-  {\r
-    int len = strlenW(lpPropSheetPage->u.pszTemplate);\r
-\r
-    ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,(len+1)*sizeof (WCHAR) );\r
-    strcpyW( (WCHAR *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );\r
-  }\r
-  if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )\r
-  {\r
-      int len = strlenW(lpPropSheetPage->u2.pszIcon);\r
-      ppsp->u2.pszIcon = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );\r
-      strcpyW( (WCHAR *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon );\r
-  }\r
-\r
-  if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))\r
-  {\r
-      int len = strlenW(lpPropSheetPage->pszTitle);\r
-      ppsp->pszTitle = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );\r
-      strcpyW( (WCHAR *)ppsp->pszTitle, lpPropSheetPage->pszTitle );\r
-  }\r
-  else if ( !(ppsp->dwFlags & PSP_USETITLE) )\r
-      ppsp->pszTitle = NULL;\r
-\r
-  return (HPROPSHEETPAGE)ppsp;\r
-}\r
-\r
-/******************************************************************************\r
- *            DestroyPropertySheetPage   (COMCTL32.@)\r
- */\r
-BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)\r
-{\r
-  PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;\r
-\r
-  if (!psp)\r
-     return FALSE;\r
-\r
-  if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )\r
-     HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);\r
-\r
-  if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )\r
-     HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);\r
-\r
-  if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))\r
-      HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);\r
-\r
-  Free(hPropPage);\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_IsDialogMessage\r
- */\r
-static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)\r
-{\r
-   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);\r
-\r
-   TRACE("\n");\r
-   if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))\r
-      return FALSE;\r
-\r
-   if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))\r
-   {\r
-      int new_page = 0;\r
-      INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);\r
-\r
-      if (!(dlgCode & DLGC_WANTMESSAGE))\r
-      {\r
-         switch (lpMsg->wParam)\r
-         {\r
-            case VK_TAB:\r
-               if (GetKeyState(VK_SHIFT) & 0x8000)\r
-                   new_page = -1;\r
-                else\r
-                   new_page = 1;\r
-               break;\r
-\r
-            case VK_NEXT:   new_page = 1;  break;\r
-            case VK_PRIOR:  new_page = -1; break;\r
-         }\r
-      }\r
-\r
-      if (new_page)\r
-      {\r
-         if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)\r
-         {\r
-            new_page += psInfo->active_page;\r
-\r
-            if (new_page < 0)\r
-               new_page = psInfo->nPages - 1;\r
-            else if (new_page >= psInfo->nPages)\r
-               new_page = 0;\r
-\r
-            PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);\r
-         }\r
-\r
-         return TRUE;\r
-      }\r
-   }\r
-\r
-   return IsDialogMessageA(hwnd, lpMsg);\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_DoCommand\r
- */\r
-static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)\r
-{\r
-\r
-    switch (wID) {\r
-\r
-    case IDOK:\r
-    case IDC_APPLY_BUTTON:\r
-       {\r
-           HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);\r
-\r
-           if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)\r
-               break;\r
-\r
-           if (wID == IDOK)\r
-               {\r
-                   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,\r
-                                                                     PropSheetInfoStr);\r
-                   int result = TRUE;\r
-\r
-                   if (psInfo->restartWindows)\r
-                       result = ID_PSRESTARTWINDOWS;\r
-\r
-                   /* reboot system takes precedence over restart windows */\r
-                   if (psInfo->rebootSystem)\r
-                       result = ID_PSREBOOTSYSTEM;\r
-\r
-                   if (psInfo->isModeless)\r
-                       psInfo->activeValid = FALSE;\r
-                   else\r
-                       EndDialog(hwnd, result);\r
-               }\r
-           else\r
-               EnableWindow(hwndApplyBtn, FALSE);\r
-\r
-           break;\r
-       }\r
-\r
-    case IDC_BACK_BUTTON:\r
-       PROPSHEET_Back(hwnd);\r
-       break;\r
-\r
-    case IDC_NEXT_BUTTON:\r
-       PROPSHEET_Next(hwnd);\r
-       break;\r
-\r
-    case IDC_FINISH_BUTTON:\r
-       PROPSHEET_Finish(hwnd);\r
-       break;\r
-\r
-    case IDCANCEL:\r
-       PROPSHEET_Cancel(hwnd, 0);\r
-       break;\r
-\r
-    case IDHELP:\r
-       PROPSHEET_Help(hwnd);\r
-       break;\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *            PROPSHEET_DialogProc\r
- */\r
-INT_PTR CALLBACK\r
-PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
-  TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n",\r
-       hwnd, uMsg, wParam, lParam);\r
-\r
-  switch (uMsg)\r
-  {\r
-    case WM_INITDIALOG:\r
-    {\r
-      PropSheetInfo* psInfo = (PropSheetInfo*) lParam;\r
-      WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));\r
-      HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);\r
-      LPCPROPSHEETPAGEW ppshpage;\r
-      int idx;\r
-\r
-      SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo);\r
-\r
-      /*\r
-       * psInfo->hwnd is not being used by WINE code - it exists\r
-       * for compatibility with "real" Windoze. The same about\r
-       * SetWindowLong - WINE is only using the PropSheetInfoStr\r
-       * property.\r
-       */\r
-      psInfo->hwnd = hwnd;\r
-      SetWindowLongW(hwnd,DWL_USER,(LONG)psInfo);\r
-\r
-      /* set up the Next and Back buttons by default */\r
-      PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);\r
-\r
-      /*\r
-       * Small icon in the title bar.\r
-       */\r
-      if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||\r
-          (psInfo->ppshheader.dwFlags & PSH_USEHICON))\r
-      {\r
-        HICON hIcon;\r
-        int icon_cx = GetSystemMetrics(SM_CXSMICON);\r
-        int icon_cy = GetSystemMetrics(SM_CYSMICON);\r
-\r
-        if (psInfo->ppshheader.dwFlags & PSH_USEICONID)\r
-          hIcon = LoadImageW(psInfo->ppshheader.hInstance,\r
-                             psInfo->ppshheader.u.pszIcon,\r
-                             IMAGE_ICON,\r
-                             icon_cx, icon_cy,\r
-                             LR_DEFAULTCOLOR);\r
-        else\r
-          hIcon = psInfo->ppshheader.u.hIcon;\r
-\r
-        SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon);\r
-      }\r
-\r
-      if (psInfo->ppshheader.dwFlags & PSH_USEHICON)\r
-        SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon);\r
-\r
-      psInfo->strPropertiesFor = strCaption;\r
-\r
-      GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);\r
-\r
-      PROPSHEET_CreateTabControl(hwnd, psInfo);\r
-\r
-      if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)\r
-      {\r
-        if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))\r
-        {\r
-          PROPSHEET_AdjustSizeWizard(hwnd, psInfo);\r
-          PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        if (PROPSHEET_SizeMismatch(hwnd, psInfo))\r
-        {\r
-          PROPSHEET_AdjustSize(hwnd, psInfo);\r
-          PROPSHEET_AdjustButtons(hwnd, psInfo);\r
-        }\r
-      }\r
-\r
-      if (psInfo->useCallback)\r
-             (*(psInfo->ppshheader.pfnCallback))(hwnd,\r
-                                             PSCB_INITIALIZED, (LPARAM)0);\r
-\r
-      idx = psInfo->active_page;\r
-      ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage;\r
-      psInfo->active_page = -1;\r
-\r
-      PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);\r
-\r
-      /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,\r
-       * as some programs call TCM_GETCURSEL to get the current selection\r
-       * from which to switch to the next page */\r
-      SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);\r
-\r
-      if (!HIWORD(psInfo->ppshheader.pszCaption) &&\r
-              psInfo->ppshheader.hInstance)\r
-      {\r
-         WCHAR szText[256];\r
-\r
-         if (LoadStringW(psInfo->ppshheader.hInstance,\r
-                 (UINT)psInfo->ppshheader.pszCaption, szText, 255))\r
-            PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);\r
-      }\r
-      else\r
-      {\r
-         PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,\r
-                         psInfo->ppshheader.pszCaption);\r
-      }\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case WM_DESTROY:\r
-      PROPSHEET_CleanUp(hwnd);\r
-      return TRUE;\r
-\r
-    case WM_CLOSE:\r
-      PROPSHEET_Cancel(hwnd, 1);\r
-      return TRUE;\r
-\r
-    case WM_COMMAND:\r
-      return PROPSHEET_DoCommand(hwnd, LOWORD(wParam));\r
-\r
-    case WM_NOTIFY:\r
-    {\r
-      NMHDR* pnmh = (LPNMHDR) lParam;\r
-\r
-      if (pnmh->code == TCN_SELCHANGE)\r
-      {\r
-        int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);\r
-        PROPSHEET_SetCurSel(hwnd, index, 1, 0);\r
-      }\r
-\r
-      if(pnmh->code == TCN_SELCHANGING)\r
-      {\r
-        BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);\r
-        SetWindowLongW(hwnd, DWL_MSGRESULT, !bRet);\r
-        return TRUE;\r
-      }\r
-\r
-      return FALSE;\r
-    }\r
-\r
-    case PSM_GETCURRENTPAGEHWND:\r
-    {\r
-      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,\r
-                                                        PropSheetInfoStr);\r
-      HWND hwndPage = 0;\r
-\r
-      if (psInfo->activeValid && psInfo->active_page != -1)\r
-        hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, (LONG)hwndPage);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_CHANGED:\r
-      PROPSHEET_Changed(hwnd, (HWND)wParam);\r
-      return TRUE;\r
-\r
-    case PSM_UNCHANGED:\r
-      PROPSHEET_UnChanged(hwnd, (HWND)wParam);\r
-      return TRUE;\r
-\r
-    case PSM_GETTABCONTROL:\r
-    {\r
-      HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, (LONG)hwndTabCtrl);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_SETCURSEL:\r
-    {\r
-      BOOL msgResult;\r
-\r
-      msgResult = PROPSHEET_CanSetCurSel(hwnd);\r
-      if(msgResult != FALSE)\r
-      {\r
-        msgResult = PROPSHEET_SetCurSel(hwnd,\r
-                                       (int)wParam,\r
-                                      1,\r
-                                       (HPROPSHEETPAGE)lParam);\r
-      }\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_CANCELTOCLOSE:\r
-    {\r
-      WCHAR buf[MAX_BUTTONTEXT_LENGTH];\r
-      HWND hwndOK = GetDlgItem(hwnd, IDOK);\r
-      HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);\r
-\r
-      EnableWindow(hwndCancel, FALSE);\r
-      if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))\r
-         SetWindowTextW(hwndOK, buf);\r
-\r
-      return FALSE;\r
-    }\r
-\r
-    case PSM_RESTARTWINDOWS:\r
-    {\r
-      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,\r
-                                                        PropSheetInfoStr);\r
-\r
-      psInfo->restartWindows = TRUE;\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_REBOOTSYSTEM:\r
-    {\r
-      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,\r
-                                                        PropSheetInfoStr);\r
-\r
-      psInfo->rebootSystem = TRUE;\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_SETTITLEA:\r
-      PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);\r
-      return TRUE;\r
-\r
-    case PSM_SETTITLEW:\r
-      PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);\r
-      return TRUE;\r
-\r
-    case PSM_APPLY:\r
-    {\r
-      BOOL msgResult = PROPSHEET_Apply(hwnd, 0);\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_QUERYSIBLINGS:\r
-    {\r
-      LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_ADDPAGE:\r
-    {\r
-      /*\r
-       * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have\r
-       *       a return value. This is not true. PSM_ADDPAGE returns TRUE\r
-       *       on success or FALSE otherwise, as specified on MSDN Online.\r
-       *       Also see the MFC code for\r
-       *       CPropertySheet::AddPage(CPropertyPage* pPage).\r
-       */\r
-\r
-      BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);\r
-\r
-      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);\r
-\r
-      return TRUE;\r
-    }\r
-\r
-    case PSM_REMOVEPAGE:\r
-      PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);\r
-      return TRUE;\r
-\r
-    case PSM_ISDIALOGMESSAGE:\r
-    {\r
-       BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);\r
-       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);\r
-       return TRUE;\r
-    }\r
-\r
-    case PSM_PRESSBUTTON:\r
-      PROPSHEET_PressButton(hwnd, (int)wParam);\r
-      return TRUE;\r
-\r
-    case PSM_SETFINISHTEXTA:\r
-      PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);\r
-      return TRUE;\r
-\r
-    case PSM_SETWIZBUTTONS:\r
-      PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);\r
-      return TRUE;\r
-\r
-    case PSM_SETCURSELID:\r
-        PROPSHEET_SetCurSelId(hwnd, (int)lParam);\r
-        return TRUE;\r
-\r
-    case PSM_SETFINISHTEXTW:\r
-        PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);\r
-        return FALSE;\r
-\r
-    default:\r
-      return FALSE;\r
-  }\r
-\r
-  return FALSE;\r
-}\r
+/*
+ * Property Sheets
+ *
+ * Copyright 1998 Francis Beaudet
+ * Copyright 1999 Thuy Nguyen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * TODO:
+ *   - Tab order
+ *   - Unicode property sheets
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "commctrl.h"
+#include "prsht.h"
+#include "comctl32.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+/******************************************************************************
+ * Data structures
+ */
+#include "pshpack2.h"
+
+typedef struct
+{
+  WORD dlgVer;
+  WORD signature;
+  DWORD helpID;
+  DWORD exStyle;
+  DWORD style;
+} MyDLGTEMPLATEEX;
+
+typedef struct
+{
+  DWORD helpid;
+  DWORD exStyle;
+  DWORD style;
+  short x;
+  short y;
+  short cx;
+  short cy;
+  DWORD id;
+} MyDLGITEMTEMPLATEEX;
+#include "poppack.h"
+
+typedef struct tagPropPageInfo
+{
+  HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
+  HWND hwndPage;
+  BOOL isDirty;
+  LPCWSTR pszText;
+  BOOL hasHelp;
+  BOOL useCallback;
+  BOOL hasIcon;
+} PropPageInfo;
+
+typedef struct tagPropSheetInfo
+{
+  HWND hwnd;
+  PROPSHEETHEADERW ppshheader;
+  BOOL unicode;
+  LPWSTR strPropertiesFor;
+  int nPages;
+  int active_page;
+  BOOL isModeless;
+  BOOL hasHelp;
+  BOOL hasApply;
+  BOOL useCallback;
+  BOOL restartWindows;
+  BOOL rebootSystem;
+  BOOL activeValid;
+  PropPageInfo* proppage;
+  int x;
+  int y;
+  int width;
+  int height;
+  HIMAGELIST hImageList;
+} PropSheetInfo;
+
+typedef struct
+{
+  int x;
+  int y;
+} PADDING_INFO;
+
+/******************************************************************************
+ * Defines and global variables
+ */
+
+const WCHAR PropSheetInfoStr[] =
+    {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };
+
+#define PSP_INTERNAL_UNICODE 0x80000000
+
+#define MAX_CAPTION_LENGTH 255
+#define MAX_TABTEXT_LENGTH 255
+#define MAX_BUTTONTEXT_LENGTH 64
+
+#define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
+
+/******************************************************************************
+ * Prototypes
+ */
+static int PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
+static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
+static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
+static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
+static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
+                                       PropSheetInfo * psInfo);
+static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
+                                       PropSheetInfo * psInfo);
+static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
+                                      PropSheetInfo * psInfo,
+                                      int index);
+static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
+                                       PropSheetInfo * psInfo);
+static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index,
+                                const PropSheetInfo * psInfo,
+                                LPCPROPSHEETPAGEW ppshpage);
+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, LPARAM lParam);
+static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
+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_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText);
+static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
+static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);
+static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
+static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
+                                int index,
+                                int skipdir,
+                                HPROPSHEETPAGE hpage);
+static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id);
+static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
+                                       WPARAM wParam, LPARAM lParam);
+static BOOL PROPSHEET_AddPage(HWND hwndDlg,
+                              HPROPSHEETPAGE hpage);
+
+static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
+                                 int index,
+                                 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, const PropSheetInfo* psInfo);
+static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
+static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
+
+INT_PTR CALLBACK
+PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
+
+#define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
+/******************************************************************************
+ *            PROPSHEET_UnImplementedFlags
+ *
+ * Document use of flags we don't implement yet.
+ */
+static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)
+{
+    CHAR string[256];
+
+    string[0] = '\0';
+
+  /*
+   * unhandled header flags:
+   *  PSH_DEFAULT            0x00000000
+   *  PSH_WIZARDHASFINISH    0x00000010
+   *  PSH_RTLREADING         0x00000800
+   *  PSH_WIZARDCONTEXTHELP  0x00001000
+   *  PSH_WIZARD97           0x00002000  (pre IE 5)
+   *  PSH_WATERMARK          0x00008000
+   *  PSH_USEHBMWATERMARK    0x00010000
+   *  PSH_USEHPLWATERMARK    0x00020000
+   *  PSH_STRETCHWATERMARK   0x00040000
+   *  PSH_HEADER             0x00080000
+   *  PSH_USEHBMHEADER       0x00100000
+   *  PSH_USEPAGELANG        0x00200000
+   *  PSH_WIZARD_LITE        0x00400000      also not in .h
+   *  PSH_WIZARD97           0x01000000  (IE 5 and above)
+   *  PSH_NOCONTEXTHELP      0x02000000      also not in .h
+   */
+
+    add_flag(PSH_WIZARDHASFINISH);
+    add_flag(PSH_RTLREADING);
+    add_flag(PSH_WIZARDCONTEXTHELP);
+    add_flag(PSH_WIZARD97_OLD);
+    add_flag(PSH_WATERMARK);
+    add_flag(PSH_USEHBMWATERMARK);
+    add_flag(PSH_USEHPLWATERMARK);
+    add_flag(PSH_STRETCHWATERMARK);
+    add_flag(PSH_HEADER);
+    add_flag(PSH_USEHBMHEADER);
+    add_flag(PSH_USEPAGELANG);
+    add_flag(PSH_WIZARD_LITE);
+    add_flag(PSH_WIZARD97_NEW);
+    add_flag(PSH_NOCONTEXTHELP);
+    if (string[0] != '\0')
+       FIXME("%s\n", string);
+}
+#undef add_flag
+
+/******************************************************************************
+ *            PROPSHEET_GetPageRect
+ *
+ * Retrieve rect from tab control and map into the dialog for SetWindowPos
+ */
+static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg, RECT *rc)
+{
+    HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+
+    GetClientRect(hwndTabCtrl, rc);
+    SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc);
+    MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2);
+}
+
+/******************************************************************************
+ *            PROPSHEET_FindPageByResId
+ *
+ * Find page index corresponding to page resource id.
+ */
+INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId)
+{
+   INT i;
+
+   for (i = 0; i < psInfo->nPages; i++)
+   {
+      LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;
+
+      /* Fixme: if resource ID is a string shall we use strcmp ??? */
+      if (lppsp->u.pszTemplate == (LPVOID)resId)
+         break;
+   }
+
+   return i;
+}
+
+/******************************************************************************
+ *            PROPSHEET_AtoW
+ *
+ * Convert ASCII to Unicode since all data is saved as Unicode.
+ */
+static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr)
+{
+    INT len;
+
+    TRACE("<%s>\n", frstr);
+    len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0);
+    *tostr = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, frstr, -1, (LPWSTR)*tostr, len);
+}
+
+/******************************************************************************
+ *            PROPSHEET_CollectSheetInfoA
+ *
+ * Collect relevant data.
+ */
+static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
+                                       PropSheetInfo * psInfo)
+{
+  DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
+  DWORD dwFlags = lppsh->dwFlags;
+
+  psInfo->hasHelp = dwFlags & PSH_HASHELP;
+  psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
+  psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);
+  psInfo->isModeless = dwFlags & PSH_MODELESS;
+
+  memcpy(&psInfo->ppshheader,lppsh,dwSize);
+  TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
+       lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,
+       debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
+
+  PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
+
+  if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
+     psInfo->ppshheader.pszCaption = NULL;
+  else
+  {
+     if (HIWORD(lppsh->pszCaption))
+     {
+        int len = strlen(lppsh->pszCaption);
+        psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
+        MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len+1);
+        /* strcpy( (char *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); */
+     }
+  }
+  psInfo->nPages = lppsh->nPages;
+
+  if (dwFlags & PSH_USEPSTARTPAGE)
+  {
+    TRACE("PSH_USEPSTARTPAGE is on");
+    psInfo->active_page = 0;
+  }
+  else
+    psInfo->active_page = lppsh->u2.nStartPage;
+
+  if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
+     psInfo->active_page = 0;
+
+  psInfo->restartWindows = FALSE;
+  psInfo->rebootSystem = FALSE;
+  psInfo->hImageList = 0;
+  psInfo->activeValid = FALSE;
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_CollectSheetInfoW
+ *
+ * Collect relevant data.
+ */
+static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
+                                       PropSheetInfo * psInfo)
+{
+  DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));
+  DWORD dwFlags = lppsh->dwFlags;
+
+  psInfo->hasHelp = dwFlags & PSH_HASHELP;
+  psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
+  psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);
+  psInfo->isModeless = dwFlags & PSH_MODELESS;
+
+  memcpy(&psInfo->ppshheader,lppsh,dwSize);
+  TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
+      lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
+
+  PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
+
+  if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
+     psInfo->ppshheader.pszCaption = NULL;
+  else
+  {
+     if (!(lppsh->dwFlags & INTRNL_ANY_WIZARD) && HIWORD(lppsh->pszCaption))
+     {
+        int len = strlenW(lppsh->pszCaption);
+        psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );
+        strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );
+     }
+  }
+  psInfo->nPages = lppsh->nPages;
+
+  if (dwFlags & PSH_USEPSTARTPAGE)
+  {
+    TRACE("PSH_USEPSTARTPAGE is on");
+    psInfo->active_page = 0;
+  }
+  else
+    psInfo->active_page = lppsh->u2.nStartPage;
+
+  if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
+     psInfo->active_page = 0;
+
+  psInfo->restartWindows = FALSE;
+  psInfo->rebootSystem = FALSE;
+  psInfo->hImageList = 0;
+  psInfo->activeValid = FALSE;
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_CollectPageInfo
+ *
+ * Collect property sheet data.
+ * With code taken from DIALOG_ParseTemplate32.
+ */
+BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
+                               PropSheetInfo * psInfo,
+                               int index)
+{
+  DLGTEMPLATE* pTemplate;
+  const WORD*  p;
+  DWORD dwFlags;
+  int width, height;
+
+  TRACE("\n");
+  psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
+  psInfo->proppage[index].hwndPage = 0;
+  psInfo->proppage[index].isDirty = FALSE;
+
+  /*
+   * Process property page flags.
+   */
+  dwFlags = lppsp->dwFlags;
+  psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
+  psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
+  psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
+
+  /* as soon as we have a page with the help flag, set the sheet flag on */
+  if (psInfo->proppage[index].hasHelp)
+    psInfo->hasHelp = TRUE;
+
+  /*
+   * Process page template.
+   */
+  if (dwFlags & PSP_DLGINDIRECT)
+    pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
+  else if(dwFlags & PSP_INTERNAL_UNICODE )
+  {
+    HRSRC hResource = FindResourceW(lppsp->hInstance,
+                                    lppsp->u.pszTemplate,
+                                    (LPWSTR)RT_DIALOG);
+    HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
+                                     hResource);
+    pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
+  }
+  else
+  {
+    HRSRC hResource = FindResourceA(lppsp->hInstance,
+                                    (LPSTR)lppsp->u.pszTemplate,
+                                    (LPSTR)RT_DIALOG);
+    HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
+                                     hResource);
+    pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
+  }
+
+  /*
+   * Extract the size of the page and the caption.
+   */
+  if (!pTemplate)
+      return FALSE;
+
+  p = (const WORD *)pTemplate;
+
+  if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
+  {
+    /* DLGTEMPLATEEX (not defined in any std. header file) */
+
+    p++;       /* dlgVer    */
+    p++;       /* signature */
+    p += 2;    /* help ID   */
+    p += 2;    /* ext style */
+    p += 2;    /* style     */
+  }
+  else
+  {
+    /* DLGTEMPLATE */
+
+    p += 2;    /* style     */
+    p += 2;    /* ext style */
+  }
+
+  p++;    /* nb items */
+  p++;    /*   x      */
+  p++;    /*   y      */
+  width  = (WORD)*p; p++;
+  height = (WORD)*p; p++;
+
+  /* remember the largest width and height */
+  if (width > psInfo->width)
+    psInfo->width = width;
+
+  if (height > psInfo->height)
+    psInfo->height = height;
+
+  /* menu */
+  switch ((WORD)*p)
+  {
+    case 0x0000:
+      p++;
+      break;
+    case 0xffff:
+      p += 2;
+      break;
+    default:
+      p += lstrlenW( (LPCWSTR)p ) + 1;
+      break;
+  }
+
+  /* class */
+  switch ((WORD)*p)
+  {
+    case 0x0000:
+      p++;
+      break;
+    case 0xffff:
+      p += 2;
+      break;
+    default:
+      p += lstrlenW( (LPCWSTR)p ) + 1;
+      break;
+  }
+
+  /* Extract the caption */
+  psInfo->proppage[index].pszText = (LPCWSTR)p;
+  TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
+  p += lstrlenW((LPCWSTR)p) + 1;
+
+  if (dwFlags & PSP_USETITLE)
+  {
+    WCHAR szTitle[256];
+    const WCHAR *pTitle;
+    static WCHAR pszNull[] = { '(','n','u','l','l',')',0 };
+    int len;
+
+    if ( !HIWORD( lppsp->pszTitle ) )
+    {
+      if (!LoadStringW( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,sizeof(szTitle) ))
+      {
+        pTitle = pszNull;
+       FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
+      }
+      else
+        pTitle = szTitle;
+    }
+    else
+      pTitle = lppsp->pszTitle;
+
+    len = strlenW(pTitle);
+    psInfo->proppage[index].pszText = Alloc( (len+1)*sizeof (WCHAR) );
+    strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle);
+  }
+
+  /*
+   * Build the image list for icons
+   */
+  if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
+  {
+    HICON hIcon;
+    int icon_cx = GetSystemMetrics(SM_CXSMICON);
+    int icon_cy = GetSystemMetrics(SM_CYSMICON);
+
+    if (dwFlags & PSP_USEICONID)
+      hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
+                         icon_cx, icon_cy, LR_DEFAULTCOLOR);
+    else
+      hIcon = lppsp->u2.hIcon;
+
+    if ( hIcon )
+    {
+      if (psInfo->hImageList == 0 )
+       psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
+
+      ImageList_AddIcon(psInfo->hImageList, hIcon);
+    }
+
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_CreateDialog
+ *
+ * Creates the actual property sheet.
+ */
+int PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
+{
+  LRESULT ret;
+  LPCVOID template;
+  LPVOID temp = 0;
+  HRSRC hRes;
+  DWORD resSize;
+  WORD resID = IDD_PROPSHEET;
+
+  TRACE("\n");
+  if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
+    resID = IDD_WIZARD;
+
+  if( psInfo->unicode )
+  {
+    if(!(hRes = FindResourceW(COMCTL32_hModule,
+                            MAKEINTRESOURCEW(resID),
+                            (LPWSTR)RT_DIALOG)))
+      return -1;
+  }
+  else
+  {
+    if(!(hRes = FindResourceA(COMCTL32_hModule,
+                            MAKEINTRESOURCEA(resID),
+                            (LPSTR)RT_DIALOG)))
+      return -1;
+  }
+
+  if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
+    return -1;
+
+  /*
+   * Make a copy of the dialog template.
+   */
+  resSize = SizeofResource(COMCTL32_hModule, hRes);
+
+  temp = Alloc(resSize);
+
+  if (!temp)
+    return -1;
+
+  memcpy(temp, template, resSize);
+
+  if (psInfo->useCallback)
+    (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
+
+  if( psInfo->unicode )
+  {
+    if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
+      ret = DialogBoxIndirectParamW(psInfo->ppshheader.hInstance,
+                                    (LPDLGTEMPLATEW) temp,
+                                    psInfo->ppshheader.hwndParent,
+                                    PROPSHEET_DialogProc,
+                                    (LPARAM)psInfo);
+    else
+    {
+      ret = (int)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,
+                                            (LPDLGTEMPLATEW) temp,
+                                            psInfo->ppshheader.hwndParent,
+                                            PROPSHEET_DialogProc,
+                                            (LPARAM)psInfo);
+      if ( !ret ) ret = -1;
+    }
+  }
+  else
+  {
+    if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
+      ret = DialogBoxIndirectParamA(psInfo->ppshheader.hInstance,
+                                    (LPDLGTEMPLATEA) temp,
+                                    psInfo->ppshheader.hwndParent,
+                                    PROPSHEET_DialogProc,
+                                    (LPARAM)psInfo);
+    else
+    {
+      ret = (int)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
+                                            (LPDLGTEMPLATEA) temp,
+                                            psInfo->ppshheader.hwndParent,
+                                            PROPSHEET_DialogProc,
+                                            (LPARAM)psInfo);
+      if ( !ret ) ret = -1;
+    }
+  }
+
+  Free(temp);
+
+  return ret;
+}
+
+/******************************************************************************
+ *            PROPSHEET_SizeMismatch
+ *
+ *     Verify that the tab control and the "largest" property sheet page dlg. template
+ *     match in size.
+ */
+static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
+{
+  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  RECT rcOrigTab, rcPage;
+
+  /*
+   * Original tab size.
+   */
+  GetClientRect(hwndTabCtrl, &rcOrigTab);
+  TRACE("orig tab %ld %ld %ld %ld\n", rcOrigTab.left, rcOrigTab.top,
+        rcOrigTab.right, rcOrigTab.bottom);
+
+  /*
+   * 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 %ld %ld %ld %ld\n", rcPage.left, rcPage.top,
+        rcPage.right, rcPage.bottom);
+
+  if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
+    return TRUE;
+  if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
+    return TRUE;
+
+  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, psInfo);
+
+  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 %ld %ld %ld %ld\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
+ *
+ * Resizes the property sheet and the tab control to fit the largest page.
+ */
+static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
+{
+  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
+  RECT rc,tabRect;
+  int tabOffsetX, tabOffsetY, buttonHeight;
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
+  RECT units;
+
+  /* Get the height of buttons */
+  GetClientRect(hwndButton, &rc);
+  buttonHeight = rc.bottom;
+
+  /*
+   * Biggest page size.
+   */
+  rc.left   = psInfo->x;
+  rc.top    = psInfo->y;
+  rc.right  = psInfo->width;
+  rc.bottom = psInfo->height;
+
+  MapDialogRect(hwndDlg, &rc);
+
+  /* retrieve the dialog units */
+  units.left = units.right = 4;
+  units.top = units.bottom = 8;
+  MapDialogRect(hwndDlg, &units);
+
+  /*
+   * Resize the tab control.
+   */
+  GetClientRect(hwndTabCtrl,&tabRect);
+
+  SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
+
+  if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
+  {
+      rc.bottom = rc.top + tabRect.bottom - tabRect.top;
+      psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
+  }
+
+  if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
+  {
+      rc.right = rc.left + tabRect.right - tabRect.left;
+      psInfo->width  = MulDiv((rc.right - rc.left),4,units.left);
+  }
+
+  SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
+
+  tabOffsetX = -(rc.left);
+  tabOffsetY = -(rc.top);
+
+  rc.right -= rc.left;
+  rc.bottom -= rc.top;
+  TRACE("setting tab %08lx, rc (0,0)-(%ld,%ld)\n",
+        (DWORD)hwndTabCtrl, rc.right, rc.bottom);
+  SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
+               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  GetClientRect(hwndTabCtrl, &rc);
+
+  TRACE("tab client rc %ld %ld %ld %ld\n",
+        rc.left, rc.top, rc.right, rc.bottom);
+
+  rc.right += ((padding.x * 2) + tabOffsetX);
+  rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
+
+  /*
+   * Resize the property sheet.
+   */
+  TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n",
+        (DWORD)hwndDlg, rc.right, rc.bottom);
+  SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
+               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+  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);
+  HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  RECT rc,tabRect;
+  int buttonHeight, lineHeight;
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
+  RECT units;
+
+  /* Get the height of buttons */
+  GetClientRect(hwndButton, &rc);
+  buttonHeight = rc.bottom;
+
+  GetClientRect(hwndLine, &rc);
+  lineHeight = rc.bottom;
+
+  /* retrieve the dialog units */
+  units.left = units.right = 4;
+  units.top = units.bottom = 8;
+  MapDialogRect(hwndDlg, &units);
+
+  /*
+   * Biggest page size.
+   */
+  rc.left   = psInfo->x;
+  rc.top    = psInfo->y;
+  rc.right  = psInfo->width;
+  rc.bottom = psInfo->height;
+
+  MapDialogRect(hwndDlg, &rc);
+
+  GetClientRect(hwndTabCtrl,&tabRect);
+
+  if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
+  {
+      rc.bottom = rc.top + tabRect.bottom - tabRect.top;
+      psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);
+  }
+
+  if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
+  {
+      rc.right = rc.left + tabRect.right - tabRect.left;
+      psInfo->width  = MulDiv((rc.right - rc.left), 4, units.left);
+  }
+
+  TRACE("Biggest page %ld %ld %ld %ld\n", rc.left, rc.top, rc.right, rc.bottom);
+  TRACE("   constants padx=%d, pady=%d, butH=%d, lH=%d\n",
+       padding.x, padding.y, buttonHeight, lineHeight);
+
+  /* Make room */
+  rc.right += (padding.x * 2);
+  rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
+
+  /*
+   * Resize the property sheet.
+   */
+  TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n",
+        (DWORD)hwndDlg, rc.right, rc.bottom);
+  SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
+               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_AdjustButtons
+ *
+ * Adjusts the buttons' positions.
+ */
+static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
+{
+  HWND hwndButton = GetDlgItem(hwndParent, IDOK);
+  RECT rcSheet;
+  int x, y;
+  int num_buttons = 2;
+  int buttonWidth, buttonHeight;
+  PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
+
+  if (psInfo->hasApply)
+    num_buttons++;
+
+  if (psInfo->hasHelp)
+    num_buttons++;
+
+  /*
+   * Obtain the size of the buttons.
+   */
+  GetClientRect(hwndButton, &rcSheet);
+  buttonWidth = rcSheet.right;
+  buttonHeight = 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 OK button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDOK);
+
+  x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  /*
+   * Position Cancel button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDCANCEL);
+
+  x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
+
+  SetWindowPos(hwndButton, 0, x, y, 0, 0,
+               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+  /*
+   * Position Apply button.
+   */
+  hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
+
+  if (psInfo->hasApply)
+  {
+    if (psInfo->hasHelp)
+      x = rcSheet.right - ((padding.x + buttonWidth) * 2);
+    else
+      x = rcSheet.right - (padding.x + buttonWidth);
+
+    SetWindowPos(hwndButton, 0, x, y, 0, 0,
+                 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+    EnableWindow(hwndButton, FALSE);
+  }
+  else
+    ShowWindow(hwndButton, SW_HIDE);
+
+  /*
+   * 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);
+
+  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, psInfo);
+
+  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
+ *
+ * Returns the layout information.
+ */
+static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
+{
+  HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  RECT rcTab;
+  POINT tl;
+  PADDING_INFO padding;
+
+  GetWindowRect(hwndTab, &rcTab);
+
+  tl.x = rcTab.left;
+  tl.y = rcTab.top;
+
+  ScreenToClient(hwndDlg, &tl);
+
+  padding.x = tl.x;
+  padding.y = tl.y;
+
+  return padding;
+}
+
+/******************************************************************************
+ *            PROPSHEET_GetPaddingInfoWizard
+ *
+ * Returns the layout information.
+ * Vertical spacing is the distance between the line and the buttons.
+ * Do NOT use the Help button to gather padding information when it isn't mapped
+ * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
+ * for it in this case !
+ * FIXME: I'm not sure about any other coordinate problems with these evil
+ * buttons. Fix it in case additional problems appear or maybe calculate
+ * a padding in a completely different way, as this is somewhat messy.
+ */
+static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
+ psInfo)
+{
+  PADDING_INFO padding;
+  RECT rc;
+  HWND hwndControl;
+  INT idButton;
+  POINT ptButton, ptLine;
+
+  TRACE("\n");
+  if (psInfo->hasHelp)
+  {
+       idButton = IDHELP;
+  }
+  else
+  {
+    if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
+    {
+       idButton = IDC_NEXT_BUTTON;
+    }
+    else
+    {
+       /* hopefully this is ok */
+       idButton = IDCANCEL;
+    }
+  }
+
+  hwndControl = GetDlgItem(hwndDlg, idButton);
+  GetWindowRect(hwndControl, &rc);
+
+  ptButton.x = rc.left;
+  ptButton.y = rc.top;
+
+  ScreenToClient(hwndDlg, &ptButton);
+
+  /* Line */
+  hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
+  GetWindowRect(hwndControl, &rc);
+
+  ptLine.x = 0;
+  ptLine.y = rc.bottom;
+
+  ScreenToClient(hwndDlg, &ptLine);
+
+  padding.y = ptButton.y - ptLine.y;
+
+  if (padding.y < 0)
+         ERR("padding negative ! Please report this !\n");
+
+  /* this is most probably not correct, but the best we have now */
+  padding.x = padding.y;
+  return padding;
+}
+
+/******************************************************************************
+ *            PROPSHEET_CreateTabControl
+ *
+ * Insert the tabs in the tab control.
+ */
+static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
+                                       PropSheetInfo * psInfo)
+{
+  HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
+  TCITEMW item;
+  int i, nTabs;
+  int iImage = 0;
+
+  TRACE("\n");
+  item.mask = TCIF_TEXT;
+  item.cchTextMax = MAX_TABTEXT_LENGTH;
+
+  nTabs = psInfo->nPages;
+
+  /*
+   * Set the image list for icons.
+   */
+  if (psInfo->hImageList)
+  {
+    SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
+  }
+
+  for (i = 0; i < nTabs; i++)
+  {
+    if ( psInfo->proppage[i].hasIcon )
+    {
+      item.mask |= TCIF_IMAGE;
+      item.iImage = iImage++;
+    }
+    else
+    {
+      item.mask &= ~TCIF_IMAGE;
+    }
+
+    item.pszText = (LPWSTR) psInfo->proppage[i].pszText;
+    SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item);
+  }
+
+  return TRUE;
+}
+/*
+ * Get the size of an in-memory Template
+ *
+ *( Based on the code of PROPSHEET_CollectPageInfo)
+ * See also dialog.c/DIALOG_ParseTemplate32().
+ */
+
+static UINT GetTemplateSize(DLGTEMPLATE* pTemplate)
+
+{
+  const WORD*  p = (const WORD *)pTemplate;
+  BOOL  istemplateex = (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF);
+  WORD nrofitems;
+
+  if (istemplateex)
+  {
+    /* DLGTEMPLATEEX (not defined in any std. header file) */
+
+    TRACE("is DLGTEMPLATEEX\n");
+    p++;       /* dlgVer    */
+    p++;       /* signature */
+    p += 2;    /* help ID   */
+    p += 2;    /* ext style */
+    p += 2;    /* style     */
+  }
+  else
+  {
+    /* DLGTEMPLATE */
+
+    TRACE("is DLGTEMPLATE\n");
+    p += 2;    /* style     */
+    p += 2;    /* ext style */
+  }
+
+  nrofitems =   (WORD)*p; p++;    /* nb items */
+  p++;    /*   x      */
+  p++;    /*   y      */
+  p++;    /*   width  */
+  p++;    /*   height */
+
+  /* menu */
+  switch ((WORD)*p)
+  {
+    case 0x0000:
+      p++;
+      break;
+    case 0xffff:
+      p += 2;
+      break;
+    default:
+      TRACE("menu %s\n",debugstr_w((LPCWSTR)p));
+      p += lstrlenW( (LPCWSTR)p ) + 1;
+      break;
+  }
+
+  /* class */
+  switch ((WORD)*p)
+  {
+    case 0x0000:
+      p++;
+      break;
+    case 0xffff:
+      p += 2; /* 0xffff plus predefined window class ordinal value */
+      break;
+    default:
+      TRACE("class %s\n",debugstr_w((LPCWSTR)p));
+      p += lstrlenW( (LPCWSTR)p ) + 1;
+      break;
+  }
+
+  /* title */
+  TRACE("title %s\n",debugstr_w((LPCWSTR)p));
+  p += lstrlenW((LPCWSTR)p) + 1;
+
+  /* font, if DS_SETFONT set */
+  if ((DS_SETFONT & ((istemplateex)?  ((MyDLGTEMPLATEEX*)pTemplate)->style :
+                    pTemplate->style)))
+    {
+      p+=(istemplateex)?3:1;
+      TRACE("font %s\n",debugstr_w((LPCWSTR)p));
+      p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */
+    }
+
+  /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)
+   * that are following the DLGTEMPLATE(EX) data */
+  TRACE("%d items\n",nrofitems);
+  while (nrofitems > 0)
+    {
+      p = (WORD*)(((DWORD)p + 3) & ~3); /* DWORD align */
+      
+      /* skip header */
+      p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD);
+      
+      /* check class */
+      switch ((WORD)*p)
+       {
+       case 0x0000:
+         p++;
+         break;
+       case 0xffff:
+         TRACE("class ordinal 0x%08lx\n",*(DWORD*)p);
+         p += 2;
+         break;
+       default:
+         TRACE("class %s\n",debugstr_w((LPCWSTR)p));
+         p += lstrlenW( (LPCWSTR)p ) + 1;
+         break;
+       }
+
+      /* check title text */
+      switch ((WORD)*p)
+       {
+       case 0x0000:
+         p++;
+         break;
+       case 0xffff:
+         TRACE("text ordinal 0x%08lx\n",*(DWORD*)p);
+         p += 2;
+         break;
+       default:
+         TRACE("text %s\n",debugstr_w((LPCWSTR)p));
+         p += lstrlenW( (LPCWSTR)p ) + 1;
+         break;
+       }
+      p += *p + 1;    /* Skip extra data */
+      --nrofitems;
+    }
+  
+  TRACE("%p %p size 0x%08x\n",p, (WORD*)pTemplate,sizeof(WORD)*(p - (WORD*)pTemplate));
+  return (p - (WORD*)pTemplate)*sizeof(WORD);
+  
+}
+
+/******************************************************************************
+ *            PROPSHEET_CreatePage
+ *
+ * Creates a page.
+ */
+static BOOL PROPSHEET_CreatePage(HWND hwndParent,
+                                int index,
+                                const PropSheetInfo * psInfo,
+                                LPCPROPSHEETPAGEW ppshpage)
+{
+  DLGTEMPLATE* pTemplate;
+  HWND hwndPage;
+  RECT rc;
+  PropPageInfo* ppInfo = psInfo->proppage;
+  PADDING_INFO padding;
+  UINT pageWidth,pageHeight;
+  DWORD resSize;
+  LPVOID temp = NULL;
+
+  TRACE("index %d\n", index);
+
+  if (ppshpage == NULL)
+  {
+    return FALSE;
+  }
+
+  if (ppshpage->dwFlags & PSP_DLGINDIRECT)
+    {
+      pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
+      resSize = GetTemplateSize(pTemplate);
+    }
+  else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
+  {
+    HRSRC hResource;
+    HANDLE hTemplate;
+
+    hResource = FindResourceW(ppshpage->hInstance,
+                                    ppshpage->u.pszTemplate,
+                                    (LPWSTR)RT_DIALOG);
+    if(!hResource)
+       return FALSE;
+
+    resSize = SizeofResource(ppshpage->hInstance, hResource);
+
+    hTemplate = LoadResource(ppshpage->hInstance, hResource);
+    if(!hTemplate)
+       return FALSE;
+
+    pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
+    /*
+     * Make a copy of the dialog template to make it writable
+     */
+  }
+  else
+  {
+    HRSRC hResource;
+    HANDLE hTemplate;
+
+    hResource = FindResourceA(ppshpage->hInstance,
+                                    (LPSTR)ppshpage->u.pszTemplate,
+                                    (LPSTR)RT_DIALOG);
+    if(!hResource)
+       return FALSE;
+
+    resSize = SizeofResource(ppshpage->hInstance, hResource);
+
+    hTemplate = LoadResource(ppshpage->hInstance, hResource);
+    if(!hTemplate)
+       return FALSE;
+
+    pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
+    /*
+     * Make a copy of the dialog template to make it writable
+     */
+  }
+  temp = Alloc(resSize);
+  if (!temp)
+    return FALSE;
+  
+  TRACE("copying pTemplate %p into temp %p (%ld)\n", pTemplate, temp, resSize);
+  memcpy(temp, pTemplate, resSize);
+  pTemplate = temp;
+
+  if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
+  {
+    ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
+    ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME;
+  }
+  else
+  {
+    pTemplate->style |= WS_CHILD | DS_CONTROL;
+    pTemplate->style &= ~DS_MODALFRAME;
+    pTemplate->style &= ~WS_CAPTION;
+    pTemplate->style &= ~WS_SYSMENU;
+    pTemplate->style &= ~WS_POPUP;
+    pTemplate->style &= ~WS_DISABLED;
+    pTemplate->style &= ~WS_VISIBLE;
+    pTemplate->style &= ~WS_THICKFRAME;
+  }
+
+  if (psInfo->proppage[index].useCallback)
+    (*(ppshpage->pfnCallback))(hwndParent,
+                               PSPCB_CREATE,
+                               (LPPROPSHEETPAGEW)ppshpage);
+
+  if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
+     hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,
+                                       pTemplate,
+                                       hwndParent,
+                                       ppshpage->pfnDlgProc,
+                                       (LPARAM)ppshpage);
+  else
+     hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
+                                       pTemplate,
+                                       hwndParent,
+                                       ppshpage->pfnDlgProc,
+                                       (LPARAM)ppshpage);
+  /* Free a no more needed copy */
+  if(temp)
+      Free(temp);
+
+  ppInfo[index].hwndPage = hwndPage;
+
+  if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {
+      /* FIXME: This code may no longer be correct.
+       *        It was not for the non-wizard path.  (GLA 6/02)
+       */
+      rc.left = psInfo->x;
+      rc.top = psInfo->y;
+      rc.right = psInfo->width;
+      rc.bottom = psInfo->height;
+
+      MapDialogRect(hwndParent, &rc);
+
+      pageWidth = rc.right - rc.left;
+      pageHeight = rc.bottom - rc.top;
+
+      padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
+      TRACE("setting page %08lx, rc (%ld,%ld)-(%ld,%ld) w=%d, h=%d, padx=%d, pady=%d\n",
+           (DWORD)hwndPage, rc.left, rc.top, rc.right, rc.bottom,
+           pageWidth, pageHeight, padding.x, padding.y);
+      SetWindowPos(hwndPage, HWND_TOP,
+                  rc.left + padding.x/2,
+                  rc.top + padding.y/2,
+                  pageWidth, pageHeight, 0);
+  }
+  else {
+      /*
+       * Ask the Tab control to reduce the client rectangle to that
+       * it has available.
+       */
+      PROPSHEET_GetPageRect(psInfo, hwndParent, &rc);
+      pageWidth = rc.right - rc.left;
+      pageHeight = rc.bottom - rc.top;
+      TRACE("setting page %08lx, rc (%ld,%ld)-(%ld,%ld) w=%d, h=%d\n",
+           (DWORD)hwndPage, rc.left, rc.top, rc.right, rc.bottom,
+           pageWidth, pageHeight);
+      SetWindowPos(hwndPage, HWND_TOP,
+                  rc.left, rc.top,
+                  pageWidth, pageHeight, 0);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_ShowPage
+ *
+ * Displays or creates the specified page.
+ */
+static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
+{
+  HWND hwndTabCtrl;
+
+  TRACE("active_page %d, index %d\n", psInfo->active_page, index);
+  if (index == psInfo->active_page)
+  {
+      if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
+          SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+      return TRUE;
+  }
+
+  if (psInfo->proppage[index].hwndPage == 0)
+  {
+     LPCPROPSHEETPAGEW ppshpage;
+
+     ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
+     PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
+  }
+
+  PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,
+                      psInfo->proppage[index].pszText);
+
+  if (psInfo->active_page != -1)
+     ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
+
+  ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
+
+  /* Synchronize current selection with tab control
+   * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
+  hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
+
+  psInfo->active_page = index;
+  psInfo->activeValid = TRUE;
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Back
+ */
+static BOOL PROPSHEET_Back(HWND hwndDlg)
+{
+  PSHNOTIFY psn;
+  HWND hwndPage;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+  LRESULT result;
+  int idx;
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return FALSE;
+
+  psn.hdr.code     = PSN_WIZBACK;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+  if (result == -1)
+    return FALSE;
+  else if (result == 0)
+     idx = psInfo->active_page - 1;
+  else
+     idx = PROPSHEET_FindPageByResId(psInfo, result);
+
+  if (idx >= 0 && idx < psInfo->nPages)
+  {
+     if (PROPSHEET_CanSetCurSel(hwndDlg))
+        PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);
+  }
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Next
+ */
+static BOOL PROPSHEET_Next(HWND hwndDlg)
+{
+  PSHNOTIFY psn;
+  HWND hwndPage;
+  LRESULT msgResult = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+  int idx;
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return FALSE;
+
+  psn.hdr.code     = PSN_WIZNEXT;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+  if (msgResult == -1)
+    return FALSE;
+  else if (msgResult == 0)
+     idx = psInfo->active_page + 1;
+  else
+     idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
+
+  if (idx < psInfo->nPages )
+  {
+     if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
+        PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Finish
+ */
+static BOOL PROPSHEET_Finish(HWND hwndDlg)
+{
+  PSHNOTIFY psn;
+  HWND hwndPage;
+  LRESULT msgResult = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return FALSE;
+
+  psn.hdr.code     = PSN_WIZFINISH;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+
+  TRACE("msg result %ld\n", msgResult);
+
+  if (msgResult != 0)
+    return FALSE;
+
+  if (psInfo->isModeless)
+    psInfo->activeValid = FALSE;
+  else
+    EndDialog(hwndDlg, TRUE);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Apply
+ */
+static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
+{
+  int i;
+  HWND hwndPage;
+  PSHNOTIFY psn;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return FALSE;
+
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+
+  /*
+   * Send PSN_KILLACTIVE to the current page.
+   */
+  psn.hdr.code = PSN_KILLACTIVE;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+  if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
+    return FALSE;
+
+  /*
+   * Send PSN_APPLY to all pages.
+   */
+  psn.hdr.code = PSN_APPLY;
+  psn.lParam   = lParam;
+
+  for (i = 0; i < psInfo->nPages; i++)
+  {
+    hwndPage = psInfo->proppage[i].hwndPage;
+    if (hwndPage)
+    {
+       switch (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
+       {
+       case PSNRET_INVALID:
+           PROPSHEET_ShowPage(hwndDlg, i, psInfo);
+           /* fall through */
+       case PSNRET_INVALID_NOCHANGEPAGE:
+           return FALSE;
+       }
+    }
+  }
+
+  if(lParam)
+  {
+     psInfo->activeValid = FALSE;
+  }
+  else if(psInfo->active_page >= 0)
+  {
+     psn.hdr.code = PSN_SETACTIVE;
+     psn.lParam   = 0;
+     hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+     SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_Cancel
+ */
+static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
+{
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+  HWND hwndPage;
+  PSHNOTIFY psn;
+  int i;
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+  psn.hdr.code     = PSN_QUERYCANCEL;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
+    return;
+
+  psn.hdr.code = PSN_RESET;
+  psn.lParam   = lParam;
+
+  for (i = 0; i < psInfo->nPages; i++)
+  {
+    hwndPage = psInfo->proppage[i].hwndPage;
+
+    if (hwndPage)
+       SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+  }
+
+  if (psInfo->isModeless)
+  {
+     /* makes PSM_GETCURRENTPAGEHWND return NULL */
+     psInfo->activeValid = FALSE;
+  }
+  else
+    EndDialog(hwndDlg, FALSE);
+}
+
+/******************************************************************************
+ *            PROPSHEET_Help
+ */
+static void PROPSHEET_Help(HWND hwndDlg)
+{
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+  HWND hwndPage;
+  PSHNOTIFY psn;
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (psInfo->active_page < 0)
+     return;
+
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+  psn.hdr.code     = PSN_HELP;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+}
+
+/******************************************************************************
+ *            PROPSHEET_Changed
+ */
+static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
+{
+  int i;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  TRACE("\n");
+  if (!psInfo) return;
+  /*
+   * Set the dirty flag of this page.
+   */
+  for (i = 0; i < psInfo->nPages; i++)
+  {
+    if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
+      psInfo->proppage[i].isDirty = TRUE;
+  }
+
+  /*
+   * Enable the Apply button.
+   */
+  if (psInfo->hasApply)
+  {
+    HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
+
+    EnableWindow(hwndApplyBtn, TRUE);
+  }
+}
+
+/******************************************************************************
+ *            PROPSHEET_UnChanged
+ */
+static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
+{
+  int i;
+  BOOL noPageDirty = TRUE;
+  HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  TRACE("\n");
+  if ( !psInfo ) return;
+  for (i = 0; i < psInfo->nPages; i++)
+  {
+    /* set the specified page as clean */
+    if (psInfo->proppage[i].hwndPage == hwndCleanPage)
+      psInfo->proppage[i].isDirty = FALSE;
+
+    /* look to see if there's any dirty pages */
+    if (psInfo->proppage[i].isDirty)
+      noPageDirty = FALSE;
+  }
+
+  /*
+   * Disable Apply button.
+   */
+  if (noPageDirty)
+    EnableWindow(hwndApplyBtn, FALSE);
+}
+
+/******************************************************************************
+ *            PROPSHEET_PressButton
+ */
+static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
+{
+  TRACE("buttonID %d\n", buttonID);
+  switch (buttonID)
+  {
+    case PSBTN_APPLYNOW:
+      PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
+      break;
+    case PSBTN_BACK:
+      PROPSHEET_Back(hwndDlg);
+      break;
+    case PSBTN_CANCEL:
+      PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
+      break;
+    case PSBTN_FINISH:
+      PROPSHEET_Finish(hwndDlg);
+      break;
+    case PSBTN_HELP:
+      PROPSHEET_DoCommand(hwndDlg, IDHELP);
+      break;
+    case PSBTN_NEXT:
+      PROPSHEET_Next(hwndDlg);
+      break;
+    case PSBTN_OK:
+      PROPSHEET_DoCommand(hwndDlg, IDOK);
+      break;
+    default:
+      FIXME("Invalid button index %d\n", buttonID);
+  }
+}
+
+
+/*************************************************************************
+ * BOOL PROPSHEET_CanSetCurSel [Internal]
+ *
+ * Test whether the current page can be changed by sending a PSN_KILLACTIVE
+ *
+ * PARAMS
+ *     hwndDlg        [I] handle to a Dialog hWnd
+ *
+ * RETURNS
+ *     TRUE if Current Selection can change
+ *
+ * NOTES
+ */
+static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
+{
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+  HWND hwndPage;
+  PSHNOTIFY psn;
+  BOOL res = FALSE;
+
+  TRACE("active_page %d\n", psInfo->active_page);
+  if (!psInfo)
+  {
+     res = FALSE;
+     goto end;
+  }
+
+  if (psInfo->active_page < 0)
+  {
+     res = TRUE;
+     goto end;
+  }
+
+  /*
+   * Notify the current page.
+   */
+  hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+  psn.hdr.code     = PSN_KILLACTIVE;
+  psn.hdr.hwndFrom = hwndDlg;
+  psn.hdr.idFrom   = 0;
+  psn.lParam       = 0;
+
+  res = !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+
+end:
+  TRACE("<-- %d\n", res);
+  return res;
+}
+
+/******************************************************************************
+ *            PROPSHEET_SetCurSel
+ */
+static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
+                                int index,
+                               int skipdir,
+                                HPROPSHEETPAGE hpage
+                               )
+{
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
+  HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
+  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+
+  TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
+  /* hpage takes precedence over index */
+  if (hpage != NULL)
+    index = PROPSHEET_GetPageIndex(hpage, psInfo);
+
+  if (index < 0 || index >= psInfo->nPages)
+  {
+    TRACE("Could not find page to select!\n");
+    return FALSE;
+  }
+
+  while (1) {
+    int result;
+    PSHNOTIFY psn;
+
+    if (hwndTabControl)
+       SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);
+
+    psn.hdr.code     = PSN_SETACTIVE;
+    psn.hdr.hwndFrom = hwndDlg;
+    psn.hdr.idFrom   = 0;
+    psn.lParam       = 0;
+
+    if (!psInfo->proppage[index].hwndPage) {
+      LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
+      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
+    }
+
+    result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
+    if (!result)
+      break;
+    if (result == -1) {
+      index+=skipdir;
+      if (index < 0) {
+       index = 0;
+       FIXME("Tried to skip before first property sheet page!\n");
+       break;
+      }
+      if (index >= psInfo->nPages) {
+       FIXME("Tried to skip after last property sheet page!\n");
+       index = psInfo->nPages-1;
+       break;
+      }
+    }
+    else if (result != 0)
+    {
+       index = PROPSHEET_FindPageByResId(psInfo, result);
+       continue;
+    }
+  }
+  /*
+   * Display the new page.
+   */
+  PROPSHEET_ShowPage(hwndDlg, index, psInfo);
+
+  if (psInfo->proppage[index].hasHelp)
+    EnableWindow(hwndHelp, TRUE);
+  else
+    EnableWindow(hwndHelp, FALSE);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_SetCurSelId
+ *
+ * Selects the page, specified by resource id.
+ */
+static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)
+{
+      int idx;
+      PropSheetInfo* psInfo =
+          (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
+
+      idx = PROPSHEET_FindPageByResId(psInfo, id);
+      if (idx < psInfo->nPages )
+      {
+          if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
+              PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
+      }
+}
+
+/******************************************************************************
+ *            PROPSHEET_SetTitleA
+ */
+static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
+{
+  if(HIWORD(lpszText))
+  {
+     WCHAR szTitle[256];
+     MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
+                            szTitle, sizeof(szTitle));
+     PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
+  }
+  else
+  {
+     PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
+  }
+}
+
+/******************************************************************************
+ *            PROPSHEET_SetTitleW
+ */
+static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
+{
+  PropSheetInfo*       psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
+  WCHAR                        szTitle[256];
+
+  TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText), dwStyle);
+  if (HIWORD(lpszText) == 0) {
+    if (!LoadStringW(psInfo->ppshheader.hInstance,
+                     LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))
+      return;
+    lpszText = szTitle;
+  }
+  if (dwStyle & PSH_PROPTITLE)
+  {
+    WCHAR* dest;
+    int lentitle = strlenW(lpszText);
+    int lenprop  = strlenW(psInfo->strPropertiesFor);
+
+    dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
+    strcpyW(dest, psInfo->strPropertiesFor);
+    strcatW(dest, lpszText);
+
+    SetWindowTextW(hwndDlg, dest);
+    Free(dest);
+  }
+  else
+    SetWindowTextW(hwndDlg, lpszText);
+}
+
+/******************************************************************************
+ *            PROPSHEET_SetFinishTextA
+ */
+static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
+{
+  HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+
+  TRACE("'%s'\n", lpszText);
+  /* 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_SetFinishTextW
+ */
+static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
+{
+  HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+
+  TRACE("'%s'\n", debugstr_w(lpszText));
+  /* Set text, show and enable the Finish button */
+  SetWindowTextW(hwndButton, lpszText);
+  ShowWindow(hwndButton, SW_SHOW);
+  EnableWindow(hwndButton, TRUE);
+
+  /* Make it default pushbutton */
+  SendMessageW(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
+ */
+static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
+                                       WPARAM wParam, LPARAM lParam)
+{
+  int i = 0;
+  HWND hwndPage;
+  LRESULT msgResult = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                    PropSheetInfoStr);
+
+  while ((i < psInfo->nPages) && (msgResult == 0))
+  {
+    hwndPage = psInfo->proppage[i].hwndPage;
+    msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
+    i++;
+  }
+
+  return msgResult;
+}
+
+
+/******************************************************************************
+ *            PROPSHEET_AddPage
+ */
+static BOOL PROPSHEET_AddPage(HWND hwndDlg,
+                              HPROPSHEETPAGE hpage)
+{
+  PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                     PropSheetInfoStr);
+  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  TCITEMW item;
+  LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
+
+  TRACE("hpage %p\n", hpage);
+  /*
+   * Allocate and fill in a new PropPageInfo entry.
+   */
+  psInfo->proppage = (PropPageInfo*) ReAlloc(psInfo->proppage,
+                                                      sizeof(PropPageInfo) *
+                                                      (psInfo->nPages + 1));
+  if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
+      return FALSE;
+
+  psInfo->proppage[psInfo->nPages].hpage = hpage;
+
+  if (ppsp->dwFlags & PSP_PREMATURE)
+  {
+     /* Create the page but don't show it */
+     PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
+  }
+
+  /*
+   * Add a new tab to the tab control.
+   */
+  item.mask = TCIF_TEXT;
+  item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
+  item.cchTextMax = MAX_TABTEXT_LENGTH;
+
+  if (psInfo->hImageList)
+  {
+    SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
+  }
+
+  if ( psInfo->proppage[psInfo->nPages].hasIcon )
+  {
+    item.mask |= TCIF_IMAGE;
+    item.iImage = psInfo->nPages;
+  }
+
+  SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
+               (LPARAM)&item);
+
+  psInfo->nPages++;
+
+  /* If it is the only page - show it */
+  if(psInfo->nPages == 1)
+     PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_RemovePage
+ */
+static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
+                                 int index,
+                                 HPROPSHEETPAGE hpage)
+{
+  PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
+                                                     PropSheetInfoStr);
+  HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
+  PropPageInfo* oldPages;
+
+  TRACE("index %d, hpage %p\n", index, hpage);
+  if (!psInfo) {
+    return FALSE;
+  }
+  oldPages = psInfo->proppage;
+  /*
+   * hpage takes precedence over index.
+   */
+  if (hpage != 0)
+  {
+    index = PROPSHEET_GetPageIndex(hpage, psInfo);
+  }
+
+  /* Make sure that index is within range */
+  if (index < 0 || index >= psInfo->nPages)
+  {
+      TRACE("Could not find page to remove!\n");
+      return FALSE;
+  }
+
+  TRACE("total pages %d removing page %d active page %d\n",
+        psInfo->nPages, index, psInfo->active_page);
+  /*
+   * Check if we're removing the active page.
+   */
+  if (index == psInfo->active_page)
+  {
+    if (psInfo->nPages > 1)
+    {
+      if (index > 0)
+      {
+        /* activate previous page  */
+        PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
+      }
+      else
+      {
+        /* activate the next page */
+        PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
+        psInfo->active_page = index;
+      }
+    }
+    else
+    {
+      psInfo->active_page = -1;
+      if (!psInfo->isModeless)
+      {
+         EndDialog(hwndDlg, FALSE);
+         return TRUE;
+      }
+    }
+  }
+  else if (index < psInfo->active_page)
+    psInfo->active_page--;
+
+  /* Destroy page dialog window */
+  DestroyWindow(psInfo->proppage[index].hwndPage);
+
+  /* Free page resources */
+  if(psInfo->proppage[index].hpage)
+  {
+     PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
+
+     if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
+
+     DestroyPropertySheetPage(psInfo->proppage[index].hpage);
+  }
+
+  /* Remove the tab */
+  SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
+
+  psInfo->nPages--;
+  psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);
+
+  if (index > 0)
+    memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
+
+  if (index < psInfo->nPages)
+    memcpy(&psInfo->proppage[index], &oldPages[index + 1],
+           (psInfo->nPages - index) * sizeof(PropPageInfo));
+
+  Free(oldPages);
+
+  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 hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
+  HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
+  HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
+
+  TRACE("%ld\n", dwFlags);
+
+  EnableWindow(hwndBack, FALSE);
+  EnableWindow(hwndNext, FALSE);
+  EnableWindow(hwndFinish, FALSE);
+
+  if (dwFlags & PSWIZB_BACK)
+    EnableWindow(hwndBack, TRUE);
+
+  if (dwFlags & PSWIZB_NEXT)
+  {
+    /* Hide the Finish button */
+    ShowWindow(hwndFinish, SW_HIDE);
+
+    /* Show and enable the Next button */
+    ShowWindow(hwndNext, SW_SHOW);
+    EnableWindow(hwndNext, 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 */
+    ShowWindow(hwndNext, SW_HIDE);
+
+    /* Show the Finish button */
+    ShowWindow(hwndFinish, SW_SHOW);
+
+    if (dwFlags & PSWIZB_FINISH)
+      EnableWindow(hwndFinish, TRUE);
+
+    /* Set the Finish button as the default pushbutton  */
+    SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
+  }
+}
+
+/******************************************************************************
+ *            PROPSHEET_GetPageIndex
+ *
+ * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
+ * the array of PropPageInfo.
+ */
+static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
+{
+  BOOL found = FALSE;
+  int index = 0;
+
+  TRACE("hpage %p\n", hpage);
+  while ((index < psInfo->nPages) && (found == FALSE))
+  {
+    if (psInfo->proppage[index].hpage == hpage)
+      found = TRUE;
+    else
+      index++;
+  }
+
+  if (found == FALSE)
+    index = -1;
+
+  return index;
+}
+
+/******************************************************************************
+ *            PROPSHEET_CleanUp
+ */
+static void PROPSHEET_CleanUp(HWND hwndDlg)
+{
+  int i;
+  PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg,
+                                                       PropSheetInfoStr);
+
+  TRACE("\n");
+  if (!psInfo) return;
+  if (HIWORD(psInfo->ppshheader.pszCaption))
+      HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
+
+  for (i = 0; i < psInfo->nPages; i++)
+  {
+     PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
+
+     if(psInfo->proppage[i].hwndPage)
+        DestroyWindow(psInfo->proppage[i].hwndPage);
+
+     if(psp)
+     {
+        if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
+           HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
+
+        DestroyPropertySheetPage(psInfo->proppage[i].hpage);
+     }
+  }
+
+  Free(psInfo->proppage);
+  Free(psInfo->strPropertiesFor);
+  ImageList_Destroy(psInfo->hImageList);
+
+  GlobalFree((HGLOBAL)psInfo);
+}
+
+/******************************************************************************
+ *            PropertySheet    (COMCTL32.@)
+ *            PropertySheetA   (COMCTL32.@)
+ */
+INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
+{
+  int bRet = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
+                                                       sizeof(PropSheetInfo));
+  UINT i, n;
+  BYTE* pByte;
+
+  TRACE("(%p)\n", lppsh);
+
+  PROPSHEET_CollectSheetInfoA(lppsh, psInfo);
+
+  psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
+                                                    lppsh->nPages);
+  pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
+
+  for (n = i = 0; i < lppsh->nPages; i++, n++)
+  {
+    if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
+      psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
+    else
+    {
+       psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
+       pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
+    }
+
+    if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
+                               psInfo, n))
+    {
+       if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
+           DestroyPropertySheetPage(psInfo->proppage[n].hpage);
+       n--;
+       psInfo->nPages--;
+    }
+  }
+
+  psInfo->unicode = FALSE;
+  bRet = PROPSHEET_CreateDialog(psInfo);
+
+  return bRet;
+}
+
+/******************************************************************************
+ *            PropertySheetW   (COMCTL32.@)
+ */
+INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
+{
+  int bRet = 0;
+  PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
+                                                       sizeof(PropSheetInfo));
+  UINT i, n;
+  BYTE* pByte;
+
+  TRACE("(%p)\n", lppsh);
+
+  PROPSHEET_CollectSheetInfoW(lppsh, psInfo);
+
+  psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
+                                                    lppsh->nPages);
+  pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
+
+  for (n = i = 0; i < lppsh->nPages; i++, n++)
+  {
+    if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
+      psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
+    else
+    {
+       psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);
+       pByte += ((LPPROPSHEETPAGEW)pByte)->dwSize;
+    }
+
+    if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
+                               psInfo, n))
+    {
+       if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
+           DestroyPropertySheetPage(psInfo->proppage[n].hpage);
+       n--;
+       psInfo->nPages--;
+    }
+  }
+
+  psInfo->unicode = TRUE;
+  bRet = PROPSHEET_CreateDialog(psInfo);
+
+  return bRet;
+}
+
+/******************************************************************************
+ *            CreatePropertySheetPage    (COMCTL32.@)
+ *            CreatePropertySheetPageA   (COMCTL32.@)
+ */
+HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
+                          LPCPROPSHEETPAGEA lpPropSheetPage)
+{
+  PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
+
+  memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
+
+  ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE;
+  if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
+  {
+     int len = strlen(lpPropSheetPage->u.pszTemplate);
+
+     ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,len+1 );
+     strcpy( (LPSTR)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );
+  }
+  if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
+  {
+      PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon);
+  }
+
+  if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
+  {
+      PROPSHEET_AtoW(&ppsp->pszTitle, lpPropSheetPage->pszTitle);
+  }
+  else if ( !(ppsp->dwFlags & PSP_USETITLE) )
+      ppsp->pszTitle = NULL;
+
+  return (HPROPSHEETPAGE)ppsp;
+}
+
+/******************************************************************************
+ *            CreatePropertySheetPageW   (COMCTL32.@)
+ */
+HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
+{
+  PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
+
+  memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));
+
+  ppsp->dwFlags |= PSP_INTERNAL_UNICODE;
+
+  if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
+  {
+    int len = strlenW(lpPropSheetPage->u.pszTemplate);
+
+    ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,(len+1)*sizeof (WCHAR) );
+    strcpyW( (WCHAR *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );
+  }
+  if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
+  {
+      int len = strlenW(lpPropSheetPage->u2.pszIcon);
+      ppsp->u2.pszIcon = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
+      strcpyW( (WCHAR *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon );
+  }
+
+  if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
+  {
+      int len = strlenW(lpPropSheetPage->pszTitle);
+      ppsp->pszTitle = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
+      strcpyW( (WCHAR *)ppsp->pszTitle, lpPropSheetPage->pszTitle );
+  }
+  else if ( !(ppsp->dwFlags & PSP_USETITLE) )
+      ppsp->pszTitle = NULL;
+
+  return (HPROPSHEETPAGE)ppsp;
+}
+
+/******************************************************************************
+ *            DestroyPropertySheetPage   (COMCTL32.@)
+ */
+BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
+{
+  PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;
+
+  if (!psp)
+     return FALSE;
+
+  if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
+     HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
+
+  if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
+     HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
+
+  if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
+      HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
+
+  Free(hPropPage);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_IsDialogMessage
+ */
+static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
+{
+   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
+
+   TRACE("\n");
+   if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
+      return FALSE;
+
+   if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
+   {
+      int new_page = 0;
+      INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
+
+      if (!(dlgCode & DLGC_WANTMESSAGE))
+      {
+         switch (lpMsg->wParam)
+         {
+            case VK_TAB:
+               if (GetKeyState(VK_SHIFT) & 0x8000)
+                   new_page = -1;
+                else
+                   new_page = 1;
+               break;
+
+            case VK_NEXT:   new_page = 1;  break;
+            case VK_PRIOR:  new_page = -1; break;
+         }
+      }
+
+      if (new_page)
+      {
+         if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
+         {
+            new_page += psInfo->active_page;
+
+            if (new_page < 0)
+               new_page = psInfo->nPages - 1;
+            else if (new_page >= psInfo->nPages)
+               new_page = 0;
+
+            PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
+         }
+
+         return TRUE;
+      }
+   }
+
+   return IsDialogMessageA(hwnd, lpMsg);
+}
+
+/******************************************************************************
+ *            PROPSHEET_DoCommand
+ */
+static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)
+{
+
+    switch (wID) {
+
+    case IDOK:
+    case IDC_APPLY_BUTTON:
+       {
+           HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
+
+           if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
+               break;
+
+           if (wID == IDOK)
+               {
+                   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
+                                                                     PropSheetInfoStr);
+                   int result = TRUE;
+
+                   if (psInfo->restartWindows)
+                       result = ID_PSRESTARTWINDOWS;
+
+                   /* reboot system takes precedence over restart windows */
+                   if (psInfo->rebootSystem)
+                       result = ID_PSREBOOTSYSTEM;
+
+                   if (psInfo->isModeless)
+                       psInfo->activeValid = FALSE;
+                   else
+                       EndDialog(hwnd, result);
+               }
+           else
+               EnableWindow(hwndApplyBtn, FALSE);
+
+           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, 0);
+       break;
+
+    case IDHELP:
+       PROPSHEET_Help(hwnd);
+       break;
+    }
+
+    return TRUE;
+}
+
+/******************************************************************************
+ *            PROPSHEET_DialogProc
+ */
+INT_PTR CALLBACK
+PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n",
+       hwnd, uMsg, wParam, lParam);
+
+  switch (uMsg)
+  {
+    case WM_INITDIALOG:
+    {
+      PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
+      WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));
+      HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
+      LPCPROPSHEETPAGEW ppshpage;
+      int idx;
+
+      SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
+
+      /*
+       * psInfo->hwnd is not being used by WINE code - it exists
+       * for compatibility with "real" Windoze. The same about
+       * SetWindowLong - WINE is only using the PropSheetInfoStr
+       * property.
+       */
+      psInfo->hwnd = hwnd;
+      SetWindowLongW(hwnd,DWL_USER,(LONG)psInfo);
+
+      /* set up the Next and Back buttons by default */
+      PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);
+
+      /*
+       * Small icon in the title bar.
+       */
+      if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
+          (psInfo->ppshheader.dwFlags & PSH_USEHICON))
+      {
+        HICON hIcon;
+        int icon_cx = GetSystemMetrics(SM_CXSMICON);
+        int icon_cy = GetSystemMetrics(SM_CYSMICON);
+
+        if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
+          hIcon = LoadImageW(psInfo->ppshheader.hInstance,
+                             psInfo->ppshheader.u.pszIcon,
+                             IMAGE_ICON,
+                             icon_cx, icon_cy,
+                             LR_DEFAULTCOLOR);
+        else
+          hIcon = psInfo->ppshheader.u.hIcon;
+
+        SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon);
+      }
+
+      if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
+        SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon);
+
+      psInfo->strPropertiesFor = strCaption;
+
+      GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
+
+      PROPSHEET_CreateTabControl(hwnd, psInfo);
+
+      if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
+      {
+        if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
+        {
+          PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
+          PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
+        }
+      }
+      else
+      {
+        if (PROPSHEET_SizeMismatch(hwnd, psInfo))
+        {
+          PROPSHEET_AdjustSize(hwnd, psInfo);
+          PROPSHEET_AdjustButtons(hwnd, psInfo);
+        }
+      }
+
+      if (psInfo->useCallback)
+             (*(psInfo->ppshheader.pfnCallback))(hwnd,
+                                             PSCB_INITIALIZED, (LPARAM)0);
+
+      idx = psInfo->active_page;
+      ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage;
+      psInfo->active_page = -1;
+
+      PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
+
+      /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
+       * as some programs call TCM_GETCURSEL to get the current selection
+       * from which to switch to the next page */
+      SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
+
+      if (!HIWORD(psInfo->ppshheader.pszCaption) &&
+              psInfo->ppshheader.hInstance)
+      {
+         WCHAR szText[256];
+
+         if (LoadStringW(psInfo->ppshheader.hInstance,
+                 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
+            PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);
+      }
+      else
+      {
+         PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,
+                         psInfo->ppshheader.pszCaption);
+      }
+
+      return TRUE;
+    }
+
+    case WM_DESTROY:
+      PROPSHEET_CleanUp(hwnd);
+      return TRUE;
+
+    case WM_CLOSE:
+      PROPSHEET_Cancel(hwnd, 1);
+      return TRUE;
+
+    case WM_COMMAND:
+      return PROPSHEET_DoCommand(hwnd, LOWORD(wParam));
+
+    case WM_NOTIFY:
+    {
+      NMHDR* pnmh = (LPNMHDR) lParam;
+
+      if (pnmh->code == TCN_SELCHANGE)
+      {
+        int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
+        PROPSHEET_SetCurSel(hwnd, index, 1, 0);
+      }
+
+      if(pnmh->code == TCN_SELCHANGING)
+      {
+        BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
+        SetWindowLongW(hwnd, DWL_MSGRESULT, !bRet);
+        return TRUE;
+      }
+
+      return FALSE;
+    }
+
+    case PSM_GETCURRENTPAGEHWND:
+    {
+      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
+                                                        PropSheetInfoStr);
+      HWND hwndPage = 0;
+
+      if (psInfo->activeValid && psInfo->active_page != -1)
+        hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, (LONG)hwndPage);
+
+      return TRUE;
+    }
+
+    case PSM_CHANGED:
+      PROPSHEET_Changed(hwnd, (HWND)wParam);
+      return TRUE;
+
+    case PSM_UNCHANGED:
+      PROPSHEET_UnChanged(hwnd, (HWND)wParam);
+      return TRUE;
+
+    case PSM_GETTABCONTROL:
+    {
+      HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, (LONG)hwndTabCtrl);
+
+      return TRUE;
+    }
+
+    case PSM_SETCURSEL:
+    {
+      BOOL msgResult;
+
+      msgResult = PROPSHEET_CanSetCurSel(hwnd);
+      if(msgResult != FALSE)
+      {
+        msgResult = PROPSHEET_SetCurSel(hwnd,
+                                       (int)wParam,
+                                      1,
+                                       (HPROPSHEETPAGE)lParam);
+      }
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
+
+      return TRUE;
+    }
+
+    case PSM_CANCELTOCLOSE:
+    {
+      WCHAR buf[MAX_BUTTONTEXT_LENGTH];
+      HWND hwndOK = GetDlgItem(hwnd, IDOK);
+      HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
+
+      EnableWindow(hwndCancel, FALSE);
+      if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
+         SetWindowTextW(hwndOK, buf);
+
+      return FALSE;
+    }
+
+    case PSM_RESTARTWINDOWS:
+    {
+      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
+                                                        PropSheetInfoStr);
+
+      psInfo->restartWindows = TRUE;
+      return TRUE;
+    }
+
+    case PSM_REBOOTSYSTEM:
+    {
+      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
+                                                        PropSheetInfoStr);
+
+      psInfo->rebootSystem = TRUE;
+      return TRUE;
+    }
+
+    case PSM_SETTITLEA:
+      PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
+      return TRUE;
+
+    case PSM_SETTITLEW:
+      PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);
+      return TRUE;
+
+    case PSM_APPLY:
+    {
+      BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
+
+      return TRUE;
+    }
+
+    case PSM_QUERYSIBLINGS:
+    {
+      LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
+
+      return TRUE;
+    }
+
+    case PSM_ADDPAGE:
+    {
+      /*
+       * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
+       *       a return value. This is not true. PSM_ADDPAGE returns TRUE
+       *       on success or FALSE otherwise, as specified on MSDN Online.
+       *       Also see the MFC code for
+       *       CPropertySheet::AddPage(CPropertyPage* pPage).
+       */
+
+      BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
+
+      SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
+
+      return TRUE;
+    }
+
+    case PSM_REMOVEPAGE:
+      PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
+      return TRUE;
+
+    case PSM_ISDIALOGMESSAGE:
+    {
+       BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
+       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
+       return TRUE;
+    }
+
+    case PSM_PRESSBUTTON:
+      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_SETCURSELID:
+        PROPSHEET_SetCurSelId(hwnd, (int)lParam);
+        return TRUE;
+
+    case PSM_SETFINISHTEXTW:
+        PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);
+        return FALSE;
+
+    default:
+      return FALSE;
+  }
+
+  return FALSE;
+}