mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3175 lines
87 KiB
3175 lines
87 KiB
#include "ctlspriv.h"
|
|
#include "help.h" // Help IDs
|
|
|
|
|
|
#ifndef WIN31
|
|
#define g_cxSmIcon GetSystemMetrics(SM_CXSMICON)
|
|
#define g_cySmIcon GetSystemMetrics(SM_CYSMICON)
|
|
#endif
|
|
|
|
#define FLAG_CHANGED 0x0001
|
|
|
|
LPVOID WINAPI MapSLFix(HANDLE);
|
|
VOID WINAPI UnMapSLFixArray(int, HANDLE *);
|
|
|
|
// to avoid warnings....
|
|
#ifdef WIN32
|
|
#define HWNDTOLONG(hwnd) (LONG)(hwnd)
|
|
#else
|
|
#define HWNDTOLONG(hwnd) MAKELONG(hwnd,0)
|
|
#endif
|
|
|
|
#ifdef WIN31
|
|
LRESULT CALLBACK Win31PropPageWndProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam);
|
|
LRESULT NEAR PASCAL Win31OnCtlColor(HWND hDlg, HDC hdcChild, HWND hwndChild, int nCtlType);
|
|
BOOL NEAR PASCAL Win31MakeDlgNonBold(HWND hDlg);
|
|
BOOL FAR PASCAL Win31IsKeyMessage(HWND hwndDlg, LPMSG lpmsg);
|
|
void NEAR PASCAL Win31RepositionDlg( HWND hDlg );
|
|
void FAR PASCAL RemoveDefaultButton(HWND hwndRoot, HWND hwndStart);
|
|
|
|
const TCHAR g_szNonBoldFont[] = TEXT("DS_3DLOOK");
|
|
const TCHAR g_szLoSubclass[] = TEXT("MS_LO_SUBCLASS");
|
|
const TCHAR g_szHiSubclass[] = TEXT("MS_HI_SUBCLASS");
|
|
#endif
|
|
|
|
#if !defined(WIN32) && !defined(WIN31)
|
|
#ifdef FE_IME
|
|
typedef void *PVOID;
|
|
DWORD WINAPI GetCurrentThreadID(VOID);
|
|
DWORD WINAPI GetCurrentProcessID(VOID);
|
|
PVOID WINAPI ImmFindThreadLink(DWORD dwThreadID);
|
|
BOOL WINAPI ImmCreateThreadLink(DWORD dwPid, DWORD dwTid);
|
|
#endif
|
|
#endif
|
|
|
|
void NEAR PASCAL ResetWizButtons(LPPROPDATA ppd);
|
|
|
|
typedef struct // tie
|
|
{
|
|
TC_ITEMHEADER tci;
|
|
HWND hwndPage;
|
|
UINT state;
|
|
} TC_ITEMEXTRA;
|
|
|
|
#define CB_ITEMEXTRA (sizeof(TC_ITEMEXTRA) - sizeof(TC_ITEMHEADER))
|
|
|
|
void NEAR PASCAL PageChange(LPPROPDATA ppd, int iAutoAdj);
|
|
void NEAR PASCAL RemovePropPageData(LPPROPDATA ppd, int nPage);
|
|
|
|
HWND WINAPI CreatePage(PSP FAR *hpage, HWND hwndParent);
|
|
#ifdef WINDOWS_ME
|
|
BOOL WINAPI GetPageInfo(PSP FAR *hpage, LPTSTR pszCaption, int cbCaption, LPPOINT ppt, HICON FAR *hIcon, BOOL FAR * bRTL);
|
|
#else
|
|
BOOL WINAPI GetPageInfo(PSP FAR *hpage, LPTSTR pszCaption, int cbCaption, LPPOINT ppt, HICON FAR *hIcon);;
|
|
#endif
|
|
|
|
//
|
|
// IMPORTANT: The IDHELP ID should always be LAST since we just subtract
|
|
// 1 from the number of IDs if no help in the page.
|
|
// IDD_APPLYNOW should always be the FIRST ID for standard IDs since it
|
|
// is sometimes not displayed and we'll start with index 1.
|
|
//
|
|
const static int IDs[] = {IDOK, IDCANCEL, IDD_APPLYNOW, IDHELP};
|
|
const static int WizIDs[] = {IDD_BACK, IDD_NEXT, IDD_FINISH, IDCANCEL, IDHELP};
|
|
|
|
void NEAR PASCAL _SetTitle(HWND hDlg, LPPROPDATA ppd)
|
|
{
|
|
TCHAR szFormat[50];
|
|
TCHAR szTitle[128];
|
|
TCHAR szTemp[128 + 50];
|
|
LPCTSTR pCaption = ppd->psh.pszCaption;
|
|
|
|
if (HIWORD(pCaption) == 0) {
|
|
LoadString(ppd->psh.hInstance, (UINT)LOWORD(pCaption), szTitle, ARRAYSIZE(szTitle));
|
|
pCaption = (LPCTSTR)szTitle;
|
|
}
|
|
|
|
if (ppd->psh.dwFlags & PSH_PROPTITLE) {
|
|
LoadString(HINST_THISDLL, IDS_PROPERTIESFOR, szFormat, ARRAYSIZE(szFormat));
|
|
if ((lstrlen(pCaption) + 1 + lstrlen(szFormat) + 1) < ARRAYSIZE(szTemp)) {
|
|
wsprintf(szTemp, szFormat, pCaption);
|
|
pCaption = szTemp;
|
|
}
|
|
}
|
|
|
|
SetWindowText(hDlg, pCaption);
|
|
}
|
|
|
|
void MoveAllButtons(HWND hDlg, const int *pids, int idLast, int dx, int dy)
|
|
{
|
|
do {
|
|
HWND hCtrl;
|
|
RECT rcCtrl;
|
|
|
|
int iCtrl = *pids;
|
|
hCtrl = GetDlgItem(hDlg, iCtrl);
|
|
GetWindowRect(hCtrl, &rcCtrl);
|
|
ScreenToClient(hDlg, (LPPOINT)&rcCtrl);
|
|
SetWindowPos(hCtrl, NULL, rcCtrl.left + dx,
|
|
rcCtrl.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
} while(*(pids++) != idLast);
|
|
}
|
|
|
|
void NEAR PASCAL RemoveButton(HWND hDlg, int idRemove, const int *pids)
|
|
{
|
|
int idPrev = 0;
|
|
HWND hRemove;
|
|
HWND hPrev;
|
|
RECT rcRemove, rcPrev;
|
|
int iWidth = 0;
|
|
const int *pidRemove;
|
|
|
|
// get the previous id
|
|
for (pidRemove = pids; *pidRemove != idRemove; pidRemove++)
|
|
idPrev = *pidRemove;
|
|
|
|
|
|
if (idPrev) {
|
|
hRemove = GetDlgItem(hDlg, idRemove);
|
|
hPrev = GetDlgItem(hDlg, idPrev);
|
|
GetWindowRect(hRemove, &rcRemove);
|
|
GetWindowRect(hPrev, &rcPrev);
|
|
iWidth = rcRemove.right - rcPrev.right;
|
|
}
|
|
|
|
MoveAllButtons(hDlg, pids, idRemove, iWidth, 0);
|
|
ShowWindow(hRemove, SW_HIDE);
|
|
}
|
|
|
|
void NEAR PASCAL InitPropSheetDlg(HWND hDlg, LPPROPDATA ppd)
|
|
{
|
|
TCHAR szTemp[128 + 50];
|
|
int dxMax, dyMax, dxDlg, dyDlg, dyGrow, dxGrow;
|
|
RECT rcMinSize, rcDlg, rcPage, rcOrigCtrl;
|
|
UINT uPages;
|
|
#ifdef WIN32
|
|
HIMAGELIST himl = NULL;
|
|
#endif
|
|
TC_ITEMEXTRA tie;
|
|
TCHAR szStartPage[128];
|
|
LPCTSTR pStartPage = NULL;
|
|
UINT nStartPage;
|
|
BOOL fPrematurePages = FALSE;
|
|
#ifdef WINDOWS_ME
|
|
BOOL bRTL; // If tab caption should be right to left reading
|
|
#endif
|
|
#ifdef DEBUG
|
|
BOOL fStartPageFound = FALSE;
|
|
#endif
|
|
|
|
// set our instance data pointer
|
|
SetWindowLong(hDlg, DWL_USER, (LONG)ppd);
|
|
|
|
// Make sure this gets inited early on.
|
|
ppd->nCurItem = 0;
|
|
|
|
// do this here instead of using DS_SETFOREGROUND so we don't hose
|
|
// pages that do things that want to set the foreground window
|
|
|
|
#ifdef WIN31
|
|
if (GetWindowStyle(hDlg) & DS_3DLOOK)
|
|
Win31MakeDlgNonBold(hDlg);
|
|
#endif
|
|
|
|
if (!(ppd->psh.dwFlags & PSH_WIZARD)) {
|
|
_SetTitle(hDlg, ppd);
|
|
}
|
|
|
|
if (ppd->psh.dwFlags & PSH_USEICONID)
|
|
{
|
|
#ifndef WIN31
|
|
ppd->psh.hIcon = LoadImage(ppd->psh.hInstance, ppd->psh.pszIcon, IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
|
|
#else
|
|
ppd->psh.hIcon = NULL;
|
|
#endif
|
|
}
|
|
|
|
if ((ppd->psh.dwFlags & (PSH_USEICONID | PSH_USEHICON)) && ppd->psh.hIcon)
|
|
SendMessage(hDlg, WM_SETICON, FALSE, (LPARAM)(UINT)ppd->psh.hIcon);
|
|
|
|
ppd->hDlg = hDlg;
|
|
ppd->hwndTabs = GetDlgItem(hDlg, IDD_PAGELIST);
|
|
TabCtrl_SetItemExtra(ppd->hwndTabs, CB_ITEMEXTRA);
|
|
|
|
// nStartPage is either ppd->psh.nStartPage or the page pStartPage
|
|
nStartPage = ppd->psh.nStartPage;
|
|
if (ppd->psh.dwFlags & PSH_USEPSTARTPAGE)
|
|
{
|
|
pStartPage = ppd->psh.pStartPage;
|
|
nStartPage = 0; // default page if pStartPage not found
|
|
|
|
if (!HIWORD(pStartPage))
|
|
{
|
|
szTemp[0] = TEXT('\0');
|
|
LoadString(ppd->psh.hInstance, (UINT)LOWORD(pStartPage),
|
|
szStartPage, ARRAYSIZE(szStartPage));
|
|
pStartPage = (LPCTSTR)szTemp;
|
|
}
|
|
}
|
|
|
|
dxMax = dyMax = 0;
|
|
|
|
#ifndef WINDOWS_ME
|
|
tie.tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE;
|
|
#endif
|
|
tie.hwndPage = NULL;
|
|
tie.tci.pszText = szTemp;
|
|
tie.state = 0;
|
|
|
|
SendMessage(ppd->hwndTabs, WM_SETREDRAW, FALSE, 0L);
|
|
|
|
for (uPages = 0; uPages < ppd->psh.nPages; uPages++)
|
|
{
|
|
POINT pt;
|
|
HICON hIcon = NULL;
|
|
|
|
if (
|
|
|
|
#if WINDOWS_ME
|
|
GetPageInfo(ppd->psh.phpage[uPages], szTemp, ARRAYSIZE(szTemp), &pt, &hIcon, &bRTL)
|
|
#else
|
|
GetPageInfo(ppd->psh.phpage[uPages], szTemp, ARRAYSIZE(szTemp), &pt, &hIcon)
|
|
#endif
|
|
|
|
)
|
|
{
|
|
// Add the page to the end of the tab list
|
|
|
|
tie.tci.iImage = -1;
|
|
#ifdef WINDOWS_ME
|
|
tie.tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE | (bRTL ? TCIF_RTLREADING : 0);
|
|
#endif
|
|
if (hIcon) {
|
|
#ifdef WIN32
|
|
if (!himl) {
|
|
himl = ImageList_Create(g_cxSmIcon, g_cySmIcon, TRUE, 8, 4);
|
|
TabCtrl_SetImageList(ppd->hwndTabs, himl);
|
|
}
|
|
|
|
tie.tci.iImage = ImageList_AddIcon(himl, hIcon);
|
|
#endif
|
|
DestroyIcon(hIcon);
|
|
}
|
|
|
|
// BUGBUG? What if this fails? Do we want to destroy the page?
|
|
if (TabCtrl_InsertItem(ppd->hwndTabs, 1000, &tie.tci) >= 0)
|
|
{
|
|
if (dxMax < pt.x)
|
|
dxMax = pt.x;
|
|
if (dyMax < pt.y)
|
|
dyMax = pt.y;
|
|
}
|
|
|
|
// remember if any page wants premature init
|
|
if (ppd->psh.phpage[uPages]->psp.dwFlags & PSP_PREMATURE)
|
|
fPrematurePages = TRUE;
|
|
|
|
// if the user is specifying the startpage via title, check it here
|
|
if (ppd->psh.dwFlags & PSH_USEPSTARTPAGE &&
|
|
!lstrcmpi(pStartPage, szTemp))
|
|
{
|
|
nStartPage = uPages;
|
|
#ifdef DEBUG
|
|
fStartPageFound = TRUE;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("PropertySheet failed to GetPageInfo"));
|
|
RemovePropPageData(ppd, uPages--);
|
|
}
|
|
}
|
|
|
|
SendMessage(ppd->hwndTabs, WM_SETREDRAW, TRUE, 0L);
|
|
|
|
if (ppd->psh.pfnCallback) {
|
|
ppd->psh.pfnCallback(hDlg, PSCB_INITIALIZED, 0);
|
|
}
|
|
|
|
//
|
|
// Now compute the size of the tab control.
|
|
//
|
|
|
|
// WARNING ================
|
|
// note that we compute everything with respect to the hDlg.
|
|
// this assumes that all the subpages are in the same dialog units and same
|
|
// font.. which may not be true. ISV's have hacked around this by having
|
|
// large dialog templates with extra space in them.
|
|
//
|
|
// we must continue to mapdialogrect with respect to hDlg.
|
|
|
|
// Compute rcPage = Size of page area in pixels
|
|
rcPage.left = rcPage.top = 0;
|
|
rcPage.right = dxMax;
|
|
rcPage.bottom = dyMax;
|
|
MapDialogRect(hDlg, &rcPage);
|
|
// WARNING ================
|
|
|
|
// Get the size of the pagelist control in pixels.
|
|
GetClientRect(ppd->hwndTabs, &rcOrigCtrl);
|
|
|
|
// Now compute the minimum size for the page region
|
|
rcMinSize = rcOrigCtrl;
|
|
if (rcMinSize.right < rcPage.right)
|
|
rcMinSize.right = rcPage.right;
|
|
if (rcMinSize.bottom < rcPage.bottom)
|
|
rcMinSize.bottom = rcPage.bottom;
|
|
|
|
//
|
|
// If this is a wizard then set the size of the page area to the entire
|
|
// size of the control. If it is a normal property sheet then adjust for
|
|
// the tabs, resize the control, and then compute the size of the page
|
|
// region only.
|
|
//
|
|
if (ppd->psh.dwFlags & PSH_WIZARD) {
|
|
// initialize
|
|
rcPage = rcMinSize;
|
|
} else {
|
|
int i;
|
|
RECT rcAdjSize;
|
|
|
|
// initialize
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
rcAdjSize = rcMinSize;
|
|
TabCtrl_AdjustRect(ppd->hwndTabs, TRUE, &rcAdjSize);
|
|
|
|
rcAdjSize.right -= rcAdjSize.left;
|
|
rcAdjSize.bottom -= rcAdjSize.top;
|
|
rcAdjSize.left = rcAdjSize.top = 0;
|
|
|
|
if (rcAdjSize.right < rcMinSize.right)
|
|
rcAdjSize.right = rcMinSize.right;
|
|
if (rcAdjSize.bottom < rcMinSize.bottom)
|
|
rcAdjSize.bottom = rcMinSize.bottom;
|
|
|
|
SetWindowPos(ppd->hwndTabs, NULL, 0,0, rcAdjSize.right, rcAdjSize.bottom,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
rcPage = rcMinSize = rcAdjSize;
|
|
TabCtrl_AdjustRect(ppd->hwndTabs, FALSE, &rcPage);
|
|
}
|
|
//
|
|
// rcMinSize now contains the size of the control, including the tabs, and
|
|
// rcPage is the rect containing the page portion (without the tabs).
|
|
//
|
|
|
|
//
|
|
// Resize the dialog to make room for the control's new size. This can
|
|
// only grow the size.
|
|
//
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
dxGrow = rcMinSize.right - rcOrigCtrl.right;
|
|
dxDlg = rcDlg.right - rcDlg.left + dxGrow;
|
|
dyGrow = rcMinSize.bottom - rcOrigCtrl.bottom;
|
|
dyDlg = rcDlg.bottom - rcDlg.top + dyGrow;
|
|
|
|
//
|
|
// Cascade property sheet windows (only for comctl32 and commctrl)
|
|
//
|
|
#ifndef WIN31
|
|
//
|
|
// HACK: Putting CW_USEDEFAULT in dialog template does not work because
|
|
// CreateWindowEx ignores it unless the window has WS_OVERLAPPED, which
|
|
// is not appropriate for a property sheet.
|
|
//
|
|
{
|
|
const TCHAR c_szStatic[] = TEXT("Static");
|
|
UINT swp = SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
if (!IsWindow(ppd->psh.hwndParent)) {
|
|
HWND hwndT = CreateWindowEx(0, c_szStatic, NULL,
|
|
WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
0, 0, NULL, NULL, HINST_THISDLL, NULL);
|
|
if (hwndT) {
|
|
GetWindowRect(hwndT, &rcDlg);
|
|
swp = SWP_NOZORDER | SWP_NOACTIVATE;
|
|
DestroyWindow(hwndT);
|
|
}
|
|
} else {
|
|
GetWindowRect(ppd->psh.hwndParent, &rcDlg);
|
|
if (IsWindowVisible(ppd->psh.hwndParent)) {
|
|
rcDlg.top += g_cySmIcon;
|
|
rcDlg.left += g_cxSmIcon;
|
|
}
|
|
swp = SWP_NOZORDER | SWP_NOACTIVATE;
|
|
}
|
|
SetWindowPos(hDlg, NULL, rcDlg.left, rcDlg.top, dxDlg, dyDlg, swp);
|
|
}
|
|
#else
|
|
SetWindowPos(hDlg, NULL, 0, 0, dxDlg, dyDlg, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
#endif
|
|
|
|
// Now we'll figure out where the page needs to start relative
|
|
// to the bottom of the tabs.
|
|
MapWindowPoints(ppd->hwndTabs, hDlg, (LPPOINT)&rcPage, 2);
|
|
|
|
ppd->xSubDlg = rcPage.left;
|
|
ppd->ySubDlg = rcPage.top;
|
|
ppd->cxSubDlg = rcPage.right - rcPage.left;
|
|
ppd->cySubDlg = rcPage.bottom - rcPage.top;
|
|
|
|
//
|
|
// move all the buttons down as needed and turn on appropriate buttons
|
|
// for a wizard.
|
|
//
|
|
{
|
|
RECT rcCtrl;
|
|
HWND hCtrl;
|
|
const int *pids;
|
|
|
|
if (ppd->psh.dwFlags & PSH_WIZARD) {
|
|
pids = WizIDs;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDD_DIVIDER);
|
|
GetWindowRect(hCtrl, &rcCtrl);
|
|
MapWindowRect(NULL, hDlg, &rcCtrl);
|
|
SetWindowPos(hCtrl, NULL, rcCtrl.left, rcCtrl.top + dyGrow,
|
|
RECTWIDTH(rcCtrl) + dxGrow, RECTHEIGHT(rcCtrl),
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
EnableWindow(GetDlgItem(hDlg, IDD_BACK), TRUE);
|
|
ppd->idDefaultFallback = IDD_NEXT;
|
|
} else {
|
|
pids = IDs;
|
|
ppd->idDefaultFallback = IDOK;
|
|
}
|
|
|
|
|
|
// first move everything over by the same amount that
|
|
// the dialog grew by.
|
|
MoveAllButtons(hDlg, pids, IDHELP, dxGrow, dyGrow);
|
|
|
|
// If there's no help, then remove the help button.
|
|
if (!(ppd->psh.dwFlags & PSH_HASHELP)) {
|
|
RemoveButton(hDlg, IDHELP, pids);
|
|
}
|
|
|
|
// If we are not a wizard, and we should NOT show apply now
|
|
if ((ppd->psh.dwFlags & PSH_NOAPPLYNOW) &&
|
|
!(ppd->psh.dwFlags & PSH_WIZARD))
|
|
{
|
|
RemoveButton(hDlg, IDD_APPLYNOW, pids);
|
|
}
|
|
|
|
if ((ppd->psh.dwFlags & PSH_WIZARD) &&
|
|
(!(ppd->psh.dwFlags & PSH_WIZARDHASFINISH))) {
|
|
|
|
RemoveButton(hDlg, IDD_FINISH, pids);
|
|
|
|
// if there's no finish button showing, we need to place it where
|
|
// the next button is
|
|
GetWindowRect(GetDlgItem(hDlg, IDD_NEXT), &rcCtrl);
|
|
MapWindowPoints(HWND_DESKTOP, hDlg, (LPPOINT)&rcCtrl, 2);
|
|
SetWindowPos(GetDlgItem(hDlg, IDD_FINISH), NULL, rcCtrl.left, rcCtrl.top,
|
|
RECTWIDTH(rcCtrl), RECTHEIGHT(rcCtrl), SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
}
|
|
|
|
// force the dialog to reposition itself based on its new size
|
|
#ifdef WIN31
|
|
Win31RepositionDlg( hDlg );
|
|
#else
|
|
SendMessage(hDlg, DM_REPOSITION, 0, 0L);
|
|
SetForegroundWindow(hDlg);
|
|
#endif // WIN31
|
|
|
|
// We set this to 1 if the user saves any changes.
|
|
// do this before initting or switching to any pages
|
|
ppd->nReturn = 0;
|
|
|
|
// Now attempt to select the starting page.
|
|
TabCtrl_SetCurSel(ppd->hwndTabs, nStartPage);
|
|
PageChange(ppd, 1);
|
|
#ifdef DEBUG
|
|
if (ppd->psh.dwFlags & PSH_USEPSTARTPAGE && !fStartPageFound)
|
|
DebugMsg(DM_WARNING, TEXT("sh WN - Property start page '%s' not found."), pStartPage);
|
|
#endif
|
|
|
|
// Now init any other pages that require it
|
|
if (fPrematurePages)
|
|
{
|
|
int nPage;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
for (nPage = 0; nPage < (int)ppd->psh.nPages; nPage++)
|
|
{
|
|
PSP FAR *hpage = ppd->psh.phpage[nPage];
|
|
|
|
if (!(hpage->psp.dwFlags & PSP_PREMATURE))
|
|
continue;
|
|
|
|
TabCtrl_GetItem(ppd->hwndTabs, nPage, &tie.tci);
|
|
|
|
if (tie.hwndPage)
|
|
continue;
|
|
|
|
if ((tie.hwndPage = CreatePage(hpage, hDlg)) == NULL)
|
|
{
|
|
RemovePropPageData(ppd, nPage--);
|
|
continue;
|
|
}
|
|
|
|
TabCtrl_SetItem(ppd->hwndTabs, nPage, &tie.tci);
|
|
}
|
|
}
|
|
}
|
|
|
|
HWND NEAR PASCAL _Ppd_GetPage(LPPROPDATA ppd, int nItem)
|
|
{
|
|
if (ppd->hwndTabs)
|
|
{
|
|
TC_ITEMEXTRA tie;
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(ppd->hwndTabs, nItem, &tie.tci);
|
|
return tie.hwndPage;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
LRESULT NEAR PASCAL _Ppd_SendNotify(LPPROPDATA ppd, int nItem, int code, LPARAM lParam)
|
|
{
|
|
PSHNOTIFY pshn;
|
|
|
|
pshn.lParam = lParam;
|
|
return SendNotifyEx(_Ppd_GetPage(ppd,nItem), ppd->hDlg, code, (LPNMHDR)&pshn, FALSE);
|
|
}
|
|
|
|
|
|
int FindPageIndex(LPPROPDATA ppd, int nCurItem, DWORD dwFind, int iAutoAdj)
|
|
{
|
|
int nActivate;
|
|
|
|
if (dwFind == 0) {
|
|
nActivate = nCurItem + iAutoAdj;
|
|
if (((UINT)nActivate) <= ppd->psh.nPages) {
|
|
return(nActivate);
|
|
}
|
|
} else {
|
|
for (nActivate = 0; (UINT)nActivate < ppd->psh.nPages; nActivate++) {
|
|
if ((DWORD)(ppd->psh.phpage[nActivate]->psp.pszTemplate) ==
|
|
dwFind) {
|
|
return(nActivate);
|
|
}
|
|
}
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
void NEAR PASCAL SetNewDefID(LPPROPDATA ppd)
|
|
{
|
|
HWND hDlg = ppd->hDlg;
|
|
#ifdef WIN31
|
|
if( ppd->psh.dwFlags & PSH_WIZARD )
|
|
{
|
|
SetFocus(ppd->hwndCurPage);
|
|
if( GetFocus()==NULL )
|
|
SetFocus( GetDlgItem( hDlg, IDD_NEXT ) );
|
|
}
|
|
#else
|
|
HWND hwndFocus;
|
|
hwndFocus = GetNextDlgTabItem(ppd->hwndCurPage, NULL, FALSE);
|
|
Assert(hwndFocus);
|
|
if (hwndFocus) {
|
|
int id;
|
|
if (((DWORD)SendMessage(hwndFocus, WM_GETDLGCODE, 0, 0L)) & DLGC_HASSETSEL)
|
|
{
|
|
// select the text
|
|
Edit_SetSel(hwndFocus, 0, -1);
|
|
}
|
|
|
|
id = GetDlgCtrlID(hwndFocus);
|
|
// HACKHACK....
|
|
// if there is no tab stop, GetDlgCtrlID will return the first item
|
|
// (don't ask me why it doesn't return NULL
|
|
// so we need to check it and set the focus to the tabs if it's not a tabstop
|
|
if ((GetWindowLong(hwndFocus, GWL_STYLE) & (WS_VISIBLE | WS_DISABLED | WS_TABSTOP)) == (WS_VISIBLE | WS_TABSTOP))
|
|
SetFocus(hwndFocus);
|
|
else {
|
|
// in prop sheet mode, focus on tabs,
|
|
// in wizard mode, tabs aren't visible, go to idDefFallback
|
|
if (ppd->psh.dwFlags & PSH_WIZARD)
|
|
SetFocus(GetDlgItem(hDlg, ppd->idDefaultFallback));
|
|
else
|
|
SetFocus(ppd->hwndTabs);
|
|
}
|
|
|
|
ResetWizButtons(ppd);
|
|
if (SendDlgItemMessage(ppd->hwndCurPage, id, WM_GETDLGCODE, 0, 0L) & DLGC_UNDEFPUSHBUTTON)
|
|
SendMessage(ppd->hwndCurPage, DM_SETDEFID, id, 0);
|
|
else {
|
|
SendMessage(hDlg, DM_SETDEFID, ppd->idDefaultFallback, 0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
** we are about to change pages. what a nice chance to let the current
|
|
** page validate itself before we go away. if the page decides not
|
|
** to be de-activated, then this'll cancel the page change.
|
|
**
|
|
** return TRUE iff this page failed validation
|
|
*/
|
|
BOOL NEAR PASCAL PageChanging(LPPROPDATA ppd)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
if (ppd && ppd->hwndCurPage)
|
|
{
|
|
bRet = (BOOL)_Ppd_SendNotify(ppd, ppd->nCurItem, PSN_KILLACTIVE, 0);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void NEAR PASCAL PageChange(LPPROPDATA ppd, int iAutoAdj)
|
|
{
|
|
HWND hwndCurPage;
|
|
HWND hwndCurFocus;
|
|
int nItem;
|
|
HWND hDlg, hwndTabs;
|
|
TC_ITEMEXTRA tie;
|
|
UINT FlailCount = 0;
|
|
LRESULT lres;
|
|
|
|
#ifdef WIN31
|
|
LRESULT (WINAPI *_DefDlgProc)(HWND, UINT, WPARAM, LPARAM);
|
|
#endif
|
|
|
|
if (!ppd)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hDlg = ppd->hDlg;
|
|
hwndTabs = ppd->hwndTabs;
|
|
|
|
// NOTE: the page was already validated (PSN_KILLACTIVE) before
|
|
// the actual page change.
|
|
|
|
hwndCurFocus = GetFocus();
|
|
|
|
TryAgain:
|
|
FlailCount++;
|
|
if (FlailCount > ppd->psh.nPages)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("PropSheet PageChange attempt to set activation more than 10 times."));
|
|
return;
|
|
}
|
|
|
|
nItem = TabCtrl_GetCurSel(hwndTabs);
|
|
if (nItem < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
|
|
TabCtrl_GetItem(hwndTabs, nItem, &tie.tci);
|
|
hwndCurPage = tie.hwndPage;
|
|
|
|
if (!hwndCurPage)
|
|
{
|
|
if ((hwndCurPage = CreatePage(ppd->psh.phpage[nItem], hDlg)) ==
|
|
NULL)
|
|
{
|
|
/* Should we put up some sort of error message here?
|
|
*/
|
|
RemovePropPageData(ppd, nItem);
|
|
TabCtrl_SetCurSel(hwndTabs, 0);
|
|
goto TryAgain;
|
|
}
|
|
|
|
// tie.tci.mask = TCIF_PARAM;
|
|
tie.hwndPage = hwndCurPage;
|
|
TabCtrl_SetItem(hwndTabs, nItem, &tie.tci);
|
|
#ifdef WIN31
|
|
// Subclass for proper color handling
|
|
// SubclassWindow(hwndCurPage, Win31PropPageWndProc);
|
|
_DefDlgProc = SubclassWindow(hwndCurPage, Win31PropPageWndProc);
|
|
SetProp(hwndCurPage,g_szLoSubclass,(HANDLE)LOWORD(_DefDlgProc));
|
|
SetProp(hwndCurPage,g_szHiSubclass,(HANDLE)HIWORD(_DefDlgProc));
|
|
|
|
// Make fonts non-bold
|
|
if (GetWindowStyle(hwndCurPage) & DS_3DLOOK)
|
|
Win31MakeDlgNonBold(hwndCurPage);
|
|
|
|
// Remove the default button - it is in the main dialog
|
|
RemoveDefaultButton(hwndCurPage,NULL);
|
|
#endif
|
|
}
|
|
|
|
// THI WAS REMOVED as part of the fix for bug 18327. The problem is we need to
|
|
// send a SETACTIVE message to a page if it is being activated.
|
|
// if (ppd->hwndCurPage == hwndCurPage)
|
|
// {
|
|
// /* we should be done at this point.
|
|
// */
|
|
// return;
|
|
// }
|
|
|
|
/* Size the dialog and move it to the top of the list before showing
|
|
** it in case there is size specific initializing to be done in the
|
|
** GETACTIVE message.
|
|
*/
|
|
if (ppd->psh.dwFlags & PSH_WIZARD) {
|
|
SetWindowPos(hwndCurPage, HWND_TOP, ppd->xSubDlg, ppd->ySubDlg, ppd->cxSubDlg, ppd->cySubDlg, 0);
|
|
} else {
|
|
RECT rcPage;
|
|
GetClientRect(ppd->hwndTabs, &rcPage);
|
|
TabCtrl_AdjustRect(ppd->hwndTabs, FALSE, &rcPage);
|
|
MapWindowPoints(ppd->hwndTabs, hDlg, (LPPOINT)&rcPage, 2);
|
|
SetWindowPos(hwndCurPage, HWND_TOP, rcPage.left, rcPage.top,
|
|
rcPage.right - rcPage.left, rcPage.bottom - rcPage.top, 0);
|
|
}
|
|
|
|
/* We want to send the SETACTIVE message before the window is visible
|
|
** to minimize on flicker if it needs to update fields.
|
|
*/
|
|
|
|
//
|
|
// If the page returns non-zero from the PSN_SETACTIVE call then
|
|
// we will set the activation to the resource ID returned from
|
|
// the call and set activation to it. This is mainly used by wizards
|
|
// to skip a step.
|
|
//
|
|
lres = _Ppd_SendNotify(ppd, nItem, PSN_SETACTIVE, 0);
|
|
|
|
if (lres) {
|
|
int iPageIndex = FindPageIndex(ppd, nItem,
|
|
(lres == -1) ? 0 : lres, iAutoAdj);
|
|
|
|
if (iPageIndex != -1) {
|
|
TabCtrl_SetCurSel(hwndTabs, iPageIndex);
|
|
ShowWindow(hwndCurPage, SW_HIDE);
|
|
goto TryAgain;
|
|
}
|
|
}
|
|
|
|
if (ppd->psh.dwFlags & PSH_HASHELP) {
|
|
Button_Enable(GetDlgItem(hDlg, IDHELP),
|
|
(BOOL)(ppd->psh.phpage[nItem]->psp.dwFlags & PSP_HASHELP));
|
|
}
|
|
|
|
//
|
|
// If this is a wizard then we'll set the dialog's title to the tab
|
|
// title.
|
|
//
|
|
if (ppd->psh.dwFlags & PSH_WIZARD) {
|
|
TC_ITEMEXTRA tie;
|
|
TCHAR szTemp[128 + 50];
|
|
|
|
tie.tci.mask = TCIF_TEXT;
|
|
tie.tci.pszText = szTemp;
|
|
tie.tci.cchTextMax = ARRAYSIZE(szTemp);
|
|
//// BUGBUG -- Check for error. Does this return false if fails??
|
|
TabCtrl_GetItem(hwndTabs, nItem, &tie.tci);
|
|
if (szTemp[0])
|
|
SetWindowText(hDlg, szTemp);
|
|
}
|
|
|
|
/* Disable all erasebkgnd messages that come through because windows
|
|
** are getting shuffled. Note that we need to call ShowWindow (and
|
|
** not show the window in some other way) because DavidDs is counting
|
|
** on the correct parameters to the WM_SHOWWINDOW message, and we may
|
|
** document how to keep your page from flashing.
|
|
*/
|
|
ppd->fFlags |= PD_NOERASE;
|
|
ShowWindow(hwndCurPage, SW_SHOW);
|
|
if (ppd->hwndCurPage && (ppd->hwndCurPage != hwndCurPage))
|
|
{
|
|
ShowWindow(ppd->hwndCurPage, SW_HIDE);
|
|
}
|
|
ppd->fFlags &= ~PD_NOERASE;
|
|
|
|
ppd->hwndCurPage = hwndCurPage;
|
|
ppd->nCurItem = nItem;
|
|
|
|
/* Newly created dialogs seem to steal the focus, so we steal it back
|
|
** to the page list, which must have had the focus to get to this
|
|
** point. If this is a wizard then set the focus to the dialog of
|
|
** the page. Otherwise, set the focus to the tabs.
|
|
*/
|
|
if (hwndCurFocus != hwndTabs)
|
|
{
|
|
SetNewDefID(ppd);
|
|
}
|
|
else
|
|
{
|
|
// The focus may have been stolen from us, bring it back
|
|
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hwndTabs, (LPARAM)TRUE);
|
|
}
|
|
}
|
|
|
|
#define DECLAREWAITCURSOR HCURSOR hcursor_wait_cursor_save
|
|
#define SetWaitCursor() hcursor_wait_cursor_save = SetCursor(LoadCursor(NULL, IDC_WAIT))
|
|
#define ResetWaitCursor() SetCursor(hcursor_wait_cursor_save)
|
|
|
|
// return TRUE iff all sheets successfully handle the notification
|
|
BOOL NEAR PASCAL ButtonPushed(LPPROPDATA ppd, WPARAM wParam)
|
|
{
|
|
HWND hwndTabs;
|
|
int nItems, nItem;
|
|
int nNotify;
|
|
TC_ITEMEXTRA tie;
|
|
BOOL bExit = FALSE;
|
|
int nReturnNew = ppd->nReturn;
|
|
int fSuccess = TRUE;
|
|
DECLAREWAITCURSOR;
|
|
LRESULT lres = 0;
|
|
LPARAM lParam = FALSE;
|
|
|
|
switch (wParam) {
|
|
case IDOK:
|
|
lParam = TRUE;
|
|
bExit = TRUE;
|
|
|
|
// Fall through...
|
|
|
|
case IDD_APPLYNOW:
|
|
// First allow the current dialog to validate itself.
|
|
if ((BOOL)_Ppd_SendNotify(ppd, ppd->nCurItem, PSN_KILLACTIVE, 0))
|
|
return FALSE;
|
|
|
|
|
|
nReturnNew = 1;
|
|
|
|
nNotify = PSN_APPLY;
|
|
break;
|
|
|
|
case IDCLOSE:
|
|
lParam = TRUE;
|
|
case IDCANCEL:
|
|
bExit = TRUE;
|
|
nNotify = PSN_RESET;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
SetWaitCursor();
|
|
|
|
hwndTabs = ppd->hwndTabs;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
|
|
nItems = TabCtrl_GetItemCount(hwndTabs);
|
|
for (nItem = 0; nItem < nItems; ++nItem)
|
|
{
|
|
|
|
TabCtrl_GetItem(hwndTabs, nItem, &tie.tci);
|
|
|
|
if (tie.hwndPage)
|
|
{
|
|
/* If the dialog fails a PSN_APPY call (by returning TRUE),
|
|
** then it has invalid information on it (should be verified
|
|
** on the PSN_KILLACTIVE, but that is not always possible)
|
|
** and we want to abort the notifications. We select the failed
|
|
** page below.
|
|
*/
|
|
lres = _Ppd_SendNotify(ppd, nItem, nNotify, lParam);
|
|
if (lres)
|
|
{
|
|
fSuccess = FALSE;
|
|
bExit = FALSE;
|
|
break;
|
|
} else {
|
|
// if we need a restart (Apply or OK), then this is an exit
|
|
if ((nNotify == PSN_APPLY) && !bExit && ppd->nRestart) {
|
|
DebugMsg(DM_TRACE, TEXT("PropertySheet: restart flags force close"));
|
|
bExit = TRUE;
|
|
}
|
|
}
|
|
|
|
/* We have either reset or applied, so everything is
|
|
** up to date.
|
|
*/
|
|
tie.state &= ~FLAG_CHANGED;
|
|
// tie.tci.mask = TCIF_PARAM; // already set
|
|
TabCtrl_SetItem(hwndTabs, nItem, &tie.tci);
|
|
}
|
|
}
|
|
|
|
/* If we leave ppd->hwndCurPage as NULL, it will tell the main
|
|
** loop to exit.
|
|
*/
|
|
if (fSuccess)
|
|
{
|
|
ppd->hwndCurPage = NULL;
|
|
}
|
|
else if (lres != PSNRET_INVALID_NOCHANGEPAGE)
|
|
{
|
|
// Need to change to the page that caused the failure.
|
|
// if lres == PSN_INVALID_NOCHANGEPAGE, then assume sheet has already
|
|
// changed to the page with the invalid information on it
|
|
TabCtrl_SetCurSel(hwndTabs, nItem);
|
|
}
|
|
|
|
if (fSuccess)
|
|
{
|
|
// Set to the cached value
|
|
ppd->nReturn = nReturnNew;
|
|
}
|
|
|
|
if (!bExit)
|
|
{
|
|
// before PageChange, so ApplyNow gets disabled faster.
|
|
if (fSuccess)
|
|
{
|
|
TCHAR szOK[30];
|
|
HWND hwndApply;
|
|
|
|
if (!(ppd->psh.dwFlags & PSH_WIZARD)) {
|
|
// The ApplyNow button should always be disabled after
|
|
// a successfull apply/cancel, since no change has been made yet.
|
|
hwndApply = GetDlgItem(ppd->hDlg, IDD_APPLYNOW);
|
|
Button_SetStyle(hwndApply, BS_PUSHBUTTON, TRUE);
|
|
EnableWindow(hwndApply, FALSE);
|
|
ResetWizButtons(ppd);
|
|
SendMessage(ppd->hDlg, DM_SETDEFID, IDOK, 0);
|
|
ppd->idDefaultFallback = IDOK;
|
|
}
|
|
|
|
// Undo PSM_CANCELTOCLOSE for the same reasons.
|
|
if (ppd->fFlags & PD_CANCELTOCLOSE)
|
|
{
|
|
ppd->fFlags &= ~PD_CANCELTOCLOSE;
|
|
LoadString(HINST_THISDLL, IDS_OK, szOK, ARRAYSIZE(szOK));
|
|
SetDlgItemText(ppd->hDlg, IDOK, szOK);
|
|
EnableWindow(GetDlgItem(ppd->hDlg, IDCANCEL), TRUE);
|
|
}
|
|
}
|
|
|
|
/* Re-"select" the current item and get the whole list to
|
|
** repaint.
|
|
*/
|
|
if (lres != PSNRET_INVALID_NOCHANGEPAGE)
|
|
PageChange(ppd, 1);
|
|
}
|
|
|
|
ResetWaitCursor();
|
|
|
|
return(fSuccess);
|
|
}
|
|
|
|
// Win3.1 USER didn't handle DM_SETDEFID very well-- it's very possible to get
|
|
// multiple buttons with the default button style look. This has been fixed
|
|
// for Win95, but the Setup wizard needs this hack when running from 3.1.
|
|
|
|
// it seems win95 doesn't handle it well either..
|
|
void NEAR PASCAL ResetWizButtons(LPPROPDATA ppd)
|
|
{
|
|
int id;
|
|
|
|
if (ppd->psh.dwFlags & PSH_WIZARD) {
|
|
|
|
for (id = 0; id < ARRAYSIZE(WizIDs); id++)
|
|
SendDlgItemMessage(ppd->hDlg, WizIDs[id], BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
|
|
}
|
|
}
|
|
|
|
void NEAR PASCAL SetWizButtons(LPPROPDATA ppd, LPARAM lParam)
|
|
{
|
|
int idDef;
|
|
int iShowID = IDD_NEXT;
|
|
int iHideID = IDD_FINISH;
|
|
BOOL bEnabled;
|
|
BOOL bResetFocus;
|
|
HWND hwndShow;
|
|
HWND hwndFocus = GetFocus();
|
|
HWND hwndHide;
|
|
HWND hwndBack;
|
|
HWND hDlg = ppd->hDlg;
|
|
|
|
idDef = (int)LOWORD(SendMessage(hDlg, DM_GETDEFID, 0, 0));
|
|
|
|
bEnabled = (lParam & PSWIZB_BACK) != 0;
|
|
hwndBack = GetDlgItem(hDlg, IDD_BACK);
|
|
EnableWindow(hwndBack, bEnabled);
|
|
|
|
bEnabled = (lParam & PSWIZB_NEXT) != 0;
|
|
hwndShow = GetDlgItem(hDlg, IDD_NEXT);
|
|
EnableWindow(hwndShow, bEnabled);
|
|
|
|
if (lParam & (PSWIZB_FINISH | PSWIZB_DISABLEDFINISH)) {
|
|
iShowID = IDD_FINISH;
|
|
iHideID = IDD_NEXT;
|
|
|
|
bEnabled = (lParam & PSWIZB_FINISH) != 0;
|
|
hwndShow = GetDlgItem(hDlg, IDD_FINISH);
|
|
EnableWindow(hwndShow, bEnabled);
|
|
}
|
|
|
|
if (!(ppd->psh.dwFlags & PSH_WIZARDHASFINISH)) {
|
|
hwndHide = GetDlgItem(hDlg, iHideID);
|
|
ShowWindow(hwndHide, SW_HIDE);
|
|
|
|
hwndShow = GetDlgItem(hDlg, iShowID);
|
|
ShowWindow(hwndShow, SW_SHOW);
|
|
}
|
|
|
|
|
|
// bResetFocus keeps track of whether or not we need to set Focus to our button
|
|
bResetFocus = FALSE;
|
|
if (hwndFocus)
|
|
{
|
|
// if the dude that has focus is a button, we want to steal focus away
|
|
// so users can just press enter all the way through a property sheet,
|
|
// getting the default as they go. this also catches the case
|
|
// of where focus is on one of our buttons which was turned off.
|
|
if (SendMessage(hwndFocus, WM_GETDLGCODE, 0, 0L) & (DLGC_UNDEFPUSHBUTTON|DLGC_DEFPUSHBUTTON))
|
|
bResetFocus = TRUE;
|
|
}
|
|
if (!bResetFocus)
|
|
{
|
|
// if there is no focus or we're focused on an invisible/disabled
|
|
// item on the sheet, grab focus.
|
|
bResetFocus = !hwndFocus || !IsWindowVisible(hwndFocus) || !IsWindowEnabled(hwndFocus) ;
|
|
}
|
|
|
|
// We used to do this code only if we nuked a button which had default
|
|
// or if bResetFocus. Unfortunately, some wizards turn off BACK+NEXT
|
|
// and then when they turn them back on, they want DEFID on NEXT.
|
|
// So now we always reset DEFID.
|
|
{
|
|
int ids[4] = { IDD_NEXT, IDD_FINISH, IDD_BACK, IDCANCEL };
|
|
int i;
|
|
HWND hwndNewFocus = NULL;
|
|
|
|
for (i = 0; i < ARRAYSIZE(ids); i++) {
|
|
hwndNewFocus = GetDlgItem(hDlg, ids[i]);
|
|
|
|
// can't do IsVisible because we may be doing this
|
|
// before the prop sheet as a whole is shown
|
|
if ((GetWindowLong(hwndNewFocus, GWL_STYLE) & WS_VISIBLE) &&
|
|
IsWindowEnabled(hwndNewFocus)) {
|
|
hwndFocus = hwndNewFocus;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ppd->idDefaultFallback = ids[i];
|
|
if (bResetFocus) {
|
|
if (!hwndNewFocus)
|
|
hwndNewFocus = hDlg;
|
|
SetFocus(hwndNewFocus);
|
|
}
|
|
ResetWizButtons(ppd);
|
|
SendMessage(hDlg, DM_SETDEFID, ids[i], 0);
|
|
|
|
}
|
|
}
|
|
|
|
int NEAR PASCAL FindItem(HWND hwndTabs, HWND hwndPage, TC_ITEMEXTRA FAR * lptie)
|
|
{
|
|
int i;
|
|
|
|
for (i = TabCtrl_GetItemCount(hwndTabs) - 1; i >= 0; --i)
|
|
{
|
|
TabCtrl_GetItem(hwndTabs, i, &lptie->tci);
|
|
|
|
if (lptie->hwndPage == hwndPage)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//this will be -1 if the for loop falls out.
|
|
return i;
|
|
}
|
|
|
|
// a page is telling us that something on it has changed and thus
|
|
// "Apply Now" should be enabled
|
|
|
|
void NEAR PASCAL PageInfoChange(LPPROPDATA ppd, HWND hwndPage)
|
|
{
|
|
int i;
|
|
TC_ITEMEXTRA tie;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
i = FindItem(ppd->hwndTabs, hwndPage, &tie);
|
|
|
|
if (i == -1)
|
|
return;
|
|
|
|
if (!(tie.state & FLAG_CHANGED))
|
|
{
|
|
// tie.tci.mask = TCIF_PARAM; // already set
|
|
tie.state |= FLAG_CHANGED;
|
|
TabCtrl_SetItem(ppd->hwndTabs, i, &tie.tci);
|
|
}
|
|
|
|
EnableWindow(GetDlgItem(ppd->hDlg, IDD_APPLYNOW), TRUE);
|
|
}
|
|
|
|
// a page is telling us that everything has reverted to its last
|
|
// saved state.
|
|
|
|
void NEAR PASCAL PageInfoUnChange(LPPROPDATA ppd, HWND hwndPage)
|
|
{
|
|
int i;
|
|
TC_ITEMEXTRA tie;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
i = FindItem(ppd->hwndTabs, hwndPage, &tie);
|
|
|
|
if (i == -1)
|
|
return;
|
|
|
|
if (tie.state & FLAG_CHANGED)
|
|
{
|
|
tie.state &= ~FLAG_CHANGED;
|
|
TabCtrl_SetItem(ppd->hwndTabs, i, &tie.tci);
|
|
}
|
|
|
|
// check all the pages, if none are FLAG_CHANGED, disable IDD_APLYNOW
|
|
for (i = ppd->psh.nPages-1 ; i >= 0 ; i--)
|
|
{
|
|
// BUGBUG? Does TabCtrl_GetItem return its information properly?!?
|
|
|
|
if (!TabCtrl_GetItem(ppd->hwndTabs, i, &tie.tci))
|
|
break;
|
|
if (tie.state & FLAG_CHANGED)
|
|
break;
|
|
}
|
|
if (i<0)
|
|
EnableWindow(GetDlgItem(ppd->hDlg, IDD_APPLYNOW), FALSE);
|
|
}
|
|
|
|
BOOL NEAR PASCAL AddPropPage(LPPROPDATA ppd, PSP FAR * hpage)
|
|
{
|
|
POINT pt;
|
|
HICON hIcon = NULL;
|
|
TCHAR szTemp[128];
|
|
TC_ITEMEXTRA tie;
|
|
int nPage;
|
|
#ifdef WIN32
|
|
HIMAGELIST himl;
|
|
#endif
|
|
#ifdef WINDOWS_ME
|
|
BOOL bRTL;
|
|
#endif
|
|
|
|
if (!hpage)
|
|
return FALSE;
|
|
|
|
if (ppd->psh.nPages >= MAXPROPPAGES)
|
|
return FALSE; // we're full
|
|
|
|
nPage = ppd->psh.nPages++;
|
|
ppd->psh.phpage[nPage] = hpage;
|
|
|
|
#ifdef WIN32
|
|
himl = TabCtrl_GetImageList(ppd->hwndTabs);
|
|
#endif
|
|
|
|
if (!GetPageInfo(hpage, szTemp, ARRAYSIZE(szTemp), &pt, &hIcon
|
|
#ifdef WINDOWS_ME
|
|
, &bRTL
|
|
#endif
|
|
))
|
|
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("AddPropPage: GetPageInfo failed"));
|
|
goto bogus;
|
|
}
|
|
|
|
#ifndef WINDOWS_ME
|
|
tie.tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE;
|
|
#else
|
|
tie.tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE | (bRTL ? TCIF_RTLREADING : 0);
|
|
#endif
|
|
tie.hwndPage = NULL;
|
|
tie.tci.pszText = szTemp;
|
|
tie.state = 0;
|
|
|
|
|
|
if (hIcon) {
|
|
#ifdef WIN32
|
|
if (himl)
|
|
tie.tci.iImage = ImageList_AddIcon(himl, hIcon);
|
|
#else
|
|
tie.tci.iImage = -1;
|
|
#endif
|
|
DestroyIcon(hIcon);
|
|
} else {
|
|
tie.tci.iImage = -1;
|
|
}
|
|
|
|
// Add the page to the end of the tab list
|
|
TabCtrl_InsertItem(ppd->hwndTabs, nPage, &tie.tci);
|
|
|
|
// If this page wants premature initialization then init it
|
|
// do this last so pages can rely on "being there" at init time
|
|
if (hpage->psp.dwFlags & PSP_PREMATURE)
|
|
{
|
|
if ((tie.hwndPage = CreatePage(hpage, ppd->hDlg)) == NULL)
|
|
{
|
|
TabCtrl_DeleteItem(ppd->hwndTabs, nPage);
|
|
// don't free the hpage here let the caller do it
|
|
goto bogus;
|
|
}
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_SetItem(ppd->hwndTabs, nPage, &tie.tci);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
bogus:
|
|
ppd->psh.nPages--;
|
|
return FALSE;
|
|
}
|
|
|
|
// removes property sheet hpage (index if NULL)
|
|
void NEAR PASCAL RemovePropPage(LPPROPDATA ppd, int index, PSP FAR * hpage)
|
|
{
|
|
int i = -1;
|
|
BOOL fReturn = TRUE;
|
|
TC_ITEMEXTRA tie;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
if (hpage) {
|
|
for (i = ppd->psh.nPages - 1; i >= 0; i--) {
|
|
if (hpage == ppd->psh.phpage[i])
|
|
break;
|
|
}
|
|
}
|
|
if (i == -1) {
|
|
i = index;
|
|
|
|
// this catches i < 0 && i >= (int)(ppd->psh.nPages)
|
|
if ((UINT)i >= ppd->psh.nPages)
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("RemovePropPage: invalid page"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
index = TabCtrl_GetCurSel(ppd->hwndTabs);
|
|
if (i == index) {
|
|
// if we're removing the current page, select another (don't worry
|
|
// about this page having invalid information on it -- we're nuking it)
|
|
PageChanging(ppd);
|
|
|
|
if (index == 0)
|
|
index++;
|
|
else
|
|
index--;
|
|
|
|
if (SendMessage(ppd->hwndTabs, TCM_SETCURSEL, index, 0L) == -1) {
|
|
// if we couldn't select (find) the new one, punt to 0th
|
|
SendMessage(ppd->hwndTabs, TCM_SETCURSEL, 0, 0L);
|
|
}
|
|
PageChange(ppd, 1);
|
|
}
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(ppd->hwndTabs, i, &tie.tci);
|
|
if (tie.hwndPage) {
|
|
if (ppd->hwndCurPage == tie.hwndPage)
|
|
ppd->hwndCurPage = NULL;
|
|
DestroyWindow(tie.hwndPage);
|
|
}
|
|
|
|
RemovePropPageData(ppd, i);
|
|
}
|
|
|
|
void NEAR PASCAL RemovePropPageData(LPPROPDATA ppd, int nPage)
|
|
{
|
|
TabCtrl_DeleteItem(ppd->hwndTabs, nPage);
|
|
DestroyPropertySheetPage(ppd->psh.phpage[nPage]);
|
|
|
|
ppd->psh.nPages--;
|
|
hmemcpy(&ppd->psh.phpage[nPage], &ppd->psh.phpage[nPage + 1],
|
|
sizeof(ppd->psh.phpage[0]) * (ppd->psh.nPages - nPage));
|
|
}
|
|
|
|
// returns TRUE iff the page was successfully set to index/hpage
|
|
// Note: The iAutoAdj should be set to 1 or -1. This value is used
|
|
// by PageChange if a page refuses a SETACTIVE to either increment
|
|
// or decrement the page index.
|
|
BOOL NEAR PASCAL PageSetSelection(LPPROPDATA ppd, int index, PSP FAR * hpage,
|
|
int iAutoAdj)
|
|
{
|
|
int i = -1;
|
|
BOOL fReturn = FALSE;
|
|
TC_ITEMEXTRA tie;
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
if (hpage) {
|
|
for (i = ppd->psh.nPages - 1; i >= 0; i--) {
|
|
if (hpage == ppd->psh.phpage[i])
|
|
break;
|
|
}
|
|
}
|
|
if (i == -1) {
|
|
if (index == -1)
|
|
return FALSE;
|
|
|
|
i = index;
|
|
}
|
|
if (i >= MAXPROPPAGES)
|
|
{
|
|
// don't go off the end of our HPROPSHEETPAGE array
|
|
return FALSE;
|
|
}
|
|
|
|
fReturn = !PageChanging(ppd);
|
|
if (fReturn)
|
|
{
|
|
index = TabCtrl_GetCurSel(ppd->hwndTabs);
|
|
if (SendMessage(ppd->hwndTabs, TCM_SETCURSEL, i, 0L) == -1) {
|
|
// if we couldn't select (find) the new one, fail out
|
|
// and restore the old one
|
|
SendMessage(ppd->hwndTabs, TCM_SETCURSEL, index, 0L);
|
|
fReturn = FALSE;
|
|
}
|
|
PageChange(ppd, iAutoAdj);
|
|
}
|
|
return fReturn;
|
|
}
|
|
|
|
LRESULT NEAR PASCAL QuerySiblings(LPPROPDATA ppd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT i;
|
|
for (i = 0 ; i < ppd->psh.nPages ; i++)
|
|
{
|
|
HWND hwndSibling = _Ppd_GetPage(ppd, i);
|
|
if (hwndSibling)
|
|
{
|
|
LRESULT lres = SendMessage(hwndSibling, PSM_QUERYSIBLINGS, wParam, lParam);
|
|
if (lres)
|
|
return lres;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// REVIEW HACK This gets round the problem of having a hotkey control
|
|
// up and trying to enter the hotkey that is already in use by a window.
|
|
BOOL NEAR PASCAL HandleHotkey(LPARAM lparam)
|
|
{
|
|
WORD wHotkey;
|
|
TCHAR szClass[32];
|
|
HWND hwnd;
|
|
|
|
// What hotkey did the user type hit?
|
|
wHotkey = (WORD)SendMessage((HWND)lparam, WM_GETHOTKEY, 0, 0);
|
|
// Were they typing in a hotkey window?
|
|
hwnd = GetFocus();
|
|
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
|
|
if (lstrcmp(szClass, HOTKEY_CLASS) == 0)
|
|
{
|
|
// Yes.
|
|
SendMessage(hwnd, HKM_SETHOTKEY, wHotkey, 0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Function handles Next and Back functions for wizards. The code will
|
|
// be either PSN_WIZNEXT or PSN_WIZBACK
|
|
//
|
|
BOOL NEAR PASCAL WizNextBack(LPPROPDATA ppd, int code)
|
|
{
|
|
DWORD dwFind;
|
|
int iPageIndex;
|
|
int iAutoAdj = (code == PSN_WIZNEXT) ? 1 : -1;
|
|
|
|
dwFind = _Ppd_SendNotify(ppd, ppd->nCurItem, code, 0);
|
|
|
|
if (dwFind == -1) {
|
|
return(FALSE);
|
|
}
|
|
|
|
iPageIndex = FindPageIndex(ppd, ppd->nCurItem, dwFind, iAutoAdj);
|
|
|
|
if (iPageIndex == -1) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(PageSetSelection(ppd, iPageIndex, NULL, iAutoAdj));
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
BOOL NEAR PASCAL Prsht_OnCommand(LPPROPDATA ppd, int id, HWND hwndCtrl, UINT codeNotify)
|
|
{
|
|
if (!hwndCtrl)
|
|
hwndCtrl = GetDlgItem(ppd->hDlg, id);
|
|
|
|
switch (id) {
|
|
|
|
case IDCLOSE:
|
|
case IDCANCEL:
|
|
if (_Ppd_SendNotify(ppd, ppd->nCurItem, PSN_QUERYCANCEL, 0) == 0) {
|
|
ButtonPushed(ppd, id);
|
|
}
|
|
break;
|
|
|
|
case IDD_APPLYNOW:
|
|
case IDOK:
|
|
if (!(ppd->psh.dwFlags & PSH_WIZARD)) {
|
|
ButtonPushed(ppd, id);
|
|
}
|
|
break;
|
|
|
|
case IDHELP:
|
|
if (IsWindowEnabled(hwndCtrl))
|
|
{
|
|
_Ppd_SendNotify(ppd, ppd->nCurItem, PSN_HELP, 0);
|
|
}
|
|
break;
|
|
|
|
case IDD_FINISH:
|
|
// b#11346 - dont let multiple clicks on FINISH.
|
|
EnableWindow(ppd->hDlg, FALSE);
|
|
if (!_Ppd_SendNotify(ppd, ppd->nCurItem, PSN_WIZFINISH, 0))
|
|
{
|
|
ppd->hwndCurPage = NULL;
|
|
ppd->nReturn = 1;
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(ppd->hDlg, TRUE);
|
|
}
|
|
break;
|
|
|
|
case IDD_NEXT:
|
|
case IDD_BACK:
|
|
ppd->idDefaultFallback = id;
|
|
WizNextBack(ppd, id == IDD_NEXT ? PSN_WIZNEXT : PSN_WIZBACK);
|
|
break;
|
|
|
|
default:
|
|
FORWARD_WM_COMMAND(_Ppd_GetPage(ppd, ppd->nCurItem), id, hwndCtrl, codeNotify, SendMessage);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL NEAR PASCAL Prop_IsDialogMessage(LPPROPDATA ppd, LPMSG32 pmsg32)
|
|
{
|
|
if ((pmsg32->message == WM_KEYDOWN) && (GetAsyncKeyState(VK_CONTROL) < 0))
|
|
{
|
|
BOOL bBack = FALSE;
|
|
|
|
switch (pmsg32->wParam) {
|
|
case VK_TAB:
|
|
bBack = GetAsyncKeyState(VK_SHIFT) < 0;
|
|
break;
|
|
|
|
case VK_PRIOR: // VK_PAGE_UP
|
|
case VK_NEXT: // VK_PAGE_DOWN
|
|
bBack = (pmsg32->wParam == VK_PRIOR);
|
|
break;
|
|
|
|
default:
|
|
goto NoKeys;
|
|
}
|
|
|
|
if (ppd->psh.dwFlags & PSH_WIZARD)
|
|
{
|
|
WizNextBack(ppd, bBack ? PSN_WIZBACK : PSN_WIZNEXT);
|
|
}
|
|
else
|
|
{
|
|
int iCur = TabCtrl_GetCurSel(ppd->hwndTabs);
|
|
// tab in reverse if shift is down
|
|
if (bBack)
|
|
iCur += (ppd->psh.nPages - 1);
|
|
else
|
|
iCur++;
|
|
|
|
iCur %= ppd->psh.nPages;
|
|
PageSetSelection(ppd, iCur, NULL, 1);
|
|
}
|
|
return TRUE;
|
|
}
|
|
NoKeys:
|
|
|
|
#ifdef WIN31
|
|
if (Win31IsKeyMessage(ppd->hDlg, pmsg32))
|
|
return TRUE;
|
|
|
|
if (IsDialogMessage32(ppd->hwndCurPage, pmsg32, TRUE))
|
|
return TRUE;
|
|
|
|
// BUGBUG:
|
|
// User 3.1 doesn't handle accelerator keys properly between
|
|
// the main and sub dialog. If a control in the main dialog has
|
|
// focus and an accelerator for a control in the subdialog is
|
|
// pressed, only the main dialog gets the message so the focus
|
|
// doesn't change. Likewise if a control in the subdialog has focus.
|
|
//
|
|
// This will only be used during setup so we won't freak about it
|
|
// (for now).
|
|
|
|
if ((pmsg32->message == WM_SYSCHAR) && (pmsg32->hwnd != ppd->hwndCurPage))
|
|
SetFocus( ppd->hwndCurPage );
|
|
#endif
|
|
|
|
if (IsDialogMessage32(ppd->hDlg, pmsg32, TRUE))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
const static DWORD aPropHelpIDs[] = { // Context Help IDs
|
|
IDD_APPLYNOW, IDH_COMM_APPLYNOW,
|
|
|
|
0, 0
|
|
};
|
|
|
|
BOOL CALLBACK PropSheetDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hwndT;
|
|
LPPROPDATA ppd = (LPPROPDATA)GetWindowLong(hDlg, DWL_USER);
|
|
|
|
switch (uMessage) {
|
|
case WM_INITDIALOG:
|
|
InitPropSheetDlg(hDlg, (LPPROPDATA)lParam);
|
|
return FALSE;
|
|
|
|
// REVIEW for dealing with hotkeys.
|
|
// BUGBUG: This code might not work with 32-bit WM_SYSCOMMAND msgs.
|
|
case WM_SYSCOMMAND:
|
|
if (wParam == SC_HOTKEY)
|
|
return HandleHotkey(lParam);
|
|
else if (wParam == SC_CLOSE)
|
|
{
|
|
UINT id = IDCLOSE;
|
|
|
|
if (ppd->psh.dwFlags & PSH_WIZARD)
|
|
id = IDCANCEL;
|
|
else if (ppd->fFlags & PD_CANCELTOCLOSE)
|
|
id = IDOK;
|
|
|
|
// system menu close should be IDCANCEL, but if we're in the
|
|
// PSM_CANCELTOCLOSE state, treat it as an IDOK (ie, "Close").
|
|
return Prsht_OnCommand(ppd, id, NULL, 0);
|
|
}
|
|
|
|
return FALSE; // Let default process happen
|
|
|
|
case WM_NCDESTROY:
|
|
if (ppd)
|
|
{
|
|
int iPage;
|
|
|
|
Assert(GetDlgItem(hDlg, IDD_PAGELIST) == NULL);
|
|
|
|
ppd->hwndTabs = NULL;
|
|
|
|
// NOTE: all of the hwnds for the pages must be destroyed by now!
|
|
|
|
// Release all page objects in REVERSE ORDER so we can have
|
|
// pages that are dependant on eachother based on the initial
|
|
// order of those pages
|
|
//
|
|
for (iPage = ppd->psh.nPages - 1; iPage >= 0; iPage--)
|
|
{
|
|
DestroyPropertySheetPage(ppd->psh.phpage[iPage]);
|
|
}
|
|
|
|
// If we are modeless, we need to free our ppd. If we are modal,
|
|
// we let _RealPropertySheet free it since one of our pages may
|
|
// set the restart flag during DestroyPropertySheetPage above.
|
|
if (ppd->psh.dwFlags & PSH_MODELESS)
|
|
{
|
|
#ifdef WIN32
|
|
LocalFree((HLOCAL)ppd);
|
|
#else
|
|
LocalFree((HLOCAL)LOWORD(ppd));
|
|
#endif
|
|
}
|
|
}
|
|
//
|
|
// NOTES:
|
|
// Must return FALSE to avoid DS leak!!!
|
|
//
|
|
return FALSE;
|
|
|
|
case WM_DESTROY:
|
|
if (ppd)
|
|
{
|
|
#ifdef WIN32
|
|
// Destroy the image list we created during our init call.
|
|
HIMAGELIST himl = TabCtrl_GetImageList(ppd->hwndTabs);
|
|
if (himl)
|
|
ImageList_Destroy(himl);
|
|
#endif
|
|
|
|
if ((ppd->psh.dwFlags & PSH_USEICONID) && ppd->psh.hIcon)
|
|
DestroyIcon(ppd->psh.hIcon);
|
|
}
|
|
#ifdef WIN31
|
|
{
|
|
// Clean up the non-bold font if we created one
|
|
HFONT hFont = GetProp(hDlg, g_szNonBoldFont);
|
|
if (hFont)
|
|
{
|
|
DeleteObject(hFont);
|
|
}
|
|
RemoveProp(hDlg, g_szNonBoldFont);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return ppd->fFlags & PD_NOERASE;
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
hdc = BeginPaint(hDlg, &ps);
|
|
|
|
if (ps.fErase) {
|
|
SendMessage (hDlg, WM_ERASEBKGND, (WPARAM) hdc, 0);
|
|
}
|
|
|
|
EndPaint(hDlg, &ps);
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
// Cannot use HANDLE_WM_COMMAND, because we want to pass a result!
|
|
return Prsht_OnCommand(ppd, GET_WM_COMMAND_ID(wParam, lParam),
|
|
GET_WM_COMMAND_HWND(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam));
|
|
|
|
#ifdef WIN31
|
|
case WM_CTLCOLOR:
|
|
return LOWORD(HANDLE_WM_CTLCOLOR(hDlg, wParam, lParam, Win31OnCtlColor));
|
|
|
|
case WM_GETDLGCODE:
|
|
return DLGC_RECURSE;
|
|
#endif
|
|
|
|
case WM_NOTIFY:
|
|
|
|
switch (((NMHDR FAR *)lParam)->code)
|
|
{
|
|
case TCN_SELCHANGE:
|
|
PageChange(ppd, 1);
|
|
break;
|
|
|
|
case TCN_SELCHANGING:
|
|
{
|
|
DWORD dwResult = PageChanging(ppd);
|
|
if (!dwResult) {
|
|
SetWindowPos(ppd->hwndCurPage, HWND_BOTTOM, 0,0,0,0, SWP_NOACTIVATE | SWP_NOSIZE |SWP_NOMOVE);
|
|
}
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, dwResult);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
case PSM_SETWIZBUTTONS:
|
|
SetWizButtons(ppd, lParam);
|
|
break;
|
|
|
|
#ifdef UNICODE
|
|
case PSM_SETFINISHTEXTA:
|
|
#endif
|
|
case PSM_SETFINISHTEXT:
|
|
{
|
|
HWND hFinish = GetDlgItem(hDlg, IDD_FINISH);
|
|
HWND hwndFocus = GetFocus();
|
|
HWND hwnd;
|
|
BOOL fSetFocus = FALSE;
|
|
|
|
if (!(ppd->psh.dwFlags & PSH_WIZARDHASFINISH)) {
|
|
hwnd = GetDlgItem(hDlg, IDD_NEXT);
|
|
if (hwnd == hwndFocus)
|
|
fSetFocus = TRUE;
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
}
|
|
|
|
hwnd = GetDlgItem(hDlg, IDD_BACK);
|
|
if (hwnd == hwndFocus)
|
|
fSetFocus = TRUE;
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
|
|
if (lParam) {
|
|
#ifdef UNICODE
|
|
if (uMessage == PSM_SETFINISHTEXTA) {
|
|
LPWSTR lpFinishText;
|
|
|
|
lpFinishText = ProduceWFromA (CP_ACP, (LPCSTR) lParam);
|
|
if (!lpFinishText)
|
|
break;
|
|
Button_SetText(hFinish, lpFinishText);
|
|
|
|
FreeProducedString (lpFinishText);
|
|
} else
|
|
#endif
|
|
Button_SetText(hFinish, (LPTSTR)lParam);
|
|
}
|
|
ShowWindow(hFinish, SW_SHOW);
|
|
Button_Enable(hFinish, TRUE);
|
|
ResetWizButtons(ppd);
|
|
SendMessage(hDlg, DM_SETDEFID, IDD_FINISH, 0);
|
|
ppd->idDefaultFallback = IDD_FINISH;
|
|
if (fSetFocus)
|
|
SetFocus(hFinish);
|
|
}
|
|
break;
|
|
|
|
#ifdef UNICODE
|
|
case PSM_SETTITLEA:
|
|
{
|
|
LPWSTR lpCaption;
|
|
|
|
if (lParam && HIWORD(lParam)) {
|
|
lpCaption = ProduceWFromA(CP_ACP, (LPCSTR)lParam);
|
|
} else {
|
|
lpCaption = (LPWSTR)lParam;
|
|
}
|
|
|
|
if (!lpCaption) {
|
|
break;
|
|
}
|
|
|
|
ppd->psh.pszCaption = (LPCWSTR) lpCaption;
|
|
ppd->psh.dwFlags = ((((DWORD)wParam) & PSH_PROPTITLE) | (ppd->psh.dwFlags & ~PSH_PROPTITLE));
|
|
_SetTitle(hDlg, ppd);
|
|
|
|
FreeProducedString(lpCaption);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case PSM_SETTITLE:
|
|
ppd->psh.pszCaption = (LPCTSTR)lParam;
|
|
ppd->psh.dwFlags = ((((DWORD)wParam) & PSH_PROPTITLE) | (ppd->psh.dwFlags & ~PSH_PROPTITLE));
|
|
_SetTitle(hDlg, ppd);
|
|
break;
|
|
|
|
case PSM_CHANGED:
|
|
PageInfoChange(ppd, (HWND)wParam);
|
|
break;
|
|
|
|
case PSM_RESTARTWINDOWS:
|
|
ppd->nRestart |= ID_PSRESTARTWINDOWS;
|
|
break;
|
|
|
|
case PSM_REBOOTSYSTEM:
|
|
ppd->nRestart |= ID_PSREBOOTSYSTEM;
|
|
break;
|
|
|
|
case PSM_CANCELTOCLOSE:
|
|
if (!(ppd->fFlags & PD_CANCELTOCLOSE))
|
|
{
|
|
TCHAR szClose[20];
|
|
|
|
ppd->fFlags |= PD_CANCELTOCLOSE;
|
|
LoadString(HINST_THISDLL, IDS_CLOSE, szClose, ARRAYSIZE(szClose));
|
|
SetDlgItemText(hDlg, IDOK, szClose);
|
|
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
|
|
}
|
|
break;
|
|
|
|
case PSM_SETCURSEL:
|
|
SetWindowLong(hDlg, DWL_MSGRESULT,
|
|
PageSetSelection(ppd, (int)wParam,(PSP FAR *)lParam, 1));
|
|
break;
|
|
|
|
case PSM_SETCURSELID:
|
|
{
|
|
int iPageIndex;
|
|
|
|
iPageIndex = FindPageIndex(ppd, ppd->nCurItem, (DWORD)lParam, 1);
|
|
|
|
if (iPageIndex == -1)
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, 0);
|
|
|
|
else
|
|
SetWindowLong(hDlg, DWL_MSGRESULT,
|
|
PageSetSelection(ppd, iPageIndex, NULL, 1));
|
|
}
|
|
break;
|
|
|
|
case PSM_REMOVEPAGE:
|
|
RemovePropPage(ppd, (int)wParam,(PSP FAR *)lParam);
|
|
break;
|
|
|
|
case PSM_ADDPAGE:
|
|
SetDlgMsgResult(hDlg, uMessage, AddPropPage(ppd,(PSP FAR *)lParam));
|
|
break;
|
|
|
|
case PSM_QUERYSIBLINGS:
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, QuerySiblings(ppd, wParam, lParam));
|
|
break;
|
|
|
|
case PSM_UNCHANGED:
|
|
PageInfoUnChange(ppd, (HWND)wParam);
|
|
break;
|
|
|
|
case PSM_APPLY:
|
|
// a page is asking us to simulate an "Apply Now".
|
|
// let the page know if we're successful
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, ButtonPushed(ppd, IDD_APPLYNOW));
|
|
break;
|
|
|
|
case PSM_GETTABCONTROL:
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)(UINT)ppd->hwndTabs);
|
|
break;
|
|
|
|
case PSM_GETCURRENTPAGEHWND:
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)(UINT)ppd->hwndCurPage);
|
|
break;
|
|
|
|
case PSM_PRESSBUTTON:
|
|
if (wParam <= PSBTN_MAX)
|
|
{
|
|
const static int IndexToID[] = {IDD_BACK, IDD_NEXT, IDD_FINISH, IDOK,
|
|
IDD_APPLYNOW, IDCANCEL, IDHELP};
|
|
Prsht_OnCommand(ppd, IndexToID[wParam], NULL, 0);
|
|
}
|
|
break;
|
|
|
|
case PSM_ISDIALOGMESSAGE:
|
|
// returning TRUE means we handled it, do a continue
|
|
// FALSE do standard translate/dispatch
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, Prop_IsDialogMessage(ppd, (LPMSG32)lParam));
|
|
break;
|
|
|
|
// these should be relayed to all created dialogs
|
|
case WM_WININICHANGE:
|
|
case WM_SYSCOLORCHANGE:
|
|
if (ppd)
|
|
{
|
|
int nItem, nItems = TabCtrl_GetItemCount(ppd->hwndTabs);
|
|
for (nItem = 0; nItem < nItems; ++nItem)
|
|
{
|
|
|
|
hwndT = _Ppd_GetPage(ppd, nItem);
|
|
if (hwndT)
|
|
SendMessage(hwndT, uMessage, wParam, lParam);
|
|
}
|
|
SendMessage(ppd->hwndTabs, uMessage, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// send toplevel messages to the current page and tab control
|
|
//
|
|
case WM_ENABLE:
|
|
case WM_QUERYNEWPALETTE:
|
|
case WM_PALETTECHANGED:
|
|
case WM_DEVICECHANGE:
|
|
case WM_QUERYENDSESSION:
|
|
case WM_ENDSESSION:
|
|
if (!ppd)
|
|
return FALSE;
|
|
if (ppd->hwndTabs)
|
|
SendMessage(ppd->hwndTabs, uMessage, wParam, lParam);
|
|
case WM_ACTIVATEAPP:
|
|
case WM_ACTIVATE:
|
|
if (ppd)
|
|
{
|
|
hwndT = _Ppd_GetPage(ppd, ppd->nCurItem);
|
|
if (hwndT && IsWindow(hwndT))
|
|
{
|
|
//
|
|
// By doing this, we are "handling" the message. Therefore
|
|
// we must set the dialog return value to whatever the child
|
|
// wanted.
|
|
//
|
|
SetWindowLong(hDlg, DWL_MSGRESULT,
|
|
SendMessage(hwndT, uMessage, wParam, lParam));
|
|
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case WM_CONTEXTMENU:
|
|
if ((ppd->hwndTabs != (HWND)wParam) && (ppd->hwndCurPage != (HWND)wParam) &&
|
|
(!(ppd->psh.dwFlags & PSH_WIZARD)))
|
|
WinHelp((HWND)wParam, NULL, HELP_CONTEXTMENU, (DWORD)(LPVOID)aPropHelpIDs);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
hwndT = (HWND)((LPHELPINFO)lParam)->hItemHandle;
|
|
if ((GetParent(hwndT) == hDlg) && (hwndT != ppd->hwndTabs))
|
|
WinHelp(hwndT, NULL, HELP_WM_HELP, (DWORD)(LPSTR) aPropHelpIDs);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef WIN31
|
|
|
|
LRESULT CALLBACK Win31PropPageWndProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT result;
|
|
HFONT hFont;
|
|
LRESULT (WINAPI *_DefDlgProc)(HWND, UINT, WPARAM, LPARAM)=NULL;
|
|
(FARPROC)_DefDlgProc = (FARPROC)(MAKELONG((UINT) GetProp(hDlg, g_szLoSubclass),
|
|
(UINT)GetProp(hDlg, g_szHiSubclass)));
|
|
|
|
switch (uMessage)
|
|
{
|
|
case WM_CTLCOLOR:
|
|
result = HANDLE_WM_CTLCOLOR(hDlg,wParam,lParam,Win31OnCtlColor);
|
|
if (result)
|
|
return result;
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return DLGC_RECURSE;
|
|
|
|
case WM_DESTROY:
|
|
// Clean up the non-bold font if we created one
|
|
hFont = GetProp(hDlg, g_szNonBoldFont);
|
|
if (hFont)
|
|
{
|
|
DeleteObject(hFont);
|
|
RemoveProp(hDlg, g_szNonBoldFont);
|
|
}
|
|
|
|
// Clean up subclass
|
|
if( _DefDlgProc )
|
|
{
|
|
RemoveProp(hDlg, g_szLoSubclass);
|
|
RemoveProp(hDlg, g_szHiSubclass);
|
|
// Now put the subclass back.
|
|
SetWindowLong(hDlg, GWL_WNDPROC, (LPARAM)(WNDPROC)(_DefDlgProc));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// return DefDlgProc(hDlg,uMessage,wParam,lParam);
|
|
if( _DefDlgProc )
|
|
return _DefDlgProc(hDlg,uMessage,wParam,lParam);
|
|
else
|
|
return DefDlgProc(hDlg,uMessage,wParam,lParam);
|
|
}
|
|
|
|
|
|
// Win31RepositionDlg( HWND hDlg )
|
|
//
|
|
// Ensures that a dialog lies entirely on the screen, used as a substitute for
|
|
// the DM_REPOSITION message in non Win4.0 environments
|
|
//
|
|
|
|
void NEAR PASCAL Win31RepositionDlg( HWND hDlg )
|
|
{
|
|
RECT rcWindow;
|
|
int dX, dY;
|
|
|
|
// set rcWindow to dimensions of property page
|
|
GetWindowRect( hDlg, &rcWindow );
|
|
|
|
// set dX if dlg needs to be moved to the right
|
|
dX = max( -rcWindow.left, 0 );
|
|
if( dX == 0 ){
|
|
// didn't need to be moved right, maybe we need to move left
|
|
dX = -max( rcWindow.right - (GetSystemMetrics( SM_CXSCREEN ) - 1 ), 0 );
|
|
}
|
|
|
|
// set dY if dlg needs to be moved down
|
|
dY = max( -rcWindow.top, 0 );
|
|
if( dY == 0 ){
|
|
// didn't need to be moved down, maybe we need to move up
|
|
dY = -max( rcWindow.bottom - (GetSystemMetrics( SM_CYSCREEN ) - 1 ), 0 );
|
|
}
|
|
|
|
if( dX != 0 || dY != 0 ) {
|
|
|
|
// we need to move the dialog
|
|
OffsetRect( &rcWindow, dX, dY );
|
|
SetWindowPos( hDlg, NULL, rcWindow.left, rcWindow.top, 0, 0,
|
|
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT NEAR PASCAL Win31OnCtlColor(HWND hDlg, HDC hdcChild, HWND hwndChild, int nCtlType)
|
|
{
|
|
COLORREF clrFore;
|
|
COLORREF clrBack;
|
|
HBRUSH hbrBack;
|
|
|
|
// Set up the supplied DC with the foreground and background
|
|
// colors we want to use in the control, and return a brush
|
|
// to use for filling.
|
|
|
|
switch (nCtlType)
|
|
{
|
|
case CTLCOLOR_STATIC:
|
|
case CTLCOLOR_DLG:
|
|
case CTLCOLOR_MSGBOX:
|
|
clrFore = g_clrWindowText;
|
|
clrBack = g_clrBtnFace;
|
|
hbrBack = g_hbrBtnFace;
|
|
break;
|
|
|
|
case CTLCOLOR_BTN:
|
|
clrFore = g_clrBtnText;
|
|
clrBack = g_clrBtnFace;
|
|
hbrBack = g_hbrBtnFace;
|
|
break;
|
|
|
|
case CTLCOLOR_EDIT:
|
|
if (GetWindowStyle(hwndChild) & ES_READONLY)
|
|
{
|
|
clrFore = g_clrWindowText;
|
|
clrBack = g_clrBtnFace;
|
|
hbrBack = g_hbrBtnFace;
|
|
break;
|
|
}
|
|
// else fall thru to default
|
|
|
|
default:
|
|
// cause defaults to be used
|
|
return (LRESULT)NULL;
|
|
}
|
|
|
|
SetTextColor(hdcChild, clrFore);
|
|
SetBkColor(hdcChild, clrBack);
|
|
return((LRESULT)(DWORD)(WORD)hbrBack);
|
|
}
|
|
|
|
BOOL NEAR PASCAL Win31MakeDlgNonBold(HWND hDlg)
|
|
{
|
|
HFONT hFont;
|
|
LOGFONT LogFont;
|
|
HWND hwndCtl;
|
|
|
|
GetObject(GetWindowFont(hDlg), sizeof(LogFont), &LogFont);
|
|
|
|
// Check if already non-bold
|
|
if (LogFont.lfWeight <= FW_NORMAL)
|
|
return TRUE;
|
|
|
|
// Create the non-bold font
|
|
LogFont.lfWeight = FW_NORMAL;
|
|
if ((hFont = CreateFontIndirect(&LogFont)) == NULL)
|
|
return FALSE;
|
|
|
|
// Save the font as a window prop so we can delete it later
|
|
SetProp(hDlg,g_szNonBoldFont,hFont);
|
|
|
|
// Set all controls non-bold
|
|
for (hwndCtl = GetWindow(hDlg,GW_CHILD);
|
|
hwndCtl != NULL;
|
|
hwndCtl = GetWindow(hwndCtl,GW_HWNDNEXT))
|
|
{
|
|
SetWindowFont(hwndCtl,hFont,FALSE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif // WIN31
|
|
|
|
|
|
int NEAR PASCAL _RealPropertySheet(LPPROPDATA ppd)
|
|
{
|
|
HWND hwndMain;
|
|
MSG32 msg32;
|
|
HWND hwndTopOwner;
|
|
int nReturn = -1;
|
|
HWND hwndOriginalFocus;
|
|
|
|
if (ppd->psh.nPages == 0)
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("no pages for prop sheet"));
|
|
goto FreePpdAndReturn;
|
|
}
|
|
|
|
ppd->hwndCurPage = NULL;
|
|
ppd->nReturn = -1;
|
|
ppd->nRestart = 0;
|
|
ppd->fFlags = FALSE;
|
|
|
|
hwndTopOwner = ppd->psh.hwndParent;
|
|
hwndOriginalFocus = GetFocus();
|
|
|
|
#ifdef DEBUG
|
|
if (GetAsyncKeyState(VK_CONTROL) < 0) {
|
|
|
|
ppd->psh.dwFlags |= PSH_WIZARDHASFINISH;
|
|
}
|
|
#endif
|
|
|
|
if (!(ppd->psh.dwFlags & PSH_MODELESS))
|
|
{
|
|
//
|
|
// Like dialog boxes, we only want to disable top level windows.
|
|
// NB The mail guys would like us to be more like a regular
|
|
// dialog box and disable the parent before putting up the sheet.
|
|
if (hwndTopOwner)
|
|
{
|
|
while (GetWindowLong(hwndTopOwner, GWL_STYLE) & WS_CHILD)
|
|
hwndTopOwner = GetParent(hwndTopOwner);
|
|
|
|
Assert(hwndTopOwner); // Should never get this!
|
|
if ((hwndTopOwner == GetDesktopWindow()) ||
|
|
(EnableWindow(hwndTopOwner, FALSE)))
|
|
{
|
|
//
|
|
// If the window was the desktop window, then don't disable
|
|
// it now and don't reenable it later.
|
|
// Also, if the window was already disabled, then don't
|
|
// enable it later.
|
|
//
|
|
hwndTopOwner = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !defined(WIN32) && !defined(WIN31)
|
|
#ifdef FE_IME
|
|
// Win95d-B#754
|
|
// When PCMCIA gets detected, NETDI calls DiCallClassInstaller().
|
|
// The class installer of setupx calls PropertySheet() for msgsrv32.
|
|
// We usually don't prepare thread link info in imm for that process as
|
|
// it won't use IME normaly but we need to treat this case as special.
|
|
//
|
|
if (!ImmFindThreadLink(GetCurrentThreadID()))
|
|
{
|
|
ImmCreateThreadLink(GetCurrentProcessID(),GetCurrentThreadID());
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if (ppd->psh.pfnCallback)
|
|
{
|
|
HRSRC hrsrc;
|
|
HGLOBAL hglbl;
|
|
LPVOID pTemplate;
|
|
LPVOID pTemplateMod;
|
|
DWORD cbTemplate;
|
|
|
|
// Setup for failure
|
|
hwndMain = NULL;
|
|
|
|
// We need to load the resource and put it into a writeable memory block
|
|
if ((hrsrc = FindResource(HINST_THISDLL,
|
|
MAKEINTRESOURCE((ppd->psh.dwFlags & PSH_WIZARD) ? DLG_WIZARD : DLG_PROPSHEET),
|
|
RT_DIALOG)) &&
|
|
(hglbl = LoadResource(HINST_THISDLL, hrsrc)))
|
|
{
|
|
pTemplate = LockResource(hglbl);
|
|
cbTemplate = SizeofResource(HINST_THISDLL, hrsrc);
|
|
|
|
pTemplateMod = (LPVOID)GlobalAlloc(GPTR, cbTemplate * 2); //double it to give some play leeway
|
|
if (pTemplateMod)
|
|
{
|
|
hmemcpy(pTemplateMod, pTemplate, cbTemplate);
|
|
|
|
ppd->psh.pfnCallback(NULL, PSCB_PRECREATE, (LPARAM)(LPVOID)pTemplateMod);
|
|
|
|
hwndMain = CreateDialogIndirectParam(HINST_THISDLL, pTemplateMod,
|
|
ppd->psh.hwndParent, PropSheetDlgProc, (LPARAM)(LPPROPDATA)ppd);
|
|
|
|
GlobalFreePtr(pTemplateMod);
|
|
}
|
|
UnlockResource(hglbl);
|
|
}
|
|
|
|
}
|
|
else
|
|
hwndMain = CreateDialogParam(HINST_THISDLL,
|
|
MAKEINTRESOURCE((ppd->psh.dwFlags & PSH_WIZARD) ? DLG_WIZARD : DLG_PROPSHEET),
|
|
ppd->psh.hwndParent, PropSheetDlgProc, (LPARAM)(LPPROPDATA)ppd);
|
|
|
|
if (!hwndMain)
|
|
{
|
|
int iPage;
|
|
|
|
DebugMsg(DM_ERROR, TEXT("PropertySheet: unable to create main dialog"));
|
|
|
|
if (hwndTopOwner && !(ppd->psh.dwFlags & PSH_MODELESS))
|
|
EnableWindow(hwndTopOwner, TRUE);
|
|
|
|
// Release all page objects in REVERSE ORDER so we can have
|
|
// pages that are dependant on eachother based on the initial
|
|
// order of those pages
|
|
//
|
|
for (iPage = (int)ppd->psh.nPages - 1; iPage >= 0; iPage--)
|
|
DestroyPropertySheetPage(ppd->psh.phpage[iPage]);
|
|
|
|
goto FreePpdAndReturn;
|
|
}
|
|
|
|
if (ppd->psh.dwFlags & PSH_MODELESS)
|
|
return (int)hwndMain;
|
|
|
|
ShowWindow(hwndMain, SW_SHOW);
|
|
|
|
while( ppd->hwndCurPage && GetMessage32(&msg32, NULL, 0, 0, TRUE) )
|
|
{
|
|
// if (PropSheet_IsDialogMessage(ppd->hDlg, (LPMSG)&msg32))
|
|
if (Prop_IsDialogMessage(ppd, &msg32))
|
|
continue;
|
|
|
|
TranslateMessage32(&msg32, TRUE);
|
|
DispatchMessage32(&msg32, TRUE);
|
|
}
|
|
|
|
if( ppd->hwndCurPage )
|
|
{
|
|
// GetMessage returned FALSE (WM_QUIT)
|
|
DebugMsg( DM_TRACE, TEXT("PropertySheet: bailing in response to WM_QUIT (and reposting quit)") );
|
|
ButtonPushed( ppd, IDCANCEL ); // nuke ourselves
|
|
PostQuitMessage( msg32.wParam ); // repost quit for next enclosing loop
|
|
}
|
|
|
|
// don't let this get mangled during destroy processing
|
|
nReturn = ppd->nReturn ;
|
|
|
|
if (ppd->psh.hwndParent && (GetActiveWindow() == hwndMain)) {
|
|
DebugMsg(DM_TRACE, TEXT("Passing activation up"));
|
|
SetActiveWindow(ppd->psh.hwndParent);
|
|
}
|
|
|
|
if (hwndTopOwner)
|
|
EnableWindow(hwndTopOwner, TRUE);
|
|
|
|
if (IsWindow(hwndOriginalFocus)) {
|
|
SetFocus(hwndOriginalFocus);
|
|
}
|
|
|
|
DestroyWindow(hwndMain);
|
|
|
|
// do pickup any PSM_REBOOTSYSTEM or PSM_RESTARTWINDOWS sent during destroy
|
|
if ((nReturn > 0) && ppd->nRestart)
|
|
nReturn = ppd->nRestart;
|
|
|
|
FreePpdAndReturn:
|
|
|
|
#ifdef WIN32
|
|
LocalFree((HLOCAL)ppd);
|
|
#else
|
|
LocalFree((HLOCAL)LOWORD(ppd));
|
|
#endif
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(WINNT)
|
|
//
|
|
// Description:
|
|
// This function creates a 32-bit proxy page object for 16-bit page object.
|
|
// The PSP_IS16 flag in psp.dwFlags indicates that this is a proxy object.
|
|
//
|
|
// Arguments:
|
|
// hpage16 -- Specifies the handle to 16-bit property sheet page object.
|
|
// hinst16 -- Specifies a handle to FreeLibrary16() when page is deleted.
|
|
//
|
|
//
|
|
HPROPSHEETPAGE WINAPI CreateProxyPage(HPROPSHEETPAGE hpage16, HINSTANCE hinst16)
|
|
{
|
|
HPROPSHEETPAGE hpage = Alloc(sizeof(PSP));
|
|
PROPSHEETPAGE * ppsp = MapSLFix(hpage16);
|
|
|
|
Assert(hpage16 != NULL);
|
|
|
|
if (hpage)
|
|
{
|
|
hpage->psp.dwSize = sizeof(hpage->psp);
|
|
if (ppsp)
|
|
{
|
|
// copy the dwFlags so we can reference PSP_HASHELP from the 32 bit side.
|
|
hpage->psp.dwFlags = ppsp->dwFlags | PSP_IS16;
|
|
}
|
|
else
|
|
{
|
|
hpage->psp.dwFlags = PSP_IS16;
|
|
}
|
|
hpage->psp.lParam = (LPARAM)hpage16;
|
|
hpage->psp.hInstance = hinst16;
|
|
}
|
|
|
|
if (ppsp)
|
|
{
|
|
UnMapSLFixArray(1, &hpage16);
|
|
}
|
|
|
|
return hpage;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(WIN32) && defined(WINNT)
|
|
HPROPSHEETPAGE WINAPI CreateProxyPage(HPROPSHEETPAGE hpage16, HINSTANCE hinst16)
|
|
{
|
|
SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
|
|
//
|
|
// ANSI entry point for PropertySheet when this code
|
|
// is build UNICODE.
|
|
//
|
|
|
|
|
|
int WINAPI PropertySheetA(LPCPROPSHEETHEADERA ppsh)
|
|
{
|
|
LPPROPSHEETHEADERW pPSHW;
|
|
int iResult;
|
|
|
|
if (ppsh->dwSize > sizeof(PROPSHEETHEADERA)) {
|
|
DebugMsg( DM_ERROR, TEXT("PropertySheet: dwSize > sizeof( PROPSHEETHEADER )") );
|
|
return -1;
|
|
}
|
|
|
|
pPSHW = ThunkPropSheetHeaderAtoW (ppsh);
|
|
|
|
if (!pPSHW) {
|
|
return -1;
|
|
}
|
|
|
|
iResult = PropertySheetW(pPSHW);
|
|
|
|
FreePropSheetHeaderW((LPPROPSHEETHEADERW)pPSHW);
|
|
|
|
GlobalFree (pPSHW);
|
|
|
|
return iResult;
|
|
}
|
|
|
|
#else
|
|
|
|
//
|
|
// Stub Unicode function for PropertySheet when this
|
|
// code is built ANSI.
|
|
//
|
|
|
|
int WINAPI PropertySheetW(LPCPROPSHEETHEADERW ppsh)
|
|
{
|
|
SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
|
|
return -1;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
// PropertySheet API
|
|
//
|
|
// This function displays the property sheet described by ppsh.
|
|
//
|
|
// Since I don't expect anyone to ever check the return value
|
|
// (we certainly don't), we need to make sure any provided phpage array
|
|
// is always freed with DestroyPropertySheetPage, even if an error occurs.
|
|
//
|
|
|
|
int WINAPI PropertySheet(LPCPROPSHEETHEADER ppsh)
|
|
{
|
|
PROPDATA NEAR *ppd;
|
|
|
|
//
|
|
// validate header
|
|
//
|
|
if (ppsh->dwSize > sizeof(PROPSHEETHEADER))
|
|
{
|
|
DebugMsg( DM_ERROR, TEXT("PropertySheet: dwSize > sizeof( PROPSHEETHEADER )") );
|
|
goto invalid_call;
|
|
}
|
|
|
|
if (ppsh->dwSize < (sizeof(PROPSHEETHEADER) - sizeof(PFNPROPSHEETCALLBACK)))
|
|
{
|
|
DebugMsg( DM_ERROR, TEXT("PropertySheet: dwSize < sizeof( old PROPSHEETHEADER )") );
|
|
goto invalid_call;
|
|
}
|
|
|
|
if (ppsh->dwFlags & ~PSH_ALL)
|
|
{
|
|
DebugMsg( DM_ERROR, TEXT("PropertySheet: invalid flags") );
|
|
goto invalid_call;
|
|
}
|
|
|
|
// BUGBUG: is this >= for a reason?
|
|
if (ppsh->nPages >= MAXPROPPAGES)
|
|
{
|
|
DebugMsg( DM_ERROR, TEXT("PropertySheet: too many pages ( use MAXPROPPAGES )") );
|
|
goto invalid_call;
|
|
}
|
|
|
|
ppd = (PROPDATA NEAR *)LocalAlloc(LPTR, sizeof(PROPDATA) + MAXPROPPAGES * sizeof(HPROPSHEETPAGE));
|
|
if (ppd == NULL)
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("failed to alloc property page data"));
|
|
|
|
invalid_call:
|
|
if (!(ppsh->dwFlags & PSH_PROPSHEETPAGE))
|
|
{
|
|
int iPage;
|
|
|
|
// Release all page objects in REVERSE ORDER so we can have
|
|
// pages that are dependant on eachother based on the initial
|
|
// order of those pages
|
|
|
|
for (iPage = (int)ppsh->nPages - 1; iPage >= 0; iPage--)
|
|
{
|
|
DestroyPropertySheetPage(ppsh->phpage[iPage]);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// make a copy of the header so we can party on it
|
|
|
|
hmemcpy(&ppd->psh, ppsh, ppsh->dwSize);
|
|
|
|
// so we don't have to check later...
|
|
if (!(ppd->psh.dwFlags & PSH_USECALLBACK))
|
|
ppd->psh.pfnCallback = NULL;
|
|
|
|
// fix up the page pointer to point to our copy of the page array
|
|
|
|
ppd->psh.phpage = (HPROPSHEETPAGE FAR *)((LPBYTE)ppd + sizeof(PROPDATA));
|
|
|
|
if (ppd->psh.dwFlags & PSH_PROPSHEETPAGE)
|
|
{
|
|
// for lazy clients convert PROPSHEETPAGE structures into page handles
|
|
int iPage;
|
|
LPCPROPSHEETPAGE ppsp = ppsh->ppsp;
|
|
|
|
for (iPage = 0; iPage < (int)ppd->psh.nPages; iPage++)
|
|
{
|
|
ppd->psh.phpage[iPage] = CreatePropertySheetPage(ppsp);
|
|
if (!ppd->psh.phpage[iPage])
|
|
{
|
|
iPage--;
|
|
ppd->psh.nPages--;
|
|
}
|
|
ppsp = (LPCPROPSHEETPAGE)((LPBYTE)ppsp + ppsp->dwSize); // next PROPSHEETPAGE structure
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// make a copy of the pages passed in, since we will party here
|
|
hmemcpy(ppd->psh.phpage, ppsh->phpage, sizeof(HPROPSHEETPAGE) * ppsh->nPages);
|
|
}
|
|
//
|
|
// Walk all pages to see if any have help and if so, set the PSH_HASHELP
|
|
// flag in the header.
|
|
//
|
|
if (!(ppd->psh.dwFlags & PSH_HASHELP))
|
|
{
|
|
int iPage;
|
|
for (iPage = 0; iPage < (int)ppd->psh.nPages; iPage++)
|
|
{
|
|
if (ppd->psh.phpage[iPage]->psp.dwFlags & PSP_HASHELP)
|
|
{
|
|
ppd->psh.dwFlags |= PSH_HASHELP;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _RealPropertySheet(ppd);
|
|
}
|
|
|
|
#ifndef WIN32
|
|
#ifndef WIN31
|
|
|
|
// crap to make this run on M7 user for setup
|
|
|
|
LPVOID GetUserProc(UINT ord)
|
|
{
|
|
return (LPVOID)GetProcAddress(GetModuleHandle("USER"), MAKEINTRESOURCE(ord));
|
|
}
|
|
|
|
// GetMessage32 = USER.820
|
|
BOOL WINAPI GetMessage32(LPMSG32 pmsg, HWND hwnd, UINT min, UINT max, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(LPMSG32, HWND, UINT, UINT, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(820);
|
|
|
|
if (pfn)
|
|
return pfn(pmsg, hwnd, min, max, f32);
|
|
else
|
|
return GetMessage((LPMSG)pmsg, hwnd, min, max);
|
|
}
|
|
|
|
// PeekMessage32 = USER.819
|
|
BOOL WINAPI PeekMessage32(LPMSG32 pmsg, HWND hwnd, UINT min, UINT max, UINT flags, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(LPMSG32, HWND, UINT, UINT, UINT, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(819);
|
|
|
|
if (pfn)
|
|
return pfn(pmsg, hwnd, min, max, flags, f32);
|
|
else
|
|
return PeekMessage((LPMSG)pmsg, hwnd, min, max, flags);
|
|
}
|
|
|
|
// TranslateMessage32 = USER.821
|
|
BOOL WINAPI TranslateMessage32(const MSG32 FAR* pmsg, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(const MSG32 FAR*, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(821);
|
|
|
|
if (pfn)
|
|
return pfn(pmsg, f32);
|
|
else
|
|
return TranslateMessage((LPMSG)pmsg);
|
|
}
|
|
|
|
// DispatchMessage32 = USER.822
|
|
LONG WINAPI DispatchMessage32(const MSG32 FAR* pmsg, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(const MSG32 FAR*, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(822);
|
|
|
|
if (pfn)
|
|
return pfn(pmsg, f32);
|
|
else
|
|
return DispatchMessage((LPMSG)pmsg);
|
|
}
|
|
|
|
// CallMsgFilter32 = USER.823
|
|
BOOL WINAPI CallMsgFilter32(LPMSG32 pmsg, int x, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(LPMSG32, int, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(823);
|
|
|
|
if (pfn)
|
|
return pfn(pmsg, x, f32);
|
|
else
|
|
return CallMsgFilter((LPMSG)pmsg, x);
|
|
}
|
|
|
|
// IsDialogMessage32 = USER.824
|
|
BOOL WINAPI IsDialogMessage32(HWND hwnd, LPMSG32 pmsg, BOOL f32)
|
|
{
|
|
static BOOL (WINAPI *pfn)(HWND, LPMSG32, BOOL) = (LPVOID)-1;
|
|
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetUserProc(824);
|
|
|
|
if (pfn)
|
|
return pfn(hwnd, pmsg, f32);
|
|
else
|
|
return IsDialogMessage(hwnd, (LPMSG)pmsg);
|
|
}
|
|
|
|
#ifdef FE_IME
|
|
// To get internal APIs within IMM
|
|
//
|
|
LPVOID GetIMMProc(UINT ord)
|
|
{
|
|
return (LPVOID)GetProcAddress(GetModuleHandle(TEXT("IMM")), MAKEINTRESOURCE(ord));
|
|
}
|
|
PVOID WINAPI ImmFindThreadLink(DWORD dwThreadID)
|
|
{
|
|
static PVOID (WINAPI *pfn)(DWORD) = (LPVOID)-1;
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetIMMProc(140);
|
|
|
|
if(pfn) return pfn(dwThreadID);
|
|
else return NULL;
|
|
}
|
|
BOOL WINAPI ImmCreateThreadLink(DWORD dwPid, DWORD dwTid)
|
|
{
|
|
static BOOL (WINAPI *pfn)(DWORD, DWORD) = (LPVOID)-1;
|
|
if (pfn == (LPVOID)-1)
|
|
pfn = GetIMMProc(33);
|
|
|
|
if(pfn) return pfn(dwPid,dwTid);
|
|
else return FALSE;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
|
|
//*************************************************************
|
|
//
|
|
// ThunkPropSheetHeaderAtoW ()
|
|
//
|
|
// Purpose: Thunks the Ansi version of PROPSHEETHEADER to
|
|
// Unicode.
|
|
//
|
|
//*************************************************************
|
|
|
|
LPPROPSHEETHEADERW ThunkPropSheetHeaderAtoW (LPCPROPSHEETHEADERA pPSHA)
|
|
{
|
|
LPPROPSHEETHEADERW pPSHW;
|
|
LPPROPSHEETPAGEW pPSPW, pTempPSPW;
|
|
LPCPROPSHEETPAGEA pTempPSPA;
|
|
HPROPSHEETPAGE FAR * pPHPageW;
|
|
LPWSTR lpIcon, lpCaption, lpStartPage;
|
|
UINT cbIcon, cbCaption, cbStartPage;
|
|
UINT i, uiSizeDiff;
|
|
|
|
pPSHW = (LPPROPSHEETHEADERW) GlobalAlloc (GPTR, sizeof(PROPSHEETHEADERW));
|
|
|
|
if (!pPSHW) {
|
|
return NULL;
|
|
}
|
|
|
|
pPSHW->dwSize = sizeof (PROPSHEETHEADERW);
|
|
pPSHW->dwFlags = pPSHA->dwFlags;
|
|
pPSHW->hwndParent = pPSHA->hwndParent;
|
|
pPSHW->hInstance = pPSHA->hInstance;
|
|
|
|
if (pPSHA->dwFlags & PSH_USEHICON) {
|
|
pPSHW->hIcon = pPSHA->hIcon;
|
|
}
|
|
|
|
if (pPSHA->dwFlags & PSH_USEICONID) {
|
|
|
|
if (pPSHA->pszIcon) {
|
|
if (HIWORD(pPSHA->pszIcon)) {
|
|
cbIcon = lstrlenA (pPSHA->pszIcon);
|
|
cbIcon++;
|
|
|
|
lpIcon = (LPWSTR) GlobalAlloc(GPTR, cbIcon * sizeof(WCHAR));
|
|
|
|
if (!lpIcon) {
|
|
return NULL;
|
|
}
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSHA->pszIcon, -1,
|
|
lpIcon, cbIcon);
|
|
pPSHW->pszIcon = (LPCWSTR)lpIcon;
|
|
} else {
|
|
pPSHW->pszIcon = (LPCWSTR) pPSHA->pszIcon;
|
|
}
|
|
|
|
} else {
|
|
pPSHW->pszIcon = NULL;
|
|
}
|
|
}
|
|
|
|
if (pPSHA->pszCaption) {
|
|
if (HIWORD(pPSHA->pszCaption)) {
|
|
cbCaption = lstrlenA (pPSHA->pszCaption);
|
|
cbCaption++;
|
|
|
|
lpCaption = (LPWSTR) GlobalAlloc(GPTR, cbCaption * sizeof(WCHAR));
|
|
|
|
if (!lpCaption) {
|
|
GlobalFree ((LPWSTR)pPSHW->pszIcon);
|
|
return NULL;
|
|
}
|
|
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSHA->pszCaption, -1,
|
|
lpCaption, cbCaption);
|
|
pPSHW->pszCaption = (LPCWSTR) lpCaption;
|
|
} else {
|
|
|
|
pPSHW->pszCaption = (LPWSTR)pPSHA->pszCaption;
|
|
}
|
|
|
|
} else {
|
|
pPSHW->pszCaption = NULL;
|
|
}
|
|
|
|
pPSHW->nPages = pPSHA->nPages;
|
|
|
|
if ( !(pPSHA->dwFlags & PSH_USEPSTARTPAGE) ) {
|
|
pPSHW->nStartPage = pPSHA->nStartPage;
|
|
|
|
} else {
|
|
|
|
if (pPSHA->pStartPage) {
|
|
if (HIWORD(pPSHA->pStartPage)) {
|
|
cbStartPage = lstrlenA (pPSHA->pStartPage);
|
|
cbStartPage++;
|
|
|
|
lpStartPage = (LPWSTR) GlobalAlloc(GPTR, cbStartPage * sizeof(WCHAR));
|
|
|
|
if (!lpStartPage) {
|
|
GlobalFree ((LPWSTR)pPSHW->pszCaption);
|
|
GlobalFree ((LPWSTR)pPSHW->pszIcon);
|
|
return NULL;
|
|
}
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSHA->pStartPage, -1,
|
|
lpStartPage, cbStartPage);
|
|
pPSHW->pStartPage = (LPCWSTR)lpStartPage;
|
|
} else {
|
|
pPSHW->pStartPage = (LPCWSTR) pPSHA->pStartPage;
|
|
}
|
|
|
|
} else {
|
|
pPSHW->pStartPage = NULL;
|
|
}
|
|
}
|
|
|
|
if ((pPSHA->dwFlags & PSH_PROPSHEETPAGE) && pPSHA->ppsp) {
|
|
|
|
if (pPSHA->ppsp->dwSize < sizeof(PROPSHEETPAGEA)) {
|
|
uiSizeDiff = 0;
|
|
} else {
|
|
uiSizeDiff = pPSHA->ppsp->dwSize - sizeof(PROPSHEETPAGEA);
|
|
}
|
|
pPSPW = (LPPROPSHEETPAGEW) GlobalAlloc (GPTR,
|
|
((sizeof(PROPSHEETPAGEW) + uiSizeDiff) *
|
|
pPSHA->nPages));
|
|
|
|
if (!pPSPW) {
|
|
GlobalFree ((LPWSTR)pPSHW->pStartPage);
|
|
GlobalFree ((LPWSTR)pPSHW->pszCaption);
|
|
GlobalFree ((LPWSTR)pPSHW->pszIcon);
|
|
return NULL;
|
|
}
|
|
|
|
pTempPSPW = pPSPW;
|
|
pTempPSPA = pPSHA->ppsp;
|
|
|
|
for (i=0; i < pPSHA->nPages; i++) {
|
|
if (!ThunkPropertyPageAtoW (pTempPSPA, pTempPSPW)) {
|
|
GlobalFree (pPSPW);
|
|
GlobalFree ((LPWSTR)pPSHW->pStartPage);
|
|
GlobalFree ((LPWSTR)pPSHW->pszCaption);
|
|
GlobalFree ((LPWSTR)pPSHW->pszIcon);
|
|
return NULL;
|
|
}
|
|
|
|
pTempPSPW->dwFlags |= PSP_ANSI;
|
|
pTempPSPW = (LPPROPSHEETPAGEW)((LPBYTE)pTempPSPW + pTempPSPW->dwSize);
|
|
pTempPSPA = (LPCPROPSHEETPAGEA)((LPBYTE)pTempPSPA + pTempPSPA->dwSize);
|
|
|
|
}
|
|
|
|
pPSHW->ppsp = (LPCPROPSHEETPAGE) pPSPW;
|
|
|
|
}
|
|
|
|
if ( (!(pPSHA->dwFlags & PSH_PROPSHEETPAGE)) && pPSHA->phpage) {
|
|
pPHPageW = (HPROPSHEETPAGE FAR *) GlobalAlloc (GPTR,
|
|
(sizeof(HPROPSHEETPAGE) * pPSHA->nPages));
|
|
|
|
if (!pPHPageW) {
|
|
GlobalFree ((LPWSTR)pPSHW->ppsp);
|
|
GlobalFree ((LPWSTR)pPSHW->pStartPage);
|
|
GlobalFree ((LPWSTR)pPSHW->pszCaption);
|
|
GlobalFree ((LPWSTR)pPSHW->pszIcon);
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; i < pPSHA->nPages; i++) {
|
|
pPHPageW[i] = pPSHA->phpage[i];
|
|
}
|
|
|
|
pPSHW->phpage = pPHPageW;
|
|
|
|
}
|
|
|
|
pPSHW->pfnCallback = (PFNPROPSHEETCALLBACK) pPSHA->pfnCallback;
|
|
|
|
return pPSHW;
|
|
}
|
|
|
|
|
|
BOOL ThunkPropertyPageAtoW (LPCPROPSHEETPAGEA pPSPA, LPPROPSHEETPAGEW pPSPW)
|
|
{
|
|
LPWSTR lpTemplate, lpIcon, lpTitle;
|
|
UINT cbTemplate, cbIcon, cbTitle, uiExtraData;
|
|
LPVOID lpExtraDataA, lpExtraDataW;
|
|
|
|
if (pPSPA->dwSize < sizeof(PROPSHEETPAGEA)) {
|
|
DebugMsg( DM_ERROR, TEXT("ThunkPropertySheetPageAtoW: PSP.dwSize < sizeof( PROPSHEETPAGEA )") );
|
|
return FALSE;
|
|
}
|
|
|
|
uiExtraData = pPSPA->dwSize - sizeof(PROPSHEETPAGEA);
|
|
pPSPW->dwSize = sizeof (PROPSHEETPAGEW) + uiExtraData;
|
|
pPSPW->dwFlags = pPSPA->dwFlags;
|
|
pPSPW->hInstance = pPSPA->hInstance;
|
|
|
|
if ( !(pPSPA->dwFlags & PSP_DLGINDIRECT) ) {
|
|
|
|
if (pPSPA->pszTemplate) {
|
|
if (HIWORD(pPSPA->pszTemplate)) {
|
|
cbTemplate = lstrlenA (pPSPA->pszTemplate);
|
|
cbTemplate++;
|
|
|
|
lpTemplate = (LPWSTR) GlobalAlloc(GPTR, cbTemplate * sizeof(WCHAR));
|
|
|
|
if (!lpTemplate) {
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSPA->pszTemplate, -1,
|
|
lpTemplate, cbTemplate);
|
|
pPSPW->pszTemplate = (LPCWSTR)lpTemplate;
|
|
} else {
|
|
pPSPW->pszTemplate = (LPCWSTR) pPSPA->pszTemplate;
|
|
}
|
|
|
|
} else {
|
|
pPSPW->pszTemplate = NULL;
|
|
}
|
|
} else {
|
|
|
|
pPSPW->pResource = pPSPA->pResource;
|
|
}
|
|
|
|
if (pPSPA->dwFlags & PSP_USEHICON) {
|
|
pPSPW->hIcon = pPSPA->hIcon;
|
|
|
|
} else {
|
|
|
|
if ( (pPSPA->dwFlags & PSP_USEICONID) && pPSPA->pszIcon) {
|
|
if (HIWORD(pPSPA->pszIcon)) {
|
|
cbIcon = lstrlenA (pPSPA->pszIcon);
|
|
cbIcon++;
|
|
|
|
lpIcon = (LPWSTR) GlobalAlloc(GPTR, cbIcon * sizeof(WCHAR));
|
|
|
|
if (!lpIcon) {
|
|
GlobalFree ((LPWSTR)pPSPW->pszTemplate);
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSPA->pszIcon, -1,
|
|
lpIcon, cbIcon);
|
|
pPSPW->pszIcon = (LPCWSTR)lpIcon;
|
|
} else {
|
|
pPSPW->pszIcon = (LPCWSTR) pPSPA->pszIcon;
|
|
}
|
|
|
|
} else {
|
|
pPSPW->pszIcon = NULL;
|
|
}
|
|
}
|
|
|
|
if ( (pPSPA->dwFlags & PSP_USETITLE) && pPSPA->pszTitle) {
|
|
if (HIWORD(pPSPA->pszTitle)) {
|
|
cbTitle = lstrlenA (pPSPA->pszTitle);
|
|
cbTitle++;
|
|
|
|
lpTitle = (LPWSTR) GlobalAlloc(GPTR, cbTitle * sizeof(WCHAR));
|
|
|
|
if (!lpTitle) {
|
|
GlobalFree ((LPWSTR)pPSPW->pszTemplate);
|
|
GlobalFree ((LPWSTR)pPSPW->pszIcon);
|
|
return FALSE;
|
|
}
|
|
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, pPSPA->pszTitle, -1,
|
|
lpTitle, cbTitle);
|
|
pPSPW->pszTitle = (LPCWSTR) lpTitle;
|
|
} else {
|
|
|
|
pPSPW->pszTitle = (LPWSTR)pPSPA->pszTitle;
|
|
}
|
|
|
|
} else {
|
|
pPSPW->pszTitle = NULL;
|
|
}
|
|
|
|
pPSPW->pfnDlgProc = pPSPA->pfnDlgProc;
|
|
pPSPW->lParam = pPSPA->lParam;
|
|
pPSPW->pfnCallback = (LPFNPSPCALLBACKW) pPSPA->pfnCallback;
|
|
pPSPW->pcRefParent = pPSPA->pcRefParent;
|
|
|
|
//
|
|
// If there is some extra data,
|
|
// then set up the pointers and copy it
|
|
// straight across.
|
|
//
|
|
|
|
if (uiExtraData) {
|
|
lpExtraDataA = (LPVOID)((LPBYTE)pPSPA + sizeof(PROPSHEETPAGEA));
|
|
lpExtraDataW = (LPVOID)((LPBYTE)pPSPW + sizeof(PROPSHEETPAGEW));
|
|
hmemcpy(lpExtraDataW, lpExtraDataA, uiExtraData);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ThunkPropertyPageWtoA (LPCPROPSHEETPAGEW pPSPW, LPPROPSHEETPAGEA pPSPA)
|
|
{
|
|
LPSTR lpTemplate, lpIcon, lpTitle;
|
|
UINT cbTemplate, cbIcon, cbTitle, uiExtraData;
|
|
LPVOID lpExtraDataA, lpExtraDataW;
|
|
|
|
if (pPSPW->dwSize < sizeof(PROPSHEETPAGEW)) {
|
|
DebugMsg( DM_ERROR, TEXT("ThunkPropertySheetPageWtoA: PSP.dwSize < sizeof( PROPSHEETPAGEW )") );
|
|
return FALSE;
|
|
}
|
|
|
|
uiExtraData = pPSPW->dwSize - sizeof(PROPSHEETPAGEW);
|
|
pPSPA->dwSize = sizeof (PROPSHEETPAGEA) + uiExtraData;;
|
|
pPSPA->dwFlags = pPSPW->dwFlags;
|
|
pPSPA->hInstance = pPSPW->hInstance;
|
|
|
|
if ( !(pPSPW->dwFlags & PSP_DLGINDIRECT) ) {
|
|
|
|
if (pPSPW->pszTemplate) {
|
|
if (HIWORD(pPSPW->pszTemplate)) {
|
|
|
|
cbTemplate = lstrlenW (pPSPW->pszTemplate);
|
|
cbTemplate++;
|
|
|
|
lpTemplate = (LPSTR) GlobalAlloc(GPTR, cbTemplate * sizeof(CHAR));
|
|
|
|
if (!lpTemplate) {
|
|
return FALSE;
|
|
}
|
|
WideCharToMultiByte (CP_ACP, 0, pPSPW->pszTemplate, -1,
|
|
lpTemplate, cbTemplate, NULL, NULL);
|
|
|
|
pPSPA->pszTemplate = (LPCSTR)lpTemplate;
|
|
} else {
|
|
pPSPA->pszTemplate = (LPCSTR) pPSPW->pszTemplate;
|
|
}
|
|
|
|
} else {
|
|
pPSPA->pszTemplate = NULL;
|
|
}
|
|
} else {
|
|
|
|
pPSPA->pResource = pPSPW->pResource;
|
|
}
|
|
|
|
if (pPSPW->dwFlags & PSP_USEHICON) {
|
|
pPSPA->hIcon = pPSPW->hIcon;
|
|
|
|
} else {
|
|
|
|
if ( (pPSPW->dwFlags & PSP_USEICONID) && pPSPW->pszIcon) {
|
|
if (HIWORD(pPSPW->pszIcon)) {
|
|
cbIcon = lstrlenW (pPSPW->pszIcon);
|
|
cbIcon++;
|
|
|
|
lpIcon = (LPSTR) GlobalAlloc(GPTR, cbIcon * sizeof(CHAR));
|
|
|
|
if (!lpIcon) {
|
|
GlobalFree ((LPSTR)pPSPA->pszTemplate);
|
|
return FALSE;
|
|
}
|
|
WideCharToMultiByte (CP_ACP, 0, pPSPW->pszIcon, -1,
|
|
lpIcon, cbIcon, NULL, NULL);
|
|
pPSPA->pszIcon = (LPCSTR)lpIcon;
|
|
} else {
|
|
pPSPA->pszIcon = (LPCSTR) pPSPW->pszIcon;
|
|
}
|
|
|
|
} else {
|
|
pPSPA->pszIcon = NULL;
|
|
}
|
|
}
|
|
|
|
if ( (pPSPW->dwFlags & PSP_USETITLE) && pPSPW->pszTitle) {
|
|
if (HIWORD(pPSPW->pszTitle)) {
|
|
|
|
cbTitle = lstrlenW ((LPWSTR) pPSPW->pszTitle);
|
|
cbTitle++;
|
|
|
|
lpTitle = (LPSTR) GlobalAlloc(GPTR, cbTitle * sizeof(CHAR));
|
|
|
|
if (!lpTitle) {
|
|
GlobalFree ((LPSTR)pPSPA->pszTemplate);
|
|
GlobalFree ((LPSTR)pPSPA->pszIcon);
|
|
return FALSE;
|
|
}
|
|
|
|
WideCharToMultiByte (CP_ACP, 0, (LPWSTR) pPSPW->pszTitle, -1,
|
|
lpTitle, cbTitle, NULL, NULL);
|
|
pPSPA->pszTitle = (LPCSTR) lpTitle;
|
|
|
|
} else {
|
|
pPSPA->pszTitle = (LPCSTR)pPSPW->pszTitle;
|
|
}
|
|
|
|
} else {
|
|
pPSPA->pszTitle = NULL;
|
|
}
|
|
|
|
pPSPA->pfnDlgProc = pPSPW->pfnDlgProc;
|
|
pPSPA->lParam = pPSPW->lParam;
|
|
pPSPA->pfnCallback = (LPFNPSPCALLBACKA) pPSPW->pfnCallback;
|
|
pPSPA->pcRefParent = pPSPW->pcRefParent;
|
|
|
|
//
|
|
// If there is some extra data,
|
|
// then set up the pointers and copy it
|
|
// straight across.
|
|
//
|
|
|
|
if (uiExtraData) {
|
|
lpExtraDataW = (LPVOID)((LPBYTE)pPSPW + sizeof(PROPSHEETPAGEW));
|
|
lpExtraDataA = (LPVOID)((LPBYTE)pPSPA + sizeof(PROPSHEETPAGEA));
|
|
hmemcpy(lpExtraDataA, lpExtraDataW, uiExtraData);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL FreePropSheetHeaderW (LPPROPSHEETHEADERW pPSHW)
|
|
{
|
|
LPPROPSHEETPAGEW pTempPSPW;
|
|
UINT i;
|
|
|
|
if (!pPSHW) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pPSHW->dwFlags & PSH_USEICONID) {
|
|
if (pPSHW->pszIcon) {
|
|
if (HIWORD(pPSHW->pszIcon)) {
|
|
GlobalFree((LPWSTR)pPSHW->pszIcon);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pPSHW->pszCaption && HIWORD(pPSHW->pszCaption)) {
|
|
GlobalFree ((LPWSTR)pPSHW->pszCaption);
|
|
}
|
|
|
|
|
|
if (pPSHW->dwFlags & PSH_USEPSTARTPAGE) {
|
|
if (pPSHW->pStartPage) {
|
|
if (HIWORD(pPSHW->pStartPage)) {
|
|
GlobalFree ((LPWSTR)pPSHW->pStartPage);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((pPSHW->dwFlags & PSH_PROPSHEETPAGE) && pPSHW->ppsp) {
|
|
|
|
pTempPSPW = (LPPROPSHEETPAGEW)pPSHW->ppsp;
|
|
|
|
for (i=0; i < pPSHW->nPages; i++) {
|
|
FreePropertyPageW ((PROPSHEETPAGE FAR *)pTempPSPW, FALSE);
|
|
pTempPSPW ++;
|
|
}
|
|
|
|
|
|
GlobalFree ((LPBYTE)pPSHW->ppsp);
|
|
}
|
|
|
|
if ( (!(pPSHW->dwFlags & PSH_PROPSHEETPAGE)) && pPSHW->phpage) {
|
|
GlobalFree ((LPBYTE)pPSHW->phpage);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FreePropertyPageW (LPPROPSHEETPAGEW pPSPW, BOOL bFromHPage)
|
|
{
|
|
|
|
if (!pPSPW) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !(pPSPW->dwFlags & PSP_DLGINDIRECT) ) {
|
|
|
|
if (pPSPW->pszTemplate) {
|
|
if (HIWORD(pPSPW->pszTemplate)) {
|
|
GlobalFree ((LPWSTR)pPSPW->pszTemplate);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (pPSPW->dwFlags & PSP_USEICONID) && pPSPW->pszIcon) {
|
|
if (HIWORD(pPSPW->pszIcon)) {
|
|
GlobalFree ((LPWSTR)pPSPW->pszIcon);
|
|
}
|
|
}
|
|
|
|
|
|
if ( !bFromHPage && (pPSPW->dwFlags & PSP_USETITLE) &&
|
|
pPSPW->pszTitle && HIWORD(pPSPW->pszTitle)) {
|
|
|
|
GlobalFree ((LPWSTR)pPSPW->pszTitle);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FreePropertyPageA (LPPROPSHEETPAGEA pPSPA)
|
|
{
|
|
|
|
if (!pPSPA) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !(pPSPA->dwFlags & PSP_DLGINDIRECT) ) {
|
|
|
|
if (pPSPA->pszTemplate) {
|
|
if (HIWORD(pPSPA->pszTemplate)) {
|
|
GlobalFree ((LPSTR)pPSPA->pszTemplate);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (pPSPA->dwFlags & PSP_USEICONID) && pPSPA->pszIcon) {
|
|
if (HIWORD(pPSPA->pszIcon)) {
|
|
GlobalFree ((LPSTR)pPSPA->pszIcon);
|
|
}
|
|
}
|
|
|
|
|
|
if ( (pPSPA->dwFlags & PSP_USETITLE) && pPSPA->pszTitle &&
|
|
HIWORD(pPSPA->pszTitle)) {
|
|
GlobalFree ((LPSTR)pPSPA->pszTitle);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#ifndef WINNT
|
|
|
|
typedef LPARAM HPROPSHEETPAGE16;
|
|
|
|
extern BOOL WINAPI GetPageInfo16(HPROPSHEETPAGE16 hpage, LPTSTR pszCaption, int cbCaption, LPPOINT ppt, HICON FAR * phIcon);
|
|
extern BOOL WINAPI GetPageInfoME(HPROPSHEETPAGE16 hpage, LPTSTR pszCaption, int cbCaption, LPPOINT ppt, HICON FAR * phIcon, BOOL FAR* bRTL);
|
|
|
|
BOOL WINAPI _GetPageInfo16(HPROPSHEETPAGE16 hpage, LPTSTR pszCaption, int cbCaption, LPPOINT ppt, HICON FAR *hIcon, BOOL FAR * bRTL)
|
|
{
|
|
|
|
// HACKHACK: after win95 shipped, the thunk was changed for this api on
|
|
// ME platforms. so we have to detect the two cases and call them differently.
|
|
if (g_fMEEnabled) {
|
|
return GetPageInfoME(hpage, pszCaption, cbCaption, ppt, hIcon, bRTL);
|
|
} else {
|
|
if (bRTL)
|
|
*bRTL = 0;
|
|
return GetPageInfo16(hpage, pszCaption, cbCaption, ppt, hIcon);
|
|
}
|
|
}
|
|
|
|
#endif
|