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