Leaked source code of windows server 2003
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.

1929 lines
54 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: spoolui.cpp
  5. //
  6. // PURPOSE: Implements the spooler UI dialogs.
  7. //
  8. #include "pch.hxx"
  9. #include "resource.h"
  10. #include "spoolui.h"
  11. #include "goptions.h"
  12. #include "imnact.h"
  13. #include "thormsgs.h"
  14. #include "shlwapip.h"
  15. #include "spengine.h"
  16. #include "ourguid.h"
  17. #include "demand.h"
  18. #include "menures.h"
  19. #include "multiusr.h"
  20. ASSERTDATA
  21. static const char c_szWndProc[] = "WndProc";
  22. //
  23. // FUNCTION: CSpoolerDlg::CSpoolerDlg()
  24. //
  25. // PURPOSE: Initializes the member variables of the spooler ui object.
  26. //
  27. CSpoolerDlg::CSpoolerDlg()
  28. {
  29. m_cRef = 1;
  30. m_pBindCtx = NULL;
  31. m_hwnd = NULL;
  32. m_hwndOwner = NULL;
  33. m_hwndEvents = NULL;
  34. m_hwndErrors = NULL;
  35. InitializeCriticalSection(&m_cs);
  36. m_himlImages = NULL;
  37. m_fTack = FALSE;
  38. m_iTab = 0;
  39. m_fIdle = FALSE;
  40. m_fErrors = FALSE;
  41. m_fShutdown = FALSE;
  42. m_fSaveSize = FALSE;
  43. m_fExpanded = TRUE;
  44. ZeroMemory(&m_rcDlg, sizeof(RECT));
  45. m_cyCollapsed = 0;
  46. m_szCount[0] = '\0';
  47. m_hIcon=NULL;
  48. m_hIconSm=NULL;
  49. m_dwIdentCookie = 0;
  50. }
  51. //
  52. // FUNCTION: CSpoolerDlg::~CSpoolerDlg()
  53. //
  54. // PURPOSE: Frees any resources allocated during the life of the class.
  55. //
  56. CSpoolerDlg::~CSpoolerDlg()
  57. {
  58. GoIdle(TRUE, FALSE, FALSE);
  59. if (m_hwnd && IsWindow(m_hwnd))
  60. DestroyWindow(m_hwnd);
  61. if (m_himlImages)
  62. ImageList_Destroy(m_himlImages);
  63. SafeRelease(m_pBindCtx);
  64. DeleteCriticalSection(&m_cs);
  65. if (m_hIcon)
  66. SideAssert(DestroyIcon(m_hIcon));
  67. if (m_hIconSm)
  68. SideAssert(DestroyIcon(m_hIconSm));
  69. }
  70. //
  71. // FUNCTION: CSpoolerDlg::Init()
  72. //
  73. // PURPOSE: Creates the spooler dialog. The dialog is not initially
  74. // visible.
  75. //
  76. // PARAMETERS:
  77. // <in> hwndOwner - Handle of the window to parent the dialog to.
  78. //
  79. // RETURN VALUE:
  80. // S_OK - The dialog was created and initialized
  81. // E_OUTOFMEMORY - The dialog could not be created
  82. // E_INVALIDARG - Think about it.
  83. //
  84. HRESULT CSpoolerDlg::Init(HWND hwndOwner)
  85. {
  86. int iReturn = -1;
  87. HWND hwnd, hwndActive;
  88. // Verify the arguments
  89. if (!IsWindow(hwndOwner))
  90. return (E_INVALIDARG);
  91. // Make a copy
  92. m_hwndOwner = hwndOwner;
  93. // Invoke the dialog
  94. hwndActive = GetForegroundWindow();
  95. hwnd = CreateDialogParam(g_hLocRes, MAKEINTRESOURCE(iddSpoolerDlg), m_hwndOwner,
  96. SpoolerDlgProc, (LPARAM) this);
  97. if (hwndActive != GetForegroundWindow())
  98. SetForegroundWindow(hwndActive);
  99. // Set the dialog icon
  100. m_hIcon = (HICON) LoadImage(g_hLocRes, MAKEINTRESOURCE(idiMail), IMAGE_ICON, 32, 32, 0);
  101. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)m_hIcon);
  102. m_hIconSm = (HICON) LoadImage(g_hLocRes, MAKEINTRESOURCE(idiMail), IMAGE_ICON, 16, 16, 0);
  103. SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hIconSm);
  104. SetTaskCounts(0, 0);
  105. // Register with identity manager
  106. SideAssert(SUCCEEDED(MU_RegisterIdentityNotifier((IUnknown *)(ISpoolerUI *)this, &m_dwIdentCookie)));
  107. return (IsWindow(hwnd) ? S_OK : E_OUTOFMEMORY);
  108. }
  109. HRESULT CSpoolerDlg::QueryInterface(REFIID riid, LPVOID *ppvObj)
  110. {
  111. if (NULL == *ppvObj)
  112. return (E_INVALIDARG);
  113. *ppvObj = NULL;
  114. if (IsEqualIID(riid, IID_IUnknown))
  115. *ppvObj = (LPVOID)(IUnknown *)(ISpoolerUI *) this;
  116. else if (IsEqualIID(riid, IID_ISpoolerUI))
  117. *ppvObj = (LPVOID)(ISpoolerUI *) this;
  118. else if (IsEqualIID(riid, IID_IIdentityChangeNotify))
  119. *ppvObj = (LPVOID)(IIdentityChangeNotify *) this;
  120. if (NULL == *ppvObj)
  121. return (E_NOINTERFACE);
  122. AddRef();
  123. return (S_OK);
  124. }
  125. ULONG CSpoolerDlg::AddRef(void)
  126. {
  127. m_cRef++;
  128. return (m_cRef);
  129. }
  130. ULONG CSpoolerDlg::Release(void)
  131. {
  132. ULONG cRefT = --m_cRef;
  133. if (0 == m_cRef)
  134. delete this;
  135. return (cRefT);
  136. }
  137. //
  138. // FUNCTION: CSpoolerDlg::RegisterBindContext()
  139. //
  140. // PURPOSE: Allows the spooler engine to provide us with a bind context
  141. // interface for us to call back into.
  142. //
  143. // PARAMETERS:
  144. // <in> pBindCtx - Pointer to the engine's bind context interface
  145. //
  146. // RETURN VALUE:
  147. // E_INVALIDARG
  148. // S_OK
  149. //
  150. HRESULT CSpoolerDlg::RegisterBindContext(ISpoolerBindContext *pBindCtx)
  151. {
  152. if (NULL == pBindCtx)
  153. return (E_INVALIDARG);
  154. EnterCriticalSection(&m_cs);
  155. m_pBindCtx = pBindCtx;
  156. m_pBindCtx->AddRef();
  157. LeaveCriticalSection(&m_cs);
  158. return (S_OK);
  159. }
  160. //
  161. // FUNCTION: CSpoolerDlg::InsertEvent()
  162. //
  163. // PURPOSE: Allows a caller to insert an event into our event list UI.
  164. //
  165. // PARAMETERS:
  166. // <in> eid - Event ID for this new event
  167. // <in> pszDescription - Description of the event
  168. //
  169. // RETURN VALUE:
  170. // E_INVALIDARG
  171. // SP_E_UNINITIALIZED
  172. // E_OUTOFMEMORY
  173. //
  174. HRESULT CSpoolerDlg::InsertEvent(EVENTID eid, LPCTSTR pszDescription,
  175. LPCWSTR pwszConnection)
  176. {
  177. HRESULT hr=S_OK;
  178. LV_ITEM lvi;
  179. int iItem = -1;
  180. TCHAR szRes[CCHMAX_STRINGRES];
  181. // Verify the arguments
  182. if (0 == pszDescription)
  183. return (E_INVALIDARG);
  184. EnterCriticalSection(&m_cs);
  185. // Make sure the listview has been initialized
  186. if (!IsWindow(m_hwndEvents))
  187. hr = SP_E_UNINITIALIZED;
  188. else
  189. {
  190. // Insert the item into the listview
  191. ZeroMemory(&lvi, sizeof(LV_ITEM));
  192. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  193. lvi.iItem = ListView_GetItemCount(m_hwndEvents);
  194. lvi.iSubItem = 0;
  195. lvi.lParam = (LPARAM) eid;
  196. lvi.iImage = IMAGE_BLANK;
  197. if (IS_INTRESOURCE(pszDescription))
  198. {
  199. AthLoadString(PtrToUlong(pszDescription), szRes, ARRAYSIZE(szRes));
  200. lvi.pszText = szRes;
  201. }
  202. else
  203. lvi.pszText = (LPTSTR) pszDescription;
  204. iItem = ListView_InsertItem(m_hwndEvents, &lvi);
  205. Assert(iItem != -1);
  206. if (iItem == -1)
  207. hr = E_OUTOFMEMORY;
  208. else
  209. {
  210. LVITEMW lviw = {0};
  211. lviw.iSubItem = 2;
  212. lviw.pszText = (LPWSTR)pwszConnection;
  213. SendMessage(m_hwndEvents, LVM_SETITEMTEXTW, (WPARAM)iItem, (LPARAM)&lviw);
  214. }
  215. }
  216. LeaveCriticalSection(&m_cs);
  217. return hr;
  218. }
  219. //
  220. // FUNCTION: CSpoolerDlg::InsertError()
  221. //
  222. // PURPOSE: Allows a task to insert an error into our error list UI.
  223. //
  224. // PARAMETERS:
  225. // <in> eid - The event ID of the event that had the error.
  226. // <in> pszError - Description of the error.
  227. //
  228. // RETURN VALUE:
  229. // E_INVALIDARG
  230. // SP_E_UNINITIALIZED
  231. // E_OUTOFMEMORY
  232. //
  233. HRESULT CSpoolerDlg::InsertError(EVENTID eid, LPCTSTR pszError)
  234. {
  235. HRESULT hr = S_OK;
  236. LBDATA *pData = NULL;
  237. int nItem;
  238. HDC hdc;
  239. HFONT hfont;
  240. // Verify the arguments
  241. if (0 == pszError)
  242. return (E_INVALIDARG);
  243. EnterCriticalSection(&m_cs);
  244. // Make sure the listview has been initialized
  245. if (!IsWindow(m_hwndErrors))
  246. hr = SP_E_UNINITIALIZED;
  247. else
  248. {
  249. // Allocate a struct for the item data
  250. if (!MemAlloc((LPVOID *) &pData, sizeof(LBDATA)))
  251. {
  252. hr = E_OUTOFMEMORY;
  253. goto exit;
  254. }
  255. pData->eid = eid;
  256. // Check to see if we need to load the string ourselves
  257. if (IS_INTRESOURCE(pszError))
  258. {
  259. pData->pszText = AthLoadString(PtrToUlong(pszError), 0, 0);
  260. }
  261. else
  262. pData->pszText = PszDupA(pszError);
  263. // Get the size of the string
  264. hfont = (HFONT) SendMessage(m_hwnd, WM_GETFONT, 0, 0);
  265. hdc = GetDC(m_hwndErrors);
  266. SelectFont(hdc, hfont);
  267. SetRect(&(pData->rcText), 0, 0, m_cxErrors - BULLET_WIDTH - 4, 0);
  268. // bug #47453, add DT_INTERNAL flag so that on FE platform (PRC and TC)
  269. // two list items is not overlapping.
  270. DrawText(hdc, pData->pszText, -1, &(pData->rcText), DT_CALCRECT | DT_WORDBREAK | DT_INTERNAL);
  271. ReleaseDC(m_hwndErrors, hdc);
  272. pData->rcText.bottom += 4;
  273. // Add the item data
  274. nItem = ListBox_AddItemData(m_hwndErrors, pData);
  275. }
  276. exit:
  277. LeaveCriticalSection(&m_cs);
  278. return hr;
  279. }
  280. //
  281. // FUNCTION: CSpoolerDlg::UpdateEventState()
  282. //
  283. // PURPOSE: Allows a task to update the description and state of an event.
  284. //
  285. // PARAMETERS:
  286. // <in> eid - ID of the event to update
  287. // <in> nImage - Image to display for the item. If this is -1,
  288. // the image is not changed.
  289. // <in> pszDescription - Description for the item. If this is NULL, the
  290. // description is not changed.
  291. // <in> pszStatus - Status of the item. If this is NULL, the status
  292. // is not changed.
  293. //
  294. // RETURN VALUE:
  295. // E_INVALIDARG
  296. // SP_E_UNINITIALIZED
  297. // SP_E_EVENTNOTFOUND
  298. // E_UNEXPECTED
  299. //
  300. HRESULT CSpoolerDlg::UpdateEventState(EVENTID eid, INT nImage,
  301. LPCTSTR pszDescription, LPCTSTR pszStatus)
  302. {
  303. LV_ITEM lvi;
  304. LV_FINDINFO lvfi;
  305. int iItem = -1;
  306. BOOL fSuccess = FALSE;
  307. HRESULT hr = S_OK;
  308. TCHAR szRes[CCHMAX_STRINGRES];
  309. EnterCriticalSection(&m_cs);
  310. ZeroMemory(&lvi, sizeof(LV_ITEM));
  311. // See if we're initialized
  312. if (!IsWindow(m_hwndEvents))
  313. {
  314. hr = SP_E_UNINITIALIZED;
  315. goto exit;
  316. }
  317. // Start by finding the event in our list
  318. lvfi.flags = LVFI_PARAM;
  319. lvfi.psz = 0;
  320. lvfi.lParam = eid;
  321. iItem = ListView_FindItem(m_hwndEvents, -1, &lvfi);
  322. if (-1 == iItem)
  323. {
  324. hr = SP_E_EVENTNOTFOUND;
  325. goto exit;
  326. }
  327. // Update the image and description
  328. lvi.mask = 0;
  329. lvi.iItem = iItem;
  330. lvi.iSubItem = 0;
  331. // Set up the image info
  332. if (-1 != nImage)
  333. {
  334. lvi.mask = LVIF_IMAGE;
  335. lvi.iImage = nImage;
  336. }
  337. // Set up the description text
  338. if (NULL != pszDescription)
  339. {
  340. // Check to see if we need to load the string ourselves
  341. if (IS_INTRESOURCE(pszDescription))
  342. {
  343. AthLoadString(PtrToUlong(pszDescription), szRes, ARRAYSIZE(szRes));
  344. lvi.pszText = szRes;
  345. }
  346. else
  347. lvi.pszText = (LPTSTR) pszDescription;
  348. lvi.mask |= LVIF_TEXT;
  349. }
  350. if (lvi.mask)
  351. fSuccess = ListView_SetItem(m_hwndEvents, &lvi);
  352. // Update the status
  353. if (NULL != pszStatus)
  354. {
  355. // Check to see if we need to load the string ourselves
  356. if (IS_INTRESOURCE(pszStatus))
  357. {
  358. AthLoadString(PtrToUlong(pszStatus), szRes, ARRAYSIZE(szRes));
  359. lvi.pszText = szRes;
  360. }
  361. else
  362. lvi.pszText = (LPTSTR) pszStatus;
  363. lvi.mask = LVIF_TEXT;
  364. lvi.iSubItem = 1;
  365. ListView_SetItemText(m_hwndEvents, lvi.iItem, 1, lvi.pszText); /* fSuccess = fSuccess && */
  366. }
  367. hr = fSuccess ? S_OK : E_UNEXPECTED;
  368. exit:
  369. LeaveCriticalSection(&m_cs);
  370. return (hr);
  371. }
  372. //
  373. // FUNCTION: CSpoolerDlg::SetProgressRange()
  374. //
  375. // PURPOSE: Resets the progress bar to zero, and then sets the upper bound
  376. // to the specified amount.
  377. //
  378. // PARAMETERS:
  379. // <in> wMax - New maximum range for the progress bar
  380. //
  381. // RETURN VALUE:
  382. // E_INVALIDARG
  383. // SP_E_UNINITIALIZED
  384. // S_OK
  385. //
  386. HRESULT CSpoolerDlg::SetProgressRange(WORD wMax)
  387. {
  388. HWND hwndProg = GetDlgItem(m_hwnd, IDC_SP_PROGRESS_BAR);
  389. HRESULT hr = S_OK;
  390. if (wMax == 0)
  391. return (E_INVALIDARG);
  392. EnterCriticalSection(&m_cs);
  393. // Make sure we have a progress bar
  394. if (!IsWindow(hwndProg))
  395. hr = SP_E_UNINITIALIZED;
  396. else
  397. {
  398. // Reset the progress bar
  399. SendMessage(hwndProg, PBM_SETPOS, 0, 0);
  400. // Set the new range
  401. SendMessage(hwndProg, PBM_SETRANGE, 0, MAKELPARAM(0, wMax));
  402. }
  403. LeaveCriticalSection(&m_cs);
  404. return (hr);
  405. }
  406. //
  407. // FUNCTION: CSpoolerDlg::IncrementProgress()
  408. //
  409. // PURPOSE: Increments the progress bar by a specified amount.
  410. //
  411. // PARAMETERS:
  412. // <in> wDelta - Amount to increment the progress bar by
  413. //
  414. // RETURN VALUE:
  415. // E_INVALIDARG
  416. // SP_E_UNINITIALIZED
  417. // S_OK
  418. //
  419. HRESULT CSpoolerDlg::IncrementProgress(WORD wDelta)
  420. {
  421. HRESULT hr = S_OK;
  422. EnterCriticalSection(&m_cs);
  423. if (!IsWindow(m_hwnd))
  424. hr = SP_E_UNINITIALIZED;
  425. else
  426. SendDlgItemMessage(m_hwnd, IDC_SP_PROGRESS_BAR, PBM_DELTAPOS, wDelta, 0);
  427. LeaveCriticalSection(&m_cs);
  428. return (hr);
  429. }
  430. //
  431. // FUNCTION: CSpoolerDlg::SetProgressPosition()
  432. //
  433. // PURPOSE: Sets the progress bar to a specific position.
  434. //
  435. // PARAMETERS:
  436. // <in> wPos - Position to set progress bar to
  437. //
  438. // RETURN VALUE:
  439. // E_INVALIDARG
  440. // SP_E_UNINITIALIZED
  441. // S_OK
  442. //
  443. HRESULT CSpoolerDlg::SetProgressPosition(WORD wPos)
  444. {
  445. HRESULT hr = S_OK;
  446. EnterCriticalSection(&m_cs);
  447. if (wPos < 0)
  448. hr = E_INVALIDARG;
  449. else if (!IsWindow(m_hwnd))
  450. hr = SP_E_UNINITIALIZED;
  451. else
  452. SendDlgItemMessage(m_hwnd, IDC_SP_PROGRESS_BAR, PBM_SETPOS, wPos, 0);
  453. LeaveCriticalSection(&m_cs);
  454. return (hr);
  455. }
  456. //
  457. // FUNCTION: CSpoolerDlg::SetGeneralProgress()
  458. //
  459. // PURPOSE: Allows the caller to update the general progress text.
  460. //
  461. // PARAMETERS:
  462. // <in> pszProgress - New progress string
  463. //
  464. // RETURN VALUE:
  465. // SP_E_UNINITIALIZED
  466. // S_OK
  467. //
  468. HRESULT CSpoolerDlg::SetGeneralProgress(LPCTSTR pszProgress)
  469. {
  470. HRESULT hr = S_OK;
  471. EnterCriticalSection(&m_cs);
  472. if (!IsWindow(m_hwnd))
  473. hr = SP_E_UNINITIALIZED;
  474. else
  475. {
  476. if (pszProgress)
  477. SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, pszProgress);
  478. else
  479. SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, _T(""));
  480. }
  481. LeaveCriticalSection(&m_cs);
  482. return (hr);
  483. }
  484. //
  485. // FUNCTION: CSpoolerDlg::SetSpecificProgress()
  486. //
  487. // PURPOSE: Allows the caller to update the specific progress text.
  488. //
  489. // PARAMETERS:
  490. // <in> pszProgress - New progress string
  491. //
  492. // RETURN VALUE:
  493. // SP_E_UNINITIALIZED
  494. // S_OK
  495. //
  496. HRESULT CSpoolerDlg::SetSpecificProgress(LPCTSTR pszProgress)
  497. {
  498. HRESULT hr = S_OK;
  499. EnterCriticalSection(&m_cs);
  500. if (!IsWindow(m_hwnd))
  501. hr = SP_E_UNINITIALIZED;
  502. else
  503. {
  504. TCHAR szRes[CCHMAX_STRINGRES];
  505. if (IS_INTRESOURCE(pszProgress))
  506. {
  507. AthLoadString(PtrToUlong(pszProgress), szRes, ARRAYSIZE(szRes));
  508. pszProgress = szRes;
  509. }
  510. if (pszProgress)
  511. SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, pszProgress);
  512. else
  513. SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, _T(""));
  514. }
  515. LeaveCriticalSection(&m_cs);
  516. return (hr);
  517. }
  518. //
  519. // FUNCTION: CSpoolerDlg::SetAnimation()
  520. //
  521. // PURPOSE: Allows the caller to choose which animation is playing
  522. //
  523. // PARAMETERS:
  524. // <in> nAnimationID - New resource id for the animation
  525. // <in> fPlay - TRUE if we should start animating it.
  526. //
  527. // RETURN VALUE:
  528. // SP_E_UNINITIALIZED
  529. // S_OK
  530. //
  531. HRESULT CSpoolerDlg::SetAnimation(int nAnimationID, BOOL fPlay)
  532. {
  533. HRESULT hr = S_OK;
  534. HWND hwndAni;
  535. EnterCriticalSection(&m_cs);
  536. #ifndef _WIN64
  537. if (!IsWindow(m_hwnd) || !IsWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE)))
  538. hr = SP_E_UNINITIALIZED;
  539. else
  540. {
  541. hwndAni = GetDlgItem(m_hwnd, IDC_SP_ANIMATE);
  542. Animate_Close(hwndAni);
  543. if (IsWindow(m_hwnd) && IsWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE)))
  544. {
  545. Animate_OpenEx(hwndAni, g_hLocRes, MAKEINTRESOURCE(nAnimationID));
  546. if (fPlay)
  547. Animate_Play(hwndAni, 0, -1, -1);
  548. }
  549. }
  550. #endif // _WIN64
  551. LeaveCriticalSection(&m_cs);
  552. return (hr);
  553. }
  554. //
  555. // FUNCTION: CSpoolerDlg::EnsureVisible()
  556. //
  557. // PURPOSE: Ensures that the specified event is visible within the listview
  558. //
  559. // PARAMETERS:
  560. // <in> eid - Event ID to make sure is visible
  561. //
  562. // RETURN VALUE:
  563. // SP_E_UNINITIALIZED
  564. // SP_E_EVENTNOTFOUND
  565. // S_OK
  566. //
  567. HRESULT CSpoolerDlg::EnsureVisible(EVENTID eid)
  568. {
  569. LV_FINDINFO lvfi;
  570. int iItem = -1;
  571. HRESULT hr = S_OK;
  572. EnterCriticalSection(&m_cs);
  573. // See if we're initialized
  574. if (!IsWindow(m_hwndEvents))
  575. hr = SP_E_UNINITIALIZED;
  576. else
  577. {
  578. // Start by finding the event in our list
  579. lvfi.flags = LVFI_PARAM;
  580. lvfi.psz = 0;
  581. lvfi.lParam = eid;
  582. iItem = ListView_FindItem(m_hwndEvents, -1, &lvfi);
  583. // Now tell the listview to make sure it's visible
  584. if (-1 != iItem)
  585. ListView_EnsureVisible(m_hwndEvents, iItem, FALSE);
  586. hr = (iItem == -1) ? SP_E_EVENTNOTFOUND : S_OK;
  587. }
  588. LeaveCriticalSection(&m_cs);
  589. return (hr);
  590. }
  591. //
  592. // FUNCTION: CSpoolerDlg::ShowWindow()
  593. //
  594. // PURPOSE: Shows or hides the spooler dialog
  595. //
  596. // PARAMETERS:
  597. // <in> nCmdShow - This is the same as the ShowWindow() API
  598. //
  599. // RETURN VALUE:
  600. // SP_E_UNINITIALIZED
  601. // S_OK
  602. //
  603. HRESULT CSpoolerDlg::ShowWindow(int nCmdShow)
  604. {
  605. HRESULT hr = S_OK;
  606. EnterCriticalSection(&m_cs);
  607. if (!IsWindow(m_hwnd))
  608. hr = SP_E_UNINITIALIZED;
  609. else
  610. {
  611. ::ShowWindow(m_hwnd, nCmdShow);
  612. if (m_pBindCtx)
  613. m_pBindCtx->OnUIChange(nCmdShow == SW_SHOW);
  614. }
  615. LeaveCriticalSection(&m_cs);
  616. return (hr);
  617. }
  618. //
  619. // FUNCTION: CSpoolerDlg::StartDelivery()
  620. //
  621. // PURPOSE: Tells the dialog the delivery has begun.
  622. //
  623. // RETURN VALUE:
  624. // S_OK
  625. // SP_E_UNINITIALIZED
  626. //
  627. HRESULT CSpoolerDlg::StartDelivery(void)
  628. {
  629. HRESULT hr = SP_E_UNINITIALIZED;
  630. EnterCriticalSection(&m_cs);
  631. if (IsWindow(m_hwnd))
  632. {
  633. //Animate_Play(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), 0, -1, -1);
  634. TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_TASKS);
  635. OnTabChange(0);
  636. ToggleStatics(FALSE);
  637. SetDlgItemText(m_hwnd, IDC_SP_GENERAL_PROG, _T(""));
  638. SetDlgItemText(m_hwnd, IDC_SP_SPECIFIC_PROG, _T(""));
  639. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
  640. hr = S_OK;
  641. }
  642. LeaveCriticalSection(&m_cs);
  643. return (hr);
  644. }
  645. //
  646. // FUNCTION: CSpoolerDlg::ClearEvents()
  647. //
  648. // PURPOSE: Clears any events and errors out of the listviews.
  649. //
  650. // RETURN VALUE:
  651. // S_OK
  652. // SP_E_UNINITIALIZED
  653. //
  654. HRESULT CSpoolerDlg::ClearEvents(void)
  655. {
  656. HRESULT hr = SP_E_UNINITIALIZED;
  657. EnterCriticalSection(&m_cs);
  658. if (IsWindow(m_hwnd))
  659. {
  660. m_fErrors = FALSE;
  661. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
  662. ListView_DeleteAllItems(m_hwndEvents);
  663. ListBox_ResetContent(m_hwndErrors);
  664. hr = S_OK;
  665. }
  666. LeaveCriticalSection(&m_cs);
  667. return (hr);
  668. }
  669. HRESULT CSpoolerDlg::SetTaskCounts(DWORD cSucceeded, DWORD cTotal)
  670. {
  671. TCHAR szBuf[CCHMAX_STRINGRES];
  672. HRESULT hr = SP_E_UNINITIALIZED;
  673. EnterCriticalSection(&m_cs);
  674. if (IsWindow(m_hwnd))
  675. {
  676. wnsprintf(szBuf, ARRAYSIZE(szBuf), m_szCount, cSucceeded, cTotal);
  677. SetDlgItemText(m_hwnd, IDC_SP_OVERALL_STATUS, szBuf);
  678. hr = S_OK;
  679. }
  680. LeaveCriticalSection(&m_cs);
  681. return (hr);
  682. }
  683. HRESULT CSpoolerDlg::AreThereErrors(void)
  684. {
  685. EnterCriticalSection(&m_cs);
  686. HRESULT hr = (m_fErrors ? S_OK : S_FALSE);
  687. LeaveCriticalSection(&m_cs);
  688. return hr;
  689. }
  690. HRESULT CSpoolerDlg::Shutdown(void)
  691. {
  692. CHAR szRes[255];
  693. EnterCriticalSection(&m_cs);
  694. m_fShutdown = TRUE;
  695. if (IsWindow(m_hwnd))
  696. {
  697. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
  698. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_MINIMIZE), TRUE);
  699. LoadString(g_hLocRes, idsClose, szRes, ARRAYSIZE(szRes));
  700. SetDlgItemText(m_hwnd, IDC_SP_MINIMIZE, szRes);
  701. }
  702. LeaveCriticalSection(&m_cs);
  703. return S_OK;
  704. }
  705. //
  706. // FUNCTION: CSpoolerDlg::GoIdle()
  707. //
  708. // PURPOSE: Tells the dialog the delivery has ended.
  709. //
  710. // PARAMETERS:
  711. // <in> fErrors - TRUE if errors occured during the download.
  712. //
  713. // RETURN VALUE:
  714. // S_OK
  715. // SP_E_UNINITIALIZED
  716. //
  717. HRESULT CSpoolerDlg::GoIdle(BOOL fErrors, BOOL fShutdown, BOOL fNoSync)
  718. {
  719. HRESULT hr = SP_E_UNINITIALIZED;
  720. TCHAR szRes[CCHMAX_STRINGRES];
  721. EnterCriticalSection(&m_cs);
  722. if (IsWindow(m_hwnd))
  723. {
  724. // Stop the animation
  725. #ifndef _WIN64
  726. Animate_Close(GetDlgItem(m_hwnd, IDC_SP_ANIMATE));
  727. #endif
  728. hr = S_OK;
  729. ToggleStatics(TRUE);
  730. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_STOP), FALSE);
  731. if (ISFLAGSET(fErrors, SPSTATE_CANCEL))
  732. {
  733. m_fErrors = TRUE;
  734. ExpandCollapse(TRUE);
  735. TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_TASKS);
  736. OnTabChange(0);
  737. AthLoadString(idsSpoolerUserCancel, szRes, ARRAYSIZE(szRes));
  738. SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
  739. SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
  740. (WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiError)), 0);
  741. }
  742. // Also if there were errors, we should switch to the error page
  743. else if (fErrors)
  744. {
  745. m_fErrors = TRUE;
  746. ExpandCollapse(TRUE);
  747. TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), TAB_ERRORS);
  748. OnTabChange(0);
  749. AthLoadString(idsSpoolerIdleErrors, szRes, ARRAYSIZE(szRes));
  750. SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
  751. SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
  752. (WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiError)), 0);
  753. }
  754. else
  755. {
  756. AthLoadString(idsSpoolerIdle, szRes, ARRAYSIZE(szRes));
  757. SetDlgItemText(m_hwnd, IDC_SP_IDLETEXT, szRes);
  758. SendDlgItemMessage(m_hwnd, IDC_SP_IDLEICON, STM_SETICON,
  759. (WPARAM) LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiMailNews)), 0);
  760. if (fNoSync)
  761. AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsNothingToSync), NULL, MB_OK | MB_ICONEXCLAMATION);
  762. // Determine if we need to hide the dialog
  763. UINT state = (UINT) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE, IDC_SP_TACK, 0);
  764. if (!(state & TBSTATE_CHECKED))
  765. ShowWindow(SW_HIDE);
  766. }
  767. }
  768. LeaveCriticalSection(&m_cs);
  769. return (hr);
  770. }
  771. //
  772. // FUNCTION: CSpoolerDlg::IsDialogMessage()
  773. //
  774. // PURPOSE: Allows the dialog to retrieve messages from the message loop.
  775. //
  776. // PARAMETERS:
  777. // <in> pMsg - Pointer to the message for us to examine.
  778. //
  779. // RETURN VALUE:
  780. // Returns S_OK if we eat the message, S_FALSE otherwise.
  781. //
  782. HRESULT CSpoolerDlg::IsDialogMessage(LPMSG pMsg)
  783. {
  784. HRESULT hr;
  785. BOOL fEaten = FALSE;
  786. BOOL fBack = FALSE;
  787. EnterCriticalSection(&m_cs);
  788. // Intended for modeless timeout dialog running on this thread?
  789. HWND hwndTimeout = (HWND)TlsGetValue(g_dwTlsTimeout);
  790. if (hwndTimeout && ::IsDialogMessage(hwndTimeout, pMsg))
  791. return(S_OK);
  792. if (pMsg->message == WM_KEYDOWN && (GetAsyncKeyState(VK_CONTROL) < 0))
  793. {
  794. switch (pMsg->wParam)
  795. {
  796. case VK_TAB:
  797. fBack = GetAsyncKeyState(VK_SHIFT) < 0;
  798. break;
  799. case VK_PRIOR: // VK_PAGE_UP
  800. case VK_NEXT: // VK_PAGE_DOWN
  801. fBack = (pMsg->wParam == VK_PRIOR);
  802. break;
  803. default:
  804. goto NoKeys;
  805. }
  806. int iCur = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS));
  807. // tab in reverse if shift is down
  808. if (fBack)
  809. iCur += (TAB_MAX - 1);
  810. else
  811. iCur++;
  812. iCur %= TAB_MAX;
  813. TabCtrl_SetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS), iCur);
  814. OnTabChange(NULL);
  815. }
  816. NoKeys:
  817. if (IsWindow(m_hwnd) && IsWindowVisible(m_hwnd))
  818. fEaten = ::IsDialogMessage(m_hwnd, pMsg);
  819. LeaveCriticalSection(&m_cs);
  820. return (fEaten ? S_OK : S_FALSE);
  821. }
  822. //
  823. // FUNCTION: CSpoolerDlg::GetWindow()
  824. //
  825. // PURPOSE: Returns the handle to the spooler dialog window.
  826. //
  827. // PARAMETERS:
  828. // <out> pHwnd - Where we return the handle.
  829. //
  830. // RETURN VALUE:
  831. // E_INVALIDARG
  832. // SP_E_UNINITIALIZED
  833. // S_OK
  834. //
  835. HRESULT CSpoolerDlg::GetWindow(HWND *pHwnd)
  836. {
  837. HRESULT hr=S_OK;
  838. if (NULL == pHwnd)
  839. return E_INVALIDARG;
  840. EnterCriticalSection(&m_cs);
  841. if (!IsWindow(m_hwnd))
  842. hr = SP_E_UNINITIALIZED;
  843. else
  844. *pHwnd = m_hwnd;
  845. LeaveCriticalSection(&m_cs);
  846. return (S_OK);
  847. }
  848. HRESULT CSpoolerDlg::Close(void)
  849. {
  850. HRESULT hr = S_OK;
  851. EnterCriticalSection(&m_cs);
  852. if (!IsWindow(m_hwnd))
  853. hr = SP_E_UNINITIALIZED;
  854. else
  855. DestroyWindow(m_hwnd);
  856. // Unregister with Identity manager
  857. if (m_dwIdentCookie != 0)
  858. {
  859. MU_UnregisterIdentityNotifier(m_dwIdentCookie);
  860. m_dwIdentCookie = 0;
  861. }
  862. LeaveCriticalSection(&m_cs);
  863. return (hr);
  864. }
  865. HRESULT CSpoolerDlg::ChangeHangupOption(BOOL fEnable, DWORD dwOption)
  866. {
  867. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), fEnable ? SW_SHOW : SW_HIDE);
  868. ::EnableWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), fEnable);
  869. SendDlgItemMessage(m_hwnd, IDC_SP_HANGUP, BM_SETCHECK, dwOption, 0);
  870. return (S_OK);
  871. }
  872. //
  873. // FUNCTION: CSpoolerDlg::PostDlgProc()
  874. //
  875. // PURPOSE: Dialog callback for the spooler dialog proc.
  876. //
  877. INT_PTR CALLBACK CSpoolerDlg::SpoolerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  878. LPARAM lParam)
  879. {
  880. CSpoolerDlg *pThis = (CSpoolerDlg *) GetWindowLongPtr(hwnd, DWLP_USER);
  881. LRESULT lResult;
  882. // Pass to spooler bind context
  883. if (pThis && pThis->m_pBindCtx && pThis->m_pBindCtx->OnWindowMessage(hwnd, uMsg, wParam, lParam) == S_OK)
  884. return (TRUE);
  885. switch (uMsg)
  886. {
  887. case WM_INITDIALOG:
  888. // Stash the this pointer so we can use it later
  889. Assert(lParam);
  890. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  891. pThis = (CSpoolerDlg *) lParam;
  892. return (BOOL) HANDLE_WM_INITDIALOG(hwnd, wParam, lParam,
  893. pThis->OnInitDialog);
  894. case WM_COMMAND:
  895. if (pThis)
  896. HANDLE_WM_COMMAND(hwnd, wParam, lParam, pThis->OnCommand);
  897. return (TRUE);
  898. case WM_NOTIFY:
  899. if (pThis)
  900. {
  901. lResult = HANDLE_WM_NOTIFY(hwnd, wParam, lParam, pThis->OnNotify);
  902. SetDlgMsgResult(hwnd, WM_NOTIFY, lResult);
  903. }
  904. return (TRUE);
  905. case WM_DRAWITEM:
  906. if (pThis)
  907. HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, pThis->OnDrawItem);
  908. return (TRUE);
  909. case WM_MEASUREITEM:
  910. if (pThis)
  911. HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, pThis->OnMeasureItem);
  912. return (TRUE);
  913. case WM_DELETEITEM:
  914. if (pThis)
  915. HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, pThis->OnDeleteItem);
  916. return (TRUE);
  917. #if 0
  918. case WM_SYSCOLORCHANGE:
  919. case WM_SETTINGCHANGE:
  920. if (pThis)
  921. HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, pThis->OnSysColorChange);
  922. return (TRUE);
  923. #endif
  924. case WM_CLOSE:
  925. if (pThis)
  926. HANDLE_WM_CLOSE(hwnd, wParam, lParam, pThis->OnClose);
  927. return (TRUE);
  928. case WM_DESTROY:
  929. if (pThis)
  930. HANDLE_WM_DESTROY(hwnd, wParam, lParam, pThis->OnDestroy);
  931. return (TRUE);
  932. case IMAIL_SHOWWINDOW:
  933. ::ShowWindow(hwnd, (int) lParam);
  934. if (pThis)
  935. pThis->ToggleStatics(lParam == SW_HIDE);
  936. return (TRUE);
  937. case WM_QUERYENDSESSION:
  938. if (pThis && pThis->m_pBindCtx)
  939. {
  940. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, pThis->m_pBindCtx->QueryEndSession(wParam, lParam));
  941. return (TRUE);
  942. }
  943. break;
  944. case WM_CONTEXTMENU:
  945. if (pThis)
  946. {
  947. HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, pThis->OnContextMenu);
  948. return (TRUE);
  949. }
  950. break;
  951. }
  952. return (FALSE);
  953. }
  954. //
  955. // FUNCTION: CSpoolerDlg::OnInitDialog()
  956. //
  957. // PURPOSE: Initializes the dialog.
  958. //
  959. // PARAMETERS:
  960. // <in> hwnd - Handle of the dialog window.
  961. // <in> hwndFocus - Handle of the control that will start with the focus.
  962. // <in> lParam - Extra data being passed to the dialog.
  963. //
  964. // RETURN VALUE:
  965. // Return TRUE to set the focus to hwndFocus
  966. //
  967. BOOL CSpoolerDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  968. {
  969. m_hwnd = hwnd;
  970. // Bug #38692 - Set the font correctly for Intl charsets
  971. SetIntlFont(hwnd);
  972. SetIntlFont(GetDlgItem(hwnd, IDC_SP_GENERAL_PROG));
  973. SetIntlFont(GetDlgItem(hwnd, IDC_SP_SPECIFIC_PROG));
  974. SetIntlFont(GetDlgItem(hwnd, IDC_SP_EVENTS));
  975. SetIntlFont(GetDlgItem(hwnd, IDC_SP_ERRORS));
  976. SetIntlFont(GetDlgItem(hwnd, IDC_SP_IDLETEXT));
  977. // Initialize the controls on the dialog
  978. InitializeTabs();
  979. InitializeLists();
  980. InitializeAnimation();
  981. InitializeToolbar();
  982. ToggleStatics(TRUE);
  983. // Hide the Hangup when done deal.
  984. // ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_HANGUP), SW_HIDE);
  985. // Set the hangup when done option
  986. Button_SetCheck(GetDlgItem(m_hwnd, IDC_SP_HANGUP), DwGetOption(OPT_DIALUP_HANGUP_DONE));
  987. // Get some information from the dialog template we'll need later
  988. GetDlgItemText(m_hwnd, IDC_SP_OVERALL_STATUS, m_szCount, ARRAYSIZE(m_szCount));
  989. // Initialize the rectangles that we'll need for sizing later
  990. RECT rcSep;
  991. GetWindowRect(GetDlgItem(hwnd, IDC_SP_SEPARATOR), &rcSep);
  992. GetWindowRect(hwnd, &m_rcDlg);
  993. m_cyCollapsed = rcSep.top - m_rcDlg.top;
  994. // Load the window size from the registry
  995. WINDOWPLACEMENT wp;
  996. wp.length = sizeof(WINDOWPLACEMENT);
  997. if (GetOption(OPT_SPOOLERDLGPOS, (LPVOID*) &wp, sizeof(WINDOWPLACEMENT)))
  998. {
  999. wp.showCmd = SW_HIDE;
  1000. SetWindowPlacement(hwnd, &wp);
  1001. ExpandCollapse(m_cyCollapsed < (DWORD) ((wp.rcNormalPosition.bottom - wp.rcNormalPosition.top)), FALSE);
  1002. }
  1003. else
  1004. {
  1005. // Center the dialog on the screen.
  1006. CenterDialog(hwnd);
  1007. ExpandCollapse(FALSE, FALSE);
  1008. }
  1009. // Set the state of the thumbtack
  1010. DWORD dwTack;
  1011. if (DwGetOption(OPT_SPOOLERTACK))
  1012. {
  1013. SendDlgItemMessage(hwnd, IDC_SP_TOOLBAR, TB_SETSTATE, IDC_SP_TACK,
  1014. MAKELONG(TBSTATE_CHECKED | TBSTATE_ENABLED, 0));
  1015. SendMessage(hwnd, WM_COMMAND, IDC_SP_TACK, 0);
  1016. }
  1017. // Disable the stop button
  1018. EnableWindow(GetDlgItem(hwnd, IDC_SP_STOP), FALSE);
  1019. // Subclass the list box
  1020. HWND hwnderr = GetDlgItem(hwnd, IDC_SP_ERRORS);
  1021. WNDPROC proc = (WNDPROC) GetWindowLongPtr(hwnderr, GWLP_WNDPROC);
  1022. SetProp(hwnderr, c_szWndProc, proc);
  1023. SetWindowLongPtr(hwnderr, GWLP_WNDPROC, (LPARAM) ListSubClassProc);
  1024. // BUG: 44376. ATOK11 has a hidden window. If we return TRUE user will do a setfocus on US, at this point the browser
  1025. // thread is block waiting for the spooler to complete and when ATOK gets a WM_ACTIVATE they interthreadsendmsg on our blocked
  1026. // browser window with inf. timeout. So we hang at startup. Don't set focus in here at startup time.
  1027. return (FALSE);
  1028. }
  1029. //
  1030. // FUNCTION: CSpoolerDlg::OnCommand()
  1031. //
  1032. // PURPOSE: Handle the various command messages dispatched from the dialog
  1033. //
  1034. void CSpoolerDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1035. {
  1036. switch (id)
  1037. {
  1038. case IDCANCEL:
  1039. case IDC_SP_MINIMIZE:
  1040. if (m_fShutdown)
  1041. {
  1042. Assert(m_pBindCtx);
  1043. EnableWindow(GetDlgItem(hwnd, IDC_SP_MINIMIZE), FALSE);
  1044. m_pBindCtx->UIShutdown();
  1045. }
  1046. else
  1047. ShowWindow(SW_HIDE);
  1048. break;
  1049. case IDC_SP_STOP:
  1050. if (m_pBindCtx)
  1051. {
  1052. m_pBindCtx->Cancel();
  1053. if (GetFocus() == GetDlgItem(hwnd, IDC_SP_STOP))
  1054. SetFocus(GetDlgItem(hwnd, IDC_SP_MINIMIZE));
  1055. EnableWindow(GetDlgItem(hwnd, IDC_SP_STOP), FALSE);
  1056. }
  1057. break;
  1058. case IDC_SP_TACK:
  1059. {
  1060. UINT state = (UINT) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE,
  1061. IDC_SP_TACK, 0);
  1062. SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_CHANGEBITMAP,
  1063. IDC_SP_TACK,
  1064. MAKELPARAM(state & TBSTATE_CHECKED ? IMAGE_TACK_IN : IMAGE_TACK_OUT, 0));
  1065. }
  1066. break;
  1067. case IDC_SP_DETAILS:
  1068. m_fSaveSize = TRUE;
  1069. ExpandCollapse(!m_fExpanded);
  1070. break;
  1071. case IDC_SP_HANGUP:
  1072. SetDwOption(OPT_DIALUP_HANGUP_DONE, BST_CHECKED == Button_GetCheck(hwndCtl), NULL, 0);
  1073. break;
  1074. }
  1075. }
  1076. //
  1077. // FUNCTION: CSpoolerDlg::OnNotify
  1078. //
  1079. // PURPOSE: Handles notifications from the common controls on the dialog.
  1080. //
  1081. LRESULT CSpoolerDlg::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
  1082. {
  1083. switch (pnmhdr->code)
  1084. {
  1085. case TCN_SELCHANGE:
  1086. OnTabChange(pnmhdr);
  1087. return (0);
  1088. }
  1089. return (0);
  1090. }
  1091. //
  1092. // FUNCTION: CSpoolerDlg::OnDrawItem()
  1093. //
  1094. // PURPOSE: Draws the link buttons
  1095. //
  1096. // PARAMETERS:
  1097. // <in> hwnd - Handle of the dialog window
  1098. // <in> lpDrawItem - Pointer to a DRAWITEMSTRUCT with the info needed to
  1099. // draw the button.
  1100. //
  1101. void CSpoolerDlg::OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem)
  1102. {
  1103. HDC hdc = lpDrawItem->hDC;
  1104. COLORREF clrText, clrBack;
  1105. RECT rcText, rcFocus;
  1106. SIZE size;
  1107. BOOL fSelected = (lpDrawItem->itemState & ODS_SELECTED) &&
  1108. (GetFocus() == lpDrawItem->hwndItem);
  1109. Assert(lpDrawItem->CtlType == ODT_LISTBOX);
  1110. if (lpDrawItem->itemID == -1)
  1111. goto exit;
  1112. // Draw the bullet first
  1113. ImageList_Draw(m_himlImages,
  1114. IMAGE_BULLET,
  1115. hdc,
  1116. BULLET_INDENT,
  1117. lpDrawItem->rcItem.top,
  1118. fSelected ? ILD_SELECTED | ILD_TRANSPARENT : ILD_TRANSPARENT);
  1119. // Set up the text rectangle
  1120. rcText = lpDrawItem->rcItem;
  1121. rcText.left += BULLET_WIDTH;
  1122. // Set up the text and background colors
  1123. clrBack = SetBkColor(hdc, GetSysColor(fSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW));
  1124. clrText = SetTextColor(hdc, GetSysColor(fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
  1125. // Draw the text
  1126. FillRect(hdc, &rcText, (HBRUSH)IntToPtr((fSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW) + 1));
  1127. InflateRect(&rcText, -2, -2);
  1128. DrawText(hdc, ((LBDATA *) lpDrawItem->itemData)->pszText, -1, &rcText, DT_NOCLIP | DT_WORDBREAK);
  1129. // If we need a focus rect, do that too
  1130. if (lpDrawItem->itemState & ODS_FOCUS)
  1131. {
  1132. rcFocus = lpDrawItem->rcItem;
  1133. rcFocus.left += BULLET_WIDTH;
  1134. // InflateRect(&rcFocus, -2, -2);
  1135. DrawFocusRect(hdc, &rcFocus);
  1136. }
  1137. SetBkColor(hdc, clrBack);
  1138. SetTextColor(hdc, clrText);
  1139. exit:
  1140. return;
  1141. }
  1142. void CSpoolerDlg::OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *pMeasureItem)
  1143. {
  1144. LBDATA *pData = NULL;
  1145. EnterCriticalSection(&m_cs);
  1146. // Set the height of the item
  1147. if (NULL != (pData = (LBDATA *) ListBox_GetItemData(m_hwndErrors, pMeasureItem->itemID)))
  1148. {
  1149. pMeasureItem->itemHeight = pData->rcText.bottom;
  1150. }
  1151. LeaveCriticalSection(&m_cs);
  1152. }
  1153. void CSpoolerDlg::OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT * lpDeleteItem)
  1154. {
  1155. EnterCriticalSection(&m_cs);
  1156. if (lpDeleteItem->itemData)
  1157. {
  1158. SafeMemFree(((LBDATA *)lpDeleteItem->itemData)->pszText);
  1159. MemFree((LPVOID) lpDeleteItem->itemData);
  1160. }
  1161. LeaveCriticalSection(&m_cs);
  1162. }
  1163. //
  1164. // FUNCTION: CSpoolerDlg::OnClose()
  1165. //
  1166. // PURPOSE: Handles the WM_CLOSE notification by sending an IDCANCEL to
  1167. // the dialog.
  1168. //
  1169. void CSpoolerDlg::OnClose(HWND hwnd)
  1170. {
  1171. SendMessage(hwnd, WM_COMMAND, IDC_SP_MINIMIZE, 0);
  1172. }
  1173. //
  1174. // FUNCTION: CSpoolerDlg::OnDestroy()
  1175. //
  1176. // PURPOSE: Handles the WM_DESTROY notification by freeing the memory stored
  1177. // in the listview items.
  1178. //
  1179. void CSpoolerDlg::OnDestroy(HWND hwnd)
  1180. {
  1181. #ifndef _WIN64
  1182. Animate_Close(GetDlgItem(m_hwnd, IDC_SP_ANIMATE));
  1183. #endif
  1184. // Save the window placement
  1185. WINDOWPLACEMENT wp;
  1186. wp.length = sizeof(WINDOWPLACEMENT);
  1187. if (GetWindowPlacement(hwnd, &wp))
  1188. {
  1189. if (!m_fSaveSize)
  1190. {
  1191. // Load the old size out of the registry
  1192. WINDOWPLACEMENT wp2;
  1193. if (GetOption(OPT_SPOOLERDLGPOS, (LPVOID*) &wp2, sizeof(WINDOWPLACEMENT)))
  1194. {
  1195. wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + (wp2.rcNormalPosition.bottom - wp2.rcNormalPosition.top);
  1196. }
  1197. else
  1198. {
  1199. wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + m_cyCollapsed;
  1200. }
  1201. }
  1202. SetOption(OPT_SPOOLERDLGPOS, (LPVOID) &wp, sizeof(WINDOWPLACEMENT), NULL, 0);
  1203. }
  1204. DWORD dwState;
  1205. dwState = (DWORD) SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETSTATE, IDC_SP_TACK, 0);
  1206. SetDwOption(OPT_SPOOLERTACK, !!(dwState & TBSTATE_CHECKED), NULL, 0);
  1207. HIMAGELIST himl;
  1208. himl = (HIMAGELIST)SendDlgItemMessage(m_hwnd, IDC_SP_TOOLBAR, TB_GETIMAGELIST, 0, 0);
  1209. if (himl)
  1210. ImageList_Destroy(himl);
  1211. HWND hwnderr = GetDlgItem(hwnd, IDC_SP_ERRORS);
  1212. WNDPROC proc = (WNDPROC)GetProp(hwnderr, c_szWndProc);
  1213. if (proc != NULL)
  1214. {
  1215. SetWindowLongPtr(hwnderr, GWLP_WNDPROC, (LPARAM)proc);
  1216. RemoveProp(hwnderr, c_szWndProc);
  1217. }
  1218. }
  1219. //
  1220. // FUNCTION: CSpoolerDlg::InitializeTabs()
  1221. //
  1222. // PURPOSE: Initializes the tab control on the dialog.
  1223. //
  1224. // RETURN VALUE:
  1225. // TRUE if everything succeeded, FALSE otherwise.
  1226. //
  1227. BOOL CSpoolerDlg::InitializeTabs(void)
  1228. {
  1229. HWND hwndTabs = GetDlgItem(m_hwnd, IDC_SP_TABS);
  1230. TC_ITEM tci;
  1231. TCHAR szRes[CCHMAX_STRINGRES];
  1232. // "Tasks"
  1233. tci.mask = TCIF_TEXT;
  1234. tci.pszText = AthLoadString(idsTasks, szRes, ARRAYSIZE(szRes));
  1235. TabCtrl_InsertItem(hwndTabs, 0, &tci);
  1236. // "Errors"
  1237. tci.pszText = AthLoadString(idsErrors, szRes, ARRAYSIZE(szRes));
  1238. TabCtrl_InsertItem(hwndTabs, 1, &tci);
  1239. return (TRUE);
  1240. }
  1241. //
  1242. // FUNCTION: CSpoolerDlg::InitializeLists()
  1243. //
  1244. // PURPOSE: Initializes the list control on the dialog.
  1245. //
  1246. // RETURN VALUE:
  1247. // TRUE if everything succeeded, FALSE otherwise.
  1248. //
  1249. BOOL CSpoolerDlg::InitializeLists(void)
  1250. {
  1251. LV_COLUMN lvc;
  1252. TCHAR szRes[CCHMAX_STRINGRES];
  1253. RECT rcClient;
  1254. DWORD cx;
  1255. // Store the handle for the events list since we use it frequently
  1256. m_hwndEvents = GetDlgItem(m_hwnd, IDC_SP_EVENTS);
  1257. // Get the size of the client rect of the listview
  1258. GetClientRect(m_hwndEvents, &rcClient);
  1259. // "Tasks" column
  1260. lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  1261. lvc.fmt = LVCFMT_CENTER;
  1262. lvc.cx = rcClient.right / 2;
  1263. lvc.pszText = AthLoadString(idsTasks, szRes, ARRAYSIZE(szRes));
  1264. lvc.iSubItem = 0;
  1265. ListView_InsertColumn(m_hwndEvents, 0, &lvc);
  1266. // "Status" column
  1267. cx = (rcClient.right / 2 - GetSystemMetrics(SM_CXVSCROLL)) / 2;
  1268. lvc.cx = cx;
  1269. lvc.pszText = AthLoadString(idsStatusCol, szRes, ARRAYSIZE(szRes));
  1270. lvc.iSubItem = 1;
  1271. ListView_InsertColumn(m_hwndEvents, 1, &lvc);
  1272. // "Connection" column
  1273. lvc.cx = cx;
  1274. lvc.pszText = AthLoadString(idsConnection, szRes, ARRAYSIZE(szRes));
  1275. lvc.iSubItem = 2;
  1276. ListView_InsertColumn(m_hwndEvents, 2, &lvc);
  1277. // Set the listview image list
  1278. m_himlImages = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbSpooler), 16, 0,
  1279. RGB(255, 0, 255));
  1280. if (m_himlImages)
  1281. ListView_SetImageList(m_hwndEvents, m_himlImages, LVSIL_SMALL);
  1282. // The listview looks better if we use full row select
  1283. ListView_SetExtendedListViewStyle(m_hwndEvents, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
  1284. // Initialize the Error list
  1285. m_hwndErrors = GetDlgItem(m_hwnd, IDC_SP_ERRORS);
  1286. ::ShowWindow(m_hwndErrors, FALSE);
  1287. EnableWindow(m_hwndErrors, FALSE);
  1288. // Save the width of the error list
  1289. GetClientRect(m_hwndErrors, &rcClient);
  1290. m_cxErrors = rcClient.right;
  1291. return (TRUE);
  1292. }
  1293. //
  1294. // FUNCTION: CSpoolerDlg::InitializeAnimation()
  1295. //
  1296. // PURPOSE: Initializes the animation controls on the dialog.
  1297. //
  1298. // RETURN VALUE:
  1299. // TRUE if everything succeeded, FALSE otherwise.
  1300. //
  1301. BOOL CSpoolerDlg::InitializeAnimation(void)
  1302. {
  1303. #ifndef _WIN64
  1304. HWND hwndAni = GetDlgItem(m_hwnd, IDC_SP_ANIMATE);
  1305. Animate_OpenEx(hwndAni, g_hLocRes, MAKEINTRESOURCE(idanOutbox));
  1306. #endif
  1307. return (0);
  1308. }
  1309. //
  1310. // FUNCTION: CSpoolerDlg::InitializeToolbar()
  1311. //
  1312. // PURPOSE: What dialog would be complete without a toolbar, eh?
  1313. //
  1314. // RETURN VALUE:
  1315. // TRUE if everything succeeded, FALSE otherwise.
  1316. //
  1317. BOOL CSpoolerDlg::InitializeToolbar(void)
  1318. {
  1319. HWND hwndTool;
  1320. RECT rcTabs;
  1321. POINT point;
  1322. HIMAGELIST himlImages = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbSpooler), 16, 0,
  1323. RGB(255, 0, 255));
  1324. GetWindowRect(GetDlgItem(m_hwnd, IDC_SP_TABS), &rcTabs);
  1325. point.x = rcTabs.right - 22;
  1326. point.y = rcTabs.bottom + 3;
  1327. ScreenToClient(m_hwnd, &point);
  1328. hwndTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  1329. CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN |
  1330. WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | TBSTYLE_FLAT,
  1331. point.x, point.y, 22, 22,
  1332. m_hwnd, (HMENU) IDC_SP_TOOLBAR,
  1333. g_hInst, 0);
  1334. if (hwndTool)
  1335. {
  1336. #ifndef WIN16
  1337. TBBUTTON tb = { IMAGE_TACK_OUT, IDC_SP_TACK, TBSTATE_ENABLED, TBSTYLE_CHECK, {0, 0}, 0, 0 };
  1338. #else
  1339. TBBUTTON tb = { IMAGE_TACK_OUT, IDC_SP_TACK, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0 };
  1340. #endif
  1341. SendMessage(hwndTool, TB_SETIMAGELIST, 0, (LPARAM) himlImages);
  1342. SendMessage(hwndTool, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  1343. SendMessage(hwndTool, TB_SETBUTTONSIZE, 0, MAKELONG(14, 14));
  1344. SendMessage(hwndTool, TB_SETBITMAPSIZE, 0, MAKELONG(14, 14));
  1345. SendMessage(hwndTool, TB_ADDBUTTONS, 1, (LPARAM) &tb);
  1346. }
  1347. return (0);
  1348. }
  1349. //
  1350. // FUNCTION: CSpoolerDlg::ExpandCollapse()
  1351. //
  1352. // PURPOSE: Takes care of showing and hiding the "details" part of the
  1353. // error dialog.
  1354. //
  1355. // PARAMETERS:
  1356. // <in> fExpand - TRUE if we should be expanding the dialog.
  1357. //
  1358. void CSpoolerDlg::ExpandCollapse(BOOL fExpand, BOOL fSetFocus)
  1359. {
  1360. RECT rcSep;
  1361. TCHAR szBuf[64];
  1362. m_fExpanded = fExpand;
  1363. GetWindowRect(GetDlgItem(m_hwnd, IDC_SP_SEPARATOR), &rcSep);
  1364. if (!m_fExpanded)
  1365. SetWindowPos(m_hwnd, 0, 0, 0, m_rcDlg.right - m_rcDlg.left,
  1366. m_cyCollapsed, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1367. else
  1368. SetWindowPos(m_hwnd, 0, 0, 0, m_rcDlg.right - m_rcDlg.left,
  1369. m_rcDlg.bottom - m_rcDlg.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1370. // Make sure the entire dialog is visible on the screen. If not,
  1371. // then push it up
  1372. RECT rc;
  1373. RECT rcWorkArea;
  1374. GetWindowRect(m_hwnd, &rc);
  1375. SystemParametersInfo(SPI_GETWORKAREA, 0, (LPVOID) &rcWorkArea, 0);
  1376. if (rc.bottom > rcWorkArea.bottom)
  1377. {
  1378. rc.top = max(0, (int) rc.top - (rc.bottom - rcWorkArea.bottom));
  1379. SetWindowPos(m_hwnd, 0, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1380. }
  1381. AthLoadString(m_fExpanded ? idsHideDetails : idsShowDetails, szBuf,
  1382. ARRAYSIZE(szBuf));
  1383. SetDlgItemText(m_hwnd, IDC_SP_DETAILS, szBuf);
  1384. if (fExpand)
  1385. {
  1386. switch (m_iTab)
  1387. {
  1388. case TAB_TASKS:
  1389. UpdateLists(TRUE, FALSE, FALSE);
  1390. break;
  1391. case TAB_ERRORS:
  1392. UpdateLists(FALSE, TRUE, FALSE);
  1393. break;
  1394. }
  1395. }
  1396. else
  1397. UpdateLists(FALSE, FALSE, FALSE);
  1398. // Raid-34387: Spooler: Closing details with ALT-D while focus is on a task disables keyboard input
  1399. if (!fExpand && fSetFocus)
  1400. SetFocus(GetDlgItem(m_hwnd, IDC_SP_DETAILS));
  1401. }
  1402. //
  1403. // FUNCTION: CSpoolerDlg::OnTabChange()
  1404. //
  1405. // PURPOSE: Gets called in response to the user changing which tab is
  1406. // the selected tab. In response, we update which listview
  1407. // is currently visible.
  1408. //
  1409. // PARAMETERS:
  1410. // <in> pnmhdr - Pointer to the notification information
  1411. //
  1412. void CSpoolerDlg::OnTabChange(LPNMHDR pnmhdr)
  1413. {
  1414. HWND hwndDisable1, hwndDisable2 = 0, hwndEnable;
  1415. // Find out which tab is currently active
  1416. m_iTab = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, IDC_SP_TABS));
  1417. if (-1 == m_iTab)
  1418. return;
  1419. // Update which listview is visible
  1420. switch (m_iTab)
  1421. {
  1422. case TAB_TASKS:
  1423. // Hide the error listview, show the tasks list
  1424. UpdateLists(TRUE, FALSE, FALSE);
  1425. break;
  1426. case TAB_ERRORS:
  1427. // Hide the error listview, show the tasks list
  1428. UpdateLists(FALSE, TRUE, FALSE);
  1429. break;
  1430. }
  1431. }
  1432. //
  1433. // FUNCTION: CSpoolerDlg::UpdateLists()
  1434. //
  1435. // PURPOSE: Does the work of hiding and showing the lists when the
  1436. // tab selection changes.
  1437. //
  1438. // PARAMETERS:
  1439. // <in> fEvents - TRUE to display the events list
  1440. // <in> fErrors - TRUE to display the error list
  1441. // <in> fHistory - TRUE to display the history list
  1442. //
  1443. void CSpoolerDlg::UpdateLists(BOOL fEvents, BOOL fErrors, BOOL fHistory)
  1444. {
  1445. if (IsWindow(m_hwndEvents))
  1446. {
  1447. EnableWindow(m_hwndEvents, fEvents);
  1448. ::ShowWindow(m_hwndEvents, fEvents ? SW_SHOWNA : SW_HIDE);
  1449. }
  1450. if (IsWindow(m_hwndErrors))
  1451. {
  1452. EnableWindow(m_hwndErrors, fErrors);
  1453. ::ShowWindow(m_hwndErrors, fErrors ? SW_SHOWNA : SW_HIDE);
  1454. }
  1455. }
  1456. void CSpoolerDlg::ToggleStatics(BOOL fIdle)
  1457. {
  1458. m_fIdle = fIdle;
  1459. if (fIdle)
  1460. {
  1461. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), FALSE);
  1462. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), FALSE);
  1463. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), FALSE);
  1464. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), TRUE);
  1465. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), TRUE);
  1466. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), SW_HIDE);
  1467. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), SW_HIDE);
  1468. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), SW_HIDE);
  1469. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), SW_SHOWNA);
  1470. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), SW_SHOWNA);
  1471. }
  1472. else
  1473. {
  1474. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), TRUE);
  1475. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), TRUE);
  1476. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), TRUE);
  1477. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), FALSE);
  1478. EnableWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), FALSE);
  1479. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_GENERAL_PROG), SW_SHOWNA);
  1480. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_SPECIFIC_PROG), SW_SHOWNA);
  1481. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_ANIMATE), SW_SHOWNA);
  1482. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLETEXT), SW_HIDE);
  1483. ::ShowWindow(GetDlgItem(m_hwnd, IDC_SP_IDLEICON), SW_HIDE);
  1484. }
  1485. }
  1486. void CSpoolerDlg::OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
  1487. {
  1488. POINT pt = {xPos, yPos};
  1489. RECT rcError;
  1490. LBDATA *pData = NULL;
  1491. // Check to see if the error window is visible
  1492. if (!IsWindowVisible(m_hwndErrors))
  1493. return;
  1494. // Check to see if the click was within the error window
  1495. GetWindowRect(m_hwndErrors, &rcError);
  1496. if (!PtInRect(&rcError, pt))
  1497. return;
  1498. // Do the context menu
  1499. HMENU hMenu = CreatePopupMenu();
  1500. // Add a "Copy..." item
  1501. TCHAR szRes[CCHMAX_STRINGRES];
  1502. AthLoadString(idsCopyTT, szRes, ARRAYSIZE(szRes));
  1503. // Add it to the menu
  1504. InsertMenu(hMenu, -1, MF_BYPOSITION | MF_STRING, ID_COPY, szRes);
  1505. // If the click is on an item in the listbox, then enable the command
  1506. ScreenToClient(m_hwndErrors, &pt);
  1507. DWORD iItem = (DWORD) SendMessage(m_hwndErrors, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));
  1508. if (iItem != -1)
  1509. {
  1510. EnterCriticalSection(&m_cs);
  1511. pData = (LBDATA *) ListBox_GetItemData(m_hwndErrors, iItem);
  1512. LeaveCriticalSection(&m_cs);
  1513. }
  1514. if (iItem == -1 || NULL == pData || ((LBDATA*)-1) == pData)
  1515. EnableMenuItem(hMenu, ID_COPY, MF_BYCOMMAND | MF_GRAYED);
  1516. // Show the menu
  1517. DWORD id;
  1518. id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY,
  1519. xPos, yPos, m_hwndErrors, NULL);
  1520. if (id == ID_COPY)
  1521. {
  1522. // Get the item data for the item they clicked on
  1523. LPTSTR pszDup;
  1524. EnterCriticalSection(&m_cs);
  1525. // Set the height of the item
  1526. if (NULL != pData && ((LBDATA*)-1) != pData)
  1527. {
  1528. // Dupe the string. Clipboard owns the copy.
  1529. pszDup = PszDupA(pData->pszText);
  1530. // Put it on the clipboard
  1531. OpenClipboard(m_hwndErrors);
  1532. EmptyClipboard();
  1533. SetClipboardData(CF_TEXT, pszDup);
  1534. CloseClipboard();
  1535. }
  1536. LeaveCriticalSection(&m_cs);
  1537. }
  1538. if (hMenu)
  1539. DestroyMenu(hMenu);
  1540. }
  1541. HRESULT CSpoolerDlg::QuerySwitchIdentities()
  1542. {
  1543. DWORD_PTR dwResult;
  1544. if (!IsWindowEnabled(m_hwnd))
  1545. return E_PROCESS_CANCELLED_SWITCH;
  1546. if (m_pBindCtx)
  1547. {
  1548. dwResult = m_pBindCtx->QueryEndSession(0, ENDSESSION_LOGOFF);
  1549. SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, dwResult);
  1550. if (dwResult != TRUE)
  1551. return E_PROCESS_CANCELLED_SWITCH;
  1552. }
  1553. return S_OK;
  1554. }
  1555. HRESULT CSpoolerDlg::SwitchIdentities()
  1556. {
  1557. return S_OK;
  1558. }
  1559. HRESULT CSpoolerDlg::IdentityInformationChanged(DWORD dwType)
  1560. {
  1561. return S_OK;
  1562. }
  1563. LRESULT CALLBACK CSpoolerDlg::ListSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1564. {
  1565. if (uMsg == WM_KEYDOWN && wParam == 'C')
  1566. {
  1567. if (0 > GetAsyncKeyState(VK_CONTROL))
  1568. {
  1569. int iSel = (int) SendMessage(hwnd, LB_GETCURSEL, 0, 0);
  1570. if (LB_ERR != iSel)
  1571. {
  1572. LBDATA *pData = NULL;
  1573. LPTSTR pszDup;
  1574. // Set the height of the item
  1575. if (NULL != (pData = (LBDATA *) ListBox_GetItemData(hwnd, iSel)))
  1576. {
  1577. // Dupe the string. Clipboard owns the copy.
  1578. pszDup = PszDupA(pData->pszText);
  1579. // Put it on the clipboard
  1580. OpenClipboard(hwnd);
  1581. EmptyClipboard();
  1582. SetClipboardData(CF_TEXT, pszDup);
  1583. CloseClipboard();
  1584. }
  1585. }
  1586. }
  1587. }
  1588. WNDPROC wp = (WNDPROC) GetProp(hwnd, c_szWndProc);
  1589. return (CallWindowProc(wp, hwnd, uMsg, wParam, lParam));
  1590. }