📄 propsheet.c
字号:
/*
* Property Sheets
*
* Copyright 1998 Francis Beaudet
* Copyright 1999 Thuy Nguyen
* Copyright 2004 Maxime Bellenge
* Copyright 2004 Filip Navara
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* This code was audited for completeness against the documented features
* of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara.
*
* Unless otherwise noted, we believe this code to be complete, as per
* the specification mentioned above.
* If you discover missing features, or bugs, please note them below.
*
* TODO:
* - Tab order
* - Wizard 97 header resizing
* - Enforcing of minimal wizard size
* - Messages:
* o PSM_INSERTPAGE
* o PSM_RECALCPAGESIZES
* o PSM_SETHEADERSUBTITLE
* o PSM_SETHEADERTITLE
* o WM_HELP
* o WM_CONTEXTMENU
* - Notifications:
* o PSN_GETOBJECT
* o PSN_QUERYINITIALFOCUS
* o PSN_TRANSLATEACCELERATOR
* - Styles:
* o PSH_RTLREADING
* o PSH_STRETCHWATERMARK
* o PSH_USEPAGELANG
* o PSH_USEPSTARTPAGE
* - Page styles:
* o PSP_USEFUSIONCONTEXT
* o PSP_USEREFPARENT
*/
#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 "uxtheme.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 hasFinish;
BOOL useCallback;
BOOL activeValid;
PropPageInfo* proppage;
HFONT hFont;
HFONT hFontBold;
int width;
int height;
HIMAGELIST hImageList;
BOOL ended;
INT result;
} PropSheetInfo;
typedef struct
{
int x;
int y;
} PADDING_INFO;
/******************************************************************************
* Defines and global variables
*/
static 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)
/* Wizard metrics specified in DLUs */
#define WIZARD_PADDING 7
#define WIZARD_HEADER_HEIGHT 36
/******************************************************************************
* Prototypes
*/
static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
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 int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
static 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_RTLREADING 0x00000800
* PSH_STRETCHWATERMARK 0x00040000
* PSH_USEPAGELANG 0x00200000
*/
add_flag(PSH_RTLREADING);
add_flag(PSH_STRETCHWATERMARK);
add_flag(PSH_USEPAGELANG);
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, LPCPROPSHEETPAGEW ppshpage)
{
if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {
HWND hwndChild;
RECT r;
if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
(psInfo->ppshheader.dwFlags & PSH_HEADER) &&
!(ppshpage->dwFlags & PSP_HIDEHEADER)) ||
(psInfo->ppshheader.dwFlags & PSH_WIZARD))
{
rc->left = rc->top = WIZARD_PADDING;
}
else
{
rc->left = rc->top = 0;
}
rc->right = psInfo->width - rc->left;
rc->bottom = psInfo->height - rc->top;
MapDialogRect(hwndDlg, rc);
if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
(psInfo->ppshheader.dwFlags & PSH_HEADER) &&
!(ppshpage->dwFlags & PSP_HIDEHEADER))
{
hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
GetClientRect(hwndChild, &r);
MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2);
rc->top += r.bottom + 1;
}
} else {
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.
*/
static 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 = Alloc(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->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);
psInfo->isModeless = dwFlags & PSH_MODELESS;
memcpy(&psInfo->ppshheader,lppsh,dwSize);
TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
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 = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0);
psInfo->ppshheader.pszCaption = Alloc( len*sizeof (WCHAR) );
MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len);
}
}
psInfo->nPages = lppsh->nPages;
if (dwFlags & PSH_USEPSTARTPAGE)
{
TRACE("PSH_USEPSTARTPAGE is on\n");
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->result = 0;
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->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);
psInfo->isModeless = dwFlags & PSH_MODELESS;
memcpy(&psInfo->ppshheader,lppsh,dwSize);
TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
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 (HIWORD(lppsh->pszCaption))
{
int len = strlenW(lppsh->pszCaption);
psInfo->ppshheader.pszCaption = Alloc( (len+1)*sizeof(WCHAR) );
strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );
}
}
psInfo->nPages = lppsh->nPages;
if (dwFlags & PSH_USEPSTARTPAGE)
{
TRACE("PSH_USEPSTARTPAGE is on\n");
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->result = 0;
psInfo->hImageList = 0;
psInfo->activeValid = FALSE;
return TRUE;
}
/******************************************************************************
* PROPSHEET_CollectPageInfo
*
* Collect property sheet data.
* With code taken from DIALOG_ParseTemplate32.
*/
static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
PropSheetInfo * psInfo,
int index)
{
DLGTEMPLATE* pTemplate;
const WORD* p;
DWORD dwFlags;
int width, height;
if (!lppsp)
return FALSE;
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,
(LPCSTR)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) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -