Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4091 lines
127 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: Progress.cpp
//
// Contents: Progress Dialog
//
// Classes:
//
// Notes:
//
// History: 05-Nov-97 Susia Created.
//
//--------------------------------------------------------------------------
#include "precomp.h"
#define TIMERID_TRAYANIMATION 3
#define TRAYANIMATION_SPEED 500 // speed in milliseconds
#define TIMERID_NOIDLEHANGUP 4 // inform wininet that connection isn't idle.
#define NOIDLEHANGUP_REFRESHRATE (1000*30) // inform of idle every 30 seconds.
#define TIMERID_KILLHANDLERS 5
#define TIMERID_KILLHANDLERSMINTIME (1000*15) // minimum timeout for kill handlers that are hung after cancel.
#define TIMERID_KILLHANDLERSWIN9XTIME (1000*60) // Timeout for for kill handlers other than NT 5.0
const TCHAR c_szTrayWindow[] = TEXT("Shell_TrayWnd");
const TCHAR c_szTrayNotifyWindow[] = TEXT("TrayNotifyWnd");
#ifndef IDANI_CAPTION
#define IDANI_CAPTION 3
#endif // IDANI_CAPTION
// list collapsed items first so only have to loop
// though first item to cbNumDlgResizeItemsCollapsed when
// not expanded.
const DlgResizeList g_ProgressResizeList[] = {
IDSTOP,DLGRESIZEFLAG_PINRIGHT,
IDC_DETAILS,DLGRESIZEFLAG_PINRIGHT,
IDC_RESULTTEXT,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT,
IDC_STATIC_WHATS_UPDATING,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT,
IDC_STATIC_WHATS_UPDATING_INFO,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT,
IDC_STATIC_HOW_MANY_COMPLETE,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT,
IDC_SP_SEPARATOR,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT,
// expanded items
IDC_TOOLBAR, DLGRESIZEFLAG_PINRIGHT,
IDC_PROGRESS_TABS,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT | DLGRESIZEFLAG_PINBOTTOM | DLGRESIZEFLAG_PINTOP,
IDC_UPDATE_LIST,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT | DLGRESIZEFLAG_PINBOTTOM | DLGRESIZEFLAG_PINTOP,
IDC_SKIP_BUTTON_MAIN,DLGRESIZEFLAG_PINBOTTOM | DLGRESIZEFLAG_PINLEFT,
IDC_STATIC_SKIP_TEXT,DLGRESIZEFLAG_PINBOTTOM | DLGRESIZEFLAG_PINLEFT,
IDC_PROGRESS_OPTIONS_BUTTON_MAIN,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINBOTTOM,
IDC_LISTBOXERROR,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINLEFT | DLGRESIZEFLAG_PINBOTTOM | DLGRESIZEFLAG_PINTOP,
IDC_PROGRESSRESIZESCROLLBAR,DLGRESIZEFLAG_PINRIGHT | DLGRESIZEFLAG_PINBOTTOM,
};
extern HINSTANCE g_hInst; // current instance
extern TCHAR g_szSyncMgrHelp[];
extern ULONG g_aContextHelpIds[];
extern OSVERSIONINFOA g_OSVersionInfo; // osVersionInfo, setup by WinMain.
extern LANGID g_LangIdSystem; // langID of system we are running on.
extern DWORD g_WMTaskbarCreated; // TaskBar Created WindowMessage;
BOOL CALLBACK ProgressWndProc(HWND hwnd, UINT uMsg,WPARAM wParam,LPARAM lParam);
//defined in progtab.cpp
extern BOOL CALLBACK UpdateProgressWndProc(HWND hwnd, UINT uMsg,WPARAM wParam,LPARAM lParam);
extern BOOL CALLBACK ResultsProgressWndProc(HWND hwnd, UINT uMsg,WPARAM wParam,LPARAM lParam);
extern BOOL OnProgressResultsMeasureItem(HWND hwnd,CProgressDlg *pProgress, UINT *horizExtent, UINT idCtl, MEASUREITEMSTRUCT *pMeasureItem);
extern BOOL OnProgressResultsDeleteItem(HWND hwnd, UINT idCtl, const DELETEITEMSTRUCT * lpDeleteItem);
extern void OnProgressResultsSize(HWND hwnd,CProgressDlg *pProgress,UINT uMsg,WPARAM wParam,LPARAM lParam);
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::CProgressDlg()
//
// PURPOSE: Constructor
//
// COMMENTS: Constructor for progress dialog
//
//
//--------------------------------------------------------------------------------
CProgressDlg::CProgressDlg(REFCLSID rclsid)
{
m_clsid = rclsid;
m_cInternalcRefs = 0;
m_hwnd = NULL;
m_hwndTabs = NULL;
m_errorimage = NULL;
m_HndlrQueue = NULL;
m_iProgressSelectedItem = -1;
m_iItem = -1; // index to any new item to the list box.
m_iResultCount = -1; // Number of logged results
m_iErrorCount = 0; // Number of logged errors
m_iWarningCount = 0; // Number of logged warnings
m_iInfoCount = 0; // Number of logged info
m_dwThreadID = -1;
m_nCmdShow = SW_SHOWNORMAL;
// m_hRasConn = NULL;
m_pSyncMgrIdle = NULL;
m_fHasShellTrayIcon = FALSE;
m_fAddedIconToTray = FALSE;
m_fnResultsListBox = NULL;
m_ulIdleRetryMinutes = 0;
m_ulDelayIdleShutDownTime = 0;
m_fHwndRightToLeft = FALSE;
m_iLastItem = -1;
m_dwLastStatusType = -1;
m_dwHandleThreadNestcount = 0;
m_dwShowErrorRefCount = 0;
m_dwSetItemStateRefCount = 0;
m_dwHandlerOutCallCount = 0;
m_dwPrepareForSyncOutCallCount = 0;
m_dwSynchronizeOutCallCount = 0;
m_dwQueueTransferCount = 0;
m_clsidHandlerInSync = GUID_NULL;
m_fForceClose = FALSE;
// setup KillTimerTimeout based on paltform
if ( (VER_PLATFORM_WIN32_NT == g_OSVersionInfo.dwPlatformId)
&& (g_OSVersionInfo.dwMajorVersion >= 5))
{
m_nKillHandlerTimeoutValue = TIMERID_KILLHANDLERSMINTIME;
}
else
{
m_nKillHandlerTimeoutValue = TIMERID_KILLHANDLERSWIN9XTIME;
}
m_dwProgressFlags = PROGRESSFLAG_NEWDIALOG;
m_pItemListView = NULL;
m_iTrayAniFrame = IDI_SYSTRAYANI6; // initialize to end.
LoadString(g_hInst, IDS_STOPPED, m_pszStatusText[0], MAX_STRING_RES);
LoadString(g_hInst, IDS_SKIPPED, m_pszStatusText[1], MAX_STRING_RES);
LoadString(g_hInst, IDS_PENDING, m_pszStatusText[2], MAX_STRING_RES);
LoadString(g_hInst, IDS_SYNCHRONIZING, m_pszStatusText[3], MAX_STRING_RES);
LoadString(g_hInst, IDS_SUCCEEDED, m_pszStatusText[4], MAX_STRING_RES);
LoadString(g_hInst, IDS_FAILED, m_pszStatusText[5], MAX_STRING_RES);
LoadString(g_hInst, IDS_PAUSED, m_pszStatusText[6], MAX_STRING_RES);
LoadString(g_hInst, IDS_RESUMING, m_pszStatusText[7], MAX_STRING_RES);
// Determine if SENS is installed
LPNETAPI pNetApi;
m_fSensInstalled = FALSE;
if (pNetApi = gSingleNetApiObj.GetNetApiObj())
{
m_fSensInstalled = pNetApi->IsSensInstalled();
pNetApi->Release();
}
m_CurrentListEntry = NULL;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::AddRefProgressDialog, private
//
// Synopsis: Called to Addref ourselves
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 26-Aug-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProgressDlg::AddRefProgressDialog()
{
ULONG cRefs;
cRefs = ::AddRefProgressDialog(m_clsid,this); // addref GlobalRef
Assert(0 <= m_cInternalcRefs);
++m_cInternalcRefs;
return cRefs;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::ReleaseProgressDialog, private
//
// Synopsis: Called to Release ourselves
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 26-Aug-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProgressDlg::ReleaseProgressDialog(BOOL fForce)
{
ULONG cRefs;
Assert(0 < m_cInternalcRefs);
--m_cInternalcRefs;
cRefs = ::ReleaseProgressDialog(m_clsid,this,fForce); // release global ref.
return cRefs;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::Initialize()
//
// PURPOSE: Initialize the Progress Dialog
//
// COMMENTS: Implemented on main thread.
//
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::Initialize(DWORD dwThreadID,int nCmdShow)
{
BOOL fCreated = FALSE;
Assert(NULL == m_hwnd);
m_nCmdShow = nCmdShow;
if (NULL == m_hwnd)
{
m_dwThreadID = dwThreadID;
m_hwnd = CreateDialogParam(g_hInst,MAKEINTRESOURCE(IDD_PROGRESS),NULL, (DLGPROC) ProgressWndProc,
(LPARAM) this);
if (!m_hwnd)
return FALSE;
// expand/collapse dialog base on use settings.
RegGetProgressDetailsState(m_clsid,&m_fPushpin, &m_fExpanded);
ExpandCollapse(m_fExpanded, TRUE);
// Set the state of the thumbtack
if (m_fPushpin)
{
SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_SETSTATE, IDC_PUSHPIN,
MAKELONG(TBSTATE_CHECKED | TBSTATE_ENABLED, 0));
SendMessage(m_hwnd, WM_COMMAND, IDC_PUSHPIN, 0);
}
m_HndlrQueue = new CHndlrQueue(QUEUETYPE_PROGRESS,this); // reivew, queueu should be created and passed in initialize??
// if this is the idle progress then need to load up msidle and
// set up the callback
if (m_clsid == GUID_PROGRESSDLGIDLE)
{
BOOL fIdleSupport = FALSE;
m_pSyncMgrIdle = new CSyncMgrIdle();
if (m_pSyncMgrIdle)
{
fIdleSupport = m_pSyncMgrIdle->Initialize();
if (FALSE == fIdleSupport)
{
delete m_pSyncMgrIdle;
m_pSyncMgrIdle = NULL;
}
}
// if couldn't load idle, then return a failure
if (FALSE == fIdleSupport)
{
return FALSE;
}
}
fCreated = TRUE;
// When Window is first created show with specified nCmdShow.
// Review if want to wait to show window until transfer comes in.
UpdateWndPosition(nCmdShow,TRUE /* fForce */);
}
Assert(m_hwnd);
UpdateWindow(m_hwnd);
return TRUE;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnSize(UINT uMsg,WPARAM wParam,LPARAM lParam)
//
// PURPOSE: moves and resizes dialog items based on current window size.
//
//--------------------------------------------------------------------------------
void CProgressDlg::OnSize(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
ULONG cbNumResizeItems;
HWND hwndSizeGrip;
cbNumResizeItems = m_fExpanded ? m_cbNumDlgResizeItemsExpanded :
m_cbNumDlgResizeItemsCollapsed;
ResizeItems(cbNumResizeItems,m_dlgResizeInfo);
// if expanded and not maximized show the resize, else hide it.
hwndSizeGrip = GetDlgItem(m_hwnd,IDC_PROGRESSRESIZESCROLLBAR);
if (hwndSizeGrip)
{
int nCmdShow = (m_fMaximized || !m_fExpanded) ? SW_HIDE : SW_NORMAL;
// temporarily always hide if right to left
if (m_fHwndRightToLeft)
{
nCmdShow = SW_HIDE;
}
ShowWindow(hwndSizeGrip,nCmdShow);
}
// tell the error listbox it needs to recalc its items heights
OnProgressResultsSize(m_hwnd,this,WM_SIZE,0,0);
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OffIdle()
//
// PURPOSE: Informs progress dialog that the machine is no longer Idle.
//
// Scenarios
//
// dialog is maximized, just keep processing.
// dialog is minimized or in tray - Set our wait timer for a specified time
// if dialog is still minimized, go away
// if dialog is now maximized just keep processing.
//
//--------------------------------------------------------------------------------
void CProgressDlg::OffIdle()
{
Assert(!(PROGRESSFLAG_DEAD & m_dwProgressFlags)); // make sure not notified after dialog gone.
m_dwProgressFlags |= PROGRESSFLAG_INOFFIDLE;
// set flag that we received the OffIdle
m_dwProgressFlags |= PROGRESSFLAG_RECEIVEDOFFIDLE;
// reset Flag so know that no longer registered for Idle.
m_dwProgressFlags &= ~PROGRESSFLAG_REGISTEREDFOROFFIDLE;
// make sure in all cases we release the idle reference.
// if in shutdownmode or cancel has already been pressed
// by the user or if window is visible but not in the Tray.
// then don't bother with the wait.
if ( !IsWindowVisible(m_hwnd) && m_fHasShellTrayIcon
&& !(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)
&& !(m_dwProgressFlags & PROGRESSFLAG_CANCELPRESSED)
&& (m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS) )
{
HANDLE hTimer = CreateEvent(NULL,TRUE,FALSE,NULL);
// should use Create/SetWaitable timer to accomplish this but these
// functions aren't available on Win9x yet.
if (hTimer)
{
UINT uTimeOutValue = m_ulDelayIdleShutDownTime;
Assert(sizeof(UINT) >= sizeof(HANDLE));
DoModalLoop(hTimer,NULL,m_hwnd,TRUE,uTimeOutValue);
CloseHandle(hTimer);
}
}
// now after our wait, check the window placement again
// if window is not visible or is in the tray
// then do a cancel on behalf of the User,
if ( (!IsWindowVisible(m_hwnd) || m_fHasShellTrayIcon)
&& !(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)
&& !(m_dwProgressFlags & PROGRESSFLAG_CANCELPRESSED) )
{
OnCancel(TRUE);
}
// now if we aren't syncing any items and no items
// waiting in the queue release our idle lock
// !!! warning. don't release until after wait above to
// don't have to worry about next idle firing before
// this method is complete.
if (!(m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS)
|| !(m_dwQueueTransferCount) )
{
ReleaseIdleLock();
}
m_dwProgressFlags &= ~PROGRESSFLAG_INOFFIDLE;
ReleaseProgressDialog(m_fForceClose); // release our addref.
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnIdle()
//
// PURPOSE: Informs progress dialog that the machine is still
// Idle after a set amount of time.
//
//
//--------------------------------------------------------------------------------
void CProgressDlg::OnIdle()
{
CSynchronizeInvoke *pSyncMgrInvoke;
Assert(!(m_dwProgressFlags & PROGRESSFLAG_DEAD)); // make sure not notified after dialog gone.
// if received and offIdle then ignore this idle until next ::transfer
if (!(m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE)
&& !(m_dwProgressFlags & PROGRESSFLAG_INOFFIDLE) )
{
AddRefProgressDialog(); // hold alive until next items are queued.
pSyncMgrInvoke = new CSynchronizeInvoke;
if (pSyncMgrInvoke)
{
pSyncMgrInvoke->RunIdle();
pSyncMgrInvoke->Release();
}
ReleaseProgressDialog(m_fForceClose);
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::SetIdleParams()
//
// PURPOSE: Sets the IdleInformation, last writer wins.
//
//
//--------------------------------------------------------------------------------
void CProgressDlg::SetIdleParams( ULONG ulIdleRetryMinutes,ULONG ulDelayIdleShutDownTime
,BOOL fRetryEnabled)
{
Assert(m_clsid == GUID_PROGRESSDLGIDLE);
m_ulIdleRetryMinutes = ulIdleRetryMinutes;
m_ulDelayIdleShutDownTime = ulDelayIdleShutDownTime;
if (fRetryEnabled)
{
m_dwProgressFlags |= PROGRESSFLAG_IDLERETRYENABLED;
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: BOOL CProgressDlg::InitializeToolbar(HWND hwnd)
//
// PURPOSE: What dialog would be complete without a toolbar, eh?
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::InitializeToolbar(HWND hwnd)
{
HWND hwndTool;
HIMAGELIST himlImages = ImageList_LoadBitmap(g_hInst,
MAKEINTRESOURCE(IDB_PUSHPIN), 16, 0,
RGB(255, 0, 255));
hwndTool = GetDlgItem(hwnd,IDC_TOOLBAR);
//If we can't create the pushpin window
//the user just won't get a pushpin.
if (hwndTool)
{
#ifdef _ZORDER
SetWindowPos(GetDlgItem(hwnd, IDC_PROGRESS_TABS),HWND_BOTTOM,0,0,0,0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
SetWindowPos(GetDlgItem(hwnd, IDC_PROGRESSRESIZESCROLLBAR),
HWND_BOTTOM,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
#endif // _ZORDER
TBBUTTON tb = { IMAGE_TACK_OUT, IDC_PUSHPIN, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0 };
SendMessage(hwndTool, TB_SETIMAGELIST, 0, (LPARAM) himlImages);
SendMessage(hwndTool, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
SendMessage(hwndTool, TB_SETBUTTONSIZE, 0, MAKELONG(14, 14));
SendMessage(hwndTool, TB_SETBITMAPSIZE, 0, MAKELONG(14, 14));
SendMessage(hwndTool, TB_ADDBUTTONS, 1, (LPARAM) &tb);
}
return (0);
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::InitializeTabs(HWND hwnd)
//
// PURPOSE: Initializes the tab control on the dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::InitializeTabs(HWND hwnd)
{
m_hwndTabs = GetDlgItem(hwnd, IDC_PROGRESS_TABS);
TC_ITEM tci;
TCHAR szRes[MAX_STRING_RES];
if (!m_hwndTabs )
return FALSE;
// "Updates"
tci.mask = TCIF_TEXT;
LoadString(g_hInst, IDS_UPDATETAB, szRes, ARRAY_SIZE(szRes));
tci.pszText = szRes;
TabCtrl_InsertItem(m_hwndTabs,PROGRESS_TAB_UPDATE, &tci);
// "Results"
LoadString(g_hInst, IDS_ERRORSTAB, szRes, ARRAY_SIZE(szRes));
tci.pszText = szRes;
TabCtrl_InsertItem(m_hwndTabs, PROGRESS_TAB_ERRORS, &tci);
//Set the tab to the Update page to begin with
m_iTab = PROGRESS_TAB_UPDATE;
if (-1 != TabCtrl_SetCurSel(m_hwndTabs, PROGRESS_TAB_UPDATE))
{
m_iTab = PROGRESS_TAB_UPDATE;
ShowWindow(GetDlgItem(hwnd, IDC_LISTBOXERROR), SW_HIDE);
}
else //ToDo: What do we do if the set tab fails?
{
m_iTab = -1;
return FALSE;
}
return (TRUE);
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::InitializeUpdateList(HWND hwnd)
//
// PURPOSE: Initializes the update list view control on the progress dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::InitializeUpdateList(HWND hwnd)
{
HWND hwndList = GetDlgItem(hwnd,IDC_UPDATE_LIST);
HIMAGELIST himage;
TCHAR pszProgressColumn[MAX_STRING_RES + 1];
int iListViewWidth;
if (hwndList)
{
m_pItemListView = new CListView(hwndList,hwnd,IDC_UPDATE_LIST,WM_BASEDLG_NOTIFYLISTVIEWEX);
}
if (!m_pItemListView)
{
return FALSE;
}
if (m_pItemListView)
{
UINT ImageListflags;
ImageListflags = ILC_COLOR | ILC_MASK;
if (IsHwndRightToLeft(hwnd))
{
ImageListflags |= ILC_MIRROR;
}
// create an imagelist
himage = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),ImageListflags,5,20);
if (himage)
{
m_pItemListView->SetImageList(himage,LVSIL_SMALL);
}
// for column widths go 35%, 20%, 45%
iListViewWidth = CalcListViewWidth(hwndList,410);
//set up the columns
LoadString(g_hInst, IDS_PROGRESS_DLG_COLUMN_NAME, pszProgressColumn, MAX_STRING_RES);
InsertListViewColumn(m_pItemListView,PROGRESSLIST_NAMECOLUMN,pszProgressColumn,
LVCFMT_LEFT,(iListViewWidth*7)/20 /* cx */);
LoadString(g_hInst, IDS_PROGRESS_DLG_COLUMN_STATUS, pszProgressColumn, MAX_STRING_RES);
InsertListViewColumn(m_pItemListView,PROGRESSLIST_STATUSCOLUMN,pszProgressColumn,
LVCFMT_LEFT,(iListViewWidth/5) /* cx */);
LoadString(g_hInst, IDS_PROGRESS_DLG_COLUMN_INFO, pszProgressColumn, MAX_STRING_RES);
InsertListViewColumn(m_pItemListView,PROGRESSLIST_INFOCOLUMN,pszProgressColumn,
LVCFMT_LEFT,(iListViewWidth*9)/20 /* cx */);
}
return (TRUE);
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::InitializeResultsList(HWND hwnd)
//
// PURPOSE: Initializes the results list view control on the progress dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::InitializeResultsList(HWND hwnd)
{
HWND hwndList = GetDlgItem(hwnd,IDC_LISTBOXERROR);
LBDATA *pData = NULL;
TCHAR pszError[MAX_STRING_RES];
UINT ImageListflags;
LoadString(g_hInst, IDS_NOERRORSREPORTED, pszError, ARRAY_SIZE(pszError));
if (!hwndList)
return FALSE;
SetCtrlFont(hwndList,g_OSVersionInfo.dwPlatformId,g_LangIdSystem);
// Allocate a struct for the item data
if (!(pData = (LBDATA *) ALLOC(sizeof(LBDATA) + sizeof(pszError))))
{
return FALSE;
}
pData->fIsJump = FALSE;
pData->fTextRectValid = FALSE;
pData->fHasBeenClicked = FALSE;
pData->fAddLineSpacingAtEnd = FALSE;
pData->ErrorID = GUID_NULL;
pData->dwErrorLevel = SYNCMGRLOGLEVEL_INFORMATION;
pData->pHandlerID = 0;
lstrcpy(pData->pszText, pszError);
// create the error image list based on the current System
// metrics
m_iIconMetricX = GetSystemMetrics(SM_CXSMICON);
m_iIconMetricY = GetSystemMetrics(SM_CYSMICON);
ImageListflags = ILC_COLOR | ILC_MASK;
if (IsHwndRightToLeft(hwnd))
{
ImageListflags |= ILC_MIRROR;
}
m_errorimage = ImageList_Create(m_iIconMetricX,m_iIconMetricY,ImageListflags, 0, MAX_ERR0R_ICONS);
// load up the Error Images, if fail then just won't be an image next to the text
if (m_errorimage)
{
m_ErrorImages[ErrorImage_Information] = ImageList_AddIcon(m_errorimage,LoadIcon(NULL,IDI_INFORMATION));
m_ErrorImages[ErrorImage_Warning] = ImageList_AddIcon(m_errorimage,LoadIcon(NULL,IDI_WARNING));
m_ErrorImages[ErrorImage_Error] = ImageList_AddIcon(m_errorimage,LoadIcon(NULL,IDI_ERROR));
}
else
{
m_ErrorImages[ErrorImage_Information] = m_ErrorImages[ErrorImage_Warning] =
m_ErrorImages[ErrorImage_Error] = -1;
}
//Add a default Icon
pData->IconIndex = m_ErrorImages[ErrorImage_Information];
// Add the item data
AddListData(pData, sizeof(pszError), hwndList);
return TRUE;
}
void CProgressDlg::ReleaseDlg(WORD wCommandID)
{
// put into dead state so know not
// addref/release
PostMessage(m_hwnd,WM_PROGRESS_RELEASEDLGCMD,wCommandID,0);
}
// notifies choice dialog when it is actually released.
void CProgressDlg::PrivReleaseDlg(WORD wCommandID)
{
m_dwProgressFlags |= PROGRESSFLAG_DEAD; // put us in the dead state.
Assert(0 == m_dwQueueTransferCount); // shouldn't be going away if transfer is in progress!!
RegSetProgressDetailsState(m_clsid,m_fPushpin, m_fExpanded);
ShowWindow(m_hwnd,SW_HIDE);
// if the tray is around hide it now.
if (m_fHasShellTrayIcon)
{
RegisterShellTrayIcon(FALSE);
m_fHasShellTrayIcon = FALSE;
}
switch (wCommandID)
{
case RELEASEDLGCMDID_OK: // on an okay sleep a little, then fall through to cancel.
case RELEASEDLGCMDID_CANCEL:
Assert(m_HndlrQueue);
case RELEASEDLGCMDID_DESTROY: // called in Thread creation or initialize failed
case RELEASEDLGCMDID_DEFAULT:
if (m_HndlrQueue)
{
m_HndlrQueue->FreeAllHandlers();
m_HndlrQueue->Release();
m_HndlrQueue = NULL;
}
break;
default:
AssertSz(0,"Unknown Command");
break;
}
Assert(m_hwnd);
if (m_fHasShellTrayIcon)
{
RegisterShellTrayIcon(FALSE);
}
if (m_pSyncMgrIdle)
{
delete m_pSyncMgrIdle;
}
// if this is an idle progress then release our lock on the idle
if (m_clsid == GUID_PROGRESSDLGIDLE)
{
ReleaseIdleLock();
}
if (m_pItemListView)
{
delete m_pItemListView;
m_pItemListView = NULL;
}
if (m_hwnd)
DestroyWindow(m_hwnd);
delete this;
return;
}
// updates window Z-Order and min/max state.
void CProgressDlg::UpdateWndPosition(int nCmdShow,BOOL fForce)
{
BOOL fRemoveTrayIcon = FALSE;
BOOL fWindowVisible = IsWindowVisible(m_hwnd);
BOOL fTrayRequest = ((nCmdShow == SW_MINIMIZE)|| (nCmdShow == SW_SHOWMINIMIZED) || (nCmdShow == SW_HIDE));
BOOL fHandledUpdate = FALSE;
// only time we go to the tray is if the request is a minimize and
// either the window is invisible or it is a force. note Hide for
// now is treated as going to the tray.
//
// other cases or on tray failure we can just do a setforeground and show window.
if (fTrayRequest && (fForce || !fWindowVisible))
{
if (m_fHasShellTrayIcon || RegisterShellTrayIcon(TRUE))
{
// if window was visible hide it and animiate
if (fWindowVisible)
{
AnimateTray(TRUE);
ShowWindow(m_hwnd,SW_HIDE);
}
fHandledUpdate = TRUE;
}
}
if (!fHandledUpdate)
{
// if haven't handled then make sure window is shown and bring to
// front
if (m_fHasShellTrayIcon)
{
AnimateTray(FALSE);
}
ShowWindow(m_hwnd,SW_SHOW);
SetForegroundWindow(m_hwnd);
// if currently have a tray then lets animate
// fAnimate = m_fHasShellTrayIcon ? TRUE : FALSE;
// if the tray is around but we didn't register it this time through then it should
// be removed
if (m_fHasShellTrayIcon)
{
RegisterShellTrayIcon(FALSE);
}
}
}
//--------------------------------------------------------------------------------
//
// Member: CProgressDlg::AnimateTray
//
// PURPOSE: does animation to the tray
//
// COMMENTS: true means we are animating to the tray, false means back to the hwnd.
//
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::AnimateTray(BOOL fTrayAdded)
{
BOOL fAnimate;
HWND hwndTray,hWndST;
RECT rcDlg;
RECT rcST;
fAnimate = FALSE;
// get rectangles for animation
if (hwndTray = FindWindow(c_szTrayWindow, NULL))
{
if (hWndST = FindWindowEx(hwndTray, NULL, c_szTrayNotifyWindow, NULL))
{
GetWindowRect(m_hwnd, &rcDlg);
GetWindowRect(hWndST, &rcST);
fAnimate = TRUE;
}
}
if (fAnimate)
{
if (fTrayAdded)
{
DrawAnimatedRects(m_hwnd, IDANI_CAPTION,&rcDlg,&rcST);
}
else
{
DrawAnimatedRects(m_hwnd, IDANI_CAPTION,&rcST,&rcDlg);
}
}
return fAnimate;
}
//--------------------------------------------------------------------------------
//
// Member: CProgressDlg::RegisterShellTrayIcon
//
// PURPOSE: Registers/Unregisters the dialog in the Tray.
//
// COMMENTS: Up to Caller to do the proper thing with the main hwnd.
//
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::RegisterShellTrayIcon(BOOL fRegister)
{
NOTIFYICONDATA icondata;
if (fRegister)
{
BOOL fResult;
m_fHasShellTrayIcon = TRUE;
fResult = UpdateTrayIcon();
if (!fResult) // if couldn't ad then say its not added.
{
m_fHasShellTrayIcon = FALSE;
}
return fResult;
}
else // remove ouselves from the tray.
{
Assert(TRUE == m_fHasShellTrayIcon);
icondata.cbSize = sizeof(NOTIFYICONDATA);
icondata.hWnd = m_hwnd;
icondata.uID = 1;
m_fHasShellTrayIcon = FALSE;
m_fAddedIconToTray = FALSE;
// ShellNotifyIcon Yields
Shell_NotifyIcon(NIM_DELETE,&icondata);
}
return TRUE;
}
// called to Update the TrayIcon, Keeps track of highest warning state
// and sets the appropriate Icon in the tray. If the item is not already
// in the tray UpdateTrayIcon will not do a thing.
BOOL CProgressDlg::UpdateTrayIcon()
{
NOTIFYICONDATA icondata;
DWORD dwReturn = 0;
if (m_fHasShellTrayIcon)
{
icondata.cbSize = sizeof(NOTIFYICONDATA);
icondata.hWnd = m_hwnd;
icondata.uID = 1;
icondata.uFlags = NIF_ICON | NIF_MESSAGE;
icondata.uCallbackMessage = WM_PROGRESS_SHELLTRAYNOTIFICATION;
// if progress animation is turned on then also animate
// the tray.
if (m_dwProgressFlags & PROGRESSFLAG_PROGRESSANIMATION)
{
// update the frame
m_iTrayAniFrame++;
if (m_iTrayAniFrame > IDI_SYSTRAYANI6)
m_iTrayAniFrame = IDI_SYSTRAYANI1;
icondata.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(m_iTrayAniFrame));
}
else
{
// update the Icon and tip text based on the current state .
// Review - Currently don't have different Icons.
if (m_iErrorCount > 0)
{
icondata.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_SYSTRAYERROR));
}
else if (m_iWarningCount > 0)
{
icondata.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_SYSTRAYWARNING));
}
else
{
icondata.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_SYSTRAYANI1));
}
}
Assert(icondata.hIcon);
TCHAR szBuf[MAX_STRING_RES];
icondata.uFlags |= NIF_TIP;
LoadString(g_hInst, IDS_SYNCMGRNAME, szBuf, ARRAY_SIZE(szBuf));
lstrcpy(icondata.szTip,szBuf);
dwReturn = Shell_NotifyIcon(m_fAddedIconToTray ? NIM_MODIFY : NIM_ADD ,&icondata);
if (0 != dwReturn)
{
// possible for Shell_NotifyIcon(NIM_DELETE) to come in while still
// in shell notify call so only set m_fAddedIconTray to true
// if still have a shell tray icon after the call.
if (m_fHasShellTrayIcon)
{
m_fAddedIconToTray = TRUE;
}
return TRUE;
}
else
{
// possible this failed becuase a Shell_DeleteIcon was in progress
// which yields check if really have a Shell Tray and if not
// reset the AddedIcon Flag
if (!m_fHasShellTrayIcon)
{
m_fAddedIconToTray = FALSE;
}
return FALSE;
}
}
return FALSE;
}
// given an ID sets the appropriate state.
BOOL CProgressDlg::SetButtonState(int nIDDlgItem,BOOL fEnabled)
{
BOOL fResult = FALSE;
HWND hwndCtrl = GetDlgItem(m_hwnd,nIDDlgItem);
HWND hwndFocus = NULL;
if (hwndCtrl)
{
if (!fEnabled) // don't bother getting focus if not disabling.
{
hwndFocus = GetFocus();
}
fResult = EnableWindow(GetDlgItem(m_hwnd,nIDDlgItem),fEnabled);
// if control had the focus. and now it doesn't then tab to the
// next control
if (hwndFocus == hwndCtrl
&& !fEnabled)
{
SetFocus(GetDlgItem(m_hwnd,IDC_DETAILS));
}
}
return fResult;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::InitializeHwnd, private
//
// Synopsis: Called by WM_INIT.
// m_hwnd member is not setup yet so refer to hwnd.
//
// Sets up items specific to the UI
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::InitializeHwnd(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
HWND hwndList = GetDlgItem(hwnd,IDC_LISTBOXERROR);
m_hwnd = hwnd; // setup the hwnd.
m_fHwndRightToLeft = IsHwndRightToLeft(m_hwnd);
// IF THE HWND IS RIGHT TO LEFT HIDE
// SIZE CONTROL UNTIL RESIZE WORKS.
if (m_fHwndRightToLeft)
{
ShowWindow(GetDlgItem(m_hwnd,IDC_PROGRESSRESIZESCROLLBAR),SW_HIDE);
}
InterlockedExchange(&m_lTimerSet, 0);
if (m_fnResultsListBox = (WNDPROC) GetWindowLongPtr(hwndList,GWLP_WNDPROC))
{
SetWindowLongPtr(hwndList, GWLP_WNDPROC, (LONG_PTR) ResultsListBoxWndProc);
}
m_cbNumDlgResizeItemsCollapsed = 0; // if fail then we don't resize anything.
m_cbNumDlgResizeItemsExpanded = 0;
// init resize items, be default nothing will move.
m_ptMinimumDlgExpandedSize.x = 0;
m_ptMinimumDlgExpandedSize.y = 0;
m_cyCollapsed = 0;
m_fExpanded = FALSE;
m_fMaximized = FALSE;
RECT rectParent;
//Setup the toolbar pushpin
InitializeToolbar(hwnd);
if (GetClientRect(hwnd,&rectParent))
{
ULONG itemCount;
DlgResizeList *pResizeList;
// loop through resize list
Assert(NUM_DLGRESIZEINFO_PROGRESS == (sizeof(g_ProgressResizeList)/sizeof(DlgResizeList)) );
pResizeList = (DlgResizeList *) &g_ProgressResizeList;
// loop through collapsed items
for (itemCount = 0; itemCount < NUM_DLGRESIZEINFO_PROGRESS_COLLAPSED; ++itemCount)
{
if(InitResizeItem(pResizeList->iCtrlId,
pResizeList->dwDlgResizeFlags,hwnd,&rectParent,&(m_dlgResizeInfo[m_cbNumDlgResizeItemsCollapsed])))
{
++m_cbNumDlgResizeItemsCollapsed; // if fail then we don't resize anything.
++m_cbNumDlgResizeItemsExpanded;
}
++pResizeList;
}
// loop through expanded items
for (itemCount = NUM_DLGRESIZEINFO_PROGRESS_COLLAPSED;
itemCount < NUM_DLGRESIZEINFO_PROGRESS; ++itemCount)
{
if(InitResizeItem(pResizeList->iCtrlId,
pResizeList->dwDlgResizeFlags,hwnd,&rectParent,&(m_dlgResizeInfo[m_cbNumDlgResizeItemsExpanded])))
{
++m_cbNumDlgResizeItemsExpanded;
}
++pResizeList;
}
}
// store the current width and height as the
// the min for expanded and as the current expanded height
// if GetWindowRect fails not much we can do.
if (GetWindowRect(hwnd,&m_rcDlg))
{
RECT rcSep;
m_ptMinimumDlgExpandedSize.x = m_rcDlg.right - m_rcDlg.left;
m_ptMinimumDlgExpandedSize.y = m_rcDlg.bottom - m_rcDlg.top;
// use the separator position as the max height when collapsed
if (GetWindowRect(GetDlgItem(hwnd, IDC_SP_SEPARATOR), &rcSep))
{
m_cyCollapsed = rcSep.top - m_rcDlg.top;
}
}
if (InitializeTabs(hwnd)) // If these fail user just won't see probress..
{
InitializeUpdateList(hwnd);
InitializeResultsList(hwnd);
}
// setup font for status text
SetCtrlFont(GetDlgItem(hwnd,IDC_STATIC_WHATS_UPDATING),g_OSVersionInfo.dwPlatformId,g_LangIdSystem);
SetCtrlFont(GetDlgItem(hwnd,IDC_STATIC_WHATS_UPDATING_INFO),g_OSVersionInfo.dwPlatformId,g_LangIdSystem);
Animate_Open(GetDlgItem(hwnd,IDC_UPDATEAVI),MAKEINTRESOURCE(IDA_UPDATE));
return TRUE; // return true if want to use default focus.
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnPaint()
//
// PURPOSE: Handle the WM_PAINT message dispatched from the dialog
//
//--------------------------------------------------------------------------------
void CProgressDlg::OnPaint(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// if not currently animating and
// have already added things to the dialog then draw the icons
if (!(m_dwProgressFlags & PROGRESSFLAG_PROGRESSANIMATION)
&& !(m_dwProgressFlags & PROGRESSFLAG_NEWDIALOG) )
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(m_hwnd, &ps);
if (hDC)
{
HICON hIcon;
if (m_iErrorCount > 0)
{
hIcon = LoadIcon(NULL,IDI_ERROR);
}
else if (m_iWarningCount > 0)
{
hIcon = LoadIcon(NULL,IDI_WARNING);
}
else
{
hIcon = LoadIcon(NULL,IDI_INFORMATION);
}
if (hIcon)
{
DrawIcon(hDC, 7, 10,hIcon);
}
EndPaint(m_hwnd, &ps);
}
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::RedrawIcon()
//
// PURPOSE: Clear/Draw the completed icon
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::RedrawIcon()
{
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 37;
rc.bottom = 40;
InvalidateRect(m_hwnd, &rc, TRUE);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnShowError, private
//
// Synopsis: Calls appropriate handlers ShowError method.
//
// Arguments: [wHandlerId] - Id of handler to call.
// [hwndParent]- hwnd to use as the parent.
// [ErrorId] - Identifies the Error.
//
// Returns: NOERROR - If ShowError was called
// S_FALSE - if already in ShowErrorCall
// appropriate error codes.
//
// Modifies:
//
// History: 04-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CProgressDlg::OnShowError(HANDLERINFO *pHandlerId,HWND hwndParent,REFSYNCMGRERRORID ErrorID)
{
HRESULT hr = S_FALSE; // if don't call ShowError should return S_FALSE
// only allow one ShowError Call at a time.
if (!(m_dwProgressFlags & PROGRESSFLAG_INSHOWERRORSCALL)
&& !(m_dwProgressFlags & PROGRESSFLAG_DEAD))
{
Assert(!(m_dwProgressFlags & PROGRESSFLAG_SHOWERRORSCALLBACKCALLED));
m_dwProgressFlags |= PROGRESSFLAG_INSHOWERRORSCALL;
// hold alive - stick two references so we can always just release
// at end of ShowError and ShowErrorCompleted methods.
m_dwShowErrorRefCount += 2;
AddRefProgressDialog();
AddRefProgressDialog();
hr = m_HndlrQueue->ShowError(pHandlerId,hwndParent,ErrorID);
m_dwProgressFlags &= ~PROGRESSFLAG_INSHOWERRORSCALL;
// if callback with an hresult or retry came in while we were
// in our out call then post the transfer
if (m_dwProgressFlags & PROGRESSFLAG_SHOWERRORSCALLBACKCALLED)
{
m_dwProgressFlags &= ~PROGRESSFLAG_SHOWERRORSCALLBACKCALLED;
// need to sendmessage so queued up before release.
SendMessage(m_hwnd,WM_PROGRESS_TRANSFERQUEUEDATA,(WPARAM) 0, (LPARAM) NULL);
}
--m_dwShowErrorRefCount;
// count can go negative if handler calls completion routine on an error. if
// this is the case just set it to zero
if ( ((LONG) m_dwShowErrorRefCount) < 0)
{
AssertSz(0,"Negative ErrorCount");
m_dwShowErrorRefCount = 0;
}
else
{
ReleaseProgressDialog(m_fForceClose);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnResetKillHandlersTimers, private
//
// Synopsis: Called to reset the Kill Handlers
// Timer. Called as a SendMessage From the handlrqueue
// Cancel Call.
//
// !!!This funciton won't create the Timer if it doesn't
// already exist by design since queue could be in a cancel
// in a state we don't want to force kill as in the case
// of an offIdle
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 19-Nov-1998 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnResetKillHandlersTimers(void)
{
if (m_lTimerSet && !(m_dwProgressFlags & PROGRESSFLAG_INTERMINATE))
{
// SetTimer with the same hwnd and Id will replace the existing.
Assert(m_nKillHandlerTimeoutValue >= TIMERID_KILLHANDLERSMINTIME);
SetTimer(m_hwnd,TIMERID_KILLHANDLERS,m_nKillHandlerTimeoutValue,NULL);
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnCancel()
//
// PURPOSE: handles cancelling of the dialog
//
//--------------------------------------------------------------------------------
void CProgressDlg::OnCancel(BOOL fOffIdle)
{
// if dialog isn't dead and not in a showerrorcall then
// already in a cancel
// addref/release. if no more refs we will go away.
if (!fOffIdle)
{
// set cancelpressed flag if the user invoked the cancel.
m_dwProgressFlags |= PROGRESSFLAG_CANCELPRESSED;
if (!m_lTimerSet)
{
InterlockedExchange(&m_lTimerSet, 1);
Assert(m_nKillHandlerTimeoutValue >= TIMERID_KILLHANDLERSMINTIME);
SetTimer(m_hwnd,TIMERID_KILLHANDLERS,m_nKillHandlerTimeoutValue,NULL);
}
if ( (m_dwProgressFlags & PROGRESSFLAG_REGISTEREDFOROFFIDLE)
&& !(m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE) )
{
IdleCallback(STATE_USER_IDLE_END); // make sure offidle gets set if user presses cancel
}
}
if (!(m_dwProgressFlags & PROGRESSFLAG_DEAD) && !m_dwShowErrorRefCount
&& !(m_dwProgressFlags & PROGRESSFLAG_INCANCELCALL)
&& !(m_dwProgressFlags & PROGRESSFLAG_INTERMINATE))
{
// just cancel the queue, when items
// come though cancel
// it is possible that the dialog has already been removed from the
// object list and the User hit stop again.
SetProgressReleaseDlgCmdId(m_clsid,this,RELEASEDLGCMDID_CANCEL); // set so cleanup knows it was stopped by user..
// if handlethread is in shutdown then just fall through
if (!(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP))
{
AddRefProgressDialog(); // hold dialog alive until cancel is complete
// Get the state of the stop button before the call
// because it could transition to close during the Canel
BOOL fForceShutdown = !(m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS);
m_dwProgressFlags |= PROGRESSFLAG_INCANCELCALL;
if (m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS)
{
//
// Replace the STOP button text with "Stopping" and
// disable the button. This gives the user positive feedback
// that the operation is being stopped. We'll re-enable
// the button whenever it's text is changed.
//
const HWND hwndStop = GetDlgItem(m_hwnd, IDSTOP);
TCHAR szText[80];
if (0 < LoadString(g_hInst, IDS_STOPPING, szText, ARRAY_SIZE(szText)))
{
SetWindowText(hwndStop, szText);
}
EnableWindow(hwndStop, FALSE);
}
m_HndlrQueue->Cancel();
m_dwProgressFlags &= ~PROGRESSFLAG_INCANCELCALL;
// addref/release lifetime in case locked open.
// OffIdle case: then do a soft release so dialog doesn't
// go away.
// Non Idle case: Set the fForceClose After the call
// incase the pushpin change or errors came in during the Cancel
ReleaseProgressDialog(fOffIdle ? m_fForceClose : fForceShutdown );
}
else
{
// set flag so shutdown knows a cancel was pressed
m_dwProgressFlags |= PROGRESSFLAG_CANCELWHILESHUTTINGDOWN;
}
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnCommand()
//
// PURPOSE: Handle the various command messages dispatched from the dialog
//
//--------------------------------------------------------------------------------
void CProgressDlg::OnCommand(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
WORD wID = LOWORD(wParam); // item, control, or accelerator identifier
WORD wNotifyCode HIWORD(wParam);
switch (wID)
{
case IDC_SKIP_BUTTON_MAIN:
{
if (m_pItemListView)
{
if (m_iProgressSelectedItem != -1)
{
//Skip this item:
if (!(m_dwProgressFlags & PROGRESSFLAG_DEAD))
{
LVHANDLERITEMBLOB lvHandlerItemBlob;
lvHandlerItemBlob.cbSize = sizeof(LVHANDLERITEMBLOB);
if (m_pItemListView->GetItemBlob(m_iProgressSelectedItem,
(LPLVBLOB) &lvHandlerItemBlob,lvHandlerItemBlob.cbSize))
{
++m_dwSetItemStateRefCount;
AddRefProgressDialog();
m_HndlrQueue->SkipItem(lvHandlerItemBlob.clsidServer,
lvHandlerItemBlob.ItemID);
--m_dwSetItemStateRefCount;
ReleaseProgressDialog(m_fForceClose);
}
}
//Disable the Skip button for this item
SetButtonState(IDC_SKIP_BUTTON_MAIN,FALSE);
}
}
break;
}
case IDC_PROGRESS_OPTIONS_BUTTON_MAIN:
{
// !!! if skip has the focus set it to settings since while the
// settings dialog is open the skip could go disabled.
if (GetFocus() == GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN))
{
SetFocus(GetDlgItem(m_hwnd,IDC_PROGRESS_OPTIONS_BUTTON_MAIN));
}
ShowOptionsDialog(m_hwnd);
}
break;
case IDCANCEL:
wNotifyCode = BN_CLICKED; // make sure notify code is clicked and fall through
case IDSTOP:
{
if (BN_CLICKED == wNotifyCode)
{
OnCancel(FALSE);
}
}
break;
case IDC_PUSHPIN:
{
UINT state = (UINT)SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_GETSTATE,
IDC_PUSHPIN, 0);
m_fPushpin = state & TBSTATE_CHECKED;
SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_CHANGEBITMAP,
IDC_PUSHPIN,
MAKELPARAM(m_fPushpin ? IMAGE_TACK_IN : IMAGE_TACK_OUT, 0));
}
break;
case IDC_DETAILS:
ExpandCollapse(!m_fExpanded, FALSE);
break;
default:
break;
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::ShowProgressTab(int iTab)
//
// PURPOSE:
//
//--------------------------------------------------------------------------------
void CProgressDlg::ShowProgressTab(int iTab)
{
int nCmdUpdateTab;
int nCmdErrorTab;
int nCmdSettingsButton;
BOOL fIsItemWorking = FALSE;
m_iTab = iTab;
EnableWindow(GetDlgItem(m_hwnd, IDC_PROGRESS_TABS), m_fExpanded); // enable/disable tabs based on if dialog is expanded.
EnableWindow(GetDlgItem(m_hwnd, IDC_TOOLBAR), m_fExpanded); // enable/disable pushpin based on if dialog is expanded.
nCmdUpdateTab = ((iTab == PROGRESS_TAB_UPDATE) && (m_fExpanded)) ? SW_SHOW: SW_HIDE;
nCmdErrorTab = ((iTab == PROGRESS_TAB_ERRORS) && (m_fExpanded)) ? SW_SHOW: SW_HIDE;
nCmdSettingsButton = ((iTab == PROGRESS_TAB_UPDATE) && (m_fExpanded)
&& m_fSensInstalled) ? SW_SHOW: SW_HIDE;
switch (iTab)
{
case PROGRESS_TAB_UPDATE:
// Hide the error listview, show the tasks list
ShowWindow(GetDlgItem(m_hwnd,IDC_LISTBOXERROR), nCmdErrorTab);
TabCtrl_SetCurSel(m_hwndTabs, iTab);
EnableWindow(GetDlgItem(m_hwnd,IDC_UPDATE_LIST),m_fExpanded);
// only enable the skip button if there is a selection
// and IsItemWorking()
if (-1 != m_iProgressSelectedItem)
{
fIsItemWorking = IsItemWorking(m_iProgressSelectedItem);
}
EnableWindow(GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN),m_fExpanded && fIsItemWorking);
EnableWindow(GetDlgItem(m_hwnd,IDC_PROGRESS_OPTIONS_BUTTON_MAIN),m_fExpanded && m_fSensInstalled);
EnableWindow(GetDlgItem(m_hwnd,IDC_LISTBOXERROR), FALSE);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_SKIP_TEXT),nCmdUpdateTab);
ShowWindow(GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN),nCmdUpdateTab);
ShowWindow(GetDlgItem(m_hwnd,IDC_PROGRESS_OPTIONS_BUTTON_MAIN),nCmdSettingsButton);
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATE_LIST),nCmdUpdateTab);
break;
case PROGRESS_TAB_ERRORS:
// Hide the update listview, show the error list
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATE_LIST),nCmdUpdateTab);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_SKIP_TEXT),nCmdUpdateTab);
ShowWindow(GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN),nCmdUpdateTab);
ShowWindow(GetDlgItem(m_hwnd,IDC_PROGRESS_OPTIONS_BUTTON_MAIN),nCmdSettingsButton);
TabCtrl_SetCurSel(m_hwndTabs, iTab);
EnableWindow(GetDlgItem(m_hwnd,IDC_UPDATE_LIST),FALSE);
EnableWindow(GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN),FALSE);
EnableWindow(GetDlgItem(m_hwnd,IDC_PROGRESS_OPTIONS_BUTTON_MAIN),FALSE);
EnableWindow(GetDlgItem(m_hwnd,IDC_LISTBOXERROR), m_fExpanded);
ShowWindow(GetDlgItem(m_hwnd,IDC_LISTBOXERROR), nCmdErrorTab);
break;
default:
AssertSz(0,"Unknown Tab");
break;
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::IsItemWorking, private
//
// Synopsis: Determines if Skip should be enabled
// for the listViewItem;
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 12-Aug-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::IsItemWorking(int iListViewItem)
{
BOOL fItemWorking;
LPARAM ItemStatus;
// lastest status is stored in the lParam of the ListBoxItem.
if (!(m_pItemListView->GetItemlParam(iListViewItem,&ItemStatus)))
{
ItemStatus = SYNCMGRSTATUS_STOPPED;
}
fItemWorking = ( ItemStatus == SYNCMGRSTATUS_PENDING ||
ItemStatus == SYNCMGRSTATUS_UPDATING ||
ItemStatus == SYNCMGRSTATUS_PAUSED ||
ItemStatus == SYNCMGRSTATUS_RESUMING );
return fItemWorking;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnNotifyListViewEx, private
//
// Synopsis: Handles ListView Notifications
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
LRESULT CProgressDlg::OnNotifyListViewEx(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int idCtrl = (int) wParam;
LPNMHDR pnmhdr = (LPNMHDR) lParam;
if ( (IDC_UPDATE_LIST != idCtrl) || (NULL == m_pItemListView))
{
Assert(IDC_UPDATE_LIST == idCtrl);
Assert(m_pItemListView);
return 0;
}
switch (pnmhdr->code)
{
case LVN_ITEMCHANGED:
{
NM_LISTVIEW *pnmv = (NM_LISTVIEW FAR *) pnmhdr;
if (pnmv->uChanged == LVIF_STATE)
{
if (pnmv->uNewState & LVIS_SELECTED)
{
m_iProgressSelectedItem = ((LPNMLISTVIEW) pnmhdr)->iItem;
// see if an item is selected and set the properties
// button accordingly
SetButtonState(IDC_SKIP_BUTTON_MAIN,IsItemWorking(m_iProgressSelectedItem));
}
else if (pnmv->uOldState & LVIS_SELECTED)
{
// on deselect see if any other selected items and if not
// set skip to false.
if (0 == m_pItemListView->GetSelectedCount())
{
m_iProgressSelectedItem = -1;
SetButtonState(IDC_SKIP_BUTTON_MAIN,FALSE);
}
}
}
break;
}
default:
break;
}
return 0;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
//
// PURPOSE: Handle the various notification messages dispatched from the dialog
//
//--------------------------------------------------------------------------------
LRESULT CProgressDlg::OnNotify(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int idFrom = (int) wParam;
LPNMHDR pnmhdr = (LPNMHDR) lParam;
// if notification for UpdateListPass it on.
if ((IDC_UPDATE_LIST == idFrom) && m_pItemListView)
{
return m_pItemListView->OnNotify(pnmhdr);
}
else if (IDC_TOOLBAR == idFrom)
{
if (pnmhdr->code == NM_KEYDOWN)
{
if (((LPNMKEY) lParam)->nVKey == TEXT(' ') )
{
UINT state = (UINT)SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_GETSTATE, IDC_PUSHPIN, 0);
state = state^TBSTATE_CHECKED;
SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_SETSTATE, IDC_PUSHPIN, state);
m_fPushpin = state & TBSTATE_CHECKED;
SendDlgItemMessage(m_hwnd, IDC_TOOLBAR, TB_CHANGEBITMAP, IDC_PUSHPIN,
MAKELPARAM(m_fPushpin ? IMAGE_TACK_IN : IMAGE_TACK_OUT, 0));
}
}
}
else if (IDC_PROGRESS_TABS == idFrom)
{
switch (pnmhdr->code)
{
case TCN_SELCHANGE:
{
// Find out which tab is currently active
m_iTab = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, IDC_PROGRESS_TABS));
if (-1 == m_iTab)
{
break;
}
ShowProgressTab(m_iTab);
break;
}
default:
break;
}
}
return 0;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::UpdateProgressValues()
//
// PURPOSE: Updates the value of the ProgressBar
//
//--------------------------------------------------------------------------------
void CProgressDlg::UpdateProgressValues()
{
int iProgValue;
int iMaxValue;
int iNumItemsComplete;
int iNumItemsTotal;
TCHAR pszcomplete[MAX_STRING_RES];
if (!m_pItemListView || !m_HndlrQueue)
{
return;
}
LoadString(g_hInst, IDS_NUM_ITEMS_COMPLETE, pszcomplete, ARRAY_SIZE(pszcomplete));
if (NOERROR == m_HndlrQueue->GetProgressInfo(&iProgValue,&iMaxValue,&iNumItemsComplete,
&iNumItemsTotal) )
{
HWND hwndProgress = GetDlgItem(m_hwnd,IDC_PROGRESSBAR);
TCHAR szHowManBuf[50];
if (hwndProgress)
{
SendMessage(hwndProgress,PBM_SETRANGE,0,MAKELPARAM(0, iMaxValue));
SendMessage(hwndProgress,PBM_SETPOS,(WPARAM) iProgValue,0);
}
wsprintf(szHowManBuf,pszcomplete,iNumItemsComplete,iNumItemsTotal);
Static_SetText(GetDlgItem(m_hwnd,IDC_STATIC_HOW_MANY_COMPLETE), szHowManBuf);
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::UpdateDetailsInfo(DWORD dwStatusType, HWND hwndList,
// int iItem, TCHAR *pszItemInfo)
//
// PURPOSE: provide info in the non-details progress view.
//
//--------------------------------------------------------------------------------
void CProgressDlg::UpdateDetailsInfo(DWORD dwStatusType,int iItem, TCHAR *pszItemInfo)
{
BOOL fNewNameField = TRUE;
BOOL fInfoField = FALSE;
TCHAR pszItemName[MAX_SYNCMGRITEMNAME + 1];
TCHAR pszFormatString[MAX_PATH + 1];
TCHAR pszNameString[MAX_PATH + 1];
if ((m_dwLastStatusType == dwStatusType) && (m_iLastItem == iItem))
{
fNewNameField = FALSE;
}
//Strip the item info of white space
if (pszItemInfo)
{
int i = lstrlen(pszItemInfo) - 1;
while (i >=0 &&
(pszItemInfo[i] == TEXT(' ') || pszItemInfo[i] == TEXT('\n')
|| pszItemInfo[i] == TEXT('\t')))
{
pszItemInfo[i] = NULL;
i--;
}
if (i >= 0)
{
fInfoField = TRUE;
}
}
// If Called Callback for an Item in Pending mode
// but no item text don't bother updating the top display.
if ((SYNCMGRSTATUS_PENDING == dwStatusType)
&& (FALSE == fInfoField))
{
return;
}
m_dwLastStatusType = dwStatusType;
m_iLastItem = iItem;
if (fNewNameField && m_pItemListView)
{
//Get the item name
*pszItemName = NULL;
m_pItemListView->GetItemText(iItem,PROGRESSLIST_NAMECOLUMN,
pszItemName, MAX_SYNCMGRITEMNAME);
switch (dwStatusType)
{
case SYNCMGRSTATUS_STOPPED:
{
LoadString(g_hInst, IDS_STOPPED_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_SKIPPED:
{
LoadString(g_hInst, IDS_SKIPPED_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_PENDING:
{
LoadString(g_hInst, IDS_PENDING_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_UPDATING:
{
LoadString(g_hInst, IDS_SYNCHRONIZING_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_SUCCEEDED:
{
LoadString(g_hInst, IDS_SUCCEEDED_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_FAILED:
{
LoadString(g_hInst, IDS_FAILED_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_PAUSED:
{
LoadString(g_hInst, IDS_PAUSED_ITEM,pszFormatString, MAX_PATH);
}
break;
case SYNCMGRSTATUS_RESUMING:
{
LoadString(g_hInst, IDS_RESUMING_ITEM,pszFormatString, MAX_PATH);
}
break;
default:
{
AssertSz(0,"Unknown Status Type");
lstrcpy(pszFormatString,TEXT("%ws"));
}
break;
}
wsprintf(pszNameString,pszFormatString, pszItemName);
Static_SetText(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING), pszNameString);
}
// if don't have an info field but did update the name then set the info field
// to blank
if (fInfoField)
{
Static_SetText(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING_INFO), pszItemInfo);
}
else if (fNewNameField)
{
Static_SetText(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING_INFO), L"");
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::HandleProgressUpdate(HWND hwnd, WPARAM wParam,LPARAM lParam)
//
// PURPOSE: Handle the progress bar update for the progress dialog
//
//--------------------------------------------------------------------------------
void CProgressDlg::HandleProgressUpdate(HWND hwnd, WPARAM wParam,LPARAM lParam)
{
PROGRESSUPDATEDATA *progressData = (PROGRESSUPDATEDATA *) wParam;
SYNCMGRPROGRESSITEM *lpSyncProgressItem = (SYNCMGRPROGRESSITEM *) lParam;
LVHANDLERITEMBLOB lvHandlerItemBlob;
int iItem = -1;
BOOL fProgressItemChanged = FALSE;
if (!m_pItemListView)
{
return;
}
// if emptyItem is in list View delete it.
lvHandlerItemBlob.cbSize = sizeof(LVHANDLERITEMBLOB);
lvHandlerItemBlob.clsidServer = (progressData->clsidHandler);
lvHandlerItemBlob.ItemID = (progressData->ItemID);
iItem = m_pItemListView->FindItemFromBlob((LPLVBLOB) &lvHandlerItemBlob);
if (-1 == iItem)
{
AssertSz(0,"Progress Update on Item not in ListView");
return;
}
if (SYNCMGRPROGRESSITEM_STATUSTYPE & lpSyncProgressItem->mask)
{
if (lpSyncProgressItem->dwStatusType <= SYNCMGRSTATUS_RESUMING)
{
// update the listview items lParam
m_pItemListView->SetItemlParam(iItem,lpSyncProgressItem->dwStatusType);
m_pItemListView->SetItemText(iItem,PROGRESSLIST_STATUSCOLUMN,
m_pszStatusText[lpSyncProgressItem->dwStatusType]);
//Update Skip button if this item is selected
if (m_iProgressSelectedItem == iItem)
{
BOOL fItemComplete = ( (lpSyncProgressItem->dwStatusType == SYNCMGRSTATUS_SUCCEEDED) ||
(lpSyncProgressItem->dwStatusType == SYNCMGRSTATUS_FAILED) ||
(lpSyncProgressItem->dwStatusType == SYNCMGRSTATUS_SKIPPED) ||
(lpSyncProgressItem->dwStatusType == SYNCMGRSTATUS_STOPPED) );
EnableWindow(GetDlgItem(m_hwnd,IDC_SKIP_BUTTON_MAIN),!fItemComplete);
}
}
}
if (SYNCMGRPROGRESSITEM_STATUSTEXT & lpSyncProgressItem->mask )
{
#define MAXDISPLAYBUF 256
TCHAR displaybuf[MAXDISPLAYBUF]; // make a local copy of ths display buf
*displaybuf = NULL;
if (NULL != lpSyncProgressItem->lpcStatusText)
{
lstrcpyn(displaybuf,lpSyncProgressItem->lpcStatusText,MAXDISPLAYBUF);
// make sure last char is a null in case handler passed us a large string.
Assert(MAXDISPLAYBUF > 0);
TCHAR *pEndBuf = displaybuf + MAXDISPLAYBUF -1;
*pEndBuf = NULL;
}
if (NULL != displaybuf)
{
m_pItemListView->SetItemText(iItem,PROGRESSLIST_INFOCOLUMN,displaybuf);
}
LPARAM ItemStatus;
if (!(SYNCMGRPROGRESSITEM_STATUSTYPE & lpSyncProgressItem->mask))
{
if (!(m_pItemListView->GetItemlParam(iItem,&ItemStatus)))
{
AssertSz(0,"failed to get item lParam");
ItemStatus = SYNCMGRSTATUS_STOPPED;
}
}
else
{
ItemStatus = lpSyncProgressItem->dwStatusType;
}
Assert(ItemStatus == ((LPARAM) (DWORD) ItemStatus));
UpdateDetailsInfo( (DWORD) ItemStatus,iItem, displaybuf);
}
// now update the items progress value information
if (S_OK == m_HndlrQueue->SetItemProgressInfo(progressData->pHandlerID,
progressData->wItemId,
lpSyncProgressItem,&fProgressItemChanged))
{
// recalcing the progress bar and numItems completed values
// can become expensive with a large amount of items so it callback
// was called but didn't change status or min/max of the item
// don't bother updating the progress values.
if (fProgressItemChanged)
{
UpdateProgressValues();
}
}
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::AddListData(LBDATA *pData,int iNumChars, HWND hwndList)
//
// PURPOSE: Handle the adding item data to the list for the results pane
//
//--------------------------------------------------------------------------------
void CProgressDlg::AddListData(LBDATA *pData, int iNumChars, HWND hwndList)
{
// Save current item in global for use by MeasureItem handler
Assert(NULL == m_CurrentListEntry); // catch any recursion case.
m_CurrentListEntry = pData;
// ... add the string first...
//the text is freed by the list box
int iItem = ListBox_AddString( hwndList, pData->pszText);
// (Note that the WM_MEASUREITEM is sent at this point)
// ...now attach the data.
ListBox_SetItemData( hwndList, iItem, pData);
m_CurrentListEntry = NULL;
// pData is freed by the list box
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::HandleLogError(HWND hwnd, WORD pHandlerID,MSGLogErrors *msgLogErrors)
//
// PURPOSE: Handle the error logging tab for the progress dialog
//
//--------------------------------------------------------------------------------
void CProgressDlg::HandleLogError(HWND hwnd, HANDLERINFO *pHandlerID,MSGLogErrors *lpmsgLogErrors)
{
LBDATA *pData = NULL;
INT iNumChars;
TCHAR szBuffer[MAX_STRING_RES]; // buffer used for loading string resources
HWND hwndList;
hwndList = GetDlgItem(m_hwnd,IDC_LISTBOXERROR);
if (!hwndList)
{
return;
}
//Remove the "No Errors" when the first error is encountered
if (++m_iResultCount == 0)
{
ListBox_ResetContent(hwndList);
}
// determine if handlerId and ItemId are valid.ItemID
// if handlerId isn't valid we don't bother with the ItemId
SYNCMGRHANDLERINFO SyncMgrHandlerInfo;
SYNCMGRITEM offlineItem;
DWORD cbItemLen = 0;
DWORD cbHandlerLen = 0;
UINT uIDResource;
// preset both to NULL
*(SyncMgrHandlerInfo.wszHandlerName) = NULL;
*(offlineItem.wszItemName) = NULL;
// if can't get the ParentInfo then don't add the Item
// pHandlerId can be NULL if we logged the Error Ourselves.
if (pHandlerID && m_HndlrQueue
&& (NOERROR == m_HndlrQueue->GetHandlerInfo(pHandlerID,&SyncMgrHandlerInfo)))
{
cbHandlerLen = lstrlen(SyncMgrHandlerInfo.wszHandlerName);
// now see if we can get the itemName.
if (lpmsgLogErrors->mask & SYNCMGRLOGERROR_ITEMID)
{
BOOL fHiddenItem;
CLSID clsidDataHandler;
if (NOERROR == m_HndlrQueue->GetItemDataAtIndex(pHandlerID,
lpmsgLogErrors->ItemID,
&clsidDataHandler,&offlineItem,&fHiddenItem) )
{
cbItemLen = lstrlen(offlineItem.wszItemName);
}
}
}
// note: handlerName can be an empty string even if GetHandlerInfo did not fail and we
// can still have an Item so need to do the right thing.
// cases
// valid handler and ItemID in LogError
// 1) <icon> <handler name> <(item name)>: <message> (valid handler and ItemID in LogError)
// 2) <icon> <(item name)>: <message> handler name NULL .
// 3) <icon> <handler name>: <message> only valid handler in LogError
// 4) <icon> <message> (handler invalid or mobsync error in LogError)
// => three different format strings
// 1,2 - "%ws (%ws): %ws" // valid item
// 3 - "%ws: %ws" // only valid handler.
// 4 - "%ws" // no handler or item
if (cbItemLen)
{
uIDResource = IDS_LOGERRORWITHITEMID;
}
else if (cbHandlerLen)
{
uIDResource = IDS_LOGERRORNOITEMID;
}
else
{
uIDResource = IDS_LOGERRORNOHANDLER;
}
if (0 == LoadString(g_hInst, uIDResource, szBuffer, ARRAY_SIZE(szBuffer)))
{
// if couldn't loadstring then set to empty string so an empty string
// gets logged. If string is truncated will just print the trucated string.
*szBuffer = NULL;
}
// get the number of characters we need to allocate for
iNumChars = lstrlen(lpmsgLogErrors->lpcErrorText)
+ cbHandlerLen
+ cbItemLen
+ lstrlen(szBuffer);
// Allocate a struct for the item data
if (!(pData = (LBDATA *) ALLOC(sizeof(LBDATA) + ((iNumChars + 1)*sizeof(TCHAR)))))
{
return;
}
// now format the string using the same logic as used to load
// the proper resource
if (cbItemLen)
{
wsprintf(pData->pszText,szBuffer,SyncMgrHandlerInfo.wszHandlerName,
offlineItem.wszItemName,lpmsgLogErrors->lpcErrorText);
}
else if (cbHandlerLen)
{
wsprintf(pData->pszText,szBuffer,SyncMgrHandlerInfo.wszHandlerName,
lpmsgLogErrors->lpcErrorText);
}
else
{
wsprintf(pData->pszText,szBuffer,lpmsgLogErrors->lpcErrorText);
}
// error text is not a jump but has same ErrorID
pData->fIsJump = FALSE;
pData->fTextRectValid = FALSE;
pData->ErrorID = lpmsgLogErrors->ErrorID;
pData->dwErrorLevel = lpmsgLogErrors->dwErrorLevel;
pData->pHandlerID = pHandlerID;
pData->fHasBeenClicked = FALSE;
pData->fAddLineSpacingAtEnd = FALSE;
//insert the icon
//ToDo:Add client customizable icons?
switch (lpmsgLogErrors->dwErrorLevel)
{
case SYNCMGRLOGLEVEL_INFORMATION:
pData->IconIndex = m_ErrorImages[ErrorImage_Information];
break;
case SYNCMGRLOGLEVEL_WARNING:
++m_iWarningCount;
pData->IconIndex = m_ErrorImages[ErrorImage_Warning];
break;
case SYNCMGRLOGLEVEL_ERROR:
default:
// if an error occurs we want to keep the dialog alive
++m_iErrorCount;
pData->IconIndex = m_ErrorImages[ErrorImage_Error];
break;
}
if (!lpmsgLogErrors->fHasErrorJumps)
{
pData->fAddLineSpacingAtEnd = TRUE;
}
// Add the item data
AddListData(pData, (iNumChars)*sizeof(TCHAR), hwndList);
if (lpmsgLogErrors->fHasErrorJumps)
{
//This is make the "For more info" apprear closer,
//More associated with the item it corresponds to
// Allocate a struct for the item data
LoadString(g_hInst, IDS_JUMPTEXT, szBuffer, ARRAY_SIZE(szBuffer));
// Review, why not strlen instead of total size of szBuffer.
if (!(pData = (LBDATA *) ALLOC(sizeof(LBDATA) + sizeof(szBuffer))))
{
return;
}
pData->IconIndex = -1;
// we always set ErrorID to GUID_NULL if one wasn't given
// and fHasErrorJumpst to false.
pData->fIsJump = lpmsgLogErrors->fHasErrorJumps;
pData->fTextRectValid = FALSE;
pData->ErrorID = lpmsgLogErrors->ErrorID;
pData->dwErrorLevel = lpmsgLogErrors->dwErrorLevel;
pData->pHandlerID = pHandlerID;
pData->fHasBeenClicked = FALSE;
pData->fAddLineSpacingAtEnd = TRUE; // always put space after
lstrcpy(pData->pszText,szBuffer);
AddListData(pData, sizeof(szBuffer), hwndList);
}
// new item could have caused the Scrollbar to be drawn. Need to
// recalc listbox
OnProgressResultsSize(m_hwnd,this,WM_SIZE,0,0);
// if tray icon is shown and not currently syncing any items
// make sure it has the most up to date info. if syncing just
// let the timer.
if (!(m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS))
{
UpdateTrayIcon();
}
return;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::HandleDeleteLogError(HWND hwnds)
//
// PURPOSE: Deletes matching errors that have been logged.
//
//--------------------------------------------------------------------------------
void CProgressDlg::HandleDeleteLogError(HWND hwnd,MSGDeleteLogErrors *pDeleteLogError)
{
HWND hwndList = GetDlgItem(m_hwnd,IDC_LISTBOXERROR);
int iItemCount;
LBDATA *pData = NULL;
if (NULL == hwndList)
return;
iItemCount = ListBox_GetCount(hwndList);
// loop through the logged errors finding any matches.
// if the passed in ErrorID is GUID_NULL then delete all errors associated with this
// handler.
while(iItemCount--)
{
if (pData = (LBDATA *) ListBox_GetItemData(hwndList,iItemCount))
{
if ((pData->pHandlerID == pDeleteLogError->pHandlerId)
&& ( (pData->ErrorID == pDeleteLogError->ErrorID)
|| (GUID_NULL == pDeleteLogError->ErrorID) )
)
{
if ( !pData->fIsJump )
{
//
// Decrement count for non-jump items only to avoid
// double decrements.
//
m_iResultCount--;
if ( pData->dwErrorLevel == SYNCMGRLOGLEVEL_WARNING )
{
Assert( m_iWarningCount > 0 );
m_iWarningCount--;
}
else if ( pData->dwErrorLevel == SYNCMGRLOGLEVEL_ERROR )
{
Assert( m_iErrorCount > 0 );
m_iErrorCount--;
}
}
ListBox_DeleteString(hwndList,iItemCount);
}
}
}
//
// If all items have been removed, add default no-error item
//
iItemCount = ListBox_GetCount(hwndList);
if ( iItemCount == 0 )
{
m_iResultCount = -1;
TCHAR pszError[MAX_STRING_RES];
LoadString(g_hInst, IDS_NOERRORSREPORTED, pszError, ARRAY_SIZE(pszError));
//
// Allocate a struct for the item data
//
LBDATA *pData = NULL;
if (!(pData = (LBDATA *) ALLOC(sizeof(LBDATA) + sizeof(pszError))))
return;
pData->fIsJump = FALSE;
pData->fTextRectValid = FALSE;
pData->fHasBeenClicked = FALSE;
pData->fAddLineSpacingAtEnd = FALSE;
pData->ErrorID = GUID_NULL;
pData->dwErrorLevel = SYNCMGRLOGLEVEL_INFORMATION;
pData->pHandlerID = 0;
lstrcpy(pData->pszText, pszError);
pData->IconIndex = m_ErrorImages[ErrorImage_Information];
AddListData(pData, sizeof(pszError), hwndList);
}
// recalc listbox heights to accomodate the new value.
OnProgressResultsSize(m_hwnd,this,WM_SIZE,0,0);
// if tray icon is shown and not currently syncing any items
// make sure it has the most up to date info. if syncing just
// let the timer.
if (!(m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS))
UpdateTrayIcon();
}
//--------------------------------------------------------------------------------
//
// FUNCTION: BOOL CProgressDlg::ShowCompletedProgress(BOOL fComplete)
//
// PURPOSE: Show the dialog in the completed state
//
//--------------------------------------------------------------------------------
BOOL CProgressDlg::ShowCompletedProgress(BOOL fComplete,BOOL fDialogIsLocked)
{
TCHAR szBuf[MAX_STRING_RES];
LoadString(g_hInst, fComplete? IDS_PROGRESSCOMPLETETITLE : IDS_PROGRESSWORKINGTITLE,
szBuf,
ARRAY_SIZE(szBuf));
SetWindowText(m_hwnd, szBuf);
if (fComplete)
{
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATEAVI), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_FOLDER1), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_FOLDER2), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING_INFO), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_PROGRESSBAR), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_HOW_MANY_COMPLETE), SW_HIDE);
if (m_iErrorCount > 0 )
{
LoadString(g_hInst, IDS_PROGRESSCOMPLETEERROR, szBuf, ARRAY_SIZE(szBuf));
}
else if (m_iWarningCount > 0 )
{
LoadString(g_hInst, IDS_PROGRESSCOMPLETEWARNING, szBuf, ARRAY_SIZE(szBuf));
}
else
{
LoadString(g_hInst, IDS_PROGRESSCOMPLETEOK, szBuf, ARRAY_SIZE(szBuf));
}
SetDlgItemText(m_hwnd, IDC_RESULTTEXT, szBuf);
ShowWindow(GetDlgItem(m_hwnd,IDC_RESULTTEXT), SW_SHOW);
//Change the Stop to "Close" if the dialog is going to be
// remained open
if (fDialogIsLocked)
{
LoadString(g_hInst, IDS_CLOSE, szBuf, ARRAY_SIZE(szBuf));
SetWindowText(GetDlgItem(m_hwnd,IDSTOP), szBuf);
EnableWindow(GetDlgItem(m_hwnd,IDSTOP), TRUE);
}
}
else
{
ShowWindow(GetDlgItem(m_hwnd,IDC_RESULTTEXT), SW_HIDE);
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATEAVI), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_FOLDER1), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_FOLDER2), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_WHATS_UPDATING_INFO), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_PROGRESSBAR), SW_SHOW);
ShowWindow(GetDlgItem(m_hwnd,IDC_STATIC_HOW_MANY_COMPLETE), SW_SHOW);
//Change the "Close" to "Stop"
LoadString(g_hInst, IDS_STOP, szBuf, ARRAY_SIZE(szBuf));
SetWindowText(GetDlgItem(m_hwnd,IDSTOP), szBuf);
EnableWindow(GetDlgItem(m_hwnd,IDSTOP), TRUE);
}
RedrawIcon();
return TRUE;
}
//--------------------------------------------------------------------------------
//
// Function: DoSyncTask
//
// Synopsis: Drives the handlers actual synchronization routines
//
//--------------------------------------------------------------------------------
void CProgressDlg::DoSyncTask(HWND hwnd)
{
HANDLERINFO *pHandlerID;
ULONG cDlgRefs;
BOOL fRepostedStart = FALSE; // set if posted message to ourselves.
CLSID pHandlerClsid;
Assert(!(m_dwProgressFlags & PROGRESSFLAG_DEAD));
++m_dwHandleThreadNestcount;
// if handlerNestCount is > 1 which it can on a transfer
// or when multiple items are going even on an error
// if this is the case then just return
if (m_dwHandleThreadNestcount > 1)
{
Assert(1 == m_dwHandleThreadNestcount);
m_dwHandleThreadNestcount--;
return;
}
// review - order should be set inhandleroutcall
// an then reset flags for completion and transfers.
// reset callback flag so receive another one if
// message comes in
m_dwProgressFlags &= ~PROGRESSFLAG_CALLBACKPOSTED;
// first thing through make sure all our state is setup.
// set the syncing flag
m_dwProgressFlags |= PROGRESSFLAG_SYNCINGITEMS;
// set our Call flag so callback knows not to post to us
// if we are handling call
Assert(!(m_dwProgressFlags & PROGRESSFLAG_INHANDLEROUTCALL));
m_dwProgressFlags |= PROGRESSFLAG_INHANDLEROUTCALL;
m_dwProgressFlags &= ~PROGRESSFLAG_COMPLETIONROUTINEWHILEINOUTCALL; // reset completion routine
m_dwProgressFlags &= ~PROGRESSFLAG_NEWITEMSINQUEUE; // reset new items in queue flag
m_dwProgressFlags &= ~PROGRESSFLAG_STARTPROGRESSPOSTED; // reset post flag.
if (!(m_dwProgressFlags & PROGRESSFLAG_IDLENETWORKTIMER))
{
m_dwProgressFlags |= PROGRESSFLAG_IDLENETWORKTIMER;
// reset network idle initially to keep hangup from happening and setup a timer
// to keep resetting the idle until the sync is complete.
ResetNetworkIdle();
SetTimer(m_hwnd,TIMERID_NOIDLEHANGUP,NOIDLEHANGUP_REFRESHRATE,NULL);
}
UpdateProgressValues();
if (m_clsid != GUID_PROGRESSDLGIDLE)
{
// if there is a server we are currently synchronizing but out count
// is zero then reset to GUID_NULL else use our clsidHandlerInSync
// so next handler matches the one we are currently syncing.
if (0 == m_dwHandlerOutCallCount) // if no outcalls we don't care what handler gets matched.
{
m_clsidHandlerInSync = GUID_NULL;
}
// find the next set of items that match our criteria by seeing
// if there is any handler that matches out guid (if guid_null just
// matches first item in state
// then loop through all handlers matching the guid
// in the same state.
// see if there are any items that need PrepareForSyncCalled on them
if (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_PREPAREFORSYNC,m_clsidHandlerInSync,
&pHandlerID,&m_clsidHandlerInSync))
{
++m_dwHandlerOutCallCount;
++m_dwPrepareForSyncOutCallCount;
m_HndlrQueue->PrepareForSync(pHandlerID,hwnd);
// see if any other handlers that match the clsid and also call their
// PrepareForSync methods.
while (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_PREPAREFORSYNC,m_clsidHandlerInSync,
&pHandlerID,&m_clsidHandlerInSync))
{
++m_dwHandlerOutCallCount;
++m_dwPrepareForSyncOutCallCount;
m_HndlrQueue->PrepareForSync(pHandlerID,hwnd);
}
}
else if ( (0 == m_dwPrepareForSyncOutCallCount)
&& (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_SYNCHRONIZE,m_clsidHandlerInSync,&pHandlerID,
&m_clsidHandlerInSync)) )
{
// no prepareforsync so if there aren't any more handlers in prerpareforsync
// calls kick off someones synchronize. see if any synchronize methods.
++m_dwHandlerOutCallCount;
++m_dwSynchronizeOutCallCount;
m_HndlrQueue->Synchronize(pHandlerID,hwnd);
// see if any other handlers that match the clsid and also call their
// synchronize methods.
while (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_SYNCHRONIZE,m_clsidHandlerInSync,
&pHandlerID,&m_clsidHandlerInSync))
{
++m_dwHandlerOutCallCount;
++m_dwSynchronizeOutCallCount;
m_HndlrQueue->Synchronize(pHandlerID,hwnd);
}
}
// set noMoreItemsToSync flag if
}
else
{
// for idle queue synchronize any items first since
// no need to call prepareforsync until we have too and don't kick off more than
// one at a time.
// a transfer can come in while processing an out call should be the only time
// this should happen. This can happen on Idle if in a Retry Error when the next
// idle fires.
// Assert(0 == m_dwHandlerOutCallCount);
// not doing anything while still in an out call emulates the old behavior of
// only ever doing one handler at a time.
if (0 == m_dwHandlerOutCallCount)
{
if (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_SYNCHRONIZE,GUID_NULL,&pHandlerID,&pHandlerClsid))
{
++m_dwHandlerOutCallCount;
++m_dwSynchronizeOutCallCount;
m_HndlrQueue->Synchronize(pHandlerID,hwnd);
}
else if (NOERROR == m_HndlrQueue->FindFirstHandlerInState(
HANDLERSTATE_PREPAREFORSYNC,GUID_NULL,&pHandlerID,&pHandlerClsid))
{
// msidle only allows one idle registration at a time.
// reset idle in case last handler we called took it away from us
if (m_pSyncMgrIdle &&
(m_dwProgressFlags & PROGRESSFLAG_REGISTEREDFOROFFIDLE))
{
// !!!don't reset the registered if idle flag will do this
// when all handlers are completed.
if (!(m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE))
{
m_pSyncMgrIdle->ReRegisterIdleDetection(this); // reregisterIdle in case handle overrode it.
m_pSyncMgrIdle->CheckForIdle();
}
}
++m_dwHandlerOutCallCount;
++m_dwPrepareForSyncOutCallCount;
m_HndlrQueue->PrepareForSync(pHandlerID,hwnd);
}
else
{
// even if nothing to do need to call
// reset idle hack
if (m_pSyncMgrIdle && !(m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE)
&& (m_dwProgressFlags & PROGRESSFLAG_REGISTEREDFOROFFIDLE))
{
m_pSyncMgrIdle->ReRegisterIdleDetection(this); // reregisterIdle in case handle overrode it.
m_pSyncMgrIdle->CheckForIdle();
}
}
}
}
UpdateProgressValues(); // update progress values when come out of calls.
// no longer in any out calls, reset our flag and see if a completion
// routine came in or items were added to the queue during our out call
m_dwProgressFlags &= ~PROGRESSFLAG_INHANDLEROUTCALL;
if ((PROGRESSFLAG_COMPLETIONROUTINEWHILEINOUTCALL & m_dwProgressFlags)
|| (PROGRESSFLAG_NEWITEMSINQUEUE & m_dwProgressFlags) )
{
Assert(!(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)); // shouldn't get here if shutting down.
fRepostedStart = TRUE;
if (!(m_dwProgressFlags & PROGRESSFLAG_STARTPROGRESSPOSTED))
{
m_dwProgressFlags |= PROGRESSFLAG_STARTPROGRESSPOSTED;
PostMessage(m_hwnd,WM_PROGRESS_STARTPROGRESS,0,0);
}
}
// if no more items to synchronize and all synchronizations
// are done and we are currently syncing items then shut things down.
// if user is currently in a cancel call then don't start shutting
Assert(!(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)); // assert if in shutdown this loop shouldn't get called.
if (!(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)
&& (0 == m_dwHandlerOutCallCount) && !(fRepostedStart)
&& (m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS))
{
BOOL fTransferAddRef;
BOOL fOffIdleBeforeShutDown = (m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE);
BOOL fKeepDialogAlive;
// if no out calls shouldn't be any call specific out calls either
Assert(0 == m_dwPrepareForSyncOutCallCount);
Assert(0 == m_dwSynchronizeOutCallCount);
m_dwProgressFlags |= PROGRESSFLAG_SHUTTINGDOWNLOOP;
// reset newItemsInQueue so know for sure it got set while we
// yielded in cleanup calls.
m_dwProgressFlags &= ~PROGRESSFLAG_NEWITEMSINQUEUE;
// treat progress as one long out call
Assert(!(m_dwProgressFlags & PROGRESSFLAG_INHANDLEROUTCALL));
m_dwProgressFlags |= PROGRESSFLAG_INHANDLEROUTCALL;
m_dwProgressFlags &= ~PROGRESSFLAG_COMPLETIONROUTINEWHILEINOUTCALL; // reset completion routine.
// reset PROGRESSFLAG_TRANSFERADDREF flag but don't release
// if another transfer happens during this shutdown then the transfer
// will reset the flag and put and addref on. need to store state
// in case get this shutdown routine called twice without another
// transfer we don't call too many releases.
fTransferAddRef = m_dwProgressFlags & PROGRESSFLAG_TRANSFERADDREF;
Assert(fTransferAddRef); // should always have a transfer at this statge.
m_dwProgressFlags &= ~PROGRESSFLAG_TRANSFERADDREF;
SetProgressReleaseDlgCmdId(m_clsid,this,RELEASEDLGCMDID_OK);
UpdateProgressValues();
m_HndlrQueue->RemoveFinishedProgressItems(); // let the queue know to reset the progress bar
// if not in a cancel or setIetmstatus go ahead and release handlers
// and kill the terminate timer.
// review if there is a better opportunity to do cleanup.
if (!(m_dwProgressFlags & PROGRESSFLAG_INCANCELCALL)
&& !(m_dwProgressFlags & PROGRESSFLAG_INTERMINATE)
&& (0 == m_dwSetItemStateRefCount) )
{
if (m_lTimerSet)
{
InterlockedExchange(&m_lTimerSet, 0);
KillTimer(m_hwnd,TIMERID_KILLHANDLERS);
}
m_HndlrQueue->ReleaseCompletedHandlers(); // munge the queue.
}
fKeepDialogAlive = KeepProgressAlive(); // determine if progress should stick around
if ((m_dwProgressFlags & PROGRESSFLAG_PROGRESSANIMATION))
{
m_dwProgressFlags &= ~PROGRESSFLAG_PROGRESSANIMATION;
KillTimer(m_hwnd,TIMERID_TRAYANIMATION);
Animate_Stop(GetDlgItem(m_hwnd,IDC_UPDATEAVI));
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATEAVI),SW_HIDE);
ShowCompletedProgress(TRUE /* fComplete */ ,fKeepDialogAlive /* fDialogIsLocked */);
}
UpdateTrayIcon(); // if Icon is showing make sure we have the uptodate one.
ConnectObj_CloseConnections(); // Close any connections we held open during the Sync.
if (m_dwProgressFlags & PROGRESSFLAG_IDLENETWORKTIMER)
{
m_dwProgressFlags &= ~PROGRESSFLAG_IDLENETWORKTIMER;
KillTimer(m_hwnd,TIMERID_NOIDLEHANGUP); // don't need to keep connection open.
}
// make sure any previous locks on dialog are removed
// before going into wait logic. This can happen in the case of a retry.
LockProgressDialog(m_clsid,this,FALSE);
// if there are no items to lock the progress open and the
// force close flag isn't set wait in a loop
// for two seconds
if (!(fKeepDialogAlive) && (FALSE == m_fForceClose))
{
HANDLE hTimer = CreateEvent(NULL,TRUE,FALSE,NULL);
// should use Create/SetWaitable timer to accomplish this but these
// functions aren't available on Win9x yet.
if (hTimer)
{
// sit in loop until timer event sets it.
DoModalLoop(hTimer,NULL,m_hwnd,TRUE,1000*2);
CloseHandle(hTimer);
}
}
else
{
LockProgressDialog(m_clsid,this,TRUE);
ExpandCollapse(TRUE,FALSE); // make sure the dialog is expanded.
ShowProgressTab(PROGRESS_TAB_ERRORS);
}
//if the user hit the pushpin after we started the 2 second delay
if ((m_fPushpin) && !(fKeepDialogAlive))
{
ShowCompletedProgress(TRUE /* fComplete */,TRUE /* fDialogIsLocked */);
LockProgressDialog(m_clsid,this,TRUE);
}
// if this is an idle dialog handle the logic for
// either releasing the IdleLock or reregistering.
if (m_pSyncMgrIdle)
{
// if we have already received an OffIdle and not
// still handling the offidle then release the Idle Lock.
if ( (m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE)
&& !(m_dwProgressFlags & PROGRESSFLAG_INOFFIDLE))
{
// Release our IdleLock so TS can fire use again even if progress
// sticks around.
ReleaseIdleLock();
}
else if ( (m_dwProgressFlags & PROGRESSFLAG_REGISTEREDFOROFFIDLE)
&& !(m_dwProgressFlags & PROGRESSFLAG_RECEIVEDOFFIDLE) )
{
// if have registere for idle but haven't seen it yet then
// we want to stay alive.
// if we aren't suppose to repeat idle or
// user has maximized the window then just call idle as if
// an OffIdle occured. Mostly done as a safety precaution
// in case someone has registered for Idle with MSIdle in
// our process space so we fail to receive the true offidle
if (!(m_dwProgressFlags & PROGRESSFLAG_IDLERETRYENABLED)
|| !m_fHasShellTrayIcon)
{
IdleCallback(STATE_USER_IDLE_END);
// release idle lock since OffIdle won't since we are still
// in the syncing Item state.
ReleaseIdleLock();
}
else
{
// if haven't yet received an offidle reregister
m_pSyncMgrIdle->ReRegisterIdleDetection(this); // reregisterIdle in case handle overrode it.
m_pSyncMgrIdle->CheckForIdle();
// first thing hide our window. Only hide if we are in the shelltray
// and no errors have occured.
if (m_fHasShellTrayIcon
&& !(KeepProgressAlive()))
{
RegisterShellTrayIcon(FALSE);
}
m_pSyncMgrIdle->ResetIdle(m_ulIdleRetryMinutes);
}
}
}
// if no new items in the queue no longer need the connection.
// do this before releasing dialog ref
if (!(m_dwProgressFlags & PROGRESSFLAG_NEWITEMSINQUEUE))
{
m_HndlrQueue->EndSyncSession();
}
// see if Release takes care or our progress, if not,
// there are more things to synchronize.
if (fTransferAddRef)
{
cDlgRefs = ReleaseProgressDialog(m_fForceClose); // release transfer addref.
}
else
{
Assert(fTransferAddRef); // this shouldn't happen but if it does addref/release.
AddRefProgressDialog();
cDlgRefs = ReleaseProgressDialog(m_fForceClose);
}
// !!!! warning - no longer hold onto a reference to
// this dialog. Do not do anything to allow this thread
// to be reentrant.
// its possible that items got placed in the queue why we were in our
// sleep loop, if so then restart the loop
m_dwProgressFlags &= ~PROGRESSFLAG_INHANDLEROUTCALL;
// if there are new items in the queue need to kick off another loop
if (m_dwProgressFlags & PROGRESSFLAG_NEWITEMSINQUEUE)
{
// m_dwProgressFlags &= ~PROGRESSFLAG_NEWITEMSINQUEUE;
Assert(0 != m_cInternalcRefs);
// reset the user cancel flag if new items comein
m_dwProgressFlags &= ~PROGRESSFLAG_CANCELPRESSED;
if (!(m_dwProgressFlags & PROGRESSFLAG_STARTPROGRESSPOSTED))
{
m_dwProgressFlags |= PROGRESSFLAG_STARTPROGRESSPOSTED;
PostMessage(hwnd,WM_PROGRESS_STARTPROGRESS,0,0); // restart the sync.
}
}
else
{
if (m_dwShowErrorRefCount || m_dwSetItemStateRefCount
|| (m_dwProgressFlags & PROGRESSFLAG_INCANCELCALL)
|| (m_dwProgressFlags & PROGRESSFLAG_INTERMINATE) )
{
// cases that crefs should not be zero caused by out calls
Assert(0 != m_cInternalcRefs);
}
else
{
// if get here refs should be zero, be an idle or a queue transfer is in
// progress.ADD
Assert(0 == m_cInternalcRefs
|| (m_dwProgressFlags & PROGRESSFLAG_INOFFIDLE)
|| (m_dwProgressFlags & PROGRESSFLAG_REGISTEREDFOROFFIDLE)
|| (m_dwQueueTransferCount));
}
m_dwProgressFlags &= ~PROGRESSFLAG_SYNCINGITEMS; // no longer syncing items.
}
m_dwProgressFlags &= ~PROGRESSFLAG_CANCELWHILESHUTTINGDOWN; // if cancel came in during shutdown reset flag now.
m_dwProgressFlags &= ~PROGRESSFLAG_SHUTTINGDOWNLOOP;
}
--m_dwHandleThreadNestcount;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::KeepProgressAlive, private
//
// Synopsis: returns true if progress dialog shouln't go away
// when the sync is complete
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::KeepProgressAlive()
{
HKEY hkKeepProgress;
//Default behavior is to stick around on warnings and errors only.
DWORD dwKeepProgressSetting = PROGRESS_STICKY_WARNINGS | PROGRESS_STICKY_ERRORS;
DWORD dwErrorsFlag = 0;
DWORD dwType = REG_DWORD;
DWORD dwDataSize = sizeof(DWORD);
if (m_fPushpin)
{
return TRUE;
}
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,TOPLEVEL_REGKEY,0,
KEY_READ,&hkKeepProgress))
{
RegQueryValueEx(hkKeepProgress,TEXT("KeepProgressLevel"),NULL, &dwType,
(LPBYTE) &(dwKeepProgressSetting),
&dwDataSize);
RegCloseKey(hkKeepProgress);
}
if (m_iInfoCount)
{
dwErrorsFlag |= PROGRESS_STICKY_INFO;
}
if (m_iWarningCount)
{
dwErrorsFlag |= PROGRESS_STICKY_WARNINGS;
}
if (m_iErrorCount)
{
dwErrorsFlag |= PROGRESS_STICKY_ERRORS;
}
if (dwKeepProgressSetting & dwErrorsFlag)
{
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::TransferQueueData(CHndlrQueue *HndlrQueue)
//
// PURPOSE: Get the queue date
//
// COMMENTS: transfer items from the specified queue into our queue
// It is legal fo the HndlrQueue arg to be NULL in the case that
// the queue is being restarted from a retry. Review - May want
// to break this function to make the bottom part for the
// retry a separate function so can assert if someone tries
// to transfer a NULL queue.
//
//--------------------------------------------------------------------------------
STDMETHODIMP CProgressDlg::TransferQueueData(CHndlrQueue *pHndlrQueue)
{
HRESULT hr = E_UNEXPECTED;
SendMessage(m_hwnd,WM_PROGRESS_TRANSFERQUEUEDATA,(WPARAM) &hr, (LPARAM) pHndlrQueue);
return hr;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::TransferQueueData(CHndlrQueue *HndlrQueue)
//
// PURPOSE: Get the queue date
//
// COMMENTS: transfer items from the specified queue into our queue
// It is legal fo the HndlrQueue arg to be NULL in the case that
// the queue is being restarted from a retry. Review - May want
// to break this function to make the bottom part for the
// retry a separate function so can assert if someone tries
// to transfer a NULL queue.
//
//--------------------------------------------------------------------------------
STDMETHODIMP CProgressDlg::PrivTransferQueueData(CHndlrQueue *HndlrQueue)
{
HRESULT hr = NOERROR;
Assert(!(m_dwProgressFlags & PROGRESSFLAG_DEAD));
Assert(m_HndlrQueue);
if (NULL == m_HndlrQueue)
{
return E_UNEXPECTED;
}
++m_dwQueueTransferCount;
if (HndlrQueue && m_HndlrQueue)
{
// set the transfer flag so main loop knows there are new items to look at
m_HndlrQueue->TransferQueueData(HndlrQueue);
// fill in the list box right away so
// a) better visual UI
// b) don't have to worry about race conditions with PrepareForSync.
// since adding UI won't make an outgoing call.
if (m_pItemListView)
{
AddItemsFromQueueToListView(m_pItemListView,m_HndlrQueue,
LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP ,SYNCMGRSTATUS_PENDING,
-1 /* iDateColumn */ ,PROGRESSLIST_STATUSCOLUMN /*status column */
,FALSE /* fUseHandlerAsParent */,TRUE /* fAddOnlyCheckedItems */);
// set the selection to the first item
m_pItemListView->SetItemState(0,
LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
}
UpdateProgressValues();
UpdateWindow(m_hwnd);
// now check if there is already a transfer in progress and if
// there isn't post the message, else Addref the progress dialog as appropriate.
}
m_dwProgressFlags &= ~PROGRESSFLAG_NEWDIALOG; // no longer a new dialog once something is in the queue.
ShowCompletedProgress(FALSE,FALSE);
// if the animation isn't going then start it up.
if (!(m_dwProgressFlags & PROGRESSFLAG_PROGRESSANIMATION))
{
m_dwProgressFlags |= PROGRESSFLAG_PROGRESSANIMATION;
RedrawIcon();
ShowProgressTab(PROGRESS_TAB_UPDATE);
Animate_Play(GetDlgItem(m_hwnd,IDC_UPDATEAVI),0,-1,-1);
ShowWindow(GetDlgItem(m_hwnd,IDC_UPDATEAVI),SW_SHOW );
SetTimer(m_hwnd,TIMERID_TRAYANIMATION,TRAYANIMATION_SPEED,NULL);
}
// if we are an idle set up our callback
// successfully loaded msIdle, then set up the callback
// review - make these progress flags
if (m_pSyncMgrIdle && !(PROGRESSFLAG_REGISTEREDFOROFFIDLE & m_dwProgressFlags))
{
m_dwProgressFlags &= ~PROGRESSFLAG_RECEIVEDOFFIDLE; // reset offidle flag
// read in the defaults to use for Idle shutdown delay and
// wait until retryIdle based on the first Job in the queue.
if (0 == m_pSyncMgrIdle->BeginIdleDetection(this,1,0))
{
m_dwProgressFlags |= PROGRESSFLAG_REGISTEREDFOROFFIDLE;
AddRefProgressDialog(); // put an addref on to keep alive, will be released in OffIdle.
}
else
{
m_dwProgressFlags &= ~PROGRESSFLAG_REGISTEREDFOROFFIDLE;
}
}
// if don't have a transfer addref then add one and make sure idle is setup
if (!(PROGRESSFLAG_TRANSFERADDREF & m_dwProgressFlags))
{
m_dwProgressFlags |= PROGRESSFLAG_TRANSFERADDREF;
AddRefProgressDialog(); // put an addref on to keep alive.
}
--m_dwQueueTransferCount;
// don't post message if we are in an out call or in the shutdown
// loop or if newitemsqueue is already set.
if (!(m_dwProgressFlags & PROGRESSFLAG_INHANDLEROUTCALL)
&& !(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)
&& !(m_dwProgressFlags & PROGRESSFLAG_NEWITEMSINQUEUE)
&& !(m_dwProgressFlags & PROGRESSFLAG_STARTPROGRESSPOSTED) )
{
if ( !(m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS) )
{
// set here even though main loop does in case power managment or another transfer
// occurs between here and the postMessage being processed.
m_dwProgressFlags |= PROGRESSFLAG_SYNCINGITEMS;
m_HndlrQueue->BeginSyncSession();
}
m_dwProgressFlags |= PROGRESSFLAG_STARTPROGRESSPOSTED;
PostMessage(m_hwnd,WM_PROGRESS_STARTPROGRESS,0,0);
}
// set newitems flag event if don't post the message so when handler comes out of
// state can check the flag.
m_dwProgressFlags |= PROGRESSFLAG_NEWITEMSINQUEUE;
// reset the user cancel flag if new items comein
m_dwProgressFlags &= ~PROGRESSFLAG_CANCELPRESSED;
if (m_lTimerSet)
{
InterlockedExchange(&m_lTimerSet, 0);
// if we are in a terminate no need to kill the Timer
if (!(m_dwProgressFlags & PROGRESSFLAG_INTERMINATE))
{
KillTimer(m_hwnd,TIMERID_KILLHANDLERS);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::CallCompletionRoutine, private
//
// Synopsis: method called when a call has been completed.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 02-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::CallCompletionRoutine(DWORD dwThreadMsg,LPCALLCOMPLETIONMSGLPARAM lpCallCompletelParam)
{
// !!!warning: This code assumes that the completion routine is only called
// after the original out call has returned. This code is currently handled
// by the queue and proxy. If switch to com need to make sure don't start winding
// up the stack if handlers are calling comletion routines before the original
// call comes back
// for anything but ShowErrors can just kick off a progress.
// for ShowErrors we need to pretend a transfer happened if a retry should occur
// else don't do anything.
switch(dwThreadMsg)
{
case ThreadMsg_ShowError:
if (lpCallCompletelParam && (S_SYNCMGR_RETRYSYNC == lpCallCompletelParam->hCallResult))
{
// if still in original ShowError Call let ShowEror post the message
// when done, else treat it like a transfer occured.
if (m_dwProgressFlags & PROGRESSFLAG_INSHOWERRORSCALL)
{
Assert(!(m_dwProgressFlags & PROGRESSFLAG_SHOWERRORSCALLBACKCALLED)); // only support one.
m_dwProgressFlags |= PROGRESSFLAG_SHOWERRORSCALLBACKCALLED;
}
else
{
// sendmessage so it is queued up before release
SendMessage(m_hwnd,WM_PROGRESS_TRANSFERQUEUEDATA,(WPARAM) 0, (LPARAM) NULL);
}
}
--m_dwShowErrorRefCount;
// count can go negative if handler calls completion routine on an error. if
// this is the case just set it to zero
if ( ((LONG) m_dwShowErrorRefCount) < 0)
{
AssertSz(0,"Negative ErrorRefCount");
m_dwShowErrorRefCount = 0;
}
else
{
ReleaseProgressDialog(m_fForceClose);
}
break;
case ThreadMsg_PrepareForSync:
case ThreadMsg_Synchronize:
{
DWORD *pdwMsgOutCallCount = (ThreadMsg_PrepareForSync == dwThreadMsg) ?
&m_dwPrepareForSyncOutCallCount : &m_dwSynchronizeOutCallCount;
if (m_dwProgressFlags & PROGRESSFLAG_INHANDLEROUTCALL)
{
m_dwProgressFlags |=PROGRESSFLAG_COMPLETIONROUTINEWHILEINOUTCALL;
}
else
{
if (!(m_dwProgressFlags & PROGRESSFLAG_STARTPROGRESSPOSTED))
{
Assert(!(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP));
m_dwProgressFlags |= PROGRESSFLAG_CALLBACKPOSTED;
m_dwProgressFlags |= PROGRESSFLAG_STARTPROGRESSPOSTED;
PostMessage(m_hwnd,WM_PROGRESS_STARTPROGRESS,0,0);
}
}
// fix up call count.
--(*pdwMsgOutCallCount);
if ( ((LONG) *pdwMsgOutCallCount) < 0)
{
AssertSz(0,"Negative Message Specific OutCall");
*pdwMsgOutCallCount = 0;
}
--m_dwHandlerOutCallCount; // decrement the handler outcall.
if ( ((LONG) m_dwHandlerOutCallCount) < 0)
{
AssertSz(0,"NegativeHandlerOutCallCount");
m_dwHandlerOutCallCount = 0;
}
}
break;
default:
AssertSz(0,"Unknown Callback method");
break;
}
// if have an lparam free it now
if (lpCallCompletelParam)
{
FREE(lpCallCompletelParam);
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::QueryCanSystemShutdown, private
//
// Synopsis: called by object manager to determine if can shutdown.
//
// !!!Warning - can be called on any thread. make sure this is
// readonly.
//
// !!!Warning - Do not yield in the function;
//
// Arguments:
//
// Returns: S_OK - if can shutdown
// S_FALSE - system should not shutdown, must fill in out params.
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
HRESULT CProgressDlg::QueryCanSystemShutdown(/* [out] */ HWND *phwnd, /* [out] */ UINT *puMessageId,
/* [out] */ BOOL *pfLetUserDecide)
{
HRESULT hr = S_OK;
if (m_dwShowErrorRefCount > 0)
{
*puMessageId = IDS_HANDLERSHOWERRORQUERYENDSESSION ;
*phwnd = NULL; // don't know showError parent so keep NULL
*pfLetUserDecide = FALSE;
hr = S_FALSE;
}
else if (m_clsid != GUID_PROGRESSDLGIDLE) // idle should allow shutdown even if syncing.
{
// if a sync is in progress prompt user to if they want to cancel.
if (PROGRESSFLAG_SYNCINGITEMS & m_dwProgressFlags)
{
*puMessageId = IDS_PROGRESSQUERYENDSESSION;
*phwnd = m_hwnd;
*pfLetUserDecide = TRUE;
hr = S_FALSE;
}
}
return hr;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: CProgressDlg::ExpandCollapse()
//
// PURPOSE: Takes care of showing and hiding the "details" part of the
// dialog.
//
// PARAMETERS:
// <in> fExpand - TRUE if we should be expanding the dialog.
// <in> fSetFocus - TRUE forces a recalc.
//
//--------------------------------------------------------------------------------
void CProgressDlg::ExpandCollapse(BOOL fExpand, BOOL fForce)
{
RECT rcSep;
TCHAR szBuf[MAX_STRING_RES];
RECT rcCurDlgRect;
BOOL fSetWindowPos = FALSE;
BOOL fOrigExpanded = m_fExpanded;
if ( (m_fExpanded == fExpand) && !fForce) // no need to do anything if already in requested state
return;
m_fExpanded = fExpand;
GetWindowRect(GetDlgItem(m_hwnd, IDC_SP_SEPARATOR), &rcSep);
GetWindowRect(m_hwnd,&rcCurDlgRect);
if (!m_fExpanded)
{
// update or rcDlg rect so can reset to proper height next time.
if (GetWindowRect(m_hwnd,&m_rcDlg))
{
fSetWindowPos = SetWindowPos(m_hwnd, HWND_NOTOPMOST, 0, 0, rcCurDlgRect.right - rcCurDlgRect.left,
m_cyCollapsed, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
else
{
fSetWindowPos = SetWindowPos(m_hwnd, HWND_NOTOPMOST, 0, 0, rcCurDlgRect.right - rcCurDlgRect.left,
m_rcDlg.bottom - m_rcDlg.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
// if couldn't change window, leave as is
if (!fSetWindowPos)
{
m_fExpanded = fOrigExpanded;
return;
}
// Make sure the entire dialog is visible on the screen. If not,
// then push it up
RECT rc;
RECT rcWorkArea;
GetWindowRect(m_hwnd, &rc);
SystemParametersInfo(SPI_GETWORKAREA, 0, (LPVOID) &rcWorkArea, 0);
if (rc.bottom > rcWorkArea.bottom)
{
rc.top = max(0, (int) rc.top - (rc.bottom - rcWorkArea.bottom));
SetWindowPos(m_hwnd, HWND_NOTOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
LoadString(g_hInst, m_fExpanded ? IDS_HIDE_DETAILS : IDS_SHOW_DETAILS, szBuf,
ARRAY_SIZE(szBuf));
SetDlgItemText(m_hwnd, IDC_DETAILS, szBuf);
// Make sure the proper tab is up to date shown.
ShowProgressTab(m_iTab);
// Raid-34387: Spooler: Closing details with ALT-D while focus is on a task disables keyboard input
// if any control other than the cancel button has the focus set the focus to details.
if (!fExpand)
{
HWND hwndFocus = GetFocus();
if (hwndFocus != GetDlgItem(m_hwnd, IDSTOP))
{
SetFocus(GetDlgItem(m_hwnd, IDC_DETAILS));
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnTimer, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnTimer(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
WORD wTimerID = (WORD) wParam;
if (wTimerID == TIMERID_TRAYANIMATION)
{
UpdateTrayIcon();
}
else if (TIMERID_NOIDLEHANGUP == wTimerID)
{
ResetNetworkIdle();
}
else if (TIMERID_KILLHANDLERS == wTimerID)
{
if (m_lTimerSet)
{
if (!(m_dwProgressFlags & PROGRESSFLAG_DEAD)
&& !(m_dwProgressFlags & PROGRESSFLAG_SHUTTINGDOWNLOOP)
&& !(m_dwProgressFlags & PROGRESSFLAG_INTERMINATE))
{
BOOL fItemToKill;
m_dwProgressFlags |= PROGRESSFLAG_INTERMINATE;
// Even though KillTimer,
// don't reset m_lTimerSet timer until done with ForceKill
// in case cancel is pressed again.
KillTimer(m_hwnd,TIMERID_KILLHANDLERS);
SetProgressReleaseDlgCmdId(m_clsid,this,RELEASEDLGCMDID_CANCEL); // set so cleanup knows it was stopped by user..
AddRefProgressDialog(); // hold dialog alive until cancel is complete
m_HndlrQueue->ForceKillHandlers(&fItemToKill);
// reset the timer if TimerSet is still set, i.e. if was
// set to zero because of a transfer or actually done don't reset.
if (m_lTimerSet)
{
// only settimer if actually killed anything. if looped through
// and found nothing then can turn off timer.
if (fItemToKill)
{
Assert(m_nKillHandlerTimeoutValue >= TIMERID_KILLHANDLERSMINTIME);
SetTimer(m_hwnd,TIMERID_KILLHANDLERS,m_nKillHandlerTimeoutValue,NULL);
}
else
{
m_lTimerSet = 0;
}
}
m_dwProgressFlags &= ~PROGRESSFLAG_INTERMINATE;
ReleaseProgressDialog(FALSE);
}
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnTaskBarCreated, private
//
// Synopsis: Receive this when the Tray has been restarted.
// Need to put back our tray icon.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 31-Aug-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnTaskBarCreated(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (m_fHasShellTrayIcon)
{
m_fAddedIconToTray = FALSE; // set added to false to force update to add again.
UpdateTrayIcon();
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnSysCommand, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::OnSysCommand(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
UINT uCmdType = (UINT) wParam; // type of system command requested
WORD xPos = LOWORD(lParam); // horizontal postion, in screen coordinates
WORD yPos = HIWORD(lParam); // vertical postion, in screen coordinates
//
// WARNING: USER uses low four bits for some undocumented feature
// (only for SC_*). We need to mask those bits to make this case
// statement work.
uCmdType &= 0xFFF0;
switch(uCmdType)
{
case SC_MINIMIZE:
// if already in the tray to nothing
if (!m_fHasShellTrayIcon)
{
if (RegisterShellTrayIcon(TRUE))
{
AnimateTray(TRUE);
ShowWindow(m_hwnd,SW_HIDE);
// AnimateTray(TRUE);
return -1;
}
}
else
{
return -1; // if already in the tray we handled.
}
break;
case SC_MAXIMIZE:
case SC_RESTORE:
{
// if we are being maximized or restored from a maximize
// make sure details is open
if ( (uCmdType == SC_RESTORE && m_fMaximized)
|| (uCmdType == SC_MAXIMIZE) )
{
if (!m_fExpanded)
{
ExpandCollapse(TRUE,FALSE);
}
}
m_fMaximized = (uCmdType == SC_MAXIMIZE) ? TRUE : FALSE;
}
break;
default:
break;
}
return FALSE; // fall through to defWndProc
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnShellTrayNotification, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnShellTrayNotification(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
DWORD dwMsg = (DWORD) lParam;
switch (dwMsg)
{
case WM_LBUTTONUP:
{
UpdateWndPosition(SW_SHOWNORMAL,TRUE /* fForce */);
}
break;
#ifdef _TRAYMENU
case WM_RBUTTONUP:
{
POINT Point;
// show the context menu
HMENU hmenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));
hmenu = CreatePopupMenu();
//AppendMenu(hmenu,0,101,"Status");
//AppendMenu(hmenu,0,100,"Settings");
GetCursorPos(&Point); // want point that click occured at.
// Review, change so TrackMenu returns index.
TrackPopupMenuEx(hmenu,TPM_HORIZONTAL | TPM_VERTICAL,
Point.x,Point.y,hwnd,NULL);
}
break;
#endif // _TRAYMENU
default:
break;
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnClose, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnClose(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
OnCancel(FALSE /* fOffIdle */); // treat close as a cancel.
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnGetMinMaxInfo, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnGetMinMaxInfo(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
MINMAXINFO *pMinMax = (MINMAXINFO *) lParam ;
// minimum width is a constant but minimum height depends on
// if dialog is collapsed or expanded.
if (!m_fExpanded)
{
pMinMax->ptMinTrackSize.y = m_cyCollapsed;
pMinMax->ptMaxTrackSize.y = m_cyCollapsed; // maximum is also the collapsed height
}
else
{
pMinMax->ptMinTrackSize.y = m_ptMinimumDlgExpandedSize.y;
}
pMinMax->ptMinTrackSize.x = m_ptMinimumDlgExpandedSize.x;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnMoving, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CProgressDlg::OnMoving(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
LPRECT lprc = (LPRECT) lParam; // screen coordinates of drag rectangle
// if we are maxmized don't allow moving
if (m_fMaximized)
{
GetWindowRect(m_hwnd,lprc);
}
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnContextMenu, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::OnContextMenu(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
WinHelp ((HWND)wParam,
g_szSyncMgrHelp,
HELP_CONTEXTMENU,
(ULONG_PTR)g_aContextHelpIds);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CProgressDlg::OnPowerBroadcast, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CProgressDlg::OnPowerBroadcast(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (wParam == PBT_APMQUERYSUSPEND)
{
// if just created or syncing don't suspend
if (m_dwProgressFlags & PROGRESSFLAG_NEWDIALOG
|| m_dwProgressFlags & PROGRESSFLAG_SYNCINGITEMS)
{
SetWindowLongPtr(m_hwnd,DWLP_MSGRESULT,BROADCAST_QUERY_DENY);
return TRUE;
}
}
return TRUE;
}
//--------------------------------------------------------------------------------
//
// FUNCTION: ProgressWndProc(HWND hwnd, UINT uMsg,WPARAM wParam,LPARAM lParam)
//
// PURPOSE: Callback for Progress Dialog
//
// COMMENTS: Implemented on main thread.
//
//
//--------------------------------------------------------------------------------
BOOL CALLBACK ProgressWndProc(HWND hwnd, UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CProgressDlg *pThis = (CProgressDlg *) GetWindowLongPtr(hwnd, DWLP_USER);
UINT horizExtent = 0;
BOOL bResult;
// spcial case destroy and init.
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0); // done with this thread.
break;
case WM_INITDIALOG:
{
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam);
pThis = (CProgressDlg *) lParam;
if (pThis)
{
pThis->InitializeHwnd(hwnd,uMsg,wParam,lParam);
}
return FALSE; // return FALSE so system doesn't give us the focus
break;
}
default:
{
if (pThis)
{
switch (uMsg)
{
case WM_POWERBROADCAST:
return pThis->OnPowerBroadcast(uMsg,wParam,lParam);
break;
case WM_CONTEXTMENU:
return pThis->OnContextMenu(uMsg,wParam,lParam);
break;
case WM_DRAWITEM:
return OnProgressResultsDrawItem(hwnd,pThis,(UINT)wParam,(const DRAWITEMSTRUCT*)lParam);
break;
case WM_MEASUREITEM:
bResult = OnProgressResultsMeasureItem(hwnd,pThis, &horizExtent,(UINT)wParam,(MEASUREITEMSTRUCT *)lParam);
if (horizExtent)
{
//make sure there is a horizontal scroll bar if needed
SendMessage(GetDlgItem(hwnd,IDC_LISTBOXERROR),
LB_SETHORIZONTALEXTENT, horizExtent, 0L);
}
return bResult;
break;
case WM_DELETEITEM:
return OnProgressResultsDeleteItem(hwnd,(UINT)wParam,(const DELETEITEMSTRUCT *)lParam);
break;
case WM_NOTIFY:
pThis->OnNotify(uMsg,wParam,lParam);
break;
case WM_COMMAND:
pThis->OnCommand(uMsg,wParam,lParam);
break;
case WM_MOVING:
pThis->OnMoving(uMsg,wParam,lParam);
break;
case WM_SIZE:
pThis->OnSize(uMsg,wParam,lParam);
break;
case WM_GETMINMAXINFO:
pThis->OnGetMinMaxInfo(uMsg,wParam,lParam);
break;
case WM_PAINT:
pThis->OnPaint(uMsg,wParam,lParam);
return 0;
break;
case WM_BASEDLG_SHOWWINDOW:
pThis->UpdateWndPosition((int)wParam,FALSE); // nCmdShow is stored in the wParam
break;
case WM_BASEDLG_NOTIFYLISTVIEWEX:
pThis->OnNotifyListViewEx(uMsg,wParam,lParam);
break;
case WM_BASEDLG_COMPLETIONROUTINE:
pThis->CallCompletionRoutine((DWORD)wParam /*dwThreadMsg */ ,(LPCALLCOMPLETIONMSGLPARAM) lParam);
break;
case WM_BASEDLG_HANDLESYSSHUTDOWN:
// set the force shutdown member then treat as a close
pThis->m_fForceClose = TRUE;
PostMessage(hwnd,WM_CLOSE,0,0);
break;
case WM_TIMER: // timer message for delat when sync is done.
pThis->OnTimer(uMsg,wParam,lParam);
break;
case WM_PROGRESS_UPDATE:
pThis->HandleProgressUpdate(hwnd,wParam,lParam);
break;
case WM_PROGRESS_LOGERROR:
pThis->HandleLogError(hwnd,(HANDLERINFO *) wParam,(MSGLogErrors *) lParam);
break;
case WM_PROGRESS_DELETELOGERROR:
pThis->HandleDeleteLogError(hwnd,(MSGDeleteLogErrors *) lParam);
break;
case WM_PROGRESS_STARTPROGRESS:
pThis->DoSyncTask(hwnd);
break;
case WM_PROGRESS_RESETKILLHANDLERSTIMER:
pThis->OnResetKillHandlersTimers();
break;
case WM_CLOSE:
pThis->OnClose(uMsg,wParam,lParam);
break;
case WM_PROGRESS_SHELLTRAYNOTIFICATION:
pThis->OnShellTrayNotification(uMsg,wParam,lParam);
break;
case WM_SYSCOMMAND:
return pThis->OnSysCommand(uMsg,wParam,lParam);
break;
case WM_PROGRESS_TRANSFERQUEUEDATA:
{
HRESULT *phr = (HRESULT *) wParam;
HRESULT hr;
hr = pThis->PrivTransferQueueData( (CHndlrQueue *) lParam);
// phr is only valid on a SendMessage.
if (NULL != phr)
{
*phr = hr;
}
return TRUE;
break;
}
case WM_PROGRESS_RELEASEDLGCMD:
pThis->PrivReleaseDlg((WORD)wParam);
break;
default:
if (uMsg == g_WMTaskbarCreated)
{
pThis->OnTaskBarCreated(uMsg,wParam,lParam);
}
break;
}
}
}
break;
}
return FALSE;
}