ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

propsheet.c
Go to the documentation of this file.
00001 /*
00002  * Property Sheets
00003  *
00004  * Copyright 1998 Francis Beaudet
00005  * Copyright 1999 Thuy Nguyen
00006  * Copyright 2004 Maxime Bellenge
00007  * Copyright 2004 Filip Navara
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  *
00023  * This code was audited for completeness against the documented features
00024  * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara.
00025  * 
00026  * Unless otherwise noted, we believe this code to be complete, as per
00027  * the specification mentioned above.
00028  * If you discover missing features, or bugs, please note them below.
00029  *
00030  * TODO:
00031  *   - Tab order
00032  *   - Wizard 97 header resizing
00033  *   - Enforcing of minimal wizard size
00034  *   - Messages:
00035  *     o PSM_INSERTPAGE
00036  *     o PSM_RECALCPAGESIZES
00037  *     o PSM_SETHEADERSUBTITLE
00038  *     o PSM_SETHEADERTITLE
00039  *     o WM_HELP
00040  *     o WM_CONTEXTMENU
00041  *   - Notifications:
00042  *     o PSN_GETOBJECT
00043  *     o PSN_QUERYINITIALFOCUS
00044  *     o PSN_TRANSLATEACCELERATOR
00045  *   - Styles:
00046  *     o PSH_RTLREADING
00047  *     o PSH_STRETCHWATERMARK
00048  *     o PSH_USEPAGELANG
00049  *     o PSH_USEPSTARTPAGE
00050  *   - Page styles:
00051  *     o PSP_USEFUSIONCONTEXT
00052  *     o PSP_USEREFPARENT
00053  */
00054 
00055 #include <stdarg.h>
00056 #include <string.h>
00057 
00058 #define NONAMELESSUNION
00059 #define NONAMELESSSTRUCT
00060 #include "windef.h"
00061 #include "winbase.h"
00062 #include "wingdi.h"
00063 #include "winuser.h"
00064 #include "winnls.h"
00065 #include "commctrl.h"
00066 #include "prsht.h"
00067 #include "comctl32.h"
00068 #include "uxtheme.h"
00069 
00070 #include "wine/debug.h"
00071 #include "wine/unicode.h"
00072 
00073 /******************************************************************************
00074  * Data structures
00075  */
00076 #include "pshpack2.h"
00077 
00078 typedef struct
00079 {
00080   WORD dlgVer;
00081   WORD signature;
00082   DWORD helpID;
00083   DWORD exStyle;
00084   DWORD style;
00085 } MyDLGTEMPLATEEX;
00086 
00087 typedef struct
00088 {
00089   DWORD helpid;
00090   DWORD exStyle;
00091   DWORD style;
00092   short x;
00093   short y;
00094   short cx;
00095   short cy;
00096   DWORD id;
00097 } MyDLGITEMTEMPLATEEX;
00098 #include "poppack.h"
00099 
00100 typedef struct tagPropPageInfo
00101 {
00102   HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
00103   HWND hwndPage;
00104   BOOL isDirty;
00105   LPCWSTR pszText;
00106   BOOL hasHelp;
00107   BOOL useCallback;
00108   BOOL hasIcon;
00109 } PropPageInfo;
00110 
00111 typedef struct tagPropSheetInfo
00112 {
00113   HWND hwnd;
00114   PROPSHEETHEADERW ppshheader;
00115   BOOL unicode;
00116   LPWSTR strPropertiesFor;
00117   int nPages;
00118   int active_page;
00119   BOOL isModeless;
00120   BOOL hasHelp;
00121   BOOL hasApply;
00122   BOOL hasFinish;
00123   BOOL usePropPage;
00124   BOOL useCallback;
00125   BOOL activeValid;
00126   PropPageInfo* proppage;
00127   HFONT hFont;
00128   HFONT hFontBold;
00129   int width;
00130   int height;
00131   HIMAGELIST hImageList;
00132   BOOL ended;
00133   INT result;
00134 } PropSheetInfo;
00135 
00136 typedef struct
00137 {
00138   int x;
00139   int y;
00140 } PADDING_INFO;
00141 
00142 /******************************************************************************
00143  * Defines and global variables
00144  */
00145 
00146 static const WCHAR PropSheetInfoStr[] =
00147     {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };
00148 
00149 #define PSP_INTERNAL_UNICODE 0x80000000
00150 
00151 #define MAX_CAPTION_LENGTH 255
00152 #define MAX_TABTEXT_LENGTH 255
00153 #define MAX_BUTTONTEXT_LENGTH 64
00154 
00155 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
00156 
00157 /* Wizard metrics specified in DLUs */
00158 #define WIZARD_PADDING 7
00159 #define WIZARD_HEADER_HEIGHT 36
00160                             
00161 /******************************************************************************
00162  * Prototypes
00163  */
00164 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
00165 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);
00166 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
00167 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
00168                                 int index,
00169                                 int skipdir,
00170                                 HPROPSHEETPAGE hpage);
00171 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo);
00172 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
00173 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
00174 
00175 static INT_PTR CALLBACK
00176 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00177 
00178 WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
00179 
00180 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
00181 /******************************************************************************
00182  *            PROPSHEET_UnImplementedFlags
00183  *
00184  * Document use of flags we don't implement yet.
00185  */
00186 static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)
00187 {
00188     CHAR string[256];
00189 
00190     string[0] = '\0';
00191 
00192   /*
00193    * unhandled header flags:
00194    *  PSH_RTLREADING         0x00000800
00195    *  PSH_STRETCHWATERMARK   0x00040000
00196    *  PSH_USEPAGELANG        0x00200000
00197    */
00198 
00199     add_flag(PSH_RTLREADING);
00200     add_flag(PSH_STRETCHWATERMARK);
00201     add_flag(PSH_USEPAGELANG);
00202     if (string[0] != '\0')
00203     FIXME("%s\n", string);
00204 }
00205 #undef add_flag
00206 
00207 /******************************************************************************
00208  *            PROPSHEET_GetPageRect
00209  *
00210  * Retrieve rect from tab control and map into the dialog for SetWindowPos
00211  */
00212 static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg,
00213                                   RECT *rc, LPCPROPSHEETPAGEW ppshpage)
00214 {
00215     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {     
00216         HWND hwndChild;
00217         RECT r;
00218 
00219         if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
00220              (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
00221              !(ppshpage->dwFlags & PSP_HIDEHEADER)) ||
00222             (psInfo->ppshheader.dwFlags & PSH_WIZARD))
00223         {
00224             rc->left = rc->top = WIZARD_PADDING;
00225         }
00226         else
00227         {
00228             rc->left = rc->top = 0;
00229         }
00230         rc->right = psInfo->width - rc->left;
00231         rc->bottom = psInfo->height - rc->top;
00232         MapDialogRect(hwndDlg, rc);
00233 
00234         if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
00235             (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
00236             !(ppshpage->dwFlags & PSP_HIDEHEADER))
00237         {
00238             hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
00239             GetClientRect(hwndChild, &r);
00240             MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2);
00241             rc->top += r.bottom + 1;
00242         }
00243     } else {
00244         HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
00245         GetClientRect(hwndTabCtrl, rc);
00246         SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc);
00247         MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2);
00248     }
00249 }
00250 
00251 /******************************************************************************
00252  *            PROPSHEET_FindPageByResId
00253  *
00254  * Find page index corresponding to page resource id.
00255  */
00256 static INT PROPSHEET_FindPageByResId(const PropSheetInfo * psInfo, LRESULT resId)
00257 {
00258    INT i;
00259 
00260    for (i = 0; i < psInfo->nPages; i++)
00261    {
00262       LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;
00263 
00264       /* Fixme: if resource ID is a string shall we use strcmp ??? */
00265       if (lppsp->u.pszTemplate == (LPVOID)resId)
00266          break;
00267    }
00268 
00269    return i;
00270 }
00271 
00272 /******************************************************************************
00273  *            PROPSHEET_AtoW
00274  *
00275  * Convert ASCII to Unicode since all data is saved as Unicode.
00276  */
00277 static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr)
00278 {
00279     INT len;
00280     WCHAR *to;
00281 
00282     TRACE("<%s>\n", frstr);
00283     len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0);
00284     to = Alloc(len * sizeof(WCHAR));
00285     MultiByteToWideChar(CP_ACP, 0, frstr, -1, to, len);
00286     *tostr = to;
00287 }
00288 
00289 /******************************************************************************
00290  *            PROPSHEET_CollectSheetInfoCommon
00291  *
00292  * Common code for PROPSHEET_CollectSheetInfoA/W
00293  */
00294 static void PROPSHEET_CollectSheetInfoCommon(PropSheetInfo * psInfo, DWORD dwFlags)
00295 {
00296   PROPSHEET_UnImplementedFlags(dwFlags);
00297 
00298   psInfo->hasHelp = dwFlags & PSH_HASHELP;
00299   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
00300   psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
00301   psInfo->isModeless = dwFlags & PSH_MODELESS;
00302   psInfo->usePropPage = dwFlags & PSH_PROPSHEETPAGE;
00303   if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
00304      psInfo->active_page = 0;
00305 
00306   psInfo->result = 0;
00307   psInfo->hImageList = 0;
00308   psInfo->activeValid = FALSE;
00309 }
00310 
00311 /******************************************************************************
00312  *            PROPSHEET_CollectSheetInfoA
00313  *
00314  * Collect relevant data.
00315  */
00316 static void PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
00317                                        PropSheetInfo * psInfo)
00318 {
00319   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
00320   DWORD dwFlags = lppsh->dwFlags;
00321 
00322   psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);
00323 
00324   memcpy(&psInfo->ppshheader,lppsh,dwSize);
00325   TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
00326     lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,
00327     debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
00328 
00329   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
00330      psInfo->ppshheader.pszCaption = NULL;
00331   else
00332   {
00333      if (!IS_INTRESOURCE(lppsh->pszCaption))
00334      {
00335         int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0);
00336         WCHAR *caption = Alloc( len*sizeof (WCHAR) );
00337 
00338         MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, caption, len);
00339         psInfo->ppshheader.pszCaption = caption;
00340      }
00341   }
00342   psInfo->nPages = lppsh->nPages;
00343 
00344   if (dwFlags & PSH_USEPSTARTPAGE)
00345   {
00346     TRACE("PSH_USEPSTARTPAGE is on\n");
00347     psInfo->active_page = 0;
00348   }
00349   else
00350     psInfo->active_page = lppsh->u2.nStartPage;
00351 
00352   PROPSHEET_CollectSheetInfoCommon(psInfo, dwFlags);
00353 }
00354 
00355 /******************************************************************************
00356  *            PROPSHEET_CollectSheetInfoW
00357  *
00358  * Collect relevant data.
00359  */
00360 static void PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
00361                                        PropSheetInfo * psInfo)
00362 {
00363   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));
00364   DWORD dwFlags = lppsh->dwFlags;
00365 
00366   psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);
00367 
00368   memcpy(&psInfo->ppshheader,lppsh,dwSize);
00369   TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t%s\nnPages\t\t%d\npfnCallback\t%p\n",
00370       lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
00371 
00372   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
00373      psInfo->ppshheader.pszCaption = NULL;
00374   else
00375   {
00376      if (!IS_INTRESOURCE(lppsh->pszCaption))
00377      {
00378         int len = strlenW(lppsh->pszCaption);
00379         WCHAR *caption = Alloc( (len+1)*sizeof(WCHAR) );
00380 
00381         psInfo->ppshheader.pszCaption = strcpyW( caption, lppsh->pszCaption );
00382      }
00383   }
00384   psInfo->nPages = lppsh->nPages;
00385 
00386   if (dwFlags & PSH_USEPSTARTPAGE)
00387   {
00388     TRACE("PSH_USEPSTARTPAGE is on\n");
00389     psInfo->active_page = 0;
00390   }
00391   else
00392     psInfo->active_page = lppsh->u2.nStartPage;
00393 
00394   PROPSHEET_CollectSheetInfoCommon(psInfo, dwFlags);
00395 }
00396 
00397 /******************************************************************************
00398  *            PROPSHEET_CollectPageInfo
00399  *
00400  * Collect property sheet data.
00401  * With code taken from DIALOG_ParseTemplate32.
00402  */
00403 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
00404                                PropSheetInfo * psInfo,
00405                                int index, BOOL resize)
00406 {
00407   const DLGTEMPLATE* pTemplate;
00408   const WORD*  p;
00409   DWORD dwFlags;
00410   int width, height;
00411 
00412   if (!lppsp)
00413     return FALSE;
00414 
00415   TRACE("\n");
00416   psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
00417   psInfo->proppage[index].hwndPage = 0;
00418   psInfo->proppage[index].isDirty = FALSE;
00419 
00420   /*
00421    * Process property page flags.
00422    */
00423   dwFlags = lppsp->dwFlags;
00424   psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
00425   psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
00426   psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
00427 
00428   /* as soon as we have a page with the help flag, set the sheet flag on */
00429   if (psInfo->proppage[index].hasHelp)
00430     psInfo->hasHelp = TRUE;
00431 
00432   /*
00433    * Process page template.
00434    */
00435   if (dwFlags & PSP_DLGINDIRECT)
00436     pTemplate = lppsp->u.pResource;
00437   else if(dwFlags & PSP_INTERNAL_UNICODE )
00438   {
00439     HRSRC hResource = FindResourceW(lppsp->hInstance,
00440                                     lppsp->u.pszTemplate,
00441                                     (LPWSTR)RT_DIALOG);
00442     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
00443                                      hResource);
00444     pTemplate = LockResource(hTemplate);
00445   }
00446   else
00447   {
00448     HRSRC hResource = FindResourceA(lppsp->hInstance,
00449                                     (LPCSTR)lppsp->u.pszTemplate,
00450                                     (LPSTR)RT_DIALOG);
00451     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
00452                                      hResource);
00453     pTemplate = LockResource(hTemplate);
00454   }
00455 
00456   /*
00457    * Extract the size of the page and the caption.
00458    */
00459   if (!pTemplate)
00460       return FALSE;
00461 
00462   p = (const WORD *)pTemplate;
00463 
00464   if (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
00465   {
00466     /* DLGTEMPLATEEX (not defined in any std. header file) */
00467 
00468     p++;       /* dlgVer    */
00469     p++;       /* signature */
00470     p += 2;    /* help ID   */
00471     p += 2;    /* ext style */
00472     p += 2;    /* style     */
00473   }
00474   else
00475   {
00476     /* DLGTEMPLATE */
00477 
00478     p += 2;    /* style     */
00479     p += 2;    /* ext style */
00480   }
00481 
00482   p++;    /* nb items */
00483   p++;    /*   x      */
00484   p++;    /*   y      */
00485   width  = (WORD)*p; p++;
00486   height = (WORD)*p; p++;
00487 
00488   /* Special calculation for interior wizard pages so the largest page is
00489    * calculated correctly. We need to add all the padding and space occupied
00490    * by the header so the width and height sums up to the whole wizard client
00491    * area. */
00492   if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
00493       (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
00494       !(dwFlags & PSP_HIDEHEADER))
00495   {
00496       height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT;
00497       width += 2 * WIZARD_PADDING;
00498   }
00499   if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
00500   {
00501       height += 2 * WIZARD_PADDING;
00502       width += 2 * WIZARD_PADDING;
00503   }
00504 
00505   /* remember the largest width and height */
00506   if (resize)
00507   {
00508       if (width > psInfo->width)
00509         psInfo->width = width;
00510 
00511       if (height > psInfo->height)
00512         psInfo->height = height;
00513   }
00514 
00515   /* menu */
00516   switch ((WORD)*p)
00517   {
00518     case 0x0000:
00519       p++;
00520       break;
00521     case 0xffff:
00522       p += 2;
00523       break;
00524     default:
00525       p += lstrlenW( p ) + 1;
00526       break;
00527   }
00528 
00529   /* class */
00530   switch ((WORD)*p)
00531   {
00532     case 0x0000:
00533       p++;
00534       break;
00535     case 0xffff:
00536       p += 2;
00537       break;
00538     default:
00539       p += lstrlenW( p ) + 1;
00540       break;
00541   }
00542 
00543   /* Extract the caption */
00544   psInfo->proppage[index].pszText = p;
00545   TRACE("Tab %d %s\n",index,debugstr_w( p ));
00546 
00547   if (dwFlags & PSP_USETITLE)
00548   {
00549     WCHAR szTitle[256];
00550     const WCHAR *pTitle;
00551     static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 };
00552     WCHAR *text;
00553     int len;
00554 
00555     if (IS_INTRESOURCE( lppsp->pszTitle ))
00556     {
00557       if (!LoadStringW( lppsp->hInstance, (DWORD_PTR)lppsp->pszTitle,szTitle,sizeof(szTitle)/sizeof(szTitle[0]) ))
00558       {
00559         pTitle = pszNull;
00560     FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
00561       }
00562       else
00563         pTitle = szTitle;
00564     }
00565     else
00566       pTitle = lppsp->pszTitle;
00567 
00568     len = strlenW(pTitle);
00569     text = Alloc( (len+1)*sizeof (WCHAR) );
00570     psInfo->proppage[index].pszText = strcpyW( text, pTitle);
00571   }
00572 
00573   /*
00574    * Build the image list for icons
00575    */
00576   if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
00577   {
00578     HICON hIcon;
00579     int icon_cx = GetSystemMetrics(SM_CXSMICON);
00580     int icon_cy = GetSystemMetrics(SM_CYSMICON);
00581 
00582     if (dwFlags & PSP_USEICONID)
00583       hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
00584                          icon_cx, icon_cy, LR_DEFAULTCOLOR);
00585     else
00586       hIcon = lppsp->u2.hIcon;
00587 
00588     if ( hIcon )
00589     {
00590       if (psInfo->hImageList == 0 )
00591     psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
00592 
00593       ImageList_AddIcon(psInfo->hImageList, hIcon);
00594     }
00595 
00596   }
00597 
00598   return TRUE;
00599 }
00600 
00601 /******************************************************************************
00602  *            PROPSHEET_CreateDialog
00603  *
00604  * Creates the actual property sheet.
00605  */
00606 static INT_PTR PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
00607 {
00608   LRESULT ret;
00609   LPCVOID template;
00610   LPVOID temp = 0;
00611   HRSRC hRes;
00612   DWORD resSize;
00613   WORD resID = IDD_PROPSHEET;
00614 
00615   TRACE("(%p)\n", psInfo);
00616   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
00617     resID = IDD_WIZARD;
00618 
00619   if( psInfo->unicode )
00620   {
00621     if(!(hRes = FindResourceW(COMCTL32_hModule,
00622                             MAKEINTRESOURCEW(resID),
00623                             (LPWSTR)RT_DIALOG)))
00624       return -1;
00625   }
00626   else
00627   {
00628     if(!(hRes = FindResourceA(COMCTL32_hModule,
00629                             MAKEINTRESOURCEA(resID),
00630                             (LPSTR)RT_DIALOG)))
00631       return -1;
00632   }
00633 
00634   if(!(template = LoadResource(COMCTL32_hModule, hRes)))
00635     return -1;
00636 
00637   /*
00638    * Make a copy of the dialog template.
00639    */
00640   resSize = SizeofResource(COMCTL32_hModule, hRes);
00641 
00642   temp = Alloc(resSize);
00643 
00644   if (!temp)
00645     return -1;
00646 
00647   memcpy(temp, template, resSize);
00648 
00649   if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP)
00650   {
00651     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
00652       ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP;
00653     else
00654       ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP;
00655   }
00656   if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) &&
00657       (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP))
00658   {
00659     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
00660       ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP;
00661     else
00662       ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP;
00663   }
00664 
00665   if (psInfo->useCallback)
00666     (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
00667 
00668   /* NOTE: MSDN states "Returns a positive value if successful, or -1
00669    * otherwise for modal property sheets.", but this is wrong. The
00670    * actual return value is either TRUE (success), FALSE (cancel) or
00671    * -1 (error). */
00672   if( psInfo->unicode )
00673   {
00674     ret = (INT_PTR)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,
00675                                           temp, psInfo->ppshheader.hwndParent,
00676                                           PROPSHEET_DialogProc, (LPARAM)psInfo);
00677     if ( !ret ) ret = -1;
00678   }
00679   else
00680   {
00681     ret = (INT_PTR)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
00682                                           temp, psInfo->ppshheader.hwndParent,
00683                                           PROPSHEET_DialogProc, (LPARAM)psInfo);
00684     if ( !ret ) ret = -1;
00685   }
00686 
00687   Free(temp);
00688 
00689   return ret;
00690 }
00691 
00692 /******************************************************************************
00693  *            PROPSHEET_SizeMismatch
00694  *
00695  *     Verify that the tab control and the "largest" property sheet page dlg. template
00696  *     match in size.
00697  */
00698 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, const PropSheetInfo* psInfo)
00699 {
00700   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
00701   RECT rcOrigTab, rcPage;
00702 
00703   /*
00704    * Original tab size.
00705    */
00706   GetClientRect(hwndTabCtrl, &rcOrigTab);
00707   TRACE("orig tab %s\n", wine_dbgstr_rect(&rcOrigTab));
00708 
00709   /*
00710    * Biggest page size.
00711    */
00712   rcPage.left   = 0;
00713   rcPage.top    = 0;
00714   rcPage.right  = psInfo->width;
00715   rcPage.bottom = psInfo->height;
00716 
00717   MapDialogRect(hwndDlg, &rcPage);
00718   TRACE("biggest page %s\n", wine_dbgstr_rect(&rcPage));
00719 
00720   if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
00721     return TRUE;
00722   if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
00723     return TRUE;
00724 
00725   return FALSE;
00726 }
00727 
00728 /******************************************************************************
00729  *            PROPSHEET_AdjustSize
00730  *
00731  * Resizes the property sheet and the tab control to fit the largest page.
00732  */
00733 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
00734 {
00735   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
00736   HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
00737   RECT rc,tabRect;
00738   int buttonHeight;
00739   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
00740   RECT units;
00741   LONG style;
00742 
00743   /* Get the height of buttons */
00744   GetClientRect(hwndButton, &rc);
00745   buttonHeight = rc.bottom;
00746 
00747   /*
00748    * Biggest page size.
00749    */
00750   rc.left   = 0;
00751   rc.top    = 0;
00752   rc.right  = psInfo->width;
00753   rc.bottom = psInfo->height;
00754 
00755   MapDialogRect(hwndDlg, &rc);
00756 
00757   /* retrieve the dialog units */
00758   units.left = units.right = 4;
00759   units.top = units.bottom = 8;
00760   MapDialogRect(hwndDlg, &units);
00761 
00762   /*
00763    * Resize the tab control.
00764    */
00765   GetClientRect(hwndTabCtrl,&tabRect);
00766 
00767   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
00768 
00769   if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
00770   {
00771       rc.bottom = rc.top + tabRect.bottom - tabRect.top;
00772       psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
00773   }
00774 
00775   if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
00776   {
00777       rc.right = rc.left + tabRect.right - tabRect.left;
00778       psInfo->width  = MulDiv((rc.right - rc.left),4,units.left);
00779   }
00780 
00781   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
00782 
00783   rc.right -= rc.left;
00784   rc.bottom -= rc.top;
00785   TRACE("setting tab %p, rc (0,0)-(%d,%d)\n",
00786         hwndTabCtrl, rc.right, rc.bottom);
00787   SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
00788                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
00789 
00790   GetClientRect(hwndTabCtrl, &rc);
00791 
00792   TRACE("tab client rc %s\n", wine_dbgstr_rect(&rc));
00793 
00794   rc.right += (padding.x * 2);
00795   rc.bottom += buttonHeight + (3 * padding.y);
00796 
00797   style = GetWindowLongW(hwndDlg, GWL_STYLE);
00798   if (!(style & WS_CHILD))
00799     AdjustWindowRect(&rc, style, FALSE);
00800 
00801   rc.right -= rc.left;
00802   rc.bottom -= rc.top;
00803 
00804   /*
00805    * Resize the property sheet.
00806    */
00807   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
00808         hwndDlg, rc.right, rc.bottom);
00809   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
00810                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
00811   return TRUE;
00812 }
00813 
00814 /******************************************************************************
00815  *            PROPSHEET_AdjustSizeWizard
00816  *
00817  * Resizes the property sheet to fit the largest page.
00818  */
00819 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, const PropSheetInfo* psInfo)
00820 {
00821   HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
00822   RECT rc, lineRect, dialogRect;
00823 
00824   /* Biggest page size */
00825   rc.left   = 0;
00826   rc.top    = 0;
00827   rc.right  = psInfo->width;
00828   rc.bottom = psInfo->height;
00829   MapDialogRect(hwndDlg, &rc);
00830 
00831   TRACE("Biggest page %s\n", wine_dbgstr_rect(&rc));
00832 
00833   /* Add space for the buttons row */
00834   GetWindowRect(hwndLine, &lineRect);
00835   MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2);
00836   GetClientRect(hwndDlg, &dialogRect);
00837   rc.bottom += dialogRect.bottom - lineRect.top - 1;
00838 
00839   /* Convert the client coordinates to window coordinates */
00840   AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE);
00841 
00842   /* Resize the property sheet */
00843   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
00844         hwndDlg, rc.right, rc.bottom);
00845   SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
00846                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
00847 
00848   return TRUE;
00849 }
00850 
00851 /******************************************************************************
00852  *            PROPSHEET_AdjustButtons
00853  *
00854  * Adjusts the buttons' positions.
00855  */
00856 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, const PropSheetInfo* psInfo)
00857 {
00858   HWND hwndButton = GetDlgItem(hwndParent, IDOK);
00859   RECT rcSheet;
00860   int x, y;
00861   int num_buttons = 2;
00862   int buttonWidth, buttonHeight;
00863   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
00864 
00865   if (psInfo->hasApply)
00866     num_buttons++;
00867 
00868   if (psInfo->hasHelp)
00869     num_buttons++;
00870 
00871   /*
00872    * Obtain the size of the buttons.
00873    */
00874   GetClientRect(hwndButton, &rcSheet);
00875   buttonWidth = rcSheet.right;
00876   buttonHeight = rcSheet.bottom;
00877 
00878   /*
00879    * Get the size of the property sheet.
00880    */
00881   GetClientRect(hwndParent, &rcSheet);
00882 
00883   /*
00884    * All buttons will be at this y coordinate.
00885    */
00886   y = rcSheet.bottom - (padding.y + buttonHeight);
00887 
00888   /*
00889    * Position OK button and make it default.
00890    */
00891   hwndButton = GetDlgItem(hwndParent, IDOK);
00892 
00893   x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
00894 
00895   SetWindowPos(hwndButton, 0, x, y, 0, 0,
00896                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00897 
00898   SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0);
00899 
00900 
00901   /*
00902    * Position Cancel button.
00903    */
00904   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
00905 
00906   x += padding.x + buttonWidth;
00907 
00908   SetWindowPos(hwndButton, 0, x, y, 0, 0,
00909                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00910 
00911   /*
00912    * Position Apply button.
00913    */
00914   hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
00915 
00916   if(psInfo->hasApply)
00917     x += padding.x + buttonWidth;
00918   else
00919     ShowWindow(hwndButton, SW_HIDE);
00920 
00921   SetWindowPos(hwndButton, 0, x, y, 0, 0,
00922               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00923   EnableWindow(hwndButton, FALSE);
00924 
00925   /*
00926    * Position Help button.
00927    */
00928   hwndButton = GetDlgItem(hwndParent, IDHELP);
00929 
00930   x += padding.x + buttonWidth;
00931   SetWindowPos(hwndButton, 0, x, y, 0, 0,
00932               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00933 
00934   if(!psInfo->hasHelp)
00935     ShowWindow(hwndButton, SW_HIDE);
00936 
00937   return TRUE;
00938 }
00939 
00940 /******************************************************************************
00941  *            PROPSHEET_AdjustButtonsWizard
00942  *
00943  * Adjusts the buttons' positions.
00944  */
00945 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
00946                                           const PropSheetInfo* psInfo)
00947 {
00948   HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
00949   HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
00950   HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER);
00951   RECT rcSheet;
00952   int x, y;
00953   int num_buttons = 3;
00954   int buttonWidth, buttonHeight, lineHeight, lineWidth;
00955   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
00956 
00957   if (psInfo->hasHelp)
00958     num_buttons++;
00959   if (psInfo->hasFinish)
00960     num_buttons++;
00961 
00962   /*
00963    * Obtain the size of the buttons.
00964    */
00965   GetClientRect(hwndButton, &rcSheet);
00966   buttonWidth = rcSheet.right;
00967   buttonHeight = rcSheet.bottom;
00968 
00969   GetClientRect(hwndLine, &rcSheet);
00970   lineHeight = rcSheet.bottom;
00971 
00972   /*
00973    * Get the size of the property sheet.
00974    */
00975   GetClientRect(hwndParent, &rcSheet);
00976 
00977   /*
00978    * All buttons will be at this y coordinate.
00979    */
00980   y = rcSheet.bottom - (padding.y + buttonHeight);
00981   
00982   /*
00983    * Position the Back button.
00984    */
00985   hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
00986 
00987   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)) - buttonWidth;
00988 
00989   SetWindowPos(hwndButton, 0, x, y, 0, 0,
00990                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00991 
00992   /*
00993    * Position the Next button.
00994    */
00995   hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
00996   
00997   x += buttonWidth;
00998   
00999   SetWindowPos(hwndButton, 0, x, y, 0, 0,
01000                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
01001 
01002   /*
01003    * Position the Finish button.
01004    */
01005   hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
01006   
01007   if (psInfo->hasFinish)
01008     x += padding.x + buttonWidth;
01009 
01010   SetWindowPos(hwndButton, 0, x, y, 0, 0,
01011                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
01012 
01013   if (!psInfo->hasFinish)
01014     ShowWindow(hwndButton, SW_HIDE);
01015 
01016   /*
01017    * Position the Cancel button.
01018    */
01019   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
01020 
01021   x += padding.x + buttonWidth;
01022 
01023   SetWindowPos(hwndButton, 0, x, y, 0, 0,
01024                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
01025 
01026   /*
01027    * Position Help button.
01028    */
01029   hwndButton = GetDlgItem(hwndParent, IDHELP);
01030 
01031   if (psInfo->hasHelp)
01032   {
01033     x += padding.x + buttonWidth;
01034 
01035     SetWindowPos(hwndButton, 0, x, y, 0, 0,
01036                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
01037   }
01038   else
01039     ShowWindow(hwndButton, SW_HIDE);
01040 
01041   if (psInfo->ppshheader.dwFlags &
01042       (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) 
01043       padding.x = 0;
01044 
01045   /*
01046    * Position and resize the sunken line.
01047    */
01048   x = padding.x;
01049   y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
01050 
01051   lineWidth = rcSheet.right - (padding.x * 2);
01052   SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
01053                SWP_NOZORDER | SWP_NOACTIVATE);
01054 
01055   /*
01056    * Position and resize the header sunken line.
01057    */
01058   
01059   SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2,
01060            SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
01061   if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)))
01062       ShowWindow(hwndLineHeader, SW_HIDE);
01063 
01064   return TRUE;
01065 }
01066 
01067 /******************************************************************************
01068  *            PROPSHEET_GetPaddingInfo
01069  *
01070  * Returns the layout information.
01071  */
01072 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
01073 {
01074   HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
01075   RECT rcTab;
01076   PADDING_INFO padding;
01077 
01078   GetWindowRect(hwndTab, &rcTab);
01079   MapWindowPoints( 0, hwndDlg, (POINT *)&rcTab, 2 );
01080 
01081   padding.x = rcTab.left;
01082   padding.y = rcTab.top;
01083 
01084   return padding;
01085 }
01086 
01087 /******************************************************************************
01088  *            PROPSHEET_GetPaddingInfoWizard
01089  *
01090  * Returns the layout information.
01091  * Vertical spacing is the distance between the line and the buttons.
01092  * Do NOT use the Help button to gather padding information when it isn't mapped
01093  * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
01094  * for it in this case !
01095  * FIXME: I'm not sure about any other coordinate problems with these evil
01096  * buttons. Fix it in case additional problems appear or maybe calculate
01097  * a padding in a completely different way, as this is somewhat messy.
01098  */
01099 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
01100  psInfo)
01101 {
01102   PADDING_INFO padding;
01103   RECT rc;
01104   HWND hwndControl;
01105   INT idButton;
01106   POINT ptButton, ptLine;
01107 
01108   TRACE("\n");
01109   if (psInfo->hasHelp)
01110   {
01111     idButton = IDHELP;
01112   }
01113   else
01114   {
01115     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
01116     {
01117     idButton = IDC_NEXT_BUTTON;
01118     }
01119     else
01120     {
01121     /* hopefully this is ok */
01122     idButton = IDCANCEL;
01123     }
01124   }
01125 
01126   hwndControl = GetDlgItem(hwndDlg, idButton);
01127   GetWindowRect(hwndControl, &rc);
01128   MapWindowPoints( 0, hwndDlg, (POINT *)&rc, 2 );
01129   ptButton.x = rc.left;
01130   ptButton.y = rc.top;
01131 
01132   /* Line */
01133   hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
01134   GetWindowRect(hwndControl, &rc);
01135   MapWindowPoints( 0, hwndDlg, (POINT *)&rc, 2 );
01136   ptLine.x = rc.left;
01137   ptLine.y = rc.bottom;
01138 
01139   padding.y = ptButton.y - ptLine.y;
01140 
01141   if (padding.y < 0)
01142       ERR("padding negative ! Please report this !\n");
01143 
01144   /* this is most probably not correct, but the best we have now */
01145   padding.x = padding.y;
01146   return padding;
01147 }
01148 
01149 /******************************************************************************
01150  *            PROPSHEET_CreateTabControl
01151  *
01152  * Insert the tabs in the tab control.
01153  */
01154 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
01155                                        const PropSheetInfo * psInfo)
01156 {
01157   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
01158   TCITEMW item;
01159   int i, nTabs;
01160   int iImage = 0;
01161 
01162   TRACE("\n");
01163   item.mask = TCIF_TEXT;
01164   item.cchTextMax = MAX_TABTEXT_LENGTH;
01165 
01166   nTabs = psInfo->nPages;
01167 
01168   /*
01169    * Set the image list for icons.
01170    */
01171   if (psInfo->hImageList)
01172   {
01173     SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
01174   }
01175 
01176   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 0, 0);
01177   for (i = 0; i < nTabs; i++)
01178   {
01179     if ( psInfo->proppage[i].hasIcon )
01180     {
01181       item.mask |= TCIF_IMAGE;
01182       item.iImage = iImage++;
01183     }
01184     else
01185     {
01186       item.mask &= ~TCIF_IMAGE;
01187     }
01188 
01189     item.pszText = (LPWSTR) psInfo->proppage[i].pszText;
01190     SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, i, (LPARAM)&item);
01191   }
01192   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 1, 0);
01193 
01194   return TRUE;
01195 }
01196 
01197 /******************************************************************************
01198  *            PROPSHEET_WizardSubclassProc
01199  *
01200  * Subclassing window procedure for wizard exterior pages to prevent drawing
01201  * background and so drawing above the watermark.
01202  */
01203 static LRESULT CALLBACK
01204 PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
01205 {
01206   switch (uMsg)
01207   {
01208     case WM_ERASEBKGND:
01209       return TRUE;
01210 
01211     case WM_CTLCOLORSTATIC:
01212       SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
01213       return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
01214   }
01215 
01216   return DefSubclassProc(hwnd, uMsg, wParam, lParam);
01217 }
01218 
01219 /*
01220  * Get the size of an in-memory Template
01221  *
01222  *( Based on the code of PROPSHEET_CollectPageInfo)
01223  * See also dialog.c/DIALOG_ParseTemplate32().
01224  */
01225 
01226 static UINT GetTemplateSize(const DLGTEMPLATE* pTemplate)
01227 
01228 {
01229   const WORD*  p = (const WORD *)pTemplate;
01230   BOOL  istemplateex = (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF);
01231   WORD nrofitems;
01232   UINT ret;
01233 
01234   if (istemplateex)
01235   {
01236     /* DLGTEMPLATEEX (not defined in any std. header file) */
01237 
01238     TRACE("is DLGTEMPLATEEX\n");
01239     p++;       /* dlgVer    */
01240     p++;       /* signature */
01241     p += 2;    /* help ID   */
01242     p += 2;    /* ext style */
01243     p += 2;    /* style     */
01244   }
01245   else
01246   {
01247     /* DLGTEMPLATE */
01248 
01249     TRACE("is DLGTEMPLATE\n");
01250     p += 2;    /* style     */
01251     p += 2;    /* ext style */
01252   }
01253 
01254   nrofitems =   (WORD)*p; p++;    /* nb items */
01255   p++;    /*   x      */
01256   p++;    /*   y      */
01257   p++;    /*   width  */
01258   p++;    /*   height */
01259 
01260   /* menu */
01261   switch ((WORD)*p)
01262   {
01263     case 0x0000:
01264       p++;
01265       break;
01266     case 0xffff:
01267       p += 2;
01268       break;
01269     default:
01270       TRACE("menu %s\n",debugstr_w( p ));
01271       p += lstrlenW( p ) + 1;
01272       break;
01273   }
01274 
01275   /* class */
01276   switch ((WORD)*p)
01277   {
01278     case 0x0000:
01279       p++;
01280       break;
01281     case 0xffff:
01282       p += 2; /* 0xffff plus predefined window class ordinal value */
01283       break;
01284     default:
01285       TRACE("class %s\n",debugstr_w( p ));
01286       p += lstrlenW( p ) + 1;
01287       break;
01288   }
01289 
01290   /* title */
01291   TRACE("title %s\n",debugstr_w( p ));
01292   p += lstrlenW( p ) + 1;
01293 
01294   /* font, if DS_SETFONT set */
01295   if ((DS_SETFONT & ((istemplateex)?  ((const MyDLGTEMPLATEEX*)pTemplate)->style :
01296              pTemplate->style)))
01297     {
01298       p+=(istemplateex)?3:1;
01299       TRACE("font %s\n",debugstr_w( p ));
01300       p += lstrlenW( p ) + 1; /* the font name */
01301     }
01302 
01303   /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)
01304    * that are following the DLGTEMPLATE(EX) data */
01305   TRACE("%d items\n",nrofitems);
01306   while (nrofitems > 0)
01307     {
01308       p = (WORD*)(((DWORD_PTR)p + 3) & ~3); /* DWORD align */
01309       
01310       /* skip header */
01311       p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD);
01312       
01313       /* check class */
01314       switch ((WORD)*p)
01315     {
01316     case 0x0000:
01317       p++;
01318       break;
01319     case 0xffff:
01320           TRACE("class ordinal 0x%08x\n",*(const DWORD*)p);
01321       p += 2;
01322       break;
01323     default:
01324       TRACE("class %s\n",debugstr_w( p ));
01325       p += lstrlenW( p ) + 1;
01326       break;
01327     }
01328 
01329       /* check title text */
01330       switch ((WORD)*p)
01331     {
01332     case 0x0000:
01333       p++;
01334       break;
01335     case 0xffff:
01336           TRACE("text ordinal 0x%08x\n",*(const DWORD*)p);
01337       p += 2;
01338       break;
01339     default:
01340       TRACE("text %s\n",debugstr_w( p ));
01341       p += lstrlenW( p ) + 1;
01342       break;
01343     }
01344       p += *p / sizeof(WORD) + 1;    /* Skip extra data */
01345       --nrofitems;
01346     }
01347   
01348   ret = (p - (const WORD*)pTemplate) * sizeof(WORD);
01349   TRACE("%p %p size 0x%08x\n", p, pTemplate, ret);
01350   return ret;
01351 }
01352 
01353 /******************************************************************************
01354  *            PROPSHEET_CreatePage
01355  *
01356  * Creates a page.
01357  */
01358 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
01359                                 int index,
01360                                 const PropSheetInfo * psInfo,
01361                                 LPCPROPSHEETPAGEW ppshpage)
01362 {
01363   const DLGTEMPLATE* pTemplate;
01364   HWND hwndPage;
01365   DWORD resSize;
01366   DLGTEMPLATE* pTemplateCopy = NULL;
01367 
01368   TRACE("index %d\n", index);
01369 
01370   if (ppshpage == NULL)
01371   {
01372     return FALSE;
01373   }
01374 
01375   if (ppshpage->dwFlags & PSP_DLGINDIRECT)
01376     {
01377       pTemplate = ppshpage->u.pResource;
01378       resSize = GetTemplateSize(pTemplate);
01379     }
01380   else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
01381   {
01382     HRSRC hResource;
01383     HANDLE hTemplate;
01384 
01385     hResource = FindResourceW(ppshpage->hInstance,
01386                                     ppshpage->u.pszTemplate,
01387                                     (LPWSTR)RT_DIALOG);
01388     if(!hResource)
01389     return FALSE;
01390 
01391     resSize = SizeofResource(ppshpage->hInstance, hResource);
01392 
01393     hTemplate = LoadResource(ppshpage->hInstance, hResource);
01394     if(!hTemplate)
01395     return FALSE;
01396 
01397     pTemplate = LockResource(hTemplate);
01398     /*
01399      * Make a copy of the dialog template to make it writable
01400      */
01401   }
01402   else
01403   {
01404     HRSRC hResource;
01405     HANDLE hTemplate;
01406 
01407     hResource = FindResourceA(ppshpage->hInstance,
01408                                     (LPCSTR)ppshpage->u.pszTemplate,
01409                                     (LPSTR)RT_DIALOG);
01410     if(!hResource)
01411     return FALSE;
01412 
01413     resSize = SizeofResource(ppshpage->hInstance, hResource);
01414 
01415     hTemplate = LoadResource(ppshpage->hInstance, hResource);
01416     if(!hTemplate)
01417     return FALSE;
01418 
01419     pTemplate = LockResource(hTemplate);
01420     /*
01421      * Make a copy of the dialog template to make it writable
01422      */
01423   }
01424   pTemplateCopy = Alloc(resSize);
01425   if (!pTemplateCopy)
01426     return FALSE;
01427   
01428   TRACE("copying pTemplate %p into pTemplateCopy %p (%d)\n", pTemplate, pTemplateCopy, resSize);
01429   memcpy(pTemplateCopy, pTemplate, resSize);
01430 
01431   if (((MyDLGTEMPLATEEX*)pTemplateCopy)->signature == 0xFFFF)
01432   {
01433     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
01434     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~DS_MODALFRAME;
01435     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_CAPTION;
01436     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_SYSMENU;
01437     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_POPUP;
01438     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_DISABLED;
01439     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_VISIBLE;
01440     ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_THICKFRAME;
01441 
01442     ((MyDLGTEMPLATEEX*)pTemplateCopy)->exStyle |= WS_EX_CONTROLPARENT;
01443   }
01444   else
01445   {
01446     pTemplateCopy->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
01447     pTemplateCopy->style &= ~DS_MODALFRAME;
01448     pTemplateCopy->style &= ~WS_CAPTION;
01449     pTemplateCopy->style &= ~WS_SYSMENU;
01450     pTemplateCopy->style &= ~WS_POPUP;
01451     pTemplateCopy->style &= ~WS_DISABLED;
01452     pTemplateCopy->style &= ~WS_VISIBLE;
01453     pTemplateCopy->style &= ~WS_THICKFRAME;
01454 
01455     pTemplateCopy->dwExtendedStyle |= WS_EX_CONTROLPARENT;
01456   }
01457 
01458   if (psInfo->proppage[index].useCallback)
01459     (*(ppshpage->pfnCallback))(0, PSPCB_CREATE,
01460                                (LPPROPSHEETPAGEW)ppshpage);
01461 
01462   if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
01463      hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,
01464                     pTemplateCopy,
01465                     hwndParent,
01466                     ppshpage->pfnDlgProc,
01467                     (LPARAM)ppshpage);
01468   else
01469      hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
01470                     pTemplateCopy,
01471                     hwndParent,
01472                     ppshpage->pfnDlgProc,
01473                     (LPARAM)ppshpage);
01474   /* Free a no more needed copy */
01475   Free(pTemplateCopy);
01476 
01477   psInfo->proppage[index].hwndPage = hwndPage;
01478 
01479   /* Subclass exterior wizard pages */
01480   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
01481      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
01482      (ppshpage->dwFlags & PSP_HIDEHEADER))
01483   {
01484       SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1,
01485                         (DWORD_PTR)ppshpage);
01486   }
01487   if (!(psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD))
01488       EnableThemeDialogTexture (hwndPage, ETDT_ENABLETAB);
01489 
01490   return TRUE;
01491 }
01492 
01493 /******************************************************************************
01494  *            PROPSHEET_LoadWizardBitmaps
01495  *
01496  * Loads the watermark and header bitmaps for a wizard.
01497  */
01498 static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo)
01499 {
01500   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD))
01501   {
01502     /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark 
01503        and put the HBITMAP in hbmWatermark. Thus all the rest of the code always 
01504        considers hbmWatermark as valid. */
01505     if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
01506         !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK))
01507     {
01508       psInfo->ppshheader.u4.hbmWatermark =
01509         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0);
01510     }
01511 
01512     /* Same behavior as for watermarks */
01513     if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
01514         !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER))
01515     {
01516       psInfo->ppshheader.u5.hbmHeader =
01517         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0);
01518     }
01519   }
01520 }
01521 
01522 
01523 /******************************************************************************
01524  *            PROPSHEET_ShowPage
01525  *
01526  * Displays or creates the specified page.
01527  */
01528 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
01529 {
01530   HWND hwndTabCtrl;
01531   HWND hwndLineHeader;
01532   HWND control;
01533   LPCPROPSHEETPAGEW ppshpage;
01534 
01535   TRACE("active_page %d, index %d\n", psInfo->active_page, index);
01536   if (index == psInfo->active_page)
01537   {
01538       if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
01539           SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
01540       return TRUE;
01541   }
01542 
01543   ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
01544   if (psInfo->proppage[index].hwndPage == 0)
01545   {
01546      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
01547   }
01548 
01549   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
01550   {
01551      PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,
01552                          psInfo->proppage[index].pszText);
01553 
01554      control = GetNextDlgTabItem(psInfo->proppage[index].hwndPage, NULL, FALSE);
01555      if(control != NULL)
01556          SetFocus(control);
01557   }
01558 
01559   if (psInfo->active_page != -1)
01560      ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
01561 
01562   ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
01563 
01564   /* Synchronize current selection with tab control
01565    * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
01566   hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
01567   SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
01568 
01569   psInfo->active_page = index;
01570   psInfo->activeValid = TRUE;
01571 
01572   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) )
01573   {
01574       hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
01575       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
01576       
01577       if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) )
01578       ShowWindow(hwndLineHeader, SW_HIDE);
01579       else
01580       ShowWindow(hwndLineHeader, SW_SHOW);
01581   }
01582 
01583   return TRUE;
01584 }
01585 
01586 /******************************************************************************
01587  *            PROPSHEET_Back
01588  */
01589 static BOOL PROPSHEET_Back(HWND hwndDlg)
01590 {
01591   PSHNOTIFY psn;
01592   HWND hwndPage;
01593   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01594   LRESULT result;
01595   int idx;
01596 
01597   TRACE("active_page %d\n", psInfo->active_page);
01598   if (psInfo->active_page < 0)
01599      return FALSE;
01600 
01601   psn.hdr.code     = PSN_WIZBACK;
01602   psn.hdr.hwndFrom = hwndDlg;
01603   psn.hdr.idFrom   = 0;
01604   psn.lParam       = 0;
01605 
01606   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01607 
01608   result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01609   if (result == -1)
01610     return FALSE;
01611   else if (result == 0)
01612      idx = psInfo->active_page - 1;
01613   else
01614      idx = PROPSHEET_FindPageByResId(psInfo, result);
01615 
01616   if (idx >= 0 && idx < psInfo->nPages)
01617   {
01618      if (PROPSHEET_CanSetCurSel(hwndDlg))
01619      {
01620         SetFocus(GetDlgItem(hwndDlg, IDC_BACK_BUTTON));
01621         SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0);
01622         PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);
01623      }
01624   }
01625   return TRUE;
01626 }
01627 
01628 /******************************************************************************
01629  *            PROPSHEET_Next
01630  */
01631 static BOOL PROPSHEET_Next(HWND hwndDlg)
01632 {
01633   PSHNOTIFY psn;
01634   HWND hwndPage;
01635   LRESULT msgResult = 0;
01636   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01637   int idx;
01638 
01639   TRACE("active_page %d\n", psInfo->active_page);
01640   if (psInfo->active_page < 0)
01641      return FALSE;
01642 
01643   psn.hdr.code     = PSN_WIZNEXT;
01644   psn.hdr.hwndFrom = hwndDlg;
01645   psn.hdr.idFrom   = 0;
01646   psn.lParam       = 0;
01647 
01648   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01649 
01650   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01651   if (msgResult == -1)
01652     return FALSE;
01653   else if (msgResult == 0)
01654      idx = psInfo->active_page + 1;
01655   else
01656      idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
01657 
01658   if (idx < psInfo->nPages )
01659   {
01660      if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
01661      {
01662         SetFocus(GetDlgItem(hwndDlg, IDC_NEXT_BUTTON));
01663         SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
01664         PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
01665      }
01666   }
01667 
01668   return TRUE;
01669 }
01670 
01671 /******************************************************************************
01672  *            PROPSHEET_Finish
01673  */
01674 static BOOL PROPSHEET_Finish(HWND hwndDlg)
01675 {
01676   PSHNOTIFY psn;
01677   HWND hwndPage;
01678   LRESULT msgResult = 0;
01679   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01680 
01681   TRACE("active_page %d\n", psInfo->active_page);
01682   if (psInfo->active_page < 0)
01683      return FALSE;
01684 
01685   psn.hdr.code     = PSN_WIZFINISH;
01686   psn.hdr.hwndFrom = hwndDlg;
01687   psn.hdr.idFrom   = 0;
01688   psn.lParam       = 0;
01689 
01690   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01691 
01692   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01693 
01694   TRACE("msg result %ld\n", msgResult);
01695 
01696   if (msgResult != 0)
01697     return FALSE;
01698 
01699   if (psInfo->result == 0)
01700       psInfo->result = IDOK;
01701   if (psInfo->isModeless)
01702     psInfo->activeValid = FALSE;
01703   else
01704     psInfo->ended = TRUE;
01705 
01706   return TRUE;
01707 }
01708 
01709 /******************************************************************************
01710  *            PROPSHEET_Apply
01711  */
01712 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
01713 {
01714   int i;
01715   HWND hwndPage;
01716   PSHNOTIFY psn;
01717   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01718 
01719   TRACE("active_page %d\n", psInfo->active_page);
01720   if (psInfo->active_page < 0)
01721      return FALSE;
01722 
01723   psn.hdr.hwndFrom = hwndDlg;
01724   psn.hdr.idFrom   = 0;
01725   psn.lParam       = 0;
01726 
01727 
01728   /*
01729    * Send PSN_KILLACTIVE to the current page.
01730    */
01731   psn.hdr.code = PSN_KILLACTIVE;
01732 
01733   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01734 
01735   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
01736     return FALSE;
01737 
01738   /*
01739    * Send PSN_APPLY to all pages.
01740    */
01741   psn.hdr.code = PSN_APPLY;
01742   psn.lParam   = lParam;
01743 
01744   for (i = 0; i < psInfo->nPages; i++)
01745   {
01746     hwndPage = psInfo->proppage[i].hwndPage;
01747     if (hwndPage)
01748     {
01749        switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
01750        {
01751        case PSNRET_INVALID:
01752            PROPSHEET_ShowPage(hwndDlg, i, psInfo);
01753            /* fall through */
01754        case PSNRET_INVALID_NOCHANGEPAGE:
01755            return FALSE;
01756        }
01757     }
01758   }
01759 
01760   if(lParam)
01761   {
01762      psInfo->activeValid = FALSE;
01763   }
01764   else if(psInfo->active_page >= 0)
01765   {
01766      psn.hdr.code = PSN_SETACTIVE;
01767      psn.lParam   = 0;
01768      hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01769      SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01770   }
01771 
01772   return TRUE;
01773 }
01774 
01775 /******************************************************************************
01776  *            PROPSHEET_Cancel
01777  */
01778 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
01779 {
01780   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01781   HWND hwndPage;
01782   PSHNOTIFY psn;
01783   int i;
01784 
01785   TRACE("active_page %d\n", psInfo->active_page);
01786   if (psInfo->active_page < 0)
01787      return;
01788 
01789   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01790   psn.hdr.code     = PSN_QUERYCANCEL;
01791   psn.hdr.hwndFrom = hwndDlg;
01792   psn.hdr.idFrom   = 0;
01793   psn.lParam       = 0;
01794 
01795   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
01796     return;
01797 
01798   psn.hdr.code = PSN_RESET;
01799   psn.lParam   = lParam;
01800 
01801   for (i = 0; i < psInfo->nPages; i++)
01802   {
01803     hwndPage = psInfo->proppage[i].hwndPage;
01804 
01805     if (hwndPage)
01806        SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01807   }
01808 
01809   if (psInfo->isModeless)
01810   {
01811      /* makes PSM_GETCURRENTPAGEHWND return NULL */
01812      psInfo->activeValid = FALSE;
01813   }
01814   else
01815     psInfo->ended = TRUE;
01816 }
01817 
01818 /******************************************************************************
01819  *            PROPSHEET_Help
01820  */
01821 static void PROPSHEET_Help(HWND hwndDlg)
01822 {
01823   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01824   HWND hwndPage;
01825   PSHNOTIFY psn;
01826 
01827   TRACE("active_page %d\n", psInfo->active_page);
01828   if (psInfo->active_page < 0)
01829      return;
01830 
01831   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01832   psn.hdr.code     = PSN_HELP;
01833   psn.hdr.hwndFrom = hwndDlg;
01834   psn.hdr.idFrom   = 0;
01835   psn.lParam       = 0;
01836 
01837   SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01838 }
01839 
01840 /******************************************************************************
01841  *            PROPSHEET_Changed
01842  */
01843 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
01844 {
01845   int i;
01846   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01847 
01848   TRACE("\n");
01849   if (!psInfo) return;
01850   /*
01851    * Set the dirty flag of this page.
01852    */
01853   for (i = 0; i < psInfo->nPages; i++)
01854   {
01855     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
01856       psInfo->proppage[i].isDirty = TRUE;
01857   }
01858 
01859   /*
01860    * Enable the Apply button.
01861    */
01862   if (psInfo->hasApply)
01863   {
01864     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
01865 
01866     EnableWindow(hwndApplyBtn, TRUE);
01867   }
01868 }
01869 
01870 /******************************************************************************
01871  *            PROPSHEET_UnChanged
01872  */
01873 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
01874 {
01875   int i;
01876   BOOL noPageDirty = TRUE;
01877   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
01878   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01879 
01880   TRACE("\n");
01881   if ( !psInfo ) return;
01882   for (i = 0; i < psInfo->nPages; i++)
01883   {
01884     /* set the specified page as clean */
01885     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
01886       psInfo->proppage[i].isDirty = FALSE;
01887 
01888     /* look to see if there's any dirty pages */
01889     if (psInfo->proppage[i].isDirty)
01890       noPageDirty = FALSE;
01891   }
01892 
01893   /*
01894    * Disable Apply button.
01895    */
01896   if (noPageDirty)
01897     EnableWindow(hwndApplyBtn, FALSE);
01898 }
01899 
01900 /******************************************************************************
01901  *            PROPSHEET_PressButton
01902  */
01903 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
01904 {
01905   TRACE("buttonID %d\n", buttonID);
01906   switch (buttonID)
01907   {
01908     case PSBTN_APPLYNOW:
01909       PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
01910       break;
01911     case PSBTN_BACK:
01912       PROPSHEET_Back(hwndDlg);
01913       break;
01914     case PSBTN_CANCEL:
01915       PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
01916       break;
01917     case PSBTN_FINISH:
01918       PROPSHEET_Finish(hwndDlg);
01919       break;
01920     case PSBTN_HELP:
01921       PROPSHEET_DoCommand(hwndDlg, IDHELP);
01922       break;
01923     case PSBTN_NEXT:
01924       PROPSHEET_Next(hwndDlg);
01925       break;
01926     case PSBTN_OK:
01927       PROPSHEET_DoCommand(hwndDlg, IDOK);
01928       break;
01929     default:
01930       FIXME("Invalid button index %d\n", buttonID);
01931   }
01932 }
01933 
01934 
01935 /*************************************************************************
01936  * BOOL PROPSHEET_CanSetCurSel [Internal]
01937  *
01938  * Test whether the current page can be changed by sending a PSN_KILLACTIVE
01939  *
01940  * PARAMS
01941  *     hwndDlg        [I] handle to a Dialog hWnd
01942  *
01943  * RETURNS
01944  *     TRUE if Current Selection can change
01945  *
01946  * NOTES
01947  */
01948 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
01949 {
01950   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01951   HWND hwndPage;
01952   PSHNOTIFY psn;
01953   BOOL res = FALSE;
01954 
01955   if (!psInfo)
01956   {
01957      res = FALSE;
01958      goto end;
01959   }
01960 
01961   TRACE("active_page %d\n", psInfo->active_page);
01962   if (psInfo->active_page < 0)
01963   {
01964      res = TRUE;
01965      goto end;
01966   }
01967 
01968   /*
01969    * Notify the current page.
01970    */
01971   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
01972   psn.hdr.code     = PSN_KILLACTIVE;
01973   psn.hdr.hwndFrom = hwndDlg;
01974   psn.hdr.idFrom   = 0;
01975   psn.lParam       = 0;
01976 
01977   res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
01978 
01979 end:
01980   TRACE("<-- %d\n", res);
01981   return res;
01982 }
01983 
01984 /******************************************************************************
01985  *            PROPSHEET_SetCurSel
01986  */
01987 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
01988                                 int index,
01989                 int skipdir,
01990                                 HPROPSHEETPAGE hpage
01991                 )
01992 {
01993   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
01994   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
01995   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
01996 
01997   TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
01998   /* hpage takes precedence over index */
01999   if (hpage != NULL)
02000     index = PROPSHEET_GetPageIndex(hpage, psInfo);
02001 
02002   if (index < 0 || index >= psInfo->nPages)
02003   {
02004     TRACE("Could not find page to select!\n");
02005     return FALSE;
02006   }
02007 
02008   /* unset active page while doing this transition. */
02009   if (psInfo->active_page != -1)
02010      ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
02011   psInfo->active_page = -1;
02012 
02013   while (1) {
02014     int result;
02015     PSHNOTIFY psn;
02016     RECT rc;
02017     LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
02018 
02019     if (hwndTabControl)
02020     SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);
02021 
02022     psn.hdr.code     = PSN_SETACTIVE;
02023     psn.hdr.hwndFrom = hwndDlg;
02024     psn.hdr.idFrom   = 0;
02025     psn.lParam       = 0;
02026 
02027     if (!psInfo->proppage[index].hwndPage) {
02028       PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
02029     }
02030 
02031     /* Resize the property sheet page to the fit in the Tab control
02032      * (for regular property sheets) or to fit in the client area (for
02033      * wizards).
02034      * NOTE: The resizing happens every time the page is selected and
02035      * not only when it's created (some applications depend on it). */
02036     PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage);
02037     TRACE("setting page %p, rc (%s) w=%d, h=%d\n",
02038           psInfo->proppage[index].hwndPage, wine_dbgstr_rect(&rc),
02039           rc.right - rc.left, rc.bottom - rc.top);
02040     SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP,
02041                  rc.left, rc.top,
02042                  rc.right - rc.left, rc.bottom - rc.top, 0);
02043 
02044     result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
02045     if (!result)
02046       break;
02047     if (result == -1) {
02048       index+=skipdir;
02049       if (index < 0) {
02050     index = 0;
02051     WARN("Tried to skip before first property sheet page!\n");
02052     break;
02053       }
02054       if (index >= psInfo->nPages) {
02055     WARN("Tried to skip after last property sheet page!\n");
02056     index = psInfo->nPages-1;
02057     break;
02058       }
02059     }
02060     else if (result != 0)
02061     {
02062       int old_index = index;
02063       index = PROPSHEET_FindPageByResId(psInfo, result);
02064       if(index >= psInfo->nPages) {
02065         index = old_index;
02066         WARN("Tried to skip to nonexistent page by res id\n");
02067         break;
02068       }
02069       continue;
02070     }
02071   }
02072 
02073   /* Invalidate the header area */
02074   if ( (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
02075        (psInfo->ppshheader.dwFlags & PSH_HEADER) )
02076   {
02077     HWND hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
02078     RECT r;
02079 
02080     GetClientRect(hwndLineHeader, &r);
02081     MapWindowPoints(hwndLineHeader, hwndDlg, (LPPOINT) &r, 2);
02082     SetRect(&r, 0, 0, r.right + 1, r.top - 1);
02083 
02084     InvalidateRect(hwndDlg, &r, TRUE);
02085   }
02086 
02087   /*
02088    * Display the new page.
02089    */
02090   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
02091 
02092   if (psInfo->proppage[index].hasHelp)
02093     EnableWindow(hwndHelp, TRUE);
02094   else
02095     EnableWindow(hwndHelp, FALSE);
02096 
02097   return TRUE;
02098 }
02099 
02100 /******************************************************************************
02101  *            PROPSHEET_SetCurSelId
02102  *
02103  * Selects the page, specified by resource id.
02104  */
02105 static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)
02106 {
02107       int idx;
02108       PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02109 
02110       idx = PROPSHEET_FindPageByResId(psInfo, id);
02111       if (idx < psInfo->nPages )
02112       {
02113           if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
02114               PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
02115       }
02116 }
02117 
02118 /******************************************************************************
02119  *            PROPSHEET_SetTitleA
02120  */
02121 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
02122 {
02123   if(!IS_INTRESOURCE(lpszText))
02124   {
02125      WCHAR szTitle[256];
02126      MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
02127                          szTitle, sizeof(szTitle)/sizeof(WCHAR));
02128      PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
02129   }
02130   else
02131   {
02132      PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
02133   }
02134 }
02135 
02136 /******************************************************************************
02137  *            PROPSHEET_SetTitleW
02138  */
02139 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
02140 {
02141   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02142   WCHAR szTitle[256];
02143 
02144   TRACE("%s (style %08x)\n", debugstr_w(lpszText), dwStyle);
02145   if (IS_INTRESOURCE(lpszText)) {
02146     if (!LoadStringW(psInfo->ppshheader.hInstance,
02147                      LOWORD(lpszText), szTitle, sizeof(szTitle)/sizeof(szTitle[0])))
02148       return;
02149     lpszText = szTitle;
02150   }
02151   if (dwStyle & PSH_PROPTITLE)
02152   {
02153     WCHAR* dest;
02154     int lentitle = strlenW(lpszText);
02155     int lenprop  = strlenW(psInfo->strPropertiesFor);
02156 
02157     dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
02158     wsprintfW(dest, psInfo->strPropertiesFor, lpszText);
02159 
02160     SetWindowTextW(hwndDlg, dest);
02161     Free(dest);
02162   }
02163   else
02164     SetWindowTextW(hwndDlg, lpszText);
02165 }
02166 
02167 /******************************************************************************
02168  *            PROPSHEET_SetFinishTextA
02169  */
02170 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
02171 {
02172   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02173   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
02174 
02175   TRACE("'%s'\n", lpszText);
02176   /* Set text, show and enable the Finish button */
02177   SetWindowTextA(hwndButton, lpszText);
02178   ShowWindow(hwndButton, SW_SHOW);
02179   EnableWindow(hwndButton, TRUE);
02180 
02181   /* Make it default pushbutton */
02182   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
02183 
02184   /* Hide Back button */
02185   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
02186   ShowWindow(hwndButton, SW_HIDE);
02187 
02188   if (!psInfo->hasFinish)
02189   {
02190     /* Hide Next button */
02191     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
02192     ShowWindow(hwndButton, SW_HIDE);
02193   }
02194 }
02195 
02196 /******************************************************************************
02197  *            PROPSHEET_SetFinishTextW
02198  */
02199 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
02200 {
02201   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02202   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
02203 
02204   TRACE("%s\n", debugstr_w(lpszText));
02205   /* Set text, show and enable the Finish button */
02206   SetWindowTextW(hwndButton, lpszText);
02207   ShowWindow(hwndButton, SW_SHOW);
02208   EnableWindow(hwndButton, TRUE);
02209 
02210   /* Make it default pushbutton */
02211   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
02212 
02213   /* Hide Back button */
02214   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
02215   ShowWindow(hwndButton, SW_HIDE);
02216 
02217   if (!psInfo->hasFinish)
02218   {
02219     /* Hide Next button */
02220     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
02221     ShowWindow(hwndButton, SW_HIDE);
02222   }
02223 }
02224 
02225 /******************************************************************************
02226  *            PROPSHEET_QuerySiblings
02227  */
02228 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
02229                                        WPARAM wParam, LPARAM lParam)
02230 {
02231   int i = 0;
02232   HWND hwndPage;
02233   LRESULT msgResult = 0;
02234   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02235 
02236   while ((i < psInfo->nPages) && (msgResult == 0))
02237   {
02238     hwndPage = psInfo->proppage[i].hwndPage;
02239     msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
02240     i++;
02241   }
02242 
02243   return msgResult;
02244 }
02245 
02246 
02247 /******************************************************************************
02248  *            PROPSHEET_AddPage
02249  */
02250 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
02251                               HPROPSHEETPAGE hpage)
02252 {
02253   PropPageInfo * ppi;
02254   PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02255   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
02256   TCITEMW item;
02257   LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
02258 
02259   TRACE("hpage %p\n", hpage);
02260   /*
02261    * Allocate and fill in a new PropPageInfo entry.
02262    */
02263   ppi = ReAlloc(psInfo->proppage, sizeof(PropPageInfo) * (psInfo->nPages + 1));
02264   if (!ppi)
02265       return FALSE;
02266 
02267   psInfo->proppage = ppi;
02268   if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages, FALSE))
02269       return FALSE;
02270 
02271   psInfo->proppage[psInfo->nPages].hpage = hpage;
02272 
02273   if (ppsp->dwFlags & PSP_PREMATURE)
02274   {
02275      /* Create the page but don't show it */
02276      PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
02277   }
02278 
02279   /*
02280    * Add a new tab to the tab control.
02281    */
02282   item.mask = TCIF_TEXT;
02283   item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
02284   item.cchTextMax = MAX_TABTEXT_LENGTH;
02285 
02286   if (psInfo->hImageList)
02287   {
02288     SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
02289   }
02290 
02291   if ( psInfo->proppage[psInfo->nPages].hasIcon )
02292   {
02293     item.mask |= TCIF_IMAGE;
02294     item.iImage = psInfo->nPages;
02295   }
02296 
02297   SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
02298                (LPARAM)&item);
02299 
02300   psInfo->nPages++;
02301 
02302   /* If it is the only page - show it */
02303   if(psInfo->nPages == 1)
02304      PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
02305   return TRUE;
02306 }
02307 
02308 /******************************************************************************
02309  *            PROPSHEET_RemovePage
02310  */
02311 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
02312                                  int index,
02313                                  HPROPSHEETPAGE hpage)
02314 {
02315   PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02316   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
02317   PropPageInfo* oldPages;
02318 
02319   TRACE("index %d, hpage %p\n", index, hpage);
02320   if (!psInfo) {
02321     return FALSE;
02322   }
02323   /*
02324    * hpage takes precedence over index.
02325    */
02326   if (hpage != 0)
02327   {
02328     index = PROPSHEET_GetPageIndex(hpage, psInfo);
02329   }
02330 
02331   /* Make sure that index is within range */
02332   if (index < 0 || index >= psInfo->nPages)
02333   {
02334       TRACE("Could not find page to remove!\n");
02335       return FALSE;
02336   }
02337 
02338   TRACE("total pages %d removing page %d active page %d\n",
02339         psInfo->nPages, index, psInfo->active_page);
02340   /*
02341    * Check if we're removing the active page.
02342    */
02343   if (index == psInfo->active_page)
02344   {
02345     if (psInfo->nPages > 1)
02346     {
02347       if (index > 0)
02348       {
02349         /* activate previous page  */
02350         PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
02351       }
02352       else
02353       {
02354         /* activate the next page */
02355         PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
02356         psInfo->active_page = index;
02357       }
02358     }
02359     else
02360     {
02361       psInfo->active_page = -1;
02362       if (!psInfo->isModeless)
02363       {
02364          psInfo->ended = TRUE;
02365          return TRUE;
02366       }
02367     }
02368   }
02369   else if (index < psInfo->active_page)
02370     psInfo->active_page--;
02371 
02372   /* Unsubclass the page dialog window */
02373   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) &&
02374      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
02375      ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER))
02376   {
02377      RemoveWindowSubclass(psInfo->proppage[index].hwndPage,
02378                           PROPSHEET_WizardSubclassProc, 1);
02379   }
02380 
02381   /* Destroy page dialog window */
02382   DestroyWindow(psInfo->proppage[index].hwndPage);
02383 
02384   /* Free page resources */
02385   if(psInfo->proppage[index].hpage)
02386   {
02387      PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
02388 
02389      if (psp->dwFlags & PSP_USETITLE)
02390         Free ((LPVOID)psInfo->proppage[index].pszText);
02391 
02392      DestroyPropertySheetPage(psInfo->proppage[index].hpage);
02393   }
02394 
02395   /* Remove the tab */
02396   SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
02397 
02398   oldPages = psInfo->proppage;
02399   psInfo->nPages--;
02400   psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);
02401 
02402   if (index > 0)
02403     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
02404 
02405   if (index < psInfo->nPages)
02406     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
02407            (psInfo->nPages - index) * sizeof(PropPageInfo));
02408 
02409   Free(oldPages);
02410 
02411   return FALSE;
02412 }
02413 
02414 /******************************************************************************
02415  *            PROPSHEET_SetWizButtons
02416  *
02417  * This code will work if (and assumes that) the Next button is on top of the
02418  * Finish button. ie. Finish comes after Next in the Z order.
02419  * This means make sure the dialog template reflects this.
02420  *
02421  */
02422 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
02423 {
02424   PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02425   HWND hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
02426   HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
02427   HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
02428   HWND hwndCancel = GetDlgItem(hwndDlg, IDCANCEL);
02429   INT iDefItem = 0;
02430   HWND hwndFocus;
02431 
02432   TRACE("%d\n", dwFlags);
02433 
02434   EnableWindow(hwndBack, FALSE);
02435   EnableWindow(hwndNext, FALSE);
02436   EnableWindow(hwndFinish, FALSE);
02437 
02438   if (dwFlags & PSWIZB_BACK)
02439     EnableWindow(hwndBack, TRUE);
02440 
02441   if (dwFlags & PSWIZB_NEXT)
02442     EnableWindow(hwndNext, TRUE);
02443 
02444   if (!psInfo->hasFinish)
02445   {
02446     if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
02447     {
02448       /* Hide the Next button */
02449       ShowWindow(hwndNext, SW_HIDE);
02450       
02451       /* Show the Finish button */
02452       ShowWindow(hwndFinish, SW_SHOW);
02453 
02454       if (!(dwFlags & PSWIZB_DISABLEDFINISH))
02455         EnableWindow(hwndFinish, TRUE);
02456     }
02457     else
02458     {
02459       /* Hide the Finish button */
02460       ShowWindow(hwndFinish, SW_HIDE);
02461       /* Show the Next button */
02462       ShowWindow(hwndNext, SW_SHOW);
02463     }
02464   }
02465   else if (!(dwFlags & PSWIZB_DISABLEDFINISH))
02466     EnableWindow(hwndFinish, TRUE);
02467 
02468   /* set the default pushbutton to an enabled button */
02469   if (((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH))
02470     iDefItem = IDC_FINISH_BUTTON;
02471   else if (dwFlags & PSWIZB_NEXT)
02472     iDefItem = IDC_NEXT_BUTTON;
02473   else if (dwFlags & PSWIZB_BACK)
02474     iDefItem = IDC_BACK_BUTTON;
02475   else
02476     iDefItem = IDCANCEL;
02477   SendMessageW(hwndDlg, DM_SETDEFID, iDefItem, 0);
02478 
02479   /* Set focus if no control has it */
02480   hwndFocus = GetFocus();
02481   if (!hwndFocus || hwndFocus == hwndCancel)
02482     SetFocus(GetDlgItem(hwndDlg, iDefItem));
02483 }
02484 
02485 /******************************************************************************
02486  *            PROPSHEET_InsertPage
02487  */
02488 static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage)
02489 {
02490     if (IS_INTRESOURCE(hpageInsertAfter))
02491         FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage);
02492     else
02493         FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage);
02494     return FALSE;
02495 }
02496 
02497 /******************************************************************************
02498  *            PROPSHEET_SetHeaderTitleW
02499  */
02500 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle)
02501 {
02502     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle));
02503 }
02504 
02505 /******************************************************************************
02506  *            PROPSHEET_SetHeaderTitleA
02507  */
02508 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle)
02509 {
02510     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle));
02511 }
02512 
02513 /******************************************************************************
02514  *            PROPSHEET_SetHeaderSubTitleW
02515  */
02516 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle)
02517 {
02518     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle));
02519 }
02520 
02521 /******************************************************************************
02522  *            PROPSHEET_SetHeaderSubTitleA
02523  */
02524 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle)
02525 {
02526     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle));
02527 }
02528 
02529 /******************************************************************************
02530  *            PROPSHEET_HwndToIndex
02531  */
02532 static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg)
02533 {
02534     int index;
02535     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02536 
02537     TRACE("(%p, %p)\n", hwndDlg, hPageDlg);
02538 
02539     for (index = 0; index < psInfo->nPages; index++)
02540         if (psInfo->proppage[index].hwndPage == hPageDlg)
02541             return index;
02542     WARN("%p not found\n", hPageDlg);
02543     return -1;
02544 }
02545 
02546 /******************************************************************************
02547  *            PROPSHEET_IndexToHwnd
02548  */
02549 static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex)
02550 {
02551     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02552     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
02553     if (!psInfo)
02554         return 0;
02555     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
02556         WARN("%d out of range.\n", iPageIndex);
02557     return 0;
02558     }
02559     return (LRESULT)psInfo->proppage[iPageIndex].hwndPage;
02560 }
02561 
02562 /******************************************************************************
02563  *            PROPSHEET_PageToIndex
02564  */
02565 static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage)
02566 {
02567     int index;
02568     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02569 
02570     TRACE("(%p, %p)\n", hwndDlg, hPage);
02571 
02572     for (index = 0; index < psInfo->nPages; index++)
02573         if (psInfo->proppage[index].hpage == hPage)
02574             return index;
02575     WARN("%p not found\n", hPage);
02576     return -1;
02577 }
02578 
02579 /******************************************************************************
02580  *            PROPSHEET_IndexToPage
02581  */
02582 static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex)
02583 {
02584     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02585     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
02586     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
02587         WARN("%d out of range.\n", iPageIndex);
02588     return 0;
02589     }
02590     return (LRESULT)psInfo->proppage[iPageIndex].hpage;
02591 }
02592 
02593 /******************************************************************************
02594  *            PROPSHEET_IdToIndex
02595  */
02596 static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId)
02597 {
02598     int index;
02599     LPCPROPSHEETPAGEW psp;
02600     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02601     TRACE("(%p, %d)\n", hwndDlg, iPageId);
02602     for (index = 0; index < psInfo->nPages; index++) {
02603         psp = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
02604         if (psp->u.pszTemplate == MAKEINTRESOURCEW(iPageId))
02605             return index;
02606     }
02607 
02608     return -1;
02609 }
02610 
02611 /******************************************************************************
02612  *            PROPSHEET_IndexToId
02613  */
02614 static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex)
02615 {
02616     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02617     LPCPROPSHEETPAGEW psp;
02618     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
02619     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
02620         WARN("%d out of range.\n", iPageIndex);
02621     return 0;
02622     }
02623     psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage;
02624     if (psp->dwFlags & PSP_DLGINDIRECT || !IS_INTRESOURCE(psp->u.pszTemplate)) {
02625         return 0;
02626     }
02627     return (LRESULT)psp->u.pszTemplate;
02628 }
02629 
02630 /******************************************************************************
02631  *            PROPSHEET_GetResult
02632  */
02633 static LRESULT PROPSHEET_GetResult(HWND hwndDlg)
02634 {
02635     PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
02636     return psInfo->result;
02637 }
02638 
02639 /******************************************************************************
02640  *            PROPSHEET_RecalcPageSizes
02641  */
02642 static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg)
02643 {
02644     FIXME("(%p): stub\n", hwndDlg);
02645     return FALSE;
02646 }
02647 
02648 /******************************************************************************
02649  *            PROPSHEET_GetPageIndex
02650  *
02651  * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
02652  * the array of PropPageInfo.
02653  */
02654 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo)
02655 {
02656   BOOL found = FALSE;
02657   int index = 0;
02658 
02659   TRACE("hpage %p\n", hpage);
02660   while ((index < psInfo->nPages) && (found == FALSE))
02661   {
02662     if (psInfo->proppage[index].hpage == hpage)
02663       found = TRUE;
02664     else
02665       index++;
02666   }
02667 
02668   if (found == FALSE)
02669     index = -1;
02670 
02671   return index;
02672 }
02673 
02674 /******************************************************************************
02675  *            PROPSHEET_CleanUp
02676  */
02677 static void PROPSHEET_CleanUp(HWND hwndDlg)
02678 {
02679   int i;
02680   PropSheetInfo* psInfo = RemovePropW(hwndDlg, PropSheetInfoStr);
02681 
02682   TRACE("\n");
02683   if (!psInfo) return;
02684   if (!IS_INTRESOURCE(psInfo->ppshheader.pszCaption))
02685       Free ((LPVOID)psInfo->ppshheader.pszCaption);
02686 
02687   for (i = 0; i < psInfo->nPages; i++)
02688   {
02689      PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
02690 
02691      /* Unsubclass the page dialog window */
02692      if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
02693         (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
02694         (psp->dwFlags & PSP_HIDEHEADER))
02695      {
02696         RemoveWindowSubclass(psInfo->proppage[i].hwndPage,
02697                              PROPSHEET_WizardSubclassProc, 1);
02698      }
02699 
02700      if(psInfo->proppage[i].hwndPage)
02701         DestroyWindow(psInfo->proppage[i].hwndPage);
02702 
02703      if(psp)
02704      {
02705         if (psp->dwFlags & PSP_USETITLE)
02706            Free ((LPVOID)psInfo->proppage[i].pszText);
02707 
02708         DestroyPropertySheetPage(psInfo->proppage[i].hpage);
02709      }
02710   }
02711 
02712   DeleteObject(psInfo->hFont);
02713   DeleteObject(psInfo->hFontBold);
02714   /* If we created the bitmaps, destroy them */
02715   if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
02716       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) )
02717       DeleteObject(psInfo->ppshheader.u4.hbmWatermark);
02718   if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
02719       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) )
02720       DeleteObject(psInfo->ppshheader.u5.hbmHeader);
02721 
02722   Free(psInfo->proppage);
02723   Free(psInfo->strPropertiesFor);
02724   ImageList_Destroy(psInfo->hImageList);
02725 
02726   GlobalFree(psInfo);
02727 }
02728 
02729 static INT do_loop(const PropSheetInfo *psInfo)
02730 {
02731     MSG msg;
02732     INT ret = -1;
02733     HWND hwnd = psInfo->hwnd;
02734 
02735     while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0)))
02736     {
02737         if(ret == -1)
02738             break;
02739 
02740         if(!IsDialogMessageW(hwnd, &msg))
02741         {
02742             TranslateMessage(&msg);
02743             DispatchMessageW(&msg);
02744         }
02745     }
02746 
02747     if(ret == 0)
02748     {
02749         PostQuitMessage(msg.wParam);
02750         ret = -1;
02751     }
02752 
02753     if(ret != -1)
02754         ret = psInfo->result;
02755 
02756     DestroyWindow(hwnd);
02757     return ret;
02758 }
02759 
02760 /******************************************************************************
02761  *            PROPSHEET_PropertySheet
02762  *
02763  * Common code between PropertySheetA/W
02764  */
02765 static INT_PTR PROPSHEET_PropertySheet(PropSheetInfo* psInfo, BOOL unicode)
02766 {
02767   INT_PTR bRet = 0;
02768   HWND parent = NULL;
02769   if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0;
02770   TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages);
02771 
02772   psInfo->unicode = unicode;
02773   psInfo->ended = FALSE;
02774 
02775   if(!psInfo->isModeless)
02776   {
02777       parent = psInfo->ppshheader.hwndParent;
02778       if (parent) EnableWindow(parent, FALSE);
02779   }
02780   bRet = PROPSHEET_CreateDialog(psInfo);
02781   if(!psInfo->isModeless)
02782   {
02783       bRet = do_loop(psInfo);
02784       if (parent) EnableWindow(parent, TRUE);
02785   }
02786   return bRet;
02787 }
02788 
02789 /******************************************************************************
02790  *            PropertySheet    (COMCTL32.@)
02791  *            PropertySheetA   (COMCTL32.@)
02792  *
02793  * Creates a property sheet in the specified property sheet header.
02794  *
02795  * RETURNS
02796  *     Modal property sheets: Positive if successful or -1 otherwise.
02797  *     Modeless property sheets: Property sheet handle.
02798  *     Or:
02799  *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect.
02800  *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect.
02801  */
02802 INT_PTR WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
02803 {
02804   PropSheetInfo* psInfo = GlobalAlloc(GPTR, sizeof(PropSheetInfo));
02805   UINT i, n;
02806   const BYTE* pByte;
02807 
02808   TRACE("(%p)\n", lppsh);
02809 
02810   PROPSHEET_CollectSheetInfoA(lppsh, psInfo);
02811 
02812   psInfo->proppage = Alloc(sizeof(PropPageInfo) * lppsh->nPages);
02813   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
02814 
02815   for (n = i = 0; i < lppsh->nPages; i++, n++)
02816   {
02817     if (!psInfo->usePropPage)
02818       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
02819     else
02820     {
02821        psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
02822        pByte += ((LPCPROPSHEETPAGEA)pByte)->dwSize;
02823     }
02824 
02825     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
02826                                psInfo, n, TRUE))
02827     {
02828     if (psInfo->usePropPage)
02829         DestroyPropertySheetPage(psInfo->proppage[n].hpage);
02830     n--;
02831     psInfo->nPages--;
02832     }
02833   }
02834 
02835   return PROPSHEET_PropertySheet(psInfo, FALSE);
02836 }
02837 
02838 /******************************************************************************
02839  *            PropertySheetW   (COMCTL32.@)
02840  *
02841  * See PropertySheetA.
02842  */
02843 INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
02844 {
02845   PropSheetInfo* psInfo = GlobalAlloc(GPTR, sizeof(PropSheetInfo));
02846   UINT i, n;
02847   const BYTE* pByte;
02848 
02849   TRACE("(%p)\n", lppsh);
02850 
02851   PROPSHEET_CollectSheetInfoW(lppsh, psInfo);
02852 
02853   psInfo->proppage = Alloc(sizeof(PropPageInfo) * lppsh->nPages);
02854   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
02855 
02856   for (n = i = 0; i < lppsh->nPages; i++, n++)
02857   {
02858     if (!psInfo->usePropPage)
02859       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
02860     else
02861     {
02862        psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);
02863        pByte += ((LPCPROPSHEETPAGEW)pByte)->dwSize;
02864     }
02865 
02866     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
02867                                psInfo, n, TRUE))
02868     {
02869     if (psInfo->usePropPage)
02870         DestroyPropertySheetPage(psInfo->proppage[n].hpage);
02871     n--;
02872     psInfo->nPages--;
02873     }
02874   }
02875 
02876   return PROPSHEET_PropertySheet(psInfo, TRUE);
02877 }
02878 
02879 static LPWSTR load_string( HINSTANCE instance, LPCWSTR str )
02880 {
02881     LPWSTR ret;
02882 
02883     if (IS_INTRESOURCE(str))
02884     {
02885         HRSRC hrsrc;
02886         HGLOBAL hmem;
02887         WCHAR *ptr;
02888         WORD i, id = LOWORD(str);
02889         UINT len;
02890 
02891         if (!(hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((id >> 4) + 1), (LPWSTR)RT_STRING )))
02892             return NULL;
02893         if (!(hmem = LoadResource( instance, hrsrc ))) return NULL;
02894         if (!(ptr = LockResource( hmem ))) return NULL;
02895         for (i = id & 0x0f; i > 0; i--) ptr += *ptr + 1;
02896         len = *ptr;
02897         if (!len) return NULL;
02898         ret = Alloc( (len + 1) * sizeof(WCHAR) );
02899         if (ret)
02900         {
02901             memcpy( ret, ptr + 1, len * sizeof(WCHAR) );
02902             ret[len] = 0;
02903         }
02904     }
02905     else
02906     {
02907         int len = (strlenW(str) + 1) * sizeof(WCHAR);
02908         ret = Alloc( len );
02909         if (ret) memcpy( ret, str, len );
02910     }
02911     return ret;
02912 }
02913 
02914 
02915 /******************************************************************************
02916  *            CreatePropertySheetPage    (COMCTL32.@)
02917  *            CreatePropertySheetPageA   (COMCTL32.@)
02918  *
02919  * Creates a new property sheet page.
02920  *
02921  * RETURNS
02922  *     Success: Handle to new property sheet page.
02923  *     Failure: NULL.
02924  *
02925  * NOTES
02926  *     An application must use the PSM_ADDPAGE message to add the new page to
02927  *     an existing property sheet.
02928  */
02929 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
02930                           LPCPROPSHEETPAGEA lpPropSheetPage)
02931 {
02932   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
02933 
02934   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
02935 
02936   ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE;
02937 
02938     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
02939     {
02940         if (!IS_INTRESOURCE( ppsp->u.pszTemplate ))
02941         {
02942             int len = strlen(lpPropSheetPage->u.pszTemplate) + 1;
02943             char *template = Alloc( len );
02944 
02945             ppsp->u.pszTemplate = (LPWSTR)strcpy( template, lpPropSheetPage->u.pszTemplate );
02946         }
02947     }
02948 
02949     if (ppsp->dwFlags & PSP_USEICONID)
02950     {
02951         if (!IS_INTRESOURCE( ppsp->u2.pszIcon ))
02952             PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon);
02953     }
02954 
02955     if (ppsp->dwFlags & PSP_USETITLE)
02956     {
02957         if (!IS_INTRESOURCE( ppsp->pszTitle ))
02958             PROPSHEET_AtoW( &ppsp->pszTitle, lpPropSheetPage->pszTitle );
02959         else
02960             ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
02961     }
02962     else
02963         ppsp->pszTitle = NULL;
02964 
02965     if (ppsp->dwFlags & PSP_HIDEHEADER)
02966         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
02967 
02968     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
02969     {
02970         if (!IS_INTRESOURCE( ppsp->pszHeaderTitle ))
02971             PROPSHEET_AtoW(&ppsp->pszHeaderTitle, lpPropSheetPage->pszHeaderTitle);
02972         else
02973             ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
02974     }
02975     else
02976         ppsp->pszHeaderTitle = NULL;
02977 
02978     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
02979     {
02980         if (!IS_INTRESOURCE( ppsp->pszHeaderSubTitle ))
02981             PROPSHEET_AtoW(&ppsp->pszHeaderSubTitle, lpPropSheetPage->pszHeaderSubTitle);
02982         else
02983             ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
02984     }
02985     else
02986         ppsp->pszHeaderSubTitle = NULL;
02987 
02988     return (HPROPSHEETPAGE)ppsp;
02989 }
02990 
02991 /******************************************************************************
02992  *            CreatePropertySheetPageW   (COMCTL32.@)
02993  *
02994  * See CreatePropertySheetA.
02995  */
02996 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
02997 {
02998   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
02999 
03000   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));
03001 
03002   ppsp->dwFlags |= PSP_INTERNAL_UNICODE;
03003 
03004     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
03005     {
03006         if (!IS_INTRESOURCE( ppsp->u.pszTemplate ))
03007         {
03008             int len = strlenW(lpPropSheetPage->u.pszTemplate) + 1;
03009             WCHAR *template = Alloc( len * sizeof (WCHAR) );
03010 
03011             ppsp->u.pszTemplate = strcpyW( template, lpPropSheetPage->u.pszTemplate );
03012         }
03013     }
03014 
03015     if ( ppsp->dwFlags & PSP_USEICONID )
03016     {
03017         if (!IS_INTRESOURCE( ppsp->u2.pszIcon ))
03018         {
03019             int len = strlenW(lpPropSheetPage->u2.pszIcon) + 1;
03020             WCHAR *icon = Alloc( len * sizeof (WCHAR) );
03021 
03022             ppsp->u2.pszIcon = strcpyW( icon, lpPropSheetPage->u2.pszIcon );
03023         }
03024     }
03025 
03026     if (ppsp->dwFlags & PSP_USETITLE)
03027         ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
03028     else
03029         ppsp->pszTitle = NULL;
03030 
03031     if (ppsp->dwFlags & PSP_HIDEHEADER)
03032         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
03033 
03034     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
03035         ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
03036     else
03037         ppsp->pszHeaderTitle = NULL;
03038 
03039     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
03040         ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
03041     else
03042         ppsp->pszHeaderSubTitle = NULL;
03043 
03044     return (HPROPSHEETPAGE)ppsp;
03045 }
03046 
03047 /******************************************************************************
03048  *            DestroyPropertySheetPage   (COMCTL32.@)
03049  *
03050  * Destroys a property sheet page previously created with
03051  * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated
03052  * memory.
03053  *
03054  * RETURNS
03055  *     Success: TRUE
03056  *     Failure: FALSE
03057  */
03058 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
03059 {
03060   PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;
03061 
03062   if (!psp)
03063      return FALSE;
03064 
03065   if (!(psp->dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE( psp->u.pszTemplate ))
03066      Free ((LPVOID)psp->u.pszTemplate);
03067 
03068   if ((psp->dwFlags & PSP_USEICONID) && !IS_INTRESOURCE( psp->u2.pszIcon ))
03069      Free ((LPVOID)psp->u2.pszIcon);
03070 
03071   if ((psp->dwFlags & PSP_USETITLE) && !IS_INTRESOURCE( psp->pszTitle ))
03072      Free ((LPVOID)psp->pszTitle);
03073 
03074   if ((psp->dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE( psp->pszHeaderTitle ))
03075      Free ((LPVOID)psp->pszHeaderTitle);
03076 
03077   if ((psp->dwFlags & PSP_USEHEADERSUBTITLE) && !IS_INTRESOURCE( psp->pszHeaderSubTitle ))
03078      Free ((LPVOID)psp->pszHeaderSubTitle);
03079 
03080   Free(hPropPage);
03081 
03082   return TRUE;
03083 }
03084 
03085 /******************************************************************************
03086  *            PROPSHEET_IsDialogMessage
03087  */
03088 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
03089 {
03090    PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03091 
03092    TRACE("\n");
03093    if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
03094       return FALSE;
03095 
03096    if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
03097    {
03098       int new_page = 0;
03099       INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
03100 
03101       if (!(dlgCode & DLGC_WANTMESSAGE))
03102       {
03103          switch (lpMsg->wParam)
03104          {
03105             case VK_TAB:
03106                if (GetKeyState(VK_SHIFT) & 0x8000)
03107                    new_page = -1;
03108                 else
03109                    new_page = 1;
03110                break;
03111 
03112             case VK_NEXT:   new_page = 1;  break;
03113             case VK_PRIOR:  new_page = -1; break;
03114          }
03115       }
03116 
03117       if (new_page)
03118       {
03119          if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
03120          {
03121             new_page += psInfo->active_page;
03122 
03123             if (new_page < 0)
03124                new_page = psInfo->nPages - 1;
03125             else if (new_page >= psInfo->nPages)
03126                new_page = 0;
03127 
03128             PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
03129          }
03130 
03131          return TRUE;
03132       }
03133    }
03134 
03135    return IsDialogMessageW(hwnd, lpMsg);
03136 }
03137 
03138 /******************************************************************************
03139  *            PROPSHEET_DoCommand
03140  */
03141 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)
03142 {
03143 
03144     switch (wID) {
03145 
03146     case IDOK:
03147     case IDC_APPLY_BUTTON:
03148     {
03149         HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
03150 
03151         if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
03152         break;
03153 
03154         if (wID == IDOK)
03155         {
03156                     PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03157 
03158                     /* don't overwrite ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM */
03159                     if (psInfo->result == 0)
03160                         psInfo->result = IDOK;
03161 
03162             if (psInfo->isModeless)
03163             psInfo->activeValid = FALSE;
03164             else
03165                         psInfo->ended = TRUE;
03166         }
03167         else
03168         EnableWindow(hwndApplyBtn, FALSE);
03169 
03170         break;
03171     }
03172 
03173     case IDC_BACK_BUTTON:
03174     PROPSHEET_Back(hwnd);
03175     break;
03176 
03177     case IDC_NEXT_BUTTON:
03178     PROPSHEET_Next(hwnd);
03179     break;
03180 
03181     case IDC_FINISH_BUTTON:
03182     PROPSHEET_Finish(hwnd);
03183     break;
03184 
03185     case IDCANCEL:
03186     PROPSHEET_Cancel(hwnd, 0);
03187     break;
03188 
03189     case IDHELP:
03190     PROPSHEET_Help(hwnd);
03191     break;
03192 
03193     default:
03194         return FALSE;
03195     }
03196 
03197     return TRUE;
03198 }
03199 
03200 /******************************************************************************
03201  *            PROPSHEET_Paint
03202  */
03203 static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam)
03204 {
03205     PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03206     PAINTSTRUCT ps;
03207     HDC hdc, hdcSrc;
03208     BITMAP bm;
03209     HBITMAP hbmp;
03210     HPALETTE hOldPal = 0;
03211     int offsety = 0;
03212     HBRUSH hbr;
03213     RECT r, rzone;
03214     LPCPROPSHEETPAGEW ppshpage;
03215     WCHAR szBuffer[256];
03216     int nLength;
03217 
03218     hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps);
03219     if (!hdc) return 1;
03220 
03221     hdcSrc = CreateCompatibleDC(0);
03222 
03223     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
03224     hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE);
03225 
03226     if (psInfo->active_page < 0)
03227         ppshpage = NULL;
03228     else
03229         ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage;
03230 
03231     if ( (ppshpage && !(ppshpage->dwFlags & PSP_HIDEHEADER)) &&
03232      (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
03233      (psInfo->ppshheader.dwFlags & PSH_HEADER) ) 
03234     {
03235     HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER);
03236     HFONT hOldFont;
03237     COLORREF clrOld = 0;
03238     int oldBkMode = 0;
03239 
03240     hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader);
03241     hOldFont = SelectObject(hdc, psInfo->hFontBold);
03242 
03243     GetClientRect(hwndLineHeader, &r);
03244     MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2);
03245     SetRect(&rzone, 0, 0, r.right + 1, r.top - 1);
03246 
03247     GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), &bm);
03248 
03249     if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD)
03250     {
03251         /* Fill the unoccupied part of the header with color of the
03252          * left-top pixel, but do it only when needed.
03253          */
03254         if (bm.bmWidth < r.right || bm.bmHeight < r.bottom)
03255         {
03256             hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
03257             CopyRect(&r, &rzone);
03258             if (bm.bmWidth < r.right)
03259             {
03260                 r.left = bm.bmWidth;
03261                 FillRect(hdc, &r, hbr);
03262             }
03263             if (bm.bmHeight < r.bottom)
03264             {
03265                 r.left = 0;
03266                 r.top = bm.bmHeight;
03267                 FillRect(hdc, &r, hbr);
03268             }
03269             DeleteObject(hbr);
03270         }
03271 
03272         /* Draw the header itself. */
03273         BitBlt(hdc, 0, 0,
03274                bm.bmWidth, min(bm.bmHeight, rzone.bottom),
03275                hdcSrc, 0, 0, SRCCOPY);
03276     }
03277     else
03278     {
03279             int margin;
03280         hbr = GetSysColorBrush(COLOR_WINDOW);
03281         FillRect(hdc, &rzone, hbr);
03282 
03283         /* Draw the header bitmap. It's always centered like a
03284          * common 49 x 49 bitmap. */
03285             margin = (rzone.bottom - 49) / 2;
03286         BitBlt(hdc, rzone.right - 49 - margin, margin,
03287                    min(bm.bmWidth, 49), min(bm.bmHeight, 49),
03288                    hdcSrc, 0, 0, SRCCOPY);
03289 
03290         /* NOTE: Native COMCTL32 draws a white stripe over the bitmap
03291          * if its height is smaller than 49 pixels. Because the reason
03292          * for this bug is unknown the current code doesn't try to
03293          * replicate it. */
03294     }
03295 
03296     clrOld = SetTextColor (hdc, 0x00000000);
03297     oldBkMode = SetBkMode (hdc, TRANSPARENT); 
03298 
03299     if (ppshpage->dwFlags & PSP_USEHEADERTITLE) {
03300         SetRect(&r, 20, 10, 0, 0);
03301             if (!IS_INTRESOURCE(ppshpage->pszHeaderTitle))
03302                 DrawTextW(hdc, ppshpage->pszHeaderTitle, -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
03303         else
03304         {
03305         nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderTitle,
03306                       szBuffer, 256);
03307         if (nLength != 0)
03308         {
03309             DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
03310         }
03311         }
03312     }
03313 
03314     if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) {
03315         SelectObject(hdc, psInfo->hFont);
03316         SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom);
03317             if (!IS_INTRESOURCE(ppshpage->pszHeaderTitle))
03318                 DrawTextW(hdc, ppshpage->pszHeaderSubTitle, -1, &r, DT_LEFT | DT_WORDBREAK);
03319         else
03320         {
03321         nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderSubTitle,
03322                       szBuffer, 256);
03323         if (nLength != 0)
03324         {
03325             DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_WORDBREAK);
03326         }
03327         }
03328     }
03329 
03330     offsety = rzone.bottom + 2;
03331 
03332     SetTextColor(hdc, clrOld);
03333     SetBkMode(hdc, oldBkMode);
03334     SelectObject(hdc, hOldFont);
03335     SelectObject(hdcSrc, hbmp);
03336     }
03337 
03338     if ( (ppshpage && (ppshpage->dwFlags & PSP_HIDEHEADER)) &&
03339      (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
03340      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) 
03341     {
03342     HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE);      
03343 
03344     GetClientRect(hwndLine, &r);
03345     MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2);
03346 
03347     rzone.left = 0;
03348     rzone.top = 0;
03349     rzone.right = r.right;
03350     rzone.bottom = r.top - 1;
03351 
03352     hbr = GetSysColorBrush(COLOR_WINDOW);
03353     FillRect(hdc, &rzone, hbr);
03354 
03355     GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), &bm);
03356     hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark);
03357 
03358         /* The watermark is truncated to a width of 164 pixels */
03359         r.right = min(r.right, 164);
03360     BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right),
03361            min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY);
03362 
03363     /* If the bitmap is not big enough, fill the remaining area
03364        with the color of pixel (0,0) of bitmap - see MSDN */
03365     if (r.top > bm.bmHeight) {
03366         r.bottom = r.top - 1;
03367         r.top = bm.bmHeight;
03368         r.left = 0;
03369         r.right = bm.bmWidth;
03370         hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
03371         FillRect(hdc, &r, hbr);
03372         DeleteObject(hbr);
03373     }
03374 
03375     SelectObject(hdcSrc, hbmp);     
03376     }
03377 
03378     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
03379     SelectPalette(hdc, hOldPal, FALSE);
03380 
03381     DeleteDC(hdcSrc);
03382 
03383     if (!hdcParam) EndPaint(hwnd, &ps);
03384 
03385     return 0;
03386 }
03387 
03388 /******************************************************************************
03389  *            PROPSHEET_DialogProc
03390  */
03391 static INT_PTR CALLBACK
03392 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
03393 {
03394   TRACE("hwnd=%p msg=0x%04x wparam=%lx lparam=%lx\n",
03395     hwnd, uMsg, wParam, lParam);
03396 
03397   switch (uMsg)
03398   {
03399     case WM_INITDIALOG:
03400     {
03401       PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
03402       WCHAR* strCaption = Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));
03403       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
03404       int idx;
03405       LOGFONTW logFont;
03406 
03407       /* Using PropSheetInfoStr to store extra data doesn't match the native
03408        * common control: native uses TCM_[GS]ETITEM
03409        */
03410       SetPropW(hwnd, PropSheetInfoStr, psInfo);
03411 
03412       /*
03413        * psInfo->hwnd is not being used by WINE code - it exists
03414        * for compatibility with "real" Windoze. The same about
03415        * SetWindowLongPtr - WINE is only using the PropSheetInfoStr
03416        * property.
03417        */
03418       psInfo->hwnd = hwnd;
03419       SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo);
03420 
03421       if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
03422       {
03423         /* set up the Next and Back buttons by default */
03424         PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);
03425       }
03426 
03427       /* Set up fonts */
03428       SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
03429       psInfo->hFont = CreateFontIndirectW (&logFont);
03430       logFont.lfWeight = FW_BOLD;
03431       psInfo->hFontBold = CreateFontIndirectW (&logFont);
03432       
03433       /*
03434        * Small icon in the title bar.
03435        */
03436       if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
03437           (psInfo->ppshheader.dwFlags & PSH_USEHICON))
03438       {
03439         HICON hIcon;
03440         int icon_cx = GetSystemMetrics(SM_CXSMICON);
03441         int icon_cy = GetSystemMetrics(SM_CYSMICON);
03442 
03443         if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
03444           hIcon = LoadImageW(psInfo->ppshheader.hInstance,
03445                              psInfo->ppshheader.u.pszIcon,
03446                              IMAGE_ICON,
03447                              icon_cx, icon_cy,
03448                              LR_DEFAULTCOLOR);
03449         else
03450           hIcon = psInfo->ppshheader.u.hIcon;
03451 
03452         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon);
03453       }
03454 
03455       if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
03456         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon);
03457 
03458       psInfo->strPropertiesFor = strCaption;
03459 
03460       GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
03461 
03462       PROPSHEET_CreateTabControl(hwnd, psInfo);
03463 
03464       PROPSHEET_LoadWizardBitmaps(psInfo);
03465 
03466       if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
03467       {
03468         ShowWindow(hwndTabCtrl, SW_HIDE);
03469         PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
03470         PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
03471         SetFocus(GetDlgItem(hwnd, IDC_NEXT_BUTTON));
03472       }
03473       else
03474       {
03475         if (PROPSHEET_SizeMismatch(hwnd, psInfo))
03476         {
03477           PROPSHEET_AdjustSize(hwnd, psInfo);
03478           PROPSHEET_AdjustButtons(hwnd, psInfo);
03479         }
03480         SetFocus(GetDlgItem(hwnd, IDOK));
03481       }
03482 
03483       if (IS_INTRESOURCE(psInfo->ppshheader.pszCaption) &&
03484               psInfo->ppshheader.hInstance)
03485       {
03486          WCHAR szText[256];
03487 
03488          if (LoadStringW(psInfo->ppshheader.hInstance,
03489                          (UINT_PTR)psInfo->ppshheader.pszCaption, szText, 255))
03490             PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);
03491       }
03492       else
03493       {
03494          PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,
03495                          psInfo->ppshheader.pszCaption);
03496       }
03497 
03498 
03499       if (psInfo->useCallback)
03500              (*(psInfo->ppshheader.pfnCallback))(hwnd, PSCB_INITIALIZED, 0);
03501 
03502       idx = psInfo->active_page;
03503       psInfo->active_page = -1;
03504 
03505       PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
03506 
03507       /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
03508        * as some programs call TCM_GETCURSEL to get the current selection
03509        * from which to switch to the next page */
03510       SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
03511 
03512       PROPSHEET_UnChanged(hwnd, NULL);
03513 
03514       /* wizards set their focus during init */
03515       if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
03516           return FALSE;
03517 
03518       return TRUE;
03519     }
03520 
03521     case WM_PRINTCLIENT:
03522     case WM_PAINT:
03523       PROPSHEET_Paint(hwnd, (HDC)wParam);
03524       return TRUE;
03525 
03526     case WM_DESTROY:
03527       PROPSHEET_CleanUp(hwnd);
03528       return TRUE;
03529 
03530     case WM_CLOSE:
03531       PROPSHEET_Cancel(hwnd, 1);
03532       return FALSE; /* let DefDlgProc post us WM_COMMAND/IDCANCEL */
03533 
03534     case WM_COMMAND:
03535       if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam)))
03536       {
03537           PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03538 
03539           if (!psInfo)
03540               return FALSE;
03541 
03542           /* No default handler, forward notification to active page */
03543           if (psInfo->activeValid && psInfo->active_page != -1)
03544           {
03545              HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
03546              SendMessageW(hwndPage, WM_COMMAND, wParam, lParam);
03547           }
03548       }
03549       return TRUE;
03550 
03551     case WM_NOTIFY:
03552     {
03553       NMHDR* pnmh = (LPNMHDR) lParam;
03554 
03555       if (pnmh->code == TCN_SELCHANGE)
03556       {
03557         int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
03558         PROPSHEET_SetCurSel(hwnd, index, 1, 0);
03559       }
03560 
03561       if(pnmh->code == TCN_SELCHANGING)
03562       {
03563         BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
03564         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet);
03565         return TRUE;
03566       }
03567 
03568       return FALSE;
03569     }
03570   
03571     case WM_SYSCOLORCHANGE:
03572       COMCTL32_RefreshSysColors();
03573       return FALSE;
03574 
03575     case PSM_GETCURRENTPAGEHWND:
03576     {
03577       PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03578       HWND hwndPage = 0;
03579 
03580       if (!psInfo)
03581         return FALSE;
03582 
03583       if (psInfo->activeValid && psInfo->active_page != -1)
03584         hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
03585 
03586       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage);
03587 
03588       return TRUE;
03589     }
03590 
03591     case PSM_CHANGED:
03592       PROPSHEET_Changed(hwnd, (HWND)wParam);
03593       return TRUE;
03594 
03595     case PSM_UNCHANGED:
03596       PROPSHEET_UnChanged(hwnd, (HWND)wParam);
03597       return TRUE;
03598 
03599     case PSM_GETTABCONTROL:
03600     {
03601       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
03602 
03603       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl);
03604 
03605       return TRUE;
03606     }
03607 
03608     case PSM_SETCURSEL:
03609     {
03610       BOOL msgResult;
03611 
03612       msgResult = PROPSHEET_CanSetCurSel(hwnd);
03613       if(msgResult != FALSE)
03614       {
03615         msgResult = PROPSHEET_SetCurSel(hwnd,
03616                                        (int)wParam,
03617                        1,
03618                                        (HPROPSHEETPAGE)lParam);
03619       }
03620 
03621       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03622 
03623       return TRUE;
03624     }
03625 
03626     case PSM_CANCELTOCLOSE:
03627     {
03628       WCHAR buf[MAX_BUTTONTEXT_LENGTH];
03629       HWND hwndOK = GetDlgItem(hwnd, IDOK);
03630       HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
03631 
03632       EnableWindow(hwndCancel, FALSE);
03633       if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)/sizeof(buf[0])))
03634          SetWindowTextW(hwndOK, buf);
03635 
03636       return FALSE;
03637     }
03638 
03639     case PSM_RESTARTWINDOWS:
03640     {
03641       PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03642 
03643       if (!psInfo)
03644         return FALSE;
03645 
03646       /* reboot system takes precedence over restart windows */
03647       if (psInfo->result != ID_PSREBOOTSYSTEM)
03648           psInfo->result = ID_PSRESTARTWINDOWS;
03649 
03650       return TRUE;
03651     }
03652 
03653     case PSM_REBOOTSYSTEM:
03654     {
03655       PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr);
03656 
03657       if (!psInfo)
03658         return FALSE;
03659 
03660       psInfo->result = ID_PSREBOOTSYSTEM;
03661 
03662       return TRUE;
03663     }
03664 
03665     case PSM_SETTITLEA:
03666       PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
03667       return TRUE;
03668 
03669     case PSM_SETTITLEW:
03670       PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);
03671       return TRUE;
03672 
03673     case PSM_APPLY:
03674     {
03675       BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
03676 
03677       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03678 
03679       return TRUE;
03680     }
03681 
03682     case PSM_QUERYSIBLINGS:
03683     {
03684       LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
03685 
03686       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03687 
03688       return TRUE;
03689     }
03690 
03691     case PSM_ADDPAGE:
03692     {
03693       /*
03694        * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
03695        *       a return value. This is not true. PSM_ADDPAGE returns TRUE
03696        *       on success or FALSE otherwise, as specified on MSDN Online.
03697        *       Also see the MFC code for
03698        *       CPropertySheet::AddPage(CPropertyPage* pPage).
03699        */
03700 
03701       BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
03702 
03703       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03704 
03705       return TRUE;
03706     }
03707 
03708     case PSM_REMOVEPAGE:
03709       PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
03710       return TRUE;
03711 
03712     case PSM_ISDIALOGMESSAGE:
03713     {
03714        BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
03715        SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03716        return TRUE;
03717     }
03718 
03719     case PSM_PRESSBUTTON:
03720       PROPSHEET_PressButton(hwnd, (int)wParam);
03721       return TRUE;
03722 
03723     case PSM_SETFINISHTEXTA:
03724       PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
03725       return TRUE;
03726 
03727     case PSM_SETWIZBUTTONS:
03728       PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
03729       return TRUE;
03730 
03731     case PSM_SETCURSELID:
03732         PROPSHEET_SetCurSelId(hwnd, (int)lParam);
03733         return TRUE;
03734 
03735     case PSM_SETFINISHTEXTW:
03736         PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);
03737         return FALSE;
03738 
03739     case PSM_INSERTPAGE:
03740     {
03741         BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam);
03742         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03743         return TRUE;
03744     }
03745 
03746     case PSM_SETHEADERTITLEW:
03747         PROPSHEET_SetHeaderTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
03748         return TRUE;
03749 
03750     case PSM_SETHEADERTITLEA:
03751         PROPSHEET_SetHeaderTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
03752         return TRUE;
03753 
03754     case PSM_SETHEADERSUBTITLEW:
03755         PROPSHEET_SetHeaderSubTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
03756         return TRUE;
03757 
03758     case PSM_SETHEADERSUBTITLEA:
03759         PROPSHEET_SetHeaderSubTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
03760         return TRUE;
03761 
03762     case PSM_HWNDTOINDEX:
03763     {
03764         LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam);
03765         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03766         return TRUE;
03767     }
03768 
03769     case PSM_INDEXTOHWND:
03770     {
03771         LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam);
03772         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03773         return TRUE;
03774     }
03775 
03776     case PSM_PAGETOINDEX:
03777     {
03778         LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam);
03779         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03780         return TRUE;
03781     }
03782 
03783     case PSM_INDEXTOPAGE:
03784     {
03785         LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam);
03786         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03787         return TRUE;
03788     }
03789 
03790     case PSM_IDTOINDEX:
03791     {
03792         LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam);
03793         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03794         return TRUE;
03795     }
03796 
03797     case PSM_INDEXTOID:
03798     {
03799         LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam);
03800         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03801         return TRUE;
03802     }
03803 
03804     case PSM_GETRESULT:
03805     {
03806         LRESULT msgResult = PROPSHEET_GetResult(hwnd);
03807         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03808         return TRUE;
03809     }
03810 
03811     case PSM_RECALCPAGESIZES:
03812     {
03813         LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd);
03814         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
03815         return TRUE;
03816     }
03817 
03818     default:
03819       return FALSE;
03820   }
03821 }

Generated on Thu May 24 2012 04:17:02 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.