Windows2003-3790/inetcore/outlookexpress/mailnews/spooler/spoolui.cpp
2020-09-30 16:53:55 +02:00

1930 lines
54 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
//
// MODULE: spoolui.cpp
//
// PURPOSE: Implements the spooler UI dialogs.
//
#include "pch.hxx"
#include "resource.h"
#include "spoolui.h"
#include "goptions.h"
#include "imnact.h"
#include "thormsgs.h"
#include "shlwapip.h"
#include "spengine.h"
#include "ourguid.h"
#include "demand.h"
#include "menures.h"
#include "multiusr.h"
ASSERTDATA
static const char c_szWndProc[] = "WndProc";
//
// FUNCTION: CSpoolerDlg::CSpoolerDlg()
//
// PURPOSE: Initializes the member variables of the spooler ui object.
//
CSpoolerDlg::CSpoolerDlg()
{
m_cRef = 1;
m_pBindCtx = NULL;
m_hwnd = NULL;
m_hwndOwner = NULL;
m_hwndEvents = NULL;
m_hwndErrors = NULL;
InitializeCriticalSection(&m_cs);
m_himlImages = NULL;
m_fTack = FALSE;
m_iTab = 0;
m_fIdle = FALSE;
m_fErrors = FALSE;
m_fShutdown = FALSE;
m_fSaveSize = FALSE;
m_fExpanded = TRUE;
ZeroMemory(&m_rcDlg, sizeof(RECT));
m_cyCollapsed = 0;
m_szCount[0] = '\0';
m_hIcon=NULL;
m_hIconSm=NULL;
m_dwIdentCookie = 0;
}
//
// FUNCTION: CSpoolerDlg::~CSpoolerDlg()
//
// PURPOSE: Frees any resources allocated during the life of the class.
//
CSpoolerDlg::~CSpoolerDlg()
{
GoIdle(TRUE, FALSE, FALSE);
if (m_hwnd && IsWindow(m_hwnd))
DestroyWindow(m_hwnd);
if (m_himlImages)
ImageList_Destroy(m_himlImages);
SafeRelease(m_pBindCtx);
DeleteCriticalSection(&m_cs);
if (m_hIcon)
SideAssert(DestroyIcon(m_hIcon));
if (m_hIconSm)
SideAssert(DestroyIcon(m_hIconSm));
}
//
// FUNCTION: CSpoolerDlg::Init()
//
// PURPOSE: Creates the spooler dialog. The dialog is not initially
// visible.
//
// PARAMETERS:
// <in> hwndOwner - Handle of the window to parent the dialog to.
//
// RETURN VALUE:
// S_OK - The dialog was created and initialized
// E_OUTOFMEMORY - The dialog could not be created
// E_INVALIDARG - Think about it.
//
HRESULT CSpoolerDlg::Init(HWND hwndOwner)
{
int iReturn = -1;
HWND hwnd, hwndActive;
// Verify the arguments
if (!IsWindow(hwndOwner))
return (E_INVALIDARG);
// Make a copy
m_hwndOwner = hwndOwner;
// Invoke the dialog
hwndActive = GetForegroundWindow();
hwnd = CreateDialogParam(g_hLocRes, MAKEINTRESOURCE(iddSpoolerDlg), m_hwndOwner,
SpoolerDlgProc, (LPARAM) this);
if (hwndActive != GetForegroundWindow())
SetForegroundWindow(hwndActive);
// Set the dialog icon
m_hIcon = (HICON) LoadImage(g_hLocRes, MAKEINTRESOURCE(idiMail), IMAGE_ICON, 32, 32, 0);
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)m_hIcon);
m_hIconSm = (HICON) LoadImage(g_hLocRes, MAKEINTRESOURCE(idiMail), IMAGE_ICON, 16, 16, 0);
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hIconSm);
SetTaskCounts(0, 0);
// Register with identity manager
SideAssert(SUCCEEDED(MU_RegisterIdentityNotifier((IUnknown *)(ISpoolerUI *)this, &m_dwIdentCookie)));
return (IsWindow(hwnd) ? S_OK : E_OUTOFMEMORY);
}
HRESULT CSpoolerDlg::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
if (NULL == *ppvObj)
return (E_INVALIDARG);
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = (LPVOID)(IUnknown *)(ISpoolerUI *) this;
else if (IsEqualIID(riid, IID_ISpoolerUI))
*ppvObj = (LPVOID)(ISpoolerUI *) this;
else if (IsEqualIID(riid, IID_IIdentityChangeNotify))
*ppvObj = (LPVOID)(IIdentityChangeNotify *) this;
if (NULL == *ppvObj)
return (E_NOINTERFACE);
AddRef();
return (S_OK);
}
ULONG CSpoolerDlg::AddRef(void)
{
m_cRef++;
return (m_cRef);
}
ULONG CSpoolerDlg::Release(void)
{
ULONG cRefT = --m_cRef;
if (0 == m_cRef)
delete this;
return (cRefT);
}
//
// FUNCTION: CSpoolerDlg::RegisterBindContext()
//
// PURPOSE: Allows the spooler engine to provide us with a bind context
// interface for us to call back into.
//
// PARAMETERS:
// <in> pBindCtx - Pointer to the engine's bind context interface
//
// RETURN VALUE:
// E_INVALIDARG
// S_OK
//
HRESULT CSpoolerDlg::RegisterBindContext(ISpoolerBindContext *pBindCtx)
{
if (NULL == pBindCtx)
return (E_INVALIDARG);
EnterCriticalSection(&m_cs);
m_pBindCtx = pBindCtx;
m_pBindCtx->AddRef();
LeaveCriticalSection(&m_cs);
return (S_OK);
}
//
// FUNCTION: CSpoolerDlg::InsertEvent()
//
// PURPOSE: Allows a caller to insert an event into our event list UI.
//
// PARAMETERS:
// <in> eid - Event ID for this new event
// <in> pszDescription - Description of the event
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// E_OUTOFMEMORY
//
HRESULT CSpoolerDlg::InsertEvent(EVENTID eid, LPCTSTR pszDescription,
LPCWSTR pwszConnection)
{
HRESULT hr=S_OK;
LV_ITEM lvi;
int iItem = -1;
TCHAR szRes[CCHMAX_STRINGRES];
// Verify the arguments
if (0 == pszDescription)
return (E_INVALIDARG);
EnterCriticalSection(&m_cs);
// Make sure the listview has been initialized
if (!IsWindow(m_hwndEvents))
hr = SP_E_UNINITIALIZED;
else
{
// Insert the item into the listview
ZeroMemory(&lvi, sizeof(LV_ITEM));
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = ListView_GetItemCount(m_hwndEvents);
lvi.iSubItem = 0;
lvi.lParam = (LPARAM) eid;
lvi.iImage = IMAGE_BLANK;
if (IS_INTRESOURCE(pszDescription))
{
AthLoadString(PtrToUlong(pszDescription), szRes, ARRAYSIZE(szRes));
lvi.pszText = szRes;
}
else
lvi.pszText = (LPTSTR) pszDescription;
iItem = ListView_InsertItem(m_hwndEvents, &lvi);
Assert(iItem != -1);
if (iItem == -1)
hr = E_OUTOFMEMORY;
else
{
LVITEMW lviw = {0};
lviw.iSubItem = 2;
lviw.pszText = (LPWSTR)pwszConnection;
SendMessage(m_hwndEvents, LVM_SETITEMTEXTW, (WPARAM)iItem, (LPARAM)&lviw);
}
}
LeaveCriticalSection(&m_cs);
return hr;
}
//
// FUNCTION: CSpoolerDlg::InsertError()
//
// PURPOSE: Allows a task to insert an error into our error list UI.
//
// PARAMETERS:
// <in> eid - The event ID of the event that had the error.
// <in> pszError - Description of the error.
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// E_OUTOFMEMORY
//
HRESULT CSpoolerDlg::InsertError(EVENTID eid, LPCTSTR pszError)
{
HRESULT hr = S_OK;
LBDATA *pData = NULL;
int nItem;
HDC hdc;
HFONT hfont;
// Verify the arguments
if (0 == pszError)
return (E_INVALIDARG);
EnterCriticalSection(&m_cs);
// Make sure the listview has been initialized
if (!IsWindow(m_hwndErrors))
hr = SP_E_UNINITIALIZED;
else
{
// Allocate a struct for the item data
if (!MemAlloc((LPVOID *) &pData, sizeof(LBDATA)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
pData->eid = eid;
// Check to see if we need to load the string ourselves
if (IS_INTRESOURCE(pszError))
{
pData->pszText = AthLoadString(PtrToUlong(pszError), 0, 0);
}
else
pData->pszText = PszDupA(pszError);
// Get the size of the string
hfont = (HFONT) SendMessage(m_hwnd, WM_GETFONT, 0, 0);
hdc = GetDC(m_hwndErrors);
SelectFont(hdc, hfont);
SetRect(&(pData->rcText), 0, 0, m_cxErrors - BULLET_WIDTH - 4, 0);
// bug #47453, add DT_INTERNAL flag so that on FE platform (PRC and TC)
// two list items is not overlapping.
DrawText(hdc, pData->pszText, -1, &(pData->rcText), DT_CALCRECT | DT_WORDBREAK | DT_INTERNAL);
ReleaseDC(m_hwndErrors, hdc);
pData->rcText.bottom += 4;
// Add the item data
nItem = ListBox_AddItemData(m_hwndErrors, pData);
}
exit:
LeaveCriticalSection(&m_cs);
return hr;
}
//
// FUNCTION: CSpoolerDlg::UpdateEventState()
//
// PURPOSE: Allows a task to update the description and state of an event.
//
// PARAMETERS:
// <in> eid - ID of the event to update
// <in> nImage - Image to display for the item. If this is -1,
// the image is not changed.
// <in> pszDescription - Description for the item. If this is NULL, the
// description is not changed.
// <in> pszStatus - Status of the item. If this is NULL, the status
// is not changed.
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// SP_E_EVENTNOTFOUND
// E_UNEXPECTED
//
HRESULT CSpoolerDlg::UpdateEventState(EVENTID eid, INT nImage,
LPCTSTR pszDescription, LPCTSTR pszStatus)
{
LV_ITEM lvi;
LV_FINDINFO lvfi;
int iItem = -1;
BOOL fSuccess = FALSE;
HRESULT hr = S_OK;
TCHAR szRes[CCHMAX_STRINGRES];
EnterCriticalSection(&m_cs);
ZeroMemory(&lvi, sizeof(LV_ITEM));
// See if we're initialized
if (!IsWindow(m_hwndEvents))
{
hr = SP_E_UNINITIALIZED;
goto exit;
}
// Start by finding the event in our list
lvfi.flags = LVFI_PARAM;
lvfi.psz = 0;
lvfi.lParam = eid;
iItem = ListView_FindItem(m_hwndEvents, -1, &lvfi);
if (-1 == iItem)
{
hr = SP_E_EVENTNOTFOUND;
goto exit;
}
// Update the image and description
lvi.mask = 0;
lvi.iItem = iItem;
lvi.iSubItem = 0;
// Set up the image info
if (-1 != nImage)
{
lvi.mask = LVIF_IMAGE;
lvi.iImage = nImage;
}
// Set up the description text
if (NULL != pszDescription)
{
// Check to see if we need to load the string ourselves
if (IS_INTRESOURCE(pszDescription))
{
AthLoadString(PtrToUlong(pszDescription), szRes, ARRAYSIZE(szRes));
lvi.pszText = szRes;
}
else
lvi.pszText = (LPTSTR) pszDescription;
lvi.mask |= LVIF_TEXT;
}
if (lvi.mask)
fSuccess = ListView_SetItem(m_hwndEvents, &lvi);
// Update the status
if (NULL != pszStatus)
{
// Check to see if we need to load the string ourselves
if (IS_INTRESOURCE(pszStatus))
{
AthLoadString(PtrToUlong(pszStatus), szRes, ARRAYSIZE(szRes));
lvi.pszText = szRes;
}
else
lvi.pszText = (LPTSTR) pszStatus;
lvi.mask = LVIF_TEXT;
lvi.iSubItem = 1;
ListView_SetItemText(m_hwndEvents, lvi.iItem, 1, lvi.pszText); /* fSuccess = fSuccess && */
}
hr = fSuccess ? S_OK : E_UNEXPECTED;
exit:
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::SetProgressRange()
//
// PURPOSE: Resets the progress bar to zero, and then sets the upper bound
// to the specified amount.
//
// PARAMETERS:
// <in> wMax - New maximum range for the progress bar
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::SetProgressRange(WORD wMax)
{
HWND hwndProg = GetDlgItem(m_hwnd, IDC_SP_PROGRESS_BAR);
HRESULT hr = S_OK;
if (wMax == 0)
return (E_INVALIDARG);
EnterCriticalSection(&m_cs);
// Make sure we have a progress bar
if (!IsWindow(hwndProg))
hr = SP_E_UNINITIALIZED;
else
{
// Reset the progress bar
SendMessage(hwndProg, PBM_SETPOS, 0, 0);
// Set the new range
SendMessage(hwndProg, PBM_SETRANGE, 0, MAKELPARAM(0, wMax));
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::IncrementProgress()
//
// PURPOSE: Increments the progress bar by a specified amount.
//
// PARAMETERS:
// <in> wDelta - Amount to increment the progress bar by
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::IncrementProgress(WORD wDelta)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
SendDlgItemMessage(m_hwnd, IDC_SP_PROGRESS_BAR, PBM_DELTAPOS, wDelta, 0);
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::SetProgressPosition()
//
// PURPOSE: Sets the progress bar to a specific position.
//
// PARAMETERS:
// <in> wPos - Position to set progress bar to
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::SetProgressPosition(WORD wPos)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (wPos < 0)
hr = E_INVALIDARG;
else if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
SendDlgItemMessage(m_hwnd, IDC_SP_PROGRESS_BAR, PBM_SETPOS, wPos, 0);
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::SetGeneralProgress()
//
// PURPOSE: Allows the caller to update the general progress text.
//
// PARAMETERS:
// <in> pszProgress - New progress string
//
// RETURN VALUE:
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::SetGeneralProgress(LPCTSTR pszProgress)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
{
if (pszProgress)
SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, pszProgress);
else
SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, _T(""));
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::SetSpecificProgress()
//
// PURPOSE: Allows the caller to update the specific progress text.
//
// PARAMETERS:
// <in> pszProgress - New progress string
//
// RETURN VALUE:
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::SetSpecificProgress(LPCTSTR pszProgress)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
{
TCHAR szRes[CCHMAX_STRINGRES];
if (IS_INTRESOURCE(pszProgress))
{
AthLoadString(PtrToUlong(pszProgress), szRes, ARRAYSIZE(szRes));
pszProgress = szRes;
}
if (pszProgress)
SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, pszProgress);
else
SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, _T(""));
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::SetAnimation()
//
// PURPOSE: Allows the caller to choose which animation is playing
//
// PARAMETERS:
// <in> nAnimationID - New resource id for the animation
// <in> fPlay - TRUE if we should start animating it.
//
// RETURN VALUE:
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::SetAnimation(int nAnimationID, BOOL fPlay)
{
HRESULT hr = S_OK;
HWND hwndAni;
EnterCriticalSection(&m_cs);
#ifndef _WIN64
if (!IsWindow(m_hwnd) || !IsWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE)))
hr = SP_E_UNINITIALIZED;
else
{
hwndAni = GetDlgItem(m_hwnd, IDC_SP_ANIMATE);
Animate_Close(hwndAni);
if (IsWindow(m_hwnd) && IsWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE)))
{
Animate_OpenEx(hwndAni, g_hLocRes, MAKEINTRESOURCE(nAnimationID));
if (fPlay)
Animate_Play(hwndAni, 0, -1, -1);
}
}
#endif // _WIN64
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::EnsureVisible()
//
// PURPOSE: Ensures that the specified event is visible within the listview
//
// PARAMETERS:
// <in> eid - Event ID to make sure is visible
//
// RETURN VALUE:
// SP_E_UNINITIALIZED
// SP_E_EVENTNOTFOUND
// S_OK
//
HRESULT CSpoolerDlg::EnsureVisible(EVENTID eid)
{
LV_FINDINFO lvfi;
int iItem = -1;
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
// See if we're initialized
if (!IsWindow(m_hwndEvents))
hr = SP_E_UNINITIALIZED;
else
{
// Start by finding the event in our list
lvfi.flags = LVFI_PARAM;
lvfi.psz = 0;
lvfi.lParam = eid;
iItem = ListView_FindItem(m_hwndEvents, -1, &lvfi);
// Now tell the listview to make sure it's visible
if (-1 != iItem)
ListView_EnsureVisible(m_hwndEvents, iItem, FALSE);
hr = (iItem == -1) ? SP_E_EVENTNOTFOUND : S_OK;
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::ShowWindow()
//
// PURPOSE: Shows or hides the spooler dialog
//
// PARAMETERS:
// <in> nCmdShow - This is the same as the ShowWindow() API
//
// RETURN VALUE:
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::ShowWindow(int nCmdShow)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
{
::ShowWindow(m_hwnd, nCmdShow);
if (m_pBindCtx)
m_pBindCtx->OnUIChange(nCmdShow == SW_SHOW);
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::StartDelivery()
//
// PURPOSE: Tells the dialog the delivery has begun.
//
// RETURN VALUE:
// S_OK
// SP_E_UNINITIALIZED
//
HRESULT CSpoolerDlg::StartDelivery(void)
{
HRESULT hr = SP_E_UNINITIALIZED;
EnterCriticalSection(&m_cs);
if (IsWindow(m_hwnd))
{
//Animate_Play(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), 0, -1, -1);
TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_TASKS);
OnTabChange(0);
ToggleStatics(FALSE);
SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, _T(""));
SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, _T(""));
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
hr = S_OK;
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::ClearEvents()
//
// PURPOSE: Clears any events and errors out of the listviews.
//
// RETURN VALUE:
// S_OK
// SP_E_UNINITIALIZED
//
HRESULT CSpoolerDlg::ClearEvents(void)
{
HRESULT hr = SP_E_UNINITIALIZED;
EnterCriticalSection(&m_cs);
if (IsWindow(m_hwnd))
{
m_fErrors = FALSE;
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
ListView_DeleteAllItems(m_hwndEvents);
ListBox_ResetContent(m_hwndErrors);
hr = S_OK;
}
LeaveCriticalSection(&m_cs);
return (hr);
}
HRESULT CSpoolerDlg::SetTaskCounts(DWORD cSucceeded, DWORD cTotal)
{
TCHAR szBuf[CCHMAX_STRINGRES];
HRESULT hr = SP_E_UNINITIALIZED;
EnterCriticalSection(&m_cs);
if (IsWindow(m_hwnd))
{
wnsprintf(szBuf, ARRAYSIZE(szBuf), m_szCount, cSucceeded, cTotal);
SetDlgItemText(m_hwnd, IDC_SP_OVERALL_STATUS, szBuf);
hr = S_OK;
}
LeaveCriticalSection(&m_cs);
return (hr);
}
HRESULT CSpoolerDlg::AreThereErrors(void)
{
EnterCriticalSection(&m_cs);
HRESULT hr = (m_fErrors ? S_OK : S_FALSE);
LeaveCriticalSection(&m_cs);
return hr;
}
HRESULT CSpoolerDlg::Shutdown(void)
{
CHAR szRes[255];
EnterCriticalSection(&m_cs);
m_fShutdown = TRUE;
if (IsWindow(m_hwnd))
{
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_MINIMIZE), TRUE);
LoadString(g_hLocRes, idsClose, szRes, ARRAYSIZE(szRes));
SetDlgItemText(m_hwnd, IDC_SP_MINIMIZE, szRes);
}
LeaveCriticalSection(&m_cs);
return S_OK;
}
//
// FUNCTION: CSpoolerDlg::GoIdle()
//
// PURPOSE: Tells the dialog the delivery has ended.
//
// PARAMETERS:
// <in> fErrors - TRUE if errors occured during the download.
//
// RETURN VALUE:
// S_OK
// SP_E_UNINITIALIZED
//
HRESULT CSpoolerDlg::GoIdle(BOOL fErrors, BOOL fShutdown, BOOL fNoSync)
{
HRESULT hr = SP_E_UNINITIALIZED;
TCHAR szRes[CCHMAX_STRINGRES];
EnterCriticalSection(&m_cs);
if (IsWindow(m_hwnd))
{
// Stop the animation
#ifndef _WIN64
Animate_Close(GetDlgItem(m_hwnd, IDC_SP_ANIMATE));
#endif
hr = S_OK;
ToggleStatics(TRUE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
if (ISFLAGSET(fErrors, SPSTATE_CANCEL))
{
m_fErrors = TRUE;
ExpandCollapse(TRUE);
TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_TASKS);
OnTabChange(0);
AthLoadString(idsSpoolerUserCancel, szRes, ARRAYSIZE(szRes));
SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
(WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiError)), 0);
}
// Also if there were errors, we should switch to the error page
else if (fErrors)
{
m_fErrors = TRUE;
ExpandCollapse(TRUE);
TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_ERRORS);
OnTabChange(0);
AthLoadString(idsSpoolerIdleErrors, szRes, ARRAYSIZE(szRes));
SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
(WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiError)), 0);
}
else
{
AthLoadString(idsSpoolerIdle, szRes, ARRAYSIZE(szRes));
SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
(WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiMailNews)), 0);
if (fNoSync)
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsNothingToSync), NULL, MB_OK | MB_ICONEXCLAMATION);
// Determine if we need to hide the dialog
UINT state = (UINT) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE, IDC_SP_TACK, 0);
if (!(state & TBSTATE_CHECKED))
ShowWindow(SW_HIDE);
}
}
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CSpoolerDlg::IsDialogMessage()
//
// PURPOSE: Allows the dialog to retrieve messages from the message loop.
//
// PARAMETERS:
// <in> pMsg - Pointer to the message for us to examine.
//
// RETURN VALUE:
// Returns S_OK if we eat the message, S_FALSE otherwise.
//
HRESULT CSpoolerDlg::IsDialogMessage(LPMSG pMsg)
{
HRESULT hr;
BOOL fEaten = FALSE;
BOOL fBack = FALSE;
EnterCriticalSection(&m_cs);
// Intended for modeless timeout dialog running on this thread?
HWND hwndTimeout = (HWND)TlsGetValue(g_dwTlsTimeout);
if (hwndTimeout && ::IsDialogMessage(hwndTimeout, pMsg))
return(S_OK);
if (pMsg->message == WM_KEYDOWN && (GetAsyncKeyState(VK_CONTROL) < 0))
{
switch (pMsg->wParam)
{
case VK_TAB:
fBack = GetAsyncKeyState(VK_SHIFT) < 0;
break;
case VK_PRIOR: // VK_PAGE_UP
case VK_NEXT: // VK_PAGE_DOWN
fBack = (pMsg->wParam == VK_PRIOR);
break;
default:
goto NoKeys;
}
int iCur = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS));
// tab in reverse if shift is down
if (fBack)
iCur += (TAB_MAX - 1);
else
iCur++;
iCur %= TAB_MAX;
TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), iCur);
OnTabChange(NULL);
}
NoKeys:
if (IsWindow(m_hwnd) && IsWindowVisible(m_hwnd))
fEaten = ::IsDialogMessage(m_hwnd, pMsg);
LeaveCriticalSection(&m_cs);
return (fEaten ? S_OK : S_FALSE);
}
//
// FUNCTION: CSpoolerDlg::GetWindow()
//
// PURPOSE: Returns the handle to the spooler dialog window.
//
// PARAMETERS:
// <out> pHwnd - Where we return the handle.
//
// RETURN VALUE:
// E_INVALIDARG
// SP_E_UNINITIALIZED
// S_OK
//
HRESULT CSpoolerDlg::GetWindow(HWND *pHwnd)
{
HRESULT hr=S_OK;
if (NULL == pHwnd)
return E_INVALIDARG;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
*pHwnd = m_hwnd;
LeaveCriticalSection(&m_cs);
return (S_OK);
}
HRESULT CSpoolerDlg::Close(void)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
if (!IsWindow(m_hwnd))
hr = SP_E_UNINITIALIZED;
else
DestroyWindow(m_hwnd);
// Unregister with Identity manager
if (m_dwIdentCookie != 0)
{
MU_UnregisterIdentityNotifier(m_dwIdentCookie);
m_dwIdentCookie = 0;
}
LeaveCriticalSection(&m_cs);
return (hr);
}
HRESULT CSpoolerDlg::ChangeHangupOption(BOOL fEnable, DWORD dwOption)
{
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), fEnable ? SW_SHOW : SW_HIDE);
::EnableWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), fEnable);
SendDlgItemMessage(m_hwnd, IDC_SP_HANGUP, BM_SETCHECK, dwOption, 0);
return (S_OK);
}
//
// FUNCTION: CSpoolerDlg::PostDlgProc()
//
// PURPOSE: Dialog callback for the spooler dialog proc.
//
INT_PTR CALLBACK CSpoolerDlg::SpoolerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
CSpoolerDlg *pThis = (CSpoolerDlg *) GetWindowLongPtr(hwnd, DWLP_USER);
LRESULT lResult;
// Pass to spooler bind context
if (pThis && pThis->m_pBindCtx && pThis->m_pBindCtx->OnWindowMessage(hwnd, uMsg, wParam, lParam) == S_OK)
return (TRUE);
switch (uMsg)
{
case WM_INITDIALOG:
// Stash the this pointer so we can use it later
Assert(lParam);
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
pThis = (CSpoolerDlg *) lParam;
return (BOOL) HANDLE_WM_INITDIALOG(hwnd, wParam, lParam,
pThis->OnInitDialog);
case WM_COMMAND:
if (pThis)
HANDLE_WM_COMMAND(hwnd, wParam, lParam, pThis->OnCommand);
return (TRUE);
case WM_NOTIFY:
if (pThis)
{
lResult = HANDLE_WM_NOTIFY(hwnd, wParam, lParam, pThis->OnNotify);
SetDlgMsgResult(hwnd, WM_NOTIFY, lResult);
}
return (TRUE);
case WM_DRAWITEM:
if (pThis)
HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, pThis->OnDrawItem);
return (TRUE);
case WM_MEASUREITEM:
if (pThis)
HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, pThis->OnMeasureItem);
return (TRUE);
case WM_DELETEITEM:
if (pThis)
HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, pThis->OnDeleteItem);
return (TRUE);
#if 0
case WM_SYSCOLORCHANGE:
case WM_SETTINGCHANGE:
if (pThis)
HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, pThis->OnSysColorChange);
return (TRUE);
#endif
case WM_CLOSE:
if (pThis)
HANDLE_WM_CLOSE(hwnd, wParam, lParam, pThis->OnClose);
return (TRUE);
case WM_DESTROY:
if (pThis)
HANDLE_WM_DESTROY(hwnd, wParam, lParam, pThis->OnDestroy);
return (TRUE);
case IMAIL_SHOWWINDOW:
::ShowWindow(hwnd, (int) lParam);
if (pThis)
pThis->ToggleStatics(lParam == SW_HIDE);
return (TRUE);
case WM_QUERYENDSESSION:
if (pThis && pThis->m_pBindCtx)
{
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pThis->m_pBindCtx->QueryEndSession(wParam, lParam));
return (TRUE);
}
break;
case WM_CONTEXTMENU:
if (pThis)
{
HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, pThis->OnContextMenu);
return (TRUE);
}
break;
}
return (FALSE);
}
//
// FUNCTION: CSpoolerDlg::OnInitDialog()
//
// PURPOSE: Initializes the dialog.
//
// PARAMETERS:
// <in> hwnd - Handle of the dialog window.
// <in> hwndFocus - Handle of the control that will start with the focus.
// <in> lParam - Extra data being passed to the dialog.
//
// RETURN VALUE:
// Return TRUE to set the focus to hwndFocus
//
BOOL CSpoolerDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
m_hwnd = hwnd;
// Bug #38692 - Set the font correctly for Intl charsets
SetIntlFont(hwnd);
SetIntlFont(GetDlgItem(hwnd, IDC_SP_GENERAL_PROG));
SetIntlFont(GetDlgItem(hwnd, IDC_SP_SPECIFIC_PROG));
SetIntlFont(GetDlgItem(hwnd, IDC_SP_EVENTS));
SetIntlFont(GetDlgItem(hwnd, IDC_SP_ERRORS));
SetIntlFont(GetDlgItem(hwnd, IDC_SP_IDLETEXT));
// Initialize the controls on the dialog
InitializeTabs();
InitializeLists();
InitializeAnimation();
InitializeToolbar();
ToggleStatics(TRUE);
// Hide the Hangup when done deal.
// ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), SW_HIDE);
// Set the hangup when done option
Button_SetCheck(GetDlgItem(m_hwnd, IDC_SP_HANGUP), DwGetOption(OPT_DIALUP_HANGUP_DONE));
// Get some information from the dialog template we'll need later
GetDlgItemText(m_hwnd, IDC_SP_OVERALL_STATUS, m_szCount, ARRAYSIZE(m_szCount));
// Initialize the rectangles that we'll need for sizing later
RECT rcSep;
GetWindowRect(GetDlgItem(hwnd, IDC_SP_SEPARATOR), &rcSep);
GetWindowRect(hwnd, &m_rcDlg);
m_cyCollapsed = rcSep.top - m_rcDlg.top;
// Load the window size from the registry
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetOption(OPT_SPOOLERDLGPOS, (LPVOID*) &wp, sizeof(WINDOWPLACEMENT)))
{
wp.showCmd = SW_HIDE;
SetWindowPlacement(hwnd, &wp);
ExpandCollapse(m_cyCollapsed < (DWORD) ((wp.rcNormalPosition.bottom - wp.rcNormalPosition.top)), FALSE);
}
else
{
// Center the dialog on the screen.
CenterDialog(hwnd);
ExpandCollapse(FALSE, FALSE);
}
// Set the state of the thumbtack
DWORD dwTack;
if (DwGetOption(OPT_SPOOLERTACK))
{
SendDlgItemMessage(hwnd, IDC_SP_TOOLBAR, TB_SETSTATE, IDC_SP_TACK,
MAKELONG(TBSTATE_CHECKED | TBSTATE_ENABLED, 0));
SendMessage(hwnd, WM_COMMAND, IDC_SP_TACK, 0);
}
// Disable the stop button
EnableWindow(GetDlgItem(hwnd, IDC_SP_STOP), FALSE);
// Subclass the list box
HWND hwnderr = GetDlgItem(hwnd, IDC_SP_ERRORS);
WNDPROC proc = (WNDPROC) GetWindowLongPtr(hwnderr, GWLP_WNDPROC);
SetProp(hwnderr, c_szWndProc, proc);
SetWindowLongPtr(hwnderr, GWLP_WNDPROC, (LPARAM) ListSubClassProc);
// BUG: 44376. ATOK11 has a hidden window. If we return TRUE user will do a setfocus on US, at this point the browser
// thread is block waiting for the spooler to complete and when ATOK gets a WM_ACTIVATE they interthreadsendmsg on our blocked
// browser window with inf. timeout. So we hang at startup. Don't set focus in here at startup time.
return (FALSE);
}
//
// FUNCTION: CSpoolerDlg::OnCommand()
//
// PURPOSE: Handle the various command messages dispatched from the dialog
//
void CSpoolerDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case IDCANCEL:
case IDC_SP_MINIMIZE:
if (m_fShutdown)
{
Assert(m_pBindCtx);
EnableWindow(GetDlgItem(hwnd, IDC_SP_MINIMIZE), FALSE);
m_pBindCtx->UIShutdown();
}
else
ShowWindow(SW_HIDE);
break;
case IDC_SP_STOP:
if (m_pBindCtx)
{
m_pBindCtx->Cancel();
if (GetFocus() == GetDlgItem(hwnd, IDC_SP_STOP))
SetFocus(GetDlgItem(hwnd, IDC_SP_MINIMIZE));
EnableWindow(GetDlgItem(hwnd, IDC_SP_STOP), FALSE);
}
break;
case IDC_SP_TACK:
{
UINT state = (UINT) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE,
IDC_SP_TACK, 0);
SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_CHANGEBITMAP,
IDC_SP_TACK,
MAKELPARAM(state & TBSTATE_CHECKED ? IMAGE_TACK_IN : IMAGE_TACK_OUT, 0));
}
break;
case IDC_SP_DETAILS:
m_fSaveSize = TRUE;
ExpandCollapse(!m_fExpanded);
break;
case IDC_SP_HANGUP:
SetDwOption(OPT_DIALUP_HANGUP_DONE, BST_CHECKED == Button_GetCheck(hwndCtl), NULL, 0);
break;
}
}
//
// FUNCTION: CSpoolerDlg::OnNotify
//
// PURPOSE: Handles notifications from the common controls on the dialog.
//
LRESULT CSpoolerDlg::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
{
switch (pnmhdr->code)
{
case TCN_SELCHANGE:
OnTabChange(pnmhdr);
return (0);
}
return (0);
}
//
// FUNCTION: CSpoolerDlg::OnDrawItem()
//
// PURPOSE: Draws the link buttons
//
// PARAMETERS:
// <in> hwnd - Handle of the dialog window
// <in> lpDrawItem - Pointer to a DRAWITEMSTRUCT with the info needed to
// draw the button.
//
void CSpoolerDlg::OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem)
{
HDC hdc = lpDrawItem->hDC;
COLORREF clrText, clrBack;
RECT rcText, rcFocus;
SIZE size;
BOOL fSelected = (lpDrawItem->itemState & ODS_SELECTED) &&
(GetFocus() == lpDrawItem->hwndItem);
Assert(lpDrawItem->CtlType == ODT_LISTBOX);
if (lpDrawItem->itemID == -1)
goto exit;
// Draw the bullet first
ImageList_Draw(m_himlImages,
IMAGE_BULLET,
hdc,
BULLET_INDENT,
lpDrawItem->rcItem.top,
fSelected ? ILD_SELECTED | ILD_TRANSPARENT : ILD_TRANSPARENT);
// Set up the text rectangle
rcText = lpDrawItem->rcItem;
rcText.left += BULLET_WIDTH;
// Set up the text and background colors
clrBack = SetBkColor(hdc, GetSysColor(fSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW));
clrText = SetTextColor(hdc, GetSysColor(fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
// Draw the text
FillRect(hdc, &rcText, (HBRUSH)IntToPtr((fSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW) + 1));
InflateRect(&rcText, -2, -2);
DrawText(hdc, ((LBDATA *) lpDrawItem->itemData)->pszText, -1, &rcText, DT_NOCLIP | DT_WORDBREAK);
// If we need a focus rect, do that too
if (lpDrawItem->itemState & ODS_FOCUS)
{
rcFocus = lpDrawItem->rcItem;
rcFocus.left += BULLET_WIDTH;
// InflateRect(&rcFocus, -2, -2);
DrawFocusRect(hdc, &rcFocus);
}
SetBkColor(hdc, clrBack);
SetTextColor(hdc, clrText);
exit:
return;
}
void CSpoolerDlg::OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *pMeasureItem)
{
LBDATA *pData = NULL;
EnterCriticalSection(&m_cs);
// Set the height of the item
if (NULL != (pData = (LBDATA *) ListBox_GetItemData(m_hwndErrors, pMeasureItem->itemID)))
{
pMeasureItem->itemHeight = pData->rcText.bottom;
}
LeaveCriticalSection(&m_cs);
}
void CSpoolerDlg::OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT * lpDeleteItem)
{
EnterCriticalSection(&m_cs);
if (lpDeleteItem->itemData)
{
SafeMemFree(((LBDATA *)lpDeleteItem->itemData)->pszText);
MemFree((LPVOID) lpDeleteItem->itemData);
}
LeaveCriticalSection(&m_cs);
}
//
// FUNCTION: CSpoolerDlg::OnClose()
//
// PURPOSE: Handles the WM_CLOSE notification by sending an IDCANCEL to
// the dialog.
//
void CSpoolerDlg::OnClose(HWND hwnd)
{
SendMessage(hwnd, WM_COMMAND, IDC_SP_MINIMIZE, 0);
}
//
// FUNCTION: CSpoolerDlg::OnDestroy()
//
// PURPOSE: Handles the WM_DESTROY notification by freeing the memory stored
// in the listview items.
//
void CSpoolerDlg::OnDestroy(HWND hwnd)
{
#ifndef _WIN64
Animate_Close(GetDlgItem(m_hwnd, IDC_SP_ANIMATE));
#endif
// Save the window placement
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hwnd, &wp))
{
if (!m_fSaveSize)
{
// Load the old size out of the registry
WINDOWPLACEMENT wp2;
if (GetOption(OPT_SPOOLERDLGPOS, (LPVOID*) &wp2, sizeof(WINDOWPLACEMENT)))
{
wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + (wp2.rcNormalPosition.bottom - wp2.rcNormalPosition.top);
}
else
{
wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + m_cyCollapsed;
}
}
SetOption(OPT_SPOOLERDLGPOS, (LPVOID) &wp, sizeof(WINDOWPLACEMENT), NULL, 0);
}
DWORD dwState;
dwState = (DWORD) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE, IDC_SP_TACK, 0);
SetDwOption(OPT_SPOOLERTACK, !!(dwState & TBSTATE_CHECKED), NULL, 0);
HIMAGELIST himl;
himl = (HIMAGELIST)SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETIMAGELIST, 0, 0);
if (himl)
ImageList_Destroy(himl);
HWND hwnderr = GetDlgItem(hwnd, IDC_SP_ERRORS);
WNDPROC proc = (WNDPROC)GetProp(hwnderr, c_szWndProc);
if (proc != NULL)
{
SetWindowLongPtr(hwnderr, GWLP_WNDPROC, (LPARAM)proc);
RemoveProp(hwnderr, c_szWndProc);
}
}
//
// FUNCTION: CSpoolerDlg::InitializeTabs()
//
// PURPOSE: Initializes the tab control on the dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
BOOL CSpoolerDlg::InitializeTabs(void)
{
HWND hwndTabs = GetDlgItem(m_hwnd, IDC_SP_TABS);
TC_ITEM tci;
TCHAR szRes[CCHMAX_STRINGRES];
// "Tasks"
tci.mask = TCIF_TEXT;
tci.pszText = AthLoadString(idsTasks, szRes, ARRAYSIZE(szRes));
TabCtrl_InsertItem(hwndTabs, 0, &tci);
// "Errors"
tci.pszText = AthLoadString(idsErrors, szRes, ARRAYSIZE(szRes));
TabCtrl_InsertItem(hwndTabs, 1, &tci);
return (TRUE);
}
//
// FUNCTION: CSpoolerDlg::InitializeLists()
//
// PURPOSE: Initializes the list control on the dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
BOOL CSpoolerDlg::InitializeLists(void)
{
LV_COLUMN lvc;
TCHAR szRes[CCHMAX_STRINGRES];
RECT rcClient;
DWORD cx;
// Store the handle for the events list since we use it frequently
m_hwndEvents = GetDlgItem(m_hwnd, IDC_SP_EVENTS);
// Get the size of the client rect of the listview
GetClientRect(m_hwndEvents, &rcClient);
// "Tasks" column
lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
lvc.fmt = LVCFMT_CENTER;
lvc.cx = rcClient.right / 2;
lvc.pszText = AthLoadString(idsTasks, szRes, ARRAYSIZE(szRes));
lvc.iSubItem = 0;
ListView_InsertColumn(m_hwndEvents, 0, &lvc);
// "Status" column
cx = (rcClient.right / 2 - GetSystemMetrics(SM_CXVSCROLL)) / 2;
lvc.cx = cx;
lvc.pszText = AthLoadString(idsStatusCol, szRes, ARRAYSIZE(szRes));
lvc.iSubItem = 1;
ListView_InsertColumn(m_hwndEvents, 1, &lvc);
// "Connection" column
lvc.cx = cx;
lvc.pszText = AthLoadString(idsConnection, szRes, ARRAYSIZE(szRes));
lvc.iSubItem = 2;
ListView_InsertColumn(m_hwndEvents, 2, &lvc);
// Set the listview image list
m_himlImages = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbSpooler), 16, 0,
RGB(255, 0, 255));
if (m_himlImages)
ListView_SetImageList(m_hwndEvents, m_himlImages, LVSIL_SMALL);
// The listview looks better if we use full row select
ListView_SetExtendedListViewStyle(m_hwndEvents, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
// Initialize the Error list
m_hwndErrors = GetDlgItem(m_hwnd, IDC_SP_ERRORS);
::ShowWindow(m_hwndErrors, FALSE);
EnableWindow(m_hwndErrors, FALSE);
// Save the width of the error list
GetClientRect(m_hwndErrors, &rcClient);
m_cxErrors = rcClient.right;
return (TRUE);
}
//
// FUNCTION: CSpoolerDlg::InitializeAnimation()
//
// PURPOSE: Initializes the animation controls on the dialog.
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
BOOL CSpoolerDlg::InitializeAnimation(void)
{
#ifndef _WIN64
HWND hwndAni = GetDlgItem(m_hwnd, IDC_SP_ANIMATE);
Animate_OpenEx(hwndAni, g_hLocRes, MAKEINTRESOURCE(idanOutbox));
#endif
return (0);
}
//
// FUNCTION: CSpoolerDlg::InitializeToolbar()
//
// PURPOSE: What dialog would be complete without a toolbar, eh?
//
// RETURN VALUE:
// TRUE if everything succeeded, FALSE otherwise.
//
BOOL CSpoolerDlg::InitializeToolbar(void)
{
HWND hwndTool;
RECT rcTabs;
POINT point;
HIMAGELIST himlImages = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbSpooler), 16, 0,
RGB(255, 0, 255));
GetWindowRect(GetDlgItem(m_hwnd, IDC_SP_TABS), &rcTabs);
point.x = rcTabs.right - 22;
point.y = rcTabs.bottom + 3;
ScreenToClient(m_hwnd, &point);
hwndTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN |
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | TBSTYLE_FLAT,
point.x, point.y, 22, 22,
m_hwnd, (HMENU) IDC_SP_TOOLBAR,
g_hInst, 0);
if (hwndTool)
{
#ifndef WIN16
TBBUTTON tb = { IMAGE_TACK_OUT, IDC_SP_TACK, TBSTATE_ENABLED, TBSTYLE_CHECK, {0, 0}, 0, 0 };
#else
TBBUTTON tb = { IMAGE_TACK_OUT, IDC_SP_TACK, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0 };
#endif
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: CSpoolerDlg::ExpandCollapse()
//
// PURPOSE: Takes care of showing and hiding the "details" part of the
// error dialog.
//
// PARAMETERS:
// <in> fExpand - TRUE if we should be expanding the dialog.
//
void CSpoolerDlg::ExpandCollapse(BOOL fExpand, BOOL fSetFocus)
{
RECT rcSep;
TCHAR szBuf[64];
m_fExpanded = fExpand;
GetWindowRect(GetDlgItem(m_hwnd, IDC_SP_SEPARATOR), &rcSep);
if (!m_fExpanded)
SetWindowPos(m_hwnd, 0, 0, 0, m_rcDlg.right - m_rcDlg.left,
m_cyCollapsed, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
else
SetWindowPos(m_hwnd, 0, 0, 0, m_rcDlg.right - m_rcDlg.left,
m_rcDlg.bottom - m_rcDlg.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
// 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, 0, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
AthLoadString(m_fExpanded ? idsHideDetails : idsShowDetails, szBuf,
ARRAYSIZE(szBuf));
SetDlgItemText(m_hwnd, IDC_SP_DETAILS, szBuf);
if (fExpand)
{
switch (m_iTab)
{
case TAB_TASKS:
UpdateLists(TRUE, FALSE, FALSE);
break;
case TAB_ERRORS:
UpdateLists(FALSE, TRUE, FALSE);
break;
}
}
else
UpdateLists(FALSE, FALSE, FALSE);
// Raid-34387: Spooler: Closing details with ALT-D while focus is on a task disables keyboard input
if (!fExpand && fSetFocus)
SetFocus(GetDlgItem(m_hwnd, IDC_SP_DETAILS));
}
//
// FUNCTION: CSpoolerDlg::OnTabChange()
//
// PURPOSE: Gets called in response to the user changing which tab is
// the selected tab. In response, we update which listview
// is currently visible.
//
// PARAMETERS:
// <in> pnmhdr - Pointer to the notification information
//
void CSpoolerDlg::OnTabChange(LPNMHDR pnmhdr)
{
HWND hwndDisable1, hwndDisable2 = 0, hwndEnable;
// Find out which tab is currently active
m_iTab = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS));
if (-1 == m_iTab)
return;
// Update which listview is visible
switch (m_iTab)
{
case TAB_TASKS:
// Hide the error listview, show the tasks list
UpdateLists(TRUE, FALSE, FALSE);
break;
case TAB_ERRORS:
// Hide the error listview, show the tasks list
UpdateLists(FALSE, TRUE, FALSE);
break;
}
}
//
// FUNCTION: CSpoolerDlg::UpdateLists()
//
// PURPOSE: Does the work of hiding and showing the lists when the
// tab selection changes.
//
// PARAMETERS:
// <in> fEvents - TRUE to display the events list
// <in> fErrors - TRUE to display the error list
// <in> fHistory - TRUE to display the history list
//
void CSpoolerDlg::UpdateLists(BOOL fEvents, BOOL fErrors, BOOL fHistory)
{
if (IsWindow(m_hwndEvents))
{
EnableWindow(m_hwndEvents, fEvents);
::ShowWindow(m_hwndEvents, fEvents ? SW_SHOWNA : SW_HIDE);
}
if (IsWindow(m_hwndErrors))
{
EnableWindow(m_hwndErrors, fErrors);
::ShowWindow(m_hwndErrors, fErrors ? SW_SHOWNA : SW_HIDE);
}
}
void CSpoolerDlg::ToggleStatics(BOOL fIdle)
{
m_fIdle = fIdle;
if (fIdle)
{
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), FALSE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), FALSE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), FALSE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), TRUE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), TRUE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), SW_HIDE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), SW_HIDE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), SW_HIDE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), SW_SHOWNA);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), SW_SHOWNA);
}
else
{
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), TRUE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), TRUE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), TRUE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), FALSE);
EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), FALSE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), SW_SHOWNA);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), SW_SHOWNA);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), SW_SHOWNA);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), SW_HIDE);
::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), SW_HIDE);
}
}
void CSpoolerDlg::OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
{
POINT pt = {xPos, yPos};
RECT rcError;
LBDATA *pData = NULL;
// Check to see if the error window is visible
if (!IsWindowVisible(m_hwndErrors))
return;
// Check to see if the click was within the error window
GetWindowRect(m_hwndErrors, &rcError);
if (!PtInRect(&rcError, pt))
return;
// Do the context menu
HMENU hMenu = CreatePopupMenu();
// Add a "Copy..." item
TCHAR szRes[CCHMAX_STRINGRES];
AthLoadString(idsCopyTT, szRes, ARRAYSIZE(szRes));
// Add it to the menu
InsertMenu(hMenu, -1, MF_BYPOSITION | MF_STRING, ID_COPY, szRes);
// If the click is on an item in the listbox, then enable the command
ScreenToClient(m_hwndErrors, &pt);
DWORD iItem = (DWORD) SendMessage(m_hwndErrors, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));
if (iItem != -1)
{
EnterCriticalSection(&m_cs);
pData = (LBDATA *) ListBox_GetItemData(m_hwndErrors, iItem);
LeaveCriticalSection(&m_cs);
}
if (iItem == -1 || NULL == pData || ((LBDATA*)-1) == pData)
EnableMenuItem(hMenu, ID_COPY, MF_BYCOMMAND | MF_GRAYED);
// Show the menu
DWORD id;
id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY,
xPos, yPos, m_hwndErrors, NULL);
if (id == ID_COPY)
{
// Get the item data for the item they clicked on
LPTSTR pszDup;
EnterCriticalSection(&m_cs);
// Set the height of the item
if (NULL != pData && ((LBDATA*)-1) != pData)
{
// Dupe the string. Clipboard owns the copy.
pszDup = PszDupA(pData->pszText);
// Put it on the clipboard
OpenClipboard(m_hwndErrors);
EmptyClipboard();
SetClipboardData(CF_TEXT, pszDup);
CloseClipboard();
}
LeaveCriticalSection(&m_cs);
}
if (hMenu)
DestroyMenu(hMenu);
}
HRESULT CSpoolerDlg::QuerySwitchIdentities()
{
DWORD_PTR dwResult;
if (!IsWindowEnabled(m_hwnd))
return E_PROCESS_CANCELLED_SWITCH;
if (m_pBindCtx)
{
dwResult = m_pBindCtx->QueryEndSession(0, ENDSESSION_LOGOFF);
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, dwResult);
if (dwResult != TRUE)
return E_PROCESS_CANCELLED_SWITCH;
}
return S_OK;
}
HRESULT CSpoolerDlg::SwitchIdentities()
{
return S_OK;
}
HRESULT CSpoolerDlg::IdentityInformationChanged(DWORD dwType)
{
return S_OK;
}
LRESULT CALLBACK CSpoolerDlg::ListSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_KEYDOWN && wParam == 'C')
{
if (0 > GetAsyncKeyState(VK_CONTROL))
{
int iSel = (int) SendMessage(hwnd, LB_GETCURSEL, 0, 0);
if (LB_ERR != iSel)
{
LBDATA *pData = NULL;
LPTSTR pszDup;
// Set the height of the item
if (NULL != (pData = (LBDATA *) ListBox_GetItemData(hwnd, iSel)))
{
// Dupe the string. Clipboard owns the copy.
pszDup = PszDupA(pData->pszText);
// Put it on the clipboard
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_TEXT, pszDup);
CloseClipboard();
}
}
}
}
WNDPROC wp = (WNDPROC) GetProp(hwnd, c_szWndProc);
return (CallWindowProc(wp, hwnd, uMsg, wParam, lParam));
}