///////////////////////////////////////////////////////////////////////////// // 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: // 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: // 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: // eid - Event ID for this new event // 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: // eid - The event ID of the event that had the error. // 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: // eid - ID of the event to update // nImage - Image to display for the item. If this is -1, // the image is not changed. // pszDescription - Description for the item. If this is NULL, the // description is not changed. // 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: // 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: // 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: // 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: // 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: // 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: // nAnimationID - New resource id for the animation // 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: // 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: // 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: // 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: // 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: // 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: // hwnd - Handle of the dialog window. // hwndFocus - Handle of the control that will start with the focus. // 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: // hwnd - Handle of the dialog window // 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: // 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: // 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: // fEvents - TRUE to display the events list // fErrors - TRUE to display the error list // 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)); }