windows-nt/Source/XPSP1/NT/shell/ext/brfcase/filesync/syncui/misc.c

1324 lines
35 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1993-1994
//
// File: misc.c
//
// This file contains miscellaneous dialog code
//
// History:
// 08-06-93 ScottH Transferred from twin code
//
//---------------------------------------------------------------------------
#include "brfprv.h" // common headers
#include "res.h"
typedef struct _MB_BUTTONS
{
UINT id; // id
UINT ids; // string ID
} MB_BUTTONS, * PMB_BUTTONS;
typedef struct _BTNSTYLE
{
UINT cButtons;
MB_BUTTONS rgmbb[4];
} BTNSTYLE;
//---------------------------------------------------------------------------
// Control manipulation stuff
//---------------------------------------------------------------------------
// Flags for SNAPCTL
#define SCF_ANCHOR 0x0001
#define SCF_VCENTER 0x0002
#define SCF_BOTTOM 0x0004
#define SCF_TOP 0x0008
#define SCF_SNAPLEFT 0x0010
#define SCF_SNAPRIGHT 0x0020
typedef struct tagSNAPCTL
{
UINT idc;
UINT uFlags;
} SNAPCTL, * PSNAPCTL;
/*----------------------------------------------------------
Purpose: Moves a control
Returns: HDWP
Cond: --
*/
HDWP PRIVATE SlideControlPos(
HDWP hdwp,
HWND hDlg,
UINT idc,
int cx,
int cy)
{
HWND hwndPos = GetDlgItem(hDlg, idc);
RECT rcPos;
GetWindowRect(hwndPos, &rcPos);
MapWindowRect(HWND_DESKTOP, hDlg, &rcPos);
return DeferWindowPos(hdwp, hwndPos, NULL,
rcPos.left + cx, rcPos.top + cy,
0, 0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
}
/*----------------------------------------------------------
Purpose: Aligns a list of controls, relative to an "anchor"
control.
Only one anchor control is supported; the first control
designated as anchor in the list is selected.
Returns: --
Cond: --
*/
void PRIVATE SnapControls(
HWND hwnd,
SNAPCTL const * psnap,
UINT csnap)
{
HWND hwndAnchor;
UINT i;
SNAPCTL const * psnapStart = psnap;
HDWP hdwp;
RECT rcAnchor;
int yCenter;
ASSERT(psnap);
// Find the anchor control
for (i = 0; i < csnap; i++, psnap++)
{
if (IsFlagSet(psnap->uFlags, SCF_ANCHOR))
{
hwndAnchor = GetDlgItem(hwnd, psnap->idc);
break;
}
}
if (i == csnap)
return; // No anchor control!
GetWindowRect(hwndAnchor, &rcAnchor);
yCenter = rcAnchor.top + (rcAnchor.bottom - rcAnchor.top)/2;
hdwp = BeginDeferWindowPos(csnap-1);
if (hdwp)
{
RECT rc;
UINT uFlags;
HWND hwndPos;
for (i = 0, psnap = psnapStart; i < csnap; i++, psnap++)
{
uFlags = psnap->uFlags;
if (IsFlagSet(uFlags, SCF_ANCHOR))
continue; // skip anchor
hwndPos = GetDlgItem(hwnd, psnap->idc);
GetWindowRect(hwndPos, &rc);
if (IsFlagSet(uFlags, SCF_VCENTER))
{
// Vertically match the center of this control with
// the center of the anchor
rc.top += yCenter - (rc.top + (rc.bottom - rc.top)/2);
}
else if (IsFlagSet(uFlags, SCF_TOP))
{
// Vertically match the top of this control with
// the top of the anchor
rc.top += rcAnchor.top - rc.top;
}
else if (IsFlagSet(uFlags, SCF_BOTTOM))
{
// Vertically match the bottom of this control with
// the bottom of the anchor
rc.top += rcAnchor.bottom - rc.bottom;
}
if (IsFlagSet(uFlags, SCF_SNAPLEFT))
{
// Snap the control so it is abut to the left side
// of the anchor control
rc.left += rcAnchor.left - rc.right;
}
else if (IsFlagSet(uFlags, SCF_SNAPRIGHT))
{
// Snap the control so it is abut to the right side
// of the anchor control
rc.left += rcAnchor.right - rc.left;
}
// Move control
MapWindowRect(HWND_DESKTOP, hwnd, &rc);
hdwp = DeferWindowPos(hdwp, hwndPos, NULL,
rc.left, rc.top, 0, 0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
}
EndDeferWindowPos(hdwp);
}
}
//---------------------------------------------------------------------------
// Abort event stuff
//---------------------------------------------------------------------------
/*----------------------------------------------------------
Purpose: Creates an abort event.
Returns: TRUE on success
Cond: --
*/
BOOL PUBLIC AbortEvt_Create(
PABORTEVT * ppabortevt,
UINT uFlags)
{
PABORTEVT this;
ASSERT(ppabortevt);
if (IsFlagSet(uFlags, AEF_SHARED))
this = SharedAllocType(ABORTEVT);
else
this = GAllocType(ABORTEVT);
if (this)
{
this->uFlags = uFlags;
}
*ppabortevt = this;
return NULL != this;
}
/*----------------------------------------------------------
Purpose: Destroys an abort event.
Returns: --
Cond: --
*/
void PUBLIC AbortEvt_Free(
PABORTEVT this)
{
if (this)
{
if (IsFlagSet(this->uFlags, AEF_SHARED))
SharedFree(&this);
else
GFree(this);
}
}
/*----------------------------------------------------------
Purpose: Sets the abort event.
Returns: Returns the previous abort event.
Cond: --
*/
BOOL PUBLIC AbortEvt_Set(
PABORTEVT this,
BOOL bAbort)
{
BOOL bRet;
if (this)
{
bRet = IsFlagSet(this->uFlags, AEF_ABORT);
if (bAbort)
{
TRACE_MSG(TF_GENERAL, TEXT("Setting abort event"));
SetFlag(this->uFlags, AEF_ABORT);
}
else
{
TRACE_MSG(TF_GENERAL, TEXT("Clearing abort event"));
ClearFlag(this->uFlags, AEF_ABORT);
}
}
else
bRet = FALSE;
return bRet;
}
/*----------------------------------------------------------
Purpose: Queries the abort event
Returns: the current abort event (TRUE or FALSE)
Cond: --
*/
BOOL PUBLIC AbortEvt_Query(
PABORTEVT this)
{
BOOL bRet;
if (this)
{
bRet = IsFlagSet(this->uFlags, AEF_ABORT);
#ifdef DEBUG
if (bRet)
TRACE_MSG(TF_GENERAL, TEXT("Abort is set!"));
#endif
}
else
bRet = FALSE;
return bRet;
}
//---------------------------------------------------------------------------
// Progress bar stuff
//---------------------------------------------------------------------------
#define MSECS_PER_SEC 1000
#define WM_QUERYABORT (WM_APP + 1)
/*----------------------------------------------------------
Purpose: Progress dialog during reconciliations
Returns: varies
Cond: --
*/
INT_PTR CALLBACK UpdateProgressProc(
HWND hDlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
PUPDBAR this = (PUPDBAR)GetWindowLongPtr(hDlg, DWLP_USER);
switch (wMsg)
{
case WM_INITDIALOG:
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
this = (PUPDBAR)lParam;
if (IsFlagSet(this->uFlags, UB_NOCANCEL))
{
ShowWindow(GetDlgItem(hDlg, IDCANCEL), SW_HIDE);
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
}
break;
case WM_COMMAND:
switch (wParam)
{
case IDCANCEL:
AbortEvt_Set(this->pabortevt, TRUE);
break;
}
break;
case WM_QUERYABORT:
if (GetTickCount() >= this->dwTickShow &&
0 != this->dwTickShow)
{
if (this->hcurSav)
{
SetCursor(this->hcurSav);
this->hcurSav = NULL;
}
ShowWindow(hDlg, SW_SHOW);
UpdateWindow(hDlg);
this->dwTickShow = 0;
}
break;
default:
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------
Purpose: Displays the update progress bar dialog
Returns: dialog handle to a modeless dialog
NULL if dialog couldn't be created
Cond: Call UpdBar_Kill when finished
*/
HWND PUBLIC UpdBar_Show(
HWND hwndParent,
UINT uFlags, // UB_*
UINT nSecs) // Valid only if UB_TIMER set
{
HWND hdlg = NULL;
PUPDBAR this;
// Create and show the progress dialog
//
this = GAlloc(sizeof(*this));
if (this)
{
// (It is okay if this fails--it just means we ignore the Cancel button)
AbortEvt_Create(&this->pabortevt, AEF_DEFAULT);
this->hwndParent = hwndParent;
this->uFlags = uFlags;
hdlg = CreateDialogParam(g_hinst, MAKEINTRESOURCE(IDD_PROGRESS),
hwndParent, UpdateProgressProc, (LPARAM)(PUPDBAR)this);
if (!hdlg)
{
GFree(this);
}
else
{
UpdBar_SetAvi(hdlg, uFlags);
if (IsFlagClear(uFlags, UB_NOSHOW))
EnableWindow(hwndParent, FALSE);
if (IsFlagSet(uFlags, UB_TIMER))
{
this->dwTickShow = GetTickCount() + (nSecs * MSECS_PER_SEC);
this->hcurSav = SetCursorRemoveWigglies(LoadCursor(NULL, IDC_WAIT));
}
else
{
this->dwTickShow = 0;
this->hcurSav = NULL;
if (IsFlagClear(uFlags, UB_NOSHOW))
{
ShowWindow(hdlg, SW_SHOW);
UpdateWindow(hdlg);
}
}
}
}
return hdlg;
}
/*----------------------------------------------------------
Purpose: Destroy the update progress bar
Returns: --
Cond: --
*/
void PUBLIC UpdBar_Kill(
HWND hdlg)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
PUPDBAR this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
ASSERT(this);
if (this)
{
if (this->hcurSav)
SetCursor(this->hcurSav);
if (IsWindow(this->hwndParent))
EnableWindow(this->hwndParent, TRUE);
GFree(this);
}
DestroyWindow(hdlg);
}
}
/*----------------------------------------------------------
Purpose: Set the progress bar range. Reset the position to 0
Returns: --
Cond: --
*/
void PUBLIC UpdBar_SetRange(
HWND hdlg,
WORD wRangeMax)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELONG(0, wRangeMax));
}
}
/*----------------------------------------------------------
Purpose: Increment the position of progress bar
Returns: --
Cond: --
*/
void PUBLIC UpdBar_DeltaPos(
HWND hdlg,
WORD wdelta)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_DELTAPOS, wdelta, 0);
}
}
/*----------------------------------------------------------
Purpose: Set the position of progress bar
Returns: --
Cond: --
*/
void PUBLIC UpdBar_SetPos(
HWND hdlg,
WORD wPos)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
SendDlgItemMessage(hdlg, IDC_PROGRESS, PBM_SETPOS, wPos, 0);
}
}
/*----------------------------------------------------------
Purpose: Set the current name we're updating in the progress
bar.
Returns: --
Cond: --
*/
void PUBLIC UpdBar_SetName(
HWND hdlg,
LPCTSTR pszName)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
HWND hwndName = GetDlgItem(hdlg, IDC_NAME);
Static_SetText(hwndName, pszName);
}
}
/*----------------------------------------------------------
Purpose: Set the current name we're updating in the progress
bar.
Returns: --
Cond: --
*/
void PUBLIC UpdBar_SetDescription(
HWND hdlg,
LPCTSTR psz)
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
HWND hwndName = GetDlgItem(hdlg, IDC_TONAME);
Static_SetText(hwndName, psz);
}
}
/*----------------------------------------------------------
Purpose: Get the window handle of the progress status text.
Returns: --
Cond: --
*/
HWND PUBLIC UpdBar_GetStatusWindow(
HWND hdlg)
{
HWND hwnd;
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
hwnd = GetDlgItem(hdlg, IDC_TEXT);
else
hwnd = NULL;
return hwnd;
}
/*----------------------------------------------------------
Purpose: Returns a pointer to the abort event owned by this
progress window.
Returns: pointer to abort event or NULL
Cond: --
*/
PABORTEVT PUBLIC UpdBar_GetAbortEvt(
HWND hdlg)
{
PABORTEVT pabortevt = NULL;
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
PUPDBAR this;
this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
if (this)
{
pabortevt = this->pabortevt;
}
}
return pabortevt;
}
/*----------------------------------------------------------
Purpose: Sets the animate control to play the avi file designated
by the UB_ flags
Returns: --
Cond: --
*/
void PUBLIC UpdBar_SetAvi(
HWND hdlg,
UINT uFlags) // UB_*
{
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
UINT ida;
UINT ids;
HWND hwndAvi = GetDlgItem(hdlg, IDC_ANIMATE);
TCHAR sz[MAXBUFLEN];
RECT rc;
if (IsFlagClear(uFlags, UB_NOSHOW))
{
SetWindowRedraw(hdlg, FALSE);
// Is the window visible yet?
if (IsFlagSet(GetWindowLong(hdlg, GWL_STYLE), WS_VISIBLE))
{
// Yes; select just the upper area of the progress bar to
// repaint
int cy;
GetWindowRect(GetDlgItem(hdlg, IDC_NAME), &rc);
MapWindowPoints(HWND_DESKTOP, hdlg, (LPPOINT)&rc, 1);
cy = rc.top;
GetClientRect(hdlg, &rc);
rc.bottom = cy;
}
else
{
// No
GetWindowRect(hdlg, &rc);
MapWindowPoints(HWND_DESKTOP, hdlg, (LPPOINT)&rc, 2);
}
}
if (IsFlagSet(uFlags, UB_NOPROGRESS))
{
ShowWindow(GetDlgItem(hdlg, IDC_PROGRESS), SW_HIDE);
}
else
{
ShowWindow(GetDlgItem(hdlg, IDC_PROGRESS), SW_SHOW);
}
// Special text when checking?
if (IsFlagSet(uFlags, UB_CHECKAVI))
{
// Yes
SetDlgItemText(hdlg, IDC_TONAME, SzFromIDS(IDS_MSG_CHECKING, sz, ARRAYSIZE(sz)));
}
else
{
// No
SetDlgItemText(hdlg, IDC_TONAME, TEXT(""));
}
// Run AVI?
if (uFlags & (UB_CHECKAVI | UB_UPDATEAVI))
{
// Yes
static const SNAPCTL rgsnap[] = {
{ IDC_ICON1, SCF_BOTTOM | SCF_SNAPLEFT },
{ IDC_ANIMATE, SCF_ANCHOR },
{ IDC_ICON2, SCF_BOTTOM | SCF_SNAPRIGHT },
};
if (IsFlagSet(uFlags, UB_CHECKAVI))
{
ida = IDA_CHECK;
ids = IDS_CAP_CHECKING;
}
else if (IsFlagSet(uFlags, UB_UPDATEAVI))
{
ida = IDA_UPDATE;
ids = IDS_CAP_UPDATING;
}
else
ASSERT(0);
SetWindowText(hdlg, SzFromIDS(ids, sz, ARRAYSIZE(sz)));
Animate_Open(hwndAvi, MAKEINTRESOURCE(ida));
// Snap the icons on either side to the animation
// control
SnapControls(hdlg, rgsnap, ARRAYSIZE(rgsnap));
Animate_Play(hwndAvi, 0, -1, -1);
}
// Don't bother setting the redraw if we're never going to show
// the progress bar
if (IsFlagClear(uFlags, UB_NOSHOW))
{
SetWindowRedraw(hdlg, TRUE);
InvalidateRect(hdlg, &rc, TRUE);
UpdateWindow(hdlg);
}
}
}
/*----------------------------------------------------------
Purpose: Yield, and check if user aborted
Returns: TRUE to abort
FALSE to continue
Cond: --
*/
BOOL PUBLIC UpdBar_QueryAbort(
HWND hdlg)
{
BOOL bAbort = FALSE;
ASSERT(IsWindow(hdlg));
if (IsWindow(hdlg))
{
MSG msg;
PUPDBAR this;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/*
* Don't use SendMessage() here to ask hdlg if reconciliation has been
* aborted. hdlg has typically been created in a different thread.
* hdlg's creator thread may already be blocked in the sync engine. We
* must avoid inter-thread SendMessage() to avoid a deadlock on the
* sync engine's briefcase critical section. The sync engine is not
* reentrant.
*/
PostMessage(hdlg, WM_QUERYABORT, 0, 0);
this = (PUPDBAR)GetWindowLongPtr(hdlg, DWLP_USER);
if (this)
{
bAbort = AbortEvt_Query(this->pabortevt);
}
}
return bAbort;
}
//---------------------------------------------------------------------------
// Confirm Replace dialog
//---------------------------------------------------------------------------
// This is the private data structure for the dialog
typedef struct
{
UINT uFlags; // CRF_*
TCHAR szDesc[MAXBUFLEN+MAXPATHLEN];
TCHAR szInfoExisting[MAXMEDLEN];
TCHAR szInfoOther[MAXMEDLEN];
HICON hicon;
} CONFIRMREPLACE;
/*----------------------------------------------------------
Purpose: Confirm replace dialog
Returns: varies
Cond: --
*/
INT_PTR CALLBACK ConfirmReplace_Proc(
HWND hDlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_INITDIALOG:
{
CONFIRMREPLACE * pcr = (CONFIRMREPLACE *)lParam;
UINT i;
UINT cButtons;
MB_BUTTONS const * pmbb;
static UINT const rgidc[4] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4 };
static BTNSTYLE const btnstyleSingle =
// (List buttons backwards)
{ 2, { { IDNO, IDS_NO },
{ IDYES, IDS_YES },
} };
static BTNSTYLE const btnstyleMulti =
// (List buttons backwards)
{ 4, { { IDCANCEL, IDS_CANCEL },
{ IDNO, IDS_NO },
{ IDC_YESTOALL, IDS_YESTOALL },
{ IDYES, IDS_YES },
} };
Static_SetText(GetDlgItem(hDlg, IDC_DESC), pcr->szDesc);
if (IsFlagClear(pcr->uFlags, CRF_FOLDER))
{
Static_SetText(GetDlgItem(hDlg, IDC_EXISTING), pcr->szInfoExisting);
Static_SetText(GetDlgItem(hDlg, IDC_OTHER), pcr->szInfoOther);
Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_EXISTING), pcr->hicon);
Static_SetIcon(GetDlgItem(hDlg, IDC_ICON_OTHER), pcr->hicon);
}
// Set the IDs and strings of used buttons
if (IsFlagSet(pcr->uFlags, CRF_MULTI))
{
cButtons = btnstyleMulti.cButtons;
pmbb = btnstyleMulti.rgmbb;
}
else
{
cButtons = btnstyleSingle.cButtons;
pmbb = btnstyleSingle.rgmbb;
}
for (i = 0; i < cButtons; i++)
{
TCHAR sz[MAXMEDLEN];
HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
SetWindowText(hwnd, sz);
}
// Disable unused buttons
for (; i < ARRAYSIZE(rgidc); i++)
{
HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
EnableWindow(hwnd, FALSE);
ShowWindow(hwnd, SW_HIDE);
}
}
break;
case WM_COMMAND:
switch (wParam)
{
case IDCANCEL:
case IDYES:
case IDC_YESTOALL:
case IDNO:
EndDialog(hDlg, wParam);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------
Purpose: Brings up the replace confirmation dialog.
Returns: IDYES, IDC_YESTOALL, IDNO or IDCANCEL
Cond: --
*/
int PUBLIC ConfirmReplace_DoModal(
HWND hwndOwner,
LPCTSTR pszPathExisting,
LPCTSTR pszPathOther,
UINT uFlags) // CRF_*
{
INT_PTR idRet;
CONFIRMREPLACE * pcr;
pcr = GAlloc(sizeof(*pcr));
if (pcr)
{
LPTSTR pszMsg;
DWORD dwAttrs = GetFileAttributes(pszPathExisting);
pcr->uFlags = uFlags;
// Is this replacing a folder?
if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_DIRECTORY))
{
// Yes
if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_MSG_ConfirmFolderReplace),
PathFindFileName(pszPathOther)))
{
lstrcpy(pcr->szDesc, pszMsg);
GFree(pszMsg);
}
else
*pcr->szDesc = 0;
SetFlag(pcr->uFlags, CRF_FOLDER);
idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FOLDER, (LPARAM)pcr);
}
else
{
// No
UINT ids;
FileInfo * pfi;
if (SUCCEEDED(FICreate(pszPathExisting, &pfi, FIF_ICON)))
{
pcr->hicon = pfi->hicon;
FIGetInfoString(pfi, pcr->szInfoExisting, ARRAYSIZE(pcr->szInfoExisting));
pfi->hicon = NULL; // (keep icon around)
FIFree(pfi);
}
if (SUCCEEDED(FICreate(pszPathOther, &pfi, FIF_DEFAULT)))
{
FIGetInfoString(pfi, pcr->szInfoOther, ARRAYSIZE(pcr->szInfoOther));
FIFree(pfi);
}
if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_READONLY))
{
ids = IDS_MSG_ConfirmFileReplace_RO;
}
else if (IsFlagSet(dwAttrs, FILE_ATTRIBUTE_SYSTEM))
{
ids = IDS_MSG_ConfirmFileReplace_Sys;
}
else
{
ids = IDS_MSG_ConfirmFileReplace;
}
if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(ids),
PathFindFileName(pszPathOther)))
{
lstrcpy(pcr->szDesc, pszMsg);
GFree(pszMsg);
}
else
*pcr->szDesc = 0;
ClearFlag(pcr->uFlags, CRF_FOLDER);
idRet = DoModal(hwndOwner, ConfirmReplace_Proc, IDD_REPLACE_FILE, (LPARAM)pcr);
if (pcr->hicon)
DestroyIcon(pcr->hicon);
}
GFree(pcr);
}
else
{
idRet = -1; // Out of memory
}
return (int)idRet;
}
//---------------------------------------------------------------------------
// Introduction dialog
//---------------------------------------------------------------------------
/*----------------------------------------------------------
Purpose: Intro dialog
Returns: varies
Cond: --
*/
INT_PTR CALLBACK Intro_Proc(
HWND hDlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
NMHDR *lpnm;
switch (wMsg)
{
case WM_INITDIALOG:
break;
case WM_NOTIFY:
lpnm = (NMHDR *)lParam;
switch(lpnm->code)
{
case PSN_SETACTIVE: {
// Only allow the Finish button. The user cannot go back and
// change the settings.
HWND hwndCancel = GetDlgItem(GetParent(hDlg), IDCANCEL);
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
// Hide cancel button
EnableWindow(hwndCancel, FALSE);
ShowWindow(hwndCancel, SW_HIDE);
}
break;
case PSN_KILLACTIVE:
case PSN_HELP:
case PSN_WIZBACK:
case PSN_WIZNEXT:
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------
Purpose: Invoke the introduction wizard.
Returns: ID of button that terminated dialog
Cond: --
*/
int PUBLIC Intro_DoModal(
HWND hwndParent)
{
PROPSHEETPAGE psp = {
sizeof(psp),
PSP_DEFAULT | PSP_HIDEHEADER,
g_hinst,
MAKEINTRESOURCE(IDD_INTRO_WIZARD),
NULL, // hicon
NULL, // caption
Intro_Proc,
0, // lParam
NULL, // pfnCallback
NULL // pointer to ref count
};
PROPSHEETHEADER psh = {
sizeof(psh),
PSH_WIZARD_LITE | PSH_WIZARD | PSH_PROPSHEETPAGE, // (use ppsp field)
hwndParent,
g_hinst,
0, // hicon
0, // caption
1, // number of pages
0, // start page
&psp
};
return (int)PropertySheet(&psh);
}
//---------------------------------------------------------------------------
// MsgBox dialog
//---------------------------------------------------------------------------
typedef struct _MSGBOX
{
LPCTSTR pszText;
LPCTSTR pszCaption;
HICON hicon;
UINT uStyle;
} MSGBOX, * PMSGBOX;
/*----------------------------------------------------------
Purpose: Determines whether to resize the dialog and reposition
the buttons to fit the text.
The dialog is not resized any smaller than its initial
size.
The dialog is only resized vertically.
Returns: --
Cond: --
*/
void PRIVATE MsgBox_Resize(
HWND hDlg,
LPCTSTR pszText,
UINT cchText)
{
HDC hdc;
HWND hwndText = GetDlgItem(hDlg, IDC_TEXT);
hdc = GetDC(hwndText);
if (hdc)
{
HFONT hfont = GetStockObject(DEFAULT_GUI_FONT);
HFONT hfontSav = SelectFont(hdc, hfont);
RECT rc;
RECT rcOrg;
// Determine new dimensions
GetClientRect(hwndText, &rcOrg);
rc = rcOrg;
DrawTextEx(hdc, (LPTSTR)pszText, cchText, &rc, DT_CALCRECT | DT_WORDBREAK | DT_LEFT, NULL);
SelectFont(hdc, hfontSav);
ReleaseDC(hwndText, hdc);
// Is the required size bigger?
if (rc.bottom > rcOrg.bottom)
{
// Yes; resize the windows
int cy = rc.bottom - rcOrg.bottom;
int cyFudge = GetSystemMetrics(SM_CYCAPTION) + 2*GetSystemMetrics(SM_CYFIXEDFRAME);
int cxFudge = 2*GetSystemMetrics(SM_CXFIXEDFRAME);
HDWP hdwp = BeginDeferWindowPos(4);
if (hdwp)
{
// Move Buttons
hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON1, 0, cy);
hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON2, 0, cy);
hdwp = SlideControlPos(hdwp, hDlg, IDC_BUTTON3, 0, cy);
// Resize Static Text
hdwp = DeferWindowPos(hdwp, hwndText, GetDlgItem(hDlg, IDC_BUTTON3),
0, 0,
rc.right-rc.left, rc.bottom-rc.top,
SWP_NOACTIVATE | SWP_NOMOVE);
EndDeferWindowPos(hdwp);
}
// Resize Dialog
GetClientRect(hDlg, &rc);
SetWindowPos(hDlg, NULL, 0, 0,
rc.right-rc.left + cxFudge, rc.bottom-rc.top + cy + cyFudge,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
}
}
}
/*----------------------------------------------------------
Purpose: MsgBox dialog
Returns: varies
Cond: --
*/
INT_PTR CALLBACK MsgBox_Proc(
HWND hDlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_INITDIALOG:
{
PMSGBOX pmsgbox = (PMSGBOX)lParam;
UINT uStyle = pmsgbox->uStyle;
UINT i;
UINT imb = uStyle & MB_TYPEMASK;
UINT cButtons;
MB_BUTTONS const * pmbb;
static UINT const rgidc[3] = { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3 };
static BTNSTYLE const rgmbstyle[] = {
// (List buttons backwards)
// MB_OK
{ 1, { { IDOK, IDS_OK },
} },
// MB_OKCANCEL
{ 2, { { IDCANCEL, IDS_CANCEL },
{ IDOK, IDS_OK },
} },
// MB_ABORTRETRYIGNORE (not supported)
{ 1, { { IDOK, IDS_OK },
} },
// MB_YESNOCANCEL
{ 3, { { IDCANCEL, IDS_CANCEL },
{ IDNO, IDS_NO },
{ IDYES, IDS_YES },
} },
// MB_YESNO
{ 2, { { IDNO, IDS_NO },
{ IDYES, IDS_YES },
} },
// MB_RETRYCANCEL
{ 2, { { IDCANCEL, IDS_CANCEL },
{ IDRETRY, IDS_RETRY },
} },
};
// Set the text
if (pmsgbox->pszText)
{
Static_SetText(GetDlgItem(hDlg, IDC_TEXT), pmsgbox->pszText);
// Resize and reposition the buttons if necessary
MsgBox_Resize(hDlg, pmsgbox->pszText, lstrlen(pmsgbox->pszText));
}
if (pmsgbox->pszCaption)
SetWindowText(hDlg, pmsgbox->pszCaption);
// Use a custom icon?
if (NULL == pmsgbox->hicon)
{
// No; use a system icon
LPCTSTR pszIcon;
if (IsFlagSet(uStyle, MB_ICONEXCLAMATION))
pszIcon = IDI_EXCLAMATION;
else if (IsFlagSet(uStyle, MB_ICONHAND))
pszIcon = IDI_HAND;
else if (IsFlagSet(uStyle, MB_ICONQUESTION))
pszIcon = IDI_QUESTION;
else
pszIcon = IDI_ASTERISK;
pmsgbox->hicon = LoadIcon(NULL, pszIcon);
}
Static_SetIcon(GetDlgItem(hDlg, IDC_MSGICON), pmsgbox->hicon);
// Set the IDs and strings of used buttons
cButtons = rgmbstyle[imb].cButtons;
pmbb = rgmbstyle[imb].rgmbb;
for (i = 0; i < cButtons; i++)
{
TCHAR sz[MAXMEDLEN];
HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
LoadString(g_hinst, pmbb[i].ids, sz, ARRAYSIZE(sz));
SetWindowLongPtr(hwnd, GWLP_ID, pmbb[i].id);
SetWindowText(hwnd, sz);
}
// Disable unused buttons
for (; i < ARRAYSIZE(rgidc); i++)
{
HWND hwnd = GetDlgItem(hDlg, rgidc[i]);
EnableWindow(hwnd, FALSE);
ShowWindow(hwnd, SW_HIDE);
}
}
break;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
case IDCANCEL:
case IDYES:
case IDNO:
case IDRETRY:
EndDialog(hDlg, wParam);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------
Purpose: Invoke the introduction dialog.
Returns: ID of button that terminated dialog
Cond: --
*/
int PUBLIC MsgBox(
HWND hwndParent,
LPCTSTR pszText,
LPCTSTR pszCaption,
HICON hicon, // May be NULL
UINT uStyle, ...)
{
INT_PTR iRet = -1;
int ids;
TCHAR szCaption[MAXPATHLEN];
LPTSTR pszRet;
va_list ArgList;
va_start(ArgList, uStyle);
pszRet = _ConstructMessageString(g_hinst, pszText, &ArgList);
va_end(ArgList);
if (pszRet)
{
// Is pszCaption a resource ID?
if (0 == HIWORD(pszCaption))
{
// Yes; load it
ids = LOWORD(pszCaption);
SzFromIDS(ids, szCaption, ARRAYSIZE(szCaption));
pszCaption = szCaption;
}
// Invoke dialog
if (pszCaption)
{
MSGBOX msgbox = { pszRet, pszCaption, hicon, uStyle };
iRet = DoModal(hwndParent, MsgBox_Proc, IDC_MSGBOX, (LPARAM)&msgbox);
}
LocalFree(pszRet);
}
return (int)iRet;
}