Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2367 lines
72 KiB

  1. //=============================================================================*
  2. // COPYRIGHT� 2001 Microsoft Corporation and Executive Software International, Inc.
  3. //=============================================================================*
  4. // File: DfrgCtl.cpp
  5. //=============================================================================*
  6. //#define ESI_MULTI_ALLOWED
  7. #include "stdafx.h"
  8. #define GLOBAL_DATAHOME
  9. #ifndef SNAPIN
  10. #ifndef NOWINDOWSH
  11. #include <windows.h>
  12. #endif
  13. #endif
  14. #include <commctrl.h>
  15. #include <htmlhelp.h>
  16. #include "adminprivs.h"
  17. extern "C" {
  18. #include "SysStruc.h"
  19. }
  20. #include "DfrgCmn.h"
  21. #include "DfrgEngn.h"
  22. #include "DiskDisp.h"
  23. #include "DfrgUI.h"
  24. #include "DfrgCtl.h"
  25. #include "DataIo.h"
  26. #include "DataIoCl.h"
  27. #include "ListView.h"
  28. #include "ErrMacro.h"
  29. #include "ErrMsg.h"
  30. #include "Graphix.h"
  31. #include "DfrgRes.h"
  32. #include "EsButton.h"
  33. #include "DlgRpt.h"
  34. #include "DfrgRes.h"
  35. #include "GetDfrgRes.h"
  36. #include "IntFuncs.h"
  37. #include "VolList.h"
  38. #include "VolCom.h"
  39. #include "MIMessage.h"
  40. #include "adminprivs.h"
  41. #include <algorithm>
  42. #include "secattr.h"
  43. #define NUM_ACCELERATORS 5
  44. #ifndef SM_REMOTESESSION
  45. #define SM_REMOTESESSION 0x1000
  46. #endif
  47. #define MULTI_INSTANCE_TIMER 1000
  48. #define PING_TIMER 3000
  49. static const MI_TIMER_ID = 1;
  50. static const LISTVIEW_TIMER_ID = 2;
  51. static const PING_TIMER_ID = 3;
  52. BOOL CALLBACK TabEnumChildren( HWND hwnd, LPARAM lParam );
  53. //-------------------------------------------------------------------*
  54. // function: CDfrgCtl::
  55. //
  56. // returns: None
  57. // note:
  58. //-------------------------------------------------------------------*
  59. CDfrgCtl::CDfrgCtl() : m_VolumeList( this ), m_ListView ( this )
  60. {
  61. ATLTRACE( _T( "Creating defrag control.\n" ) );
  62. m_bStart = TRUE;
  63. m_bNeedMultiInstanceMessage = TRUE;
  64. m_bNeedIllegalVolumeMessage = FALSE;
  65. m_dwInstanceRegister = 0;
  66. m_hIsOkToRunSemaphore = NULL;
  67. // Determine if we're the first instance of the control running.
  68. m_IsOkToRun = IsOnlyInstance();
  69. if ( m_IsOkToRun )
  70. {
  71. //
  72. // Register the dataio with the system.
  73. //
  74. m_dwInstanceRegister = InitializeDataIo( CLSID_DfrgCtlDataIo, REGCLS_MULTIPLEUSE );
  75. }
  76. m_LegendHeight = 34;
  77. m_FontHeight = 0; // calculated later
  78. m_LegendTextSpacer = 0; // calculated later
  79. m_LegendTopSpace = 10;
  80. m_EtchedLineOffset = 5;
  81. #ifdef ESI_PROGRESS_BAR
  82. m_ProgressBarOffset = 7; // offset top and bottom in legend window
  83. m_ProgressBarLength = 121;
  84. #endif
  85. m_Margin = 14;
  86. m_GraphicWellHeight = 40;
  87. m_LegendGraphicSpacer = 5;
  88. m_LegendTextWidth = 0; // calculated later
  89. m_BitmapVOffset = 0; // calculated later
  90. m_ButtonTopBottomSpacer = 14;
  91. m_ButtonHeight = 26;
  92. m_ButtonWidth = 84;
  93. m_ButtonSpacer = 6;
  94. m_GraphicWellSpacer = 40;
  95. m_hFont = NULL;
  96. m_bHaveButtons = FALSE;
  97. m_pAnalyzeButton = (ESButton *) NULL;
  98. m_pDefragButton = (ESButton *) NULL;
  99. m_pPauseButton = (ESButton *) NULL;
  100. m_pStopButton = (ESButton *) NULL;
  101. m_pReportButton = (ESButton *) NULL;
  102. m_pLegend = (CBmp *) NULL;
  103. ZeroMemory(&rcLegendBG, sizeof(RECT));
  104. ZeroMemory(&rcReportButton, sizeof(RECT));
  105. // Initialize the legend.
  106. INT_PTR iBmp[20];
  107. if(SIMPLE_DISPLAY){
  108. iBmp[0] = (INT_PTR)MAKEINTRESOURCE(IDB_FRAGMENTED_FILES);
  109. iBmp[1] = (INT_PTR)MAKEINTRESOURCE(IDB_CONTIGUOUS_FILES);
  110. iBmp[2] = (INT_PTR)MAKEINTRESOURCE(IDB_SYSTEM_FILES);
  111. iBmp[3] = (INT_PTR)MAKEINTRESOURCE(IDB_FREE_SPACE);
  112. m_pLegend = new CBmp(GetDfrgResHandle(), iBmp, 4);
  113. EV_ASSERT(m_pLegend);
  114. // load the strings into all the text strings
  115. m_LegendData[0].text.LoadString(IDS_FRAGMENTED_FILES, GetDfrgResHandle());
  116. m_LegendData[1].text.LoadString(IDS_CONTIGUOUS_FILES, GetDfrgResHandle());
  117. m_LegendData[2].text.LoadString(IDS_SYSTEM_FILES, GetDfrgResHandle());
  118. m_LegendData[3].text.LoadString(IDS_FREE_SPACE, GetDfrgResHandle());
  119. }
  120. else{
  121. iBmp[0] = (INT_PTR)MAKEINTRESOURCE(IDB_SYSTEM_FILES);
  122. iBmp[1] = (INT_PTR)MAKEINTRESOURCE(IDB_RESERVED_SPACE);
  123. iBmp[2] = (INT_PTR)MAKEINTRESOURCE(IDB_PAGE_FILE);
  124. iBmp[3] = (INT_PTR)MAKEINTRESOURCE(IDB_DIRECTORY_FILES);
  125. iBmp[4] = (INT_PTR)MAKEINTRESOURCE(IDB_FRAGMENTED_FILES);
  126. iBmp[5] = (INT_PTR)MAKEINTRESOURCE(IDB_CONTIGUOUS_FILES);
  127. iBmp[6] = (INT_PTR)MAKEINTRESOURCE(IDB_FREE_SPACE);
  128. m_pLegend = new CBmp(GetDfrgResHandle(), iBmp, 7);
  129. EV_ASSERT(m_pLegend);
  130. m_LegendData[0].text.LoadString(IDS_SYSTEM_FILES, GetDfrgResHandle());
  131. m_LegendData[1].text.LoadString(IDS_RESERVED_SPACE, GetDfrgResHandle());
  132. m_LegendData[2].text.LoadString(IDS_PAGE_FILE, GetDfrgResHandle());
  133. m_LegendData[3].text.LoadString(IDS_DIRECTORY_FILES, GetDfrgResHandle());
  134. m_LegendData[3].text.LoadString(IDS_FRAGMENTED_FILES, GetDfrgResHandle());
  135. m_LegendData[3].text.LoadString(IDS_CONTIGUOUS_FILES, GetDfrgResHandle());
  136. m_LegendData[3].text.LoadString(IDS_FREE_SPACE, GetDfrgResHandle());
  137. }
  138. }
  139. //-------------------------------------------------------------------*
  140. // function: CDfrgCtl::~CDfrgCtl
  141. //
  142. // returns: None
  143. // note:
  144. //-------------------------------------------------------------------*
  145. CDfrgCtl::~CDfrgCtl()
  146. {
  147. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  148. if (pVolume) {
  149. pVolume->StoppedByUser(TRUE);
  150. }
  151. DestroyButtons();
  152. if(m_pLegend){
  153. delete m_pLegend;
  154. }
  155. ::DeleteObject(m_hFont);
  156. //
  157. // Remove our instance handler.
  158. //
  159. if ( m_dwInstanceRegister )
  160. CoRevokeClassObject( m_dwInstanceRegister );
  161. if(m_hIsOkToRunSemaphore) {
  162. if (m_IsOkToRun) {
  163. // this would increment the count, and make the semaphore seem like
  164. // is was available (signaled). Only do this if this is the running instance
  165. ReleaseSemaphore(m_hIsOkToRunSemaphore, 1, NULL);
  166. }
  167. CloseHandle(m_hIsOkToRunSemaphore);
  168. }
  169. return;
  170. }
  171. //-------------------------------------------------------------------*
  172. // function: CDfrgCtl::OnClose
  173. //
  174. // returns: None
  175. // note:
  176. //-------------------------------------------------------------------*
  177. HRESULT CDfrgCtl::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult){
  178. return S_OK;
  179. }
  180. //-------------------------------------------------------------------*
  181. // function: CDfrgCtl::InterfaceSupportsErrorInfo
  182. //
  183. // returns: None
  184. // note:
  185. //-------------------------------------------------------------------*
  186. STDMETHODIMP CDfrgCtl::InterfaceSupportsErrorInfo(REFIID riid)
  187. {
  188. static const IID* arr[] = { &IID_IDfrgCtl,};
  189. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++) {
  190. if (InlineIsEqualGUID(*arr[i],riid))
  191. return S_OK;
  192. }
  193. return S_FALSE;
  194. }
  195. //-------------------------------------------------------------------*
  196. // function: CDfrgCtl::OnNotify
  197. //
  198. // returns: None
  199. // note:
  200. //-------------------------------------------------------------------*
  201. HRESULT CDfrgCtl::OnNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  202. {
  203. m_ListView.NotifyListView(lParam);
  204. return S_OK;
  205. }
  206. //-------------------------------------------------------------------*
  207. // function: CDfrgCtl::OnCommand
  208. //
  209. // returns: None
  210. // note:
  211. //-------------------------------------------------------------------*
  212. HRESULT CDfrgCtl::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  213. {
  214. switch (LOWORD(wParam)) {
  215. case ID_ANALYZE:
  216. put_Command(ID_ANALYZE);
  217. break;
  218. case ID_DEFRAG:
  219. put_Command(ID_DEFRAG);
  220. break;
  221. case ID_PAUSE:
  222. put_Command(ID_PAUSE);
  223. break;
  224. case ID_STOP:
  225. put_Command(ID_STOP);
  226. break;
  227. case ID_REFRESH:
  228. put_Command(ID_REFRESH);
  229. break;
  230. case ID_HELP_CONTENTS:
  231. put_Command(ID_HELP_CONTENTS);
  232. break;
  233. case ID_REPORT:
  234. {
  235. // is the engine IDLE?
  236. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  237. if (pVolume){
  238. if(pVolume->EngineState() == ENGINE_STATE_IDLE){
  239. RaiseReportDialog(pVolume);
  240. ::SetFocus(m_pReportButton->GetWindowHandle());
  241. }
  242. }
  243. }
  244. break;
  245. }
  246. return S_OK;
  247. }
  248. //-------------------------------------------------------------------*
  249. // function: CDfrgCtl::OnSize
  250. //
  251. // returns: None
  252. // note:
  253. //-------------------------------------------------------------------*
  254. HRESULT CDfrgCtl::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  255. {
  256. TCHAR msg[200];
  257. _stprintf(msg, TEXT("CDfrgCtl::OnSize() lParam LO=%d, HI=%d"), LOWORD(lParam), HIWORD(lParam));
  258. Message(msg, -1, NULL);
  259. //Zero is passed in the first time this function is called. This puts incorrect data into
  260. //the rectangles below for a fraction of a second. Probably harmless, but better safe than sorry.
  261. if(!lParam) {
  262. ZeroMemory(&m_rcCtlRect, sizeof(RECT));
  263. return S_OK;
  264. }
  265. m_rcCtlRect.top = 0;
  266. m_rcCtlRect.left = 0;
  267. m_rcCtlRect.right = LOWORD(lParam);
  268. m_rcCtlRect.bottom = HIWORD(lParam);
  269. SizeWindow();
  270. return S_OK;
  271. }
  272. //-------------------------------------------------------------------*
  273. // function: CDfrgCtl::SizeWindow
  274. //
  275. // returns: None
  276. // note:
  277. //-------------------------------------------------------------------*
  278. HRESULT CDfrgCtl::SizeWindow()
  279. {
  280. TCHAR msg[200];
  281. _stprintf(msg, TEXT("CDfrgCtl::SizeWindow() m_bStart=%d"), m_bStart);
  282. Message(msg, -1, NULL);
  283. if( m_bStart) {
  284. NONCLIENTMETRICS ncm;
  285. ncm.cbSize = sizeof(ncm);
  286. ::SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof (ncm), &ncm, 0);
  287. ncm.lfMenuFont.lfWeight = FW_NORMAL;
  288. m_hFont = ::CreateFontIndirect(&ncm.lfMenuFont);
  289. m_FontHeight = -ncm.lfMenuFont.lfHeight;
  290. EH_ASSERT(m_hFont);
  291. VString windowText(IDS_DK_TITLE, GetDfrgResHandle());
  292. SetWindowText(windowText.GetBuffer());
  293. CreateButtons();
  294. // Initialize list view and graphix windows.
  295. m_ListView.InitializeListView(&m_VolumeList, m_hWndCD, _Module.GetModuleInstance());
  296. // Display the drives available in the listview.
  297. m_ListView.GetDrivesToListView();
  298. // get the first drive hilited (check command line)
  299. m_ListView.SelectInitialListViewDrive(&m_bNeedIllegalVolumeMessage);
  300. // Hide or show the listview
  301. m_ListView.EnableWindow(m_IsOkToRun);
  302. // get the buttons enabled/disables properly
  303. SetButtonState();
  304. //Set the multi-instance timer.
  305. SetTimer(MI_TIMER_ID, MULTI_INSTANCE_TIMER, NULL);
  306. //Set the list view timer.
  307. SetTimer(LISTVIEW_TIMER_ID, m_VolumeList.GetRefreshInterval(), NULL);
  308. //Set the ping timer.
  309. SetTimer(PING_TIMER_ID, PING_TIMER, NULL);
  310. m_bStart = FALSE;
  311. }
  312. // size the legend and progress bar
  313. SizeLegend();
  314. // Size the buttons
  315. SizeButtons();
  316. m_pAnalyzeButton->ShowButton(SW_SHOW);
  317. m_pDefragButton->ShowButton(SW_SHOW);
  318. m_pReportButton->ShowButton(SW_SHOW);
  319. m_pPauseButton->ShowButton(SW_SHOW);
  320. m_pStopButton->ShowButton(SW_SHOW);
  321. ::SetFocus(m_pAnalyzeButton->GetWindowHandle());
  322. // Now size the graphics window.
  323. SizeGraphicsWindow();
  324. // size the list view (he gets the screen that is left over)
  325. rcListView.bottom = rcGraphicsBG.top;
  326. rcListView.top = 0;
  327. rcListView.left = 0;
  328. rcListView.right = m_rcCtlRect.right;
  329. // Now size the listview
  330. m_ListView.SizeListView(
  331. rcListView.left,
  332. rcListView.top,
  333. rcListView.right - rcListView.left, // width
  334. rcListView.bottom - rcListView.top); // height
  335. Invalidate(FALSE);
  336. return S_OK;
  337. }
  338. //-------------------------------------------------------------------*
  339. // function: CDfrgCtl::OnEraseBkgnd
  340. //
  341. // returns: None
  342. // note:
  343. //-------------------------------------------------------------------*
  344. HRESULT CDfrgCtl::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  345. {
  346. return S_OK;
  347. }
  348. //-------------------------------------------------------------------*
  349. // function: CDfrgCtl::RefreshListViewRow
  350. //
  351. // returns: None
  352. // note:
  353. //-------------------------------------------------------------------*
  354. HRESULT CDfrgCtl::RefreshListViewRow(CVolume *pVolume)
  355. {
  356. // refresh this row of the list view
  357. m_ListView.Update(pVolume);
  358. return S_OK;
  359. }
  360. //-------------------------------------------------------------------*
  361. // function: CDfrgCtl::OnPaint
  362. //
  363. // returns: None
  364. // note:
  365. //-------------------------------------------------------------------*
  366. HRESULT CDfrgCtl::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  367. {
  368. PAINTSTRUCT paintStruct;
  369. HDC OutputDC = BeginPaint(&paintStruct);
  370. // Paint the various windows.
  371. if (OutputDC){
  372. DrawLegend(OutputDC);
  373. #ifdef ESI_PROGRESS_BAR
  374. DrawProgressBar(OutputDC);
  375. #endif
  376. PaintGraphicsWindow(OutputDC);
  377. DrawButtons(OutputDC);
  378. }
  379. EndPaint(&paintStruct);
  380. // display the multi-instance screen if needed
  381. if (!m_IsOkToRun && m_bNeedMultiInstanceMessage){
  382. m_bNeedMultiInstanceMessage = FALSE;
  383. if (CheckForAdminPrivs() == FALSE) {
  384. SetLastError(ESI_VOLLIST_ERR_NON_ADMIN);
  385. VString title(IDS_DK_TITLE, GetDfrgResHandle());
  386. VString msg(IDS_NEED_ADMIN_PRIVS, GetDfrgResHandle());
  387. MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK|MB_ICONWARNING);
  388. }
  389. else if (!RaiseMIDialog(m_hWndCD)) {
  390. ATLTRACE( _T( "MI Dialog failed\n" ) );
  391. }
  392. }
  393. // display the illegal volume dialog if needed
  394. if (m_bNeedIllegalVolumeMessage) {
  395. // don't need to do it again
  396. m_bNeedIllegalVolumeMessage = FALSE;
  397. // warn user he can't defrag illegal volume
  398. VString title(IDS_DK_TITLE, GetDfrgResHandle());
  399. VString msg(IDS_VOLUME_TYPE_NOT_SUPPORTED, GetDfrgResHandle());
  400. MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK | MB_ICONWARNING);
  401. }
  402. return S_OK;
  403. }
  404. //-------------------------------------------------------------------*
  405. // function: CDfrgCtl::OnTimer
  406. //
  407. // returns: None
  408. // note:
  409. //-------------------------------------------------------------------*
  410. HRESULT CDfrgCtl::OnTimer(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  411. {
  412. switch (wParam)
  413. {
  414. // This timer checks the multi-instance semaphore
  415. case MI_TIMER_ID:
  416. // if we are in a Terminal Server session, don't change anything
  417. // if (GetSystemMetrics(SM_REMOTESESSION)){
  418. // return S_OK;
  419. //}
  420. //
  421. // Refresh whether or not we're the only instance.
  422. //
  423. if ( m_IsOkToRun == FALSE )
  424. {
  425. m_IsOkToRun = IsOnlyInstance();
  426. if ( m_IsOkToRun == TRUE )
  427. {
  428. m_dwInstanceRegister = InitializeDataIo( CLSID_DfrgCtlDataIo, REGCLS_MULTIPLEUSE );
  429. SetButtonState();
  430. // Hide or show the listview
  431. m_ListView.EnableWindow(m_IsOkToRun);
  432. // Send OKToRun property change to advises.
  433. SendOKToRun( TRUE );
  434. Invalidate(TRUE);
  435. }
  436. }
  437. KillTimer(MI_TIMER_ID);
  438. SetTimer(MI_TIMER_ID, MULTI_INSTANCE_TIMER, NULL);
  439. break;
  440. // This timer refreshes the list view
  441. case LISTVIEW_TIMER_ID:
  442. KillTimer(LISTVIEW_TIMER_ID);
  443. m_ListView.GetDrivesToListView();
  444. SetTimer(LISTVIEW_TIMER_ID, m_VolumeList.GetRefreshInterval(), NULL);
  445. break;
  446. // This timer pings the engine
  447. case PING_TIMER_ID:
  448. {
  449. KillTimer(PING_TIMER_ID);
  450. CVolume *pVolume;
  451. for (UINT ii = 0; ii < m_VolumeList.GetVolumeCount(); ii++)
  452. {
  453. pVolume = (CVolume *) m_VolumeList.GetVolumeAt(ii);
  454. if (pVolume)
  455. {
  456. pVolume->PingEngine();
  457. }
  458. }
  459. SetTimer(PING_TIMER_ID, PING_TIMER, NULL);
  460. break;
  461. }
  462. default:
  463. EE_ASSERT(FALSE);
  464. break;
  465. }
  466. return S_OK;
  467. }
  468. //-------------------------------------------------------------------*
  469. // function: CDfrgCtl::get_EngineState
  470. //
  471. // returns: None
  472. // note:
  473. //-------------------------------------------------------------------*
  474. STDMETHODIMP CDfrgCtl::get_EngineState(short * pVal)
  475. {
  476. // sets pVal to current engine state
  477. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  478. if (pVolume) {
  479. *pVal = (short) pVolume->EngineState();
  480. }
  481. else {
  482. *pVal = 0;
  483. }
  484. return S_OK;
  485. }
  486. //-------------------------------------------------------------------*
  487. // function: CDfrgCtl::get_IsEngineRunning
  488. //
  489. // returns: None
  490. // note:
  491. //-------------------------------------------------------------------*
  492. STDMETHODIMP CDfrgCtl::get_IsEngineRunning(BOOL *pVal)
  493. {
  494. // TRUE or FALSE whether current engine is running
  495. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  496. if (pVolume) {
  497. *pVal = (pVolume->EngineState() == ENGINE_STATE_RUNNING);
  498. }
  499. else {
  500. *pVal = FALSE;
  501. }
  502. return S_OK;
  503. }
  504. //-------------------------------------------------------------------*
  505. // function: CDfrgCtl::get_IsOkToRun
  506. //
  507. // returns: None
  508. // note:
  509. //-------------------------------------------------------------------*
  510. STDMETHODIMP CDfrgCtl::get_IsOkToRun(BOOL *pVal)
  511. {
  512. *pVal = m_IsOkToRun;
  513. return S_OK;
  514. }
  515. //-------------------------------------------------------------------*
  516. // function: CDfrgCtl::get_IsEnginePaused
  517. //
  518. // returns: None
  519. // note:
  520. //-------------------------------------------------------------------*
  521. STDMETHODIMP CDfrgCtl::get_IsEnginePaused(BOOL *pVal)
  522. {
  523. // TRUE or FALSE whether current engine is paused
  524. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  525. if (pVolume) {
  526. *pVal = pVolume->Paused();
  527. }
  528. else {
  529. *pVal = FALSE;
  530. }
  531. return S_OK;
  532. }
  533. //-------------------------------------------------------------------*
  534. // function: CDfrgCtl::get_IsDefragInProcess
  535. //
  536. // returns: None
  537. // note:
  538. //-------------------------------------------------------------------*
  539. STDMETHODIMP CDfrgCtl::get_IsDefragInProcess(BOOL *pVal)
  540. {
  541. // TRUE or FALSE whether any engine is running
  542. *pVal = m_VolumeList.DefragInProcess();
  543. return S_OK;
  544. }
  545. //-------------------------------------------------------------------*
  546. // function: CDfrgCtl::get_IsVolListLocked
  547. //
  548. // returns: None
  549. // note:
  550. //-------------------------------------------------------------------*
  551. STDMETHODIMP CDfrgCtl::get_IsVolListLocked(BOOL *pVal)
  552. {
  553. // TRUE or FALSE if current volume is locked
  554. *pVal = m_VolumeList.Locked();
  555. return S_OK;
  556. }
  557. //-------------------------------------------------------------------*
  558. // function: CDfrgCtl::get_ReportStatus
  559. //
  560. // returns: None
  561. // note:
  562. //-------------------------------------------------------------------*
  563. STDMETHODIMP CDfrgCtl::get_ReportStatus(BOOL * pVal)
  564. {
  565. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  566. if (pVolume) {
  567. *pVal = pVolume->IsReportOKToDisplay();
  568. }
  569. else {
  570. *pVal = FALSE;
  571. }
  572. return S_OK;
  573. }
  574. //-------------------------------------------------------------------*
  575. // function: CDfrgCtl::get_Command
  576. //
  577. // returns: None
  578. // note:
  579. //-------------------------------------------------------------------*
  580. STDMETHODIMP CDfrgCtl::get_Command(short * pVal)
  581. {
  582. // not used so far
  583. return S_OK;
  584. }
  585. //-------------------------------------------------------------------*
  586. // function: CDfrgCtl::put_Command
  587. //
  588. // returns: None
  589. // note:
  590. //-------------------------------------------------------------------*
  591. STDMETHODIMP CDfrgCtl::put_Command(short newVal)
  592. {
  593. // get a pointer to the current volume
  594. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  595. if (pVolume == (CVolume *) NULL) {
  596. return S_OK;
  597. }
  598. switch (newVal){
  599. case ID_REFRESH:
  600. // Display the drives available in the listview.
  601. m_ListView.GetDrivesToListView();
  602. Invalidate(TRUE);
  603. break;
  604. case ID_REPORT:
  605. pVolume->ShowReport();
  606. ::SetFocus(m_pReportButton->GetWindowHandle());
  607. break;
  608. case ID_HELP_CONTENTS:
  609. HtmlHelp(
  610. m_hWndCD,
  611. TEXT("defrag.chm::/defrag_overview.htm"),
  612. HH_DISPLAY_TOPIC, //HH_TP_HELP_CONTEXTMENU,
  613. NULL); //(DWORD)(LPVOID)myarray);
  614. break;
  615. case ID_STOP:
  616. m_ListView.SetFocus(); // list box gets focus
  617. pVolume->StopEngine();
  618. break;
  619. case ID_ABORT:
  620. pVolume->AbortEngine();
  621. break;
  622. case ID_PAUSE:
  623. pVolume->PauseEngine();
  624. break;
  625. case ID_CONTINUE:
  626. if (!pVolume->ContinueEngine()){
  627. if (GetLastError() == ESI_VOLLIST_ERR_MUST_RESTART){
  628. VString msg(IDS_MUST_RESTART, GetDfrgResHandle());
  629. VString title(IDS_DK_TITLE, GetDfrgResHandle());
  630. MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK|MB_ICONWARNING);
  631. }
  632. }
  633. break;
  634. case ID_ANALYZE:
  635. m_ListView.SetFocus(); // list box gets focus
  636. m_VolumeList.Locked(TRUE);
  637. pVolume->Analyze();
  638. m_VolumeList.Locked(FALSE);
  639. break;
  640. case ID_DEFRAG:
  641. m_ListView.SetFocus(); // list box gets focus
  642. m_VolumeList.Locked(TRUE);
  643. pVolume->Defragment();
  644. m_VolumeList.Locked(FALSE);
  645. break;
  646. default:
  647. return S_OK;
  648. }
  649. SetButtonState();
  650. return S_OK;
  651. }
  652. //-------------------------------------------------------------------*
  653. // function: CDfrgCtl::CreateButtons
  654. //
  655. // returns: None
  656. // note:
  657. //-------------------------------------------------------------------*
  658. HRESULT CDfrgCtl::CreateButtons(void)
  659. {
  660. m_pAnalyzeButton = new ESButton(m_hWndCD, ID_ANALYZE, _Module.GetModuleInstance());
  661. m_pDefragButton = new ESButton(m_hWndCD, ID_DEFRAG, _Module.GetModuleInstance());
  662. m_pPauseButton = new ESButton(m_hWndCD, ID_PAUSE, _Module.GetModuleInstance());
  663. m_pStopButton = new ESButton(m_hWndCD, ID_STOP, _Module.GetModuleInstance());
  664. m_pReportButton = new ESButton(m_hWndCD, ID_REPORT, _Module.GetModuleInstance());
  665. // if any buttons fail, abort the whole thing and mark have buttons false
  666. if (m_pAnalyzeButton == NULL || m_pDefragButton == NULL || m_pPauseButton == NULL ||
  667. m_pStopButton == NULL || m_pReportButton == NULL) {
  668. Message(TEXT("CDfrgCtl::CreateButtons failed to alloc memory"), -1, NULL);
  669. m_bHaveButtons = FALSE;
  670. DestroyButtons();
  671. return E_OUTOFMEMORY;
  672. }
  673. // if all ok, set up buttons
  674. m_bHaveButtons = TRUE;
  675. m_pAnalyzeButton->SetFont(m_hFont);
  676. m_pAnalyzeButton->LoadString(GetDfrgResHandle(), IDS_BTN_ANALYZE);
  677. m_pDefragButton->SetFont(m_hFont);
  678. m_pDefragButton->LoadString(GetDfrgResHandle(), IDS_BTN_DEFRAGMENT);
  679. m_pPauseButton->SetFont(m_hFont);
  680. m_pPauseButton->LoadString(GetDfrgResHandle(), IDS_BTN_PAUSE);
  681. m_pStopButton->SetFont(m_hFont);
  682. m_pStopButton->LoadString(GetDfrgResHandle(), IDS_BTN_STOP);
  683. m_pReportButton->SetFont(m_hFont);
  684. m_pReportButton->LoadString(GetDfrgResHandle(), IDS_BTN_REPORT);
  685. SetButtonState();
  686. return S_OK;
  687. }
  688. //-------------------------------------------------------------------*
  689. // function: CDfrgCtl::DestroyButtons
  690. //
  691. // returns: None
  692. // note:
  693. //-------------------------------------------------------------------*
  694. HRESULT CDfrgCtl::DestroyButtons(void)
  695. {
  696. if (m_pAnalyzeButton) {
  697. delete m_pAnalyzeButton;
  698. }
  699. if (m_pDefragButton) {
  700. delete m_pDefragButton;
  701. }
  702. if (m_pPauseButton) {
  703. delete m_pPauseButton;
  704. }
  705. if (m_pStopButton) {
  706. delete m_pStopButton;
  707. }
  708. if (m_pReportButton) {
  709. delete m_pReportButton;
  710. }
  711. return S_OK;
  712. }
  713. //-------------------------------------------------------------------*
  714. // function: CDfrgCtl::PaintClusterMap
  715. //
  716. // returns: None
  717. // note:
  718. //-------------------------------------------------------------------*
  719. BOOL CDfrgCtl::PaintClusterMap(
  720. IN BOOL bPartialRedraw,
  721. HDC WorkDC
  722. )
  723. {
  724. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  725. if (pVolume == (CVolume *) NULL) {
  726. return FALSE;
  727. }
  728. /////////////////////////////////////////////////////////////////
  729. // Status text written in the graphics wells
  730. /////////////////////////////////////////////////////////////////
  731. // make the text white in all color schemes
  732. // SetTextColor(WorkDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  733. // SetBkMode(WorkDC, TRANSPARENT);
  734. UINT defaultId;
  735. if (pVolume->NoGraphicsMemory() ||
  736. pVolume->m_AnalyzeDisplay.NoGraphicsMemory() ||
  737. pVolume->m_DefragDisplay.NoGraphicsMemory()) {
  738. defaultId = IDS_NO_GRAPHICS_MEMORY;
  739. }
  740. else {
  741. defaultId = IDS_LABEL_RESIZING;
  742. }
  743. // get the label that appears in the graphics wells
  744. VString defragLabel;
  745. VString analyzeLabel;
  746. VString statusLabel;
  747. VString compactingLabel(IDS_COMPACTING_FILES, GetDfrgResHandle());
  748. VString movingLabel(IDS_MOVING_FILES, GetDfrgResHandle());
  749. analyzeLabel.Empty();
  750. defragLabel.Empty();
  751. statusLabel.Empty();
  752. switch (pVolume->DefragState()){
  753. case DEFRAG_STATE_ANALYZING:
  754. case DEFRAG_STATE_REANALYZING:
  755. analyzeLabel = pVolume->DisplayLabel();
  756. analyzeLabel.AddChar(L' ');
  757. analyzeLabel += pVolume->sDefragState();
  758. statusLabel = analyzeLabel;
  759. //acs bug #101862//
  760. statusLabel += _T(" ");
  761. statusLabel += pVolume->cPercentDone();
  762. statusLabel += _T("%");
  763. if (pVolume->PausedBySnapshot()) {
  764. pVolume->m_AnalyzeDisplay.SetReadyToDraw(FALSE);
  765. }
  766. break;
  767. case DEFRAG_STATE_ENGINE_DEAD:
  768. analyzeLabel = pVolume->DisplayLabel();
  769. analyzeLabel.AddChar(L' ');
  770. analyzeLabel += pVolume->sDefragState();
  771. statusLabel = analyzeLabel;
  772. break;
  773. case DEFRAG_STATE_DEFRAGMENTING:
  774. analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
  775. defragLabel = pVolume->DisplayLabel();
  776. defragLabel.AddChar(L' ');
  777. defragLabel += pVolume->sDefragState();
  778. statusLabel += defragLabel;
  779. //acs bug #101862//
  780. UINT mmpass;
  781. mmpass = pVolume->Pass();
  782. if (pVolume->PausedBySnapshot()) {
  783. pVolume->m_DefragDisplay.SetReadyToDraw(FALSE);
  784. }
  785. else {
  786. if(mmpass == 2 || mmpass == 4 || mmpass == 6)
  787. {
  788. statusLabel += _T(" ");
  789. statusLabel += pVolume->cPercentDone();
  790. statusLabel += _T("%");
  791. statusLabel += compactingLabel;
  792. } else
  793. {
  794. statusLabel += _T(" ");
  795. statusLabel += pVolume->cPercentDone();
  796. statusLabel += _T("%");
  797. statusLabel += movingLabel;
  798. statusLabel += pVolume->m_fileName;
  799. }
  800. }
  801. break;
  802. case DEFRAG_STATE_BOOT_OPTIMIZING:
  803. analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
  804. defragLabel = pVolume->DisplayLabel();
  805. defragLabel.AddChar(L' ');
  806. defragLabel += pVolume->sDefragState();
  807. statusLabel += defragLabel;
  808. if (pVolume->PausedBySnapshot()) {
  809. pVolume->m_DefragDisplay.SetReadyToDraw(FALSE);
  810. }
  811. else {
  812. statusLabel += _T(" ");
  813. statusLabel += pVolume->cPercentDone();
  814. statusLabel += _T("%");
  815. statusLabel += compactingLabel;
  816. }
  817. break;
  818. case DEFRAG_STATE_ANALYZED:
  819. analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
  820. statusLabel = pVolume->DisplayLabel();
  821. statusLabel.AddChar(L' ');
  822. statusLabel += pVolume->sDefragState();
  823. break;
  824. case DEFRAG_STATE_DEFRAGMENTED:
  825. analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
  826. defragLabel.LoadString(defaultId, GetDfrgResHandle());
  827. statusLabel = pVolume->DisplayLabel();
  828. statusLabel.AddChar(L' ');
  829. statusLabel += pVolume->sDefragState();
  830. break;
  831. }
  832. // override the others if the user pressed "Stop"
  833. if (pVolume->StoppedByUser()){
  834. analyzeLabel.Empty();
  835. defragLabel.Empty();
  836. statusLabel.Empty();
  837. }
  838. pVolume->m_AnalyzeDisplay.SetLabel(analyzeLabel.GetBuffer());
  839. pVolume->m_DefragDisplay.SetLabel(defragLabel.GetBuffer());
  840. // write the text into the graphic wells
  841. // ::DrawText(WorkDC, analyzeLabel, analyzeLabel.GetLength(), &rcAnalyzeDisp, DT_CENTER);
  842. // ::DrawText(WorkDC, defragLabel, defragLabel.GetLength(), &rcDefragDisp, DT_CENTER);
  843. #ifndef ESI_PROGRESS_BAR
  844. // add the progress bar percent to the status text
  845. // Format: "left status well text"|"%percentdone"|"right status well text"
  846. // we are not currently using the right well, but we could if we ever
  847. // get an accurate progress bar percentage...
  848. statusLabel += _T("|%");
  849. statusLabel += pVolume->cPercentDone();
  850. #endif
  851. // send the status text to the lower-left status box
  852. SendStatusChange(statusLabel.GetBuffer());
  853. //Do the draw.
  854. pVolume->m_AnalyzeDisplay.DrawLinesInHDC(WorkDC);
  855. //Do the draw.
  856. pVolume->m_DefragDisplay.DrawLinesInHDC(WorkDC);
  857. return TRUE;
  858. }
  859. //-------------------------------------------------------------------*
  860. // function: CDfrgCtl::InvalidateProgressBar
  861. //
  862. // returns: None
  863. // note:
  864. //-------------------------------------------------------------------*
  865. #ifdef ESI_PROGRESS_BAR
  866. void CDfrgCtl::InvalidateProgressBar(void)
  867. {
  868. if (!InvalidateRect(&rcProgressBarBG, FALSE)){
  869. Message(L"CDfrgCtl::InvalidateProgressBar()", GetLastError(), NULL);
  870. }
  871. }
  872. #endif
  873. //-------------------------------------------------------------------*
  874. // function: CDfrgCtl::InvalidateGraphicsWindow
  875. //
  876. // returns: None
  877. // note:
  878. //-------------------------------------------------------------------*
  879. void CDfrgCtl::InvalidateGraphicsWindow(void)
  880. {
  881. if(::IsWindow(m_hWnd))
  882. {
  883. if (!InvalidateRect(&rcGraphicsBG, FALSE))
  884. {
  885. Message(L"CDfrgCtl::InvalidateGraphicsWindow()", GetLastError(), NULL);
  886. }
  887. }
  888. }
  889. //-------------------------------------------------------------------*
  890. // function: CDfrgCtl::PaintGraphicsWindow
  891. //
  892. // returns: None
  893. // note:
  894. //-------------------------------------------------------------------*
  895. BOOL CDfrgCtl::PaintGraphicsWindow(HDC OutputDC)
  896. {
  897. // total background in local coordinates
  898. RECT tmpGraphicsBGLocal = {0};
  899. tmpGraphicsBGLocal.bottom = rcGraphicsBG.bottom - rcGraphicsBG.top;
  900. tmpGraphicsBGLocal.right = rcGraphicsBG.right - rcGraphicsBG.left;
  901. HANDLE hBitmap = ::CreateCompatibleBitmap(
  902. OutputDC,
  903. rcGraphicsBG.right - rcGraphicsBG.left,
  904. rcGraphicsBG.bottom - rcGraphicsBG.top);
  905. if (hBitmap == NULL)
  906. return 0;
  907. // Now we need a memory DC to copy old bitmap to new one.
  908. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  909. EF_ASSERT(WorkDC);
  910. HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
  911. // Paint the background of the legend
  912. HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  913. EF_ASSERT(hBrush);
  914. ::FillRect(WorkDC, &tmpGraphicsBGLocal, hBrush);
  915. ::DeleteObject(hBrush);
  916. // edge below the list view is at the very top of this window
  917. ::DrawEdge(WorkDC, &tmpGraphicsBGLocal, EDGE_SUNKEN, BF_TOP);
  918. /////////////////////////////////////////////////////////////////
  919. // Draw the graphics wells
  920. /////////////////////////////////////////////////////////////////
  921. // Fill the dark gray analyze and defrag graphics area
  922. // hBrush = ::CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
  923. // EF_ASSERT(hBrush);
  924. // ::FillRect(WorkDC, &rcAnalyzeDisp, hBrush);
  925. // ::FillRect(WorkDC, &rcDefragDisp, hBrush);
  926. // ::DeleteObject(hBrush);
  927. // Draw the sunken box borders around the analyze and defragment graphics displays
  928. // ::DrawBorderEx(WorkDC, rcAnalyzeBorder, SUNKEN_BOX);
  929. // ::DrawBorderEx(WorkDC, rcDefragBorder, SUNKEN_BOX);
  930. // Draw the text above the analyze and defrag displays
  931. ::SetBkColor(WorkDC, GetSysColor(COLOR_BTNFACE));
  932. ::SetBkMode(WorkDC, OPAQUE);
  933. if (m_IsOkToRun){
  934. ::SetTextColor(WorkDC, GetSysColor(COLOR_BTNTEXT));
  935. }
  936. else {
  937. ::SetTextColor(WorkDC, GetSysColor(COLOR_GRAYTEXT));
  938. }
  939. ::SelectObject(WorkDC, m_hFont);
  940. // write the graphic wells' labels
  941. VString textMsg;
  942. textMsg.LoadString(IDS_LABEL_ANALYSIS_DISPLAY, GetDfrgResHandle());
  943. UINT oldTxtAlignMode = ::SetTextAlign(WorkDC, TA_BOTTOM|TA_LEFT);
  944. ::TextOut(
  945. WorkDC,
  946. rcAnalyzeDisp.left-0,
  947. rcAnalyzeDisp.top-6,
  948. textMsg.GetBuffer(),
  949. textMsg.GetLength());
  950. textMsg.LoadString(IDS_LABEL_DEFRAG_DISPLAY, GetDfrgResHandle());
  951. ::TextOut(
  952. WorkDC,
  953. rcDefragDisp.left-1,
  954. rcDefragDisp.top-6,
  955. textMsg.GetBuffer(),
  956. textMsg.GetLength());
  957. ::SetTextAlign(WorkDC, oldTxtAlignMode);
  958. PaintClusterMap(FALSE, WorkDC);
  959. ::BitBlt(OutputDC, // screen DC
  960. rcGraphicsBG.left,
  961. rcGraphicsBG.top,
  962. rcGraphicsBG.right-rcGraphicsBG.left,
  963. rcGraphicsBG.bottom-rcGraphicsBG.top,
  964. WorkDC,
  965. 0, 0,
  966. SRCCOPY);
  967. // Cleanup the bitmap stuff.
  968. ::SelectObject(WorkDC, hOld);
  969. ::DeleteObject(hBitmap);
  970. ::DeleteDC(WorkDC);
  971. return TRUE;
  972. }
  973. //-------------------------------------------------------------------*
  974. // function: CDfrgCtl::DrawButtons
  975. //
  976. // returns: None
  977. // note:
  978. //-------------------------------------------------------------------*
  979. BOOL CDfrgCtl::DrawButtons(HDC OutputDC)
  980. {
  981. // total background in local coordinates
  982. RECT tmpButtonBGLocal = {0};
  983. tmpButtonBGLocal.bottom = rcButtonBG.bottom - rcButtonBG.top;
  984. tmpButtonBGLocal.right = rcButtonBG.right - rcButtonBG.left;
  985. HANDLE hBitmap = ::CreateCompatibleBitmap(
  986. OutputDC,
  987. rcButtonBG.right - rcButtonBG.left,
  988. rcButtonBG.bottom - rcButtonBG.top);
  989. if (hBitmap == NULL)
  990. return 0;
  991. // Now we need a memory DC to copy old bitmap to new one.
  992. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  993. EF_ASSERT(WorkDC);
  994. HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
  995. // Paint the background of the buttons
  996. HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  997. EF_ASSERT(hBrush);
  998. ::FillRect(WorkDC, &tmpButtonBGLocal, hBrush);
  999. ::DeleteObject(hBrush);
  1000. ::BitBlt(OutputDC, // screen DC
  1001. rcButtonBG.left,
  1002. rcButtonBG.top,
  1003. rcButtonBG.right-rcButtonBG.left,
  1004. rcButtonBG.bottom-rcButtonBG.top,
  1005. WorkDC,
  1006. 0, 0,
  1007. SRCCOPY);
  1008. // Cleanup the bitmap stuff.
  1009. ::SelectObject(WorkDC, hOld);
  1010. ::DeleteObject(hBitmap);
  1011. ::DeleteDC(WorkDC);
  1012. return TRUE;
  1013. }
  1014. //-------------------------------------------------------------------*
  1015. // function: CDfrgCtl::SizeLegend
  1016. //
  1017. // returns: None
  1018. // note:
  1019. //-------------------------------------------------------------------*
  1020. void CDfrgCtl::SizeLegend()
  1021. {
  1022. int x = 0, y = 0, i;
  1023. // get the x and y size of the legend bitmap
  1024. // use the size of number 0 as representative of all bitmaps
  1025. // if they someday vary in size, put this call back into the loop
  1026. m_pLegend->GetBmpSize(0, &x, &y);
  1027. if (m_LegendTextWidth == 0) {
  1028. // calculate the width of the legend with all the
  1029. // entries on one line
  1030. HDC OutputDC = GetDC();
  1031. EV_ASSERT(OutputDC);
  1032. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  1033. EV_ASSERT(WorkDC);
  1034. ::SelectObject(WorkDC, m_hFont);
  1035. // use the width of X to determine the spacer between legend entries
  1036. m_LegendTextSpacer = 3 * GetStringWidth(_T("X"), WorkDC);
  1037. m_LegendTextWidth = m_Margin;
  1038. UINT iStringWidth;
  1039. for (i=0; i < (SIMPLE_DISPLAY?4:7); i++) {
  1040. // calc the width of the legend string
  1041. iStringWidth = GetStringWidth(m_LegendData[i].text.GetBuffer(), WorkDC);
  1042. // save the string width
  1043. m_LegendData[i].length = x + iStringWidth + m_LegendTextSpacer;
  1044. // calculate the overall length
  1045. m_LegendTextWidth += m_LegendData[i].length; // add the space and the bitmap
  1046. }
  1047. // calculate the spacer between the top of the bitmaps and the legend rectangle
  1048. m_BitmapVOffset = (m_LegendHeight - y) / 2;
  1049. // subtract off the last spacers
  1050. m_LegendTextWidth -= x + m_LegendTextSpacer;
  1051. ::DeleteDC(WorkDC);
  1052. EH_ASSERT(ReleaseDC(OutputDC)); // member function
  1053. }
  1054. // this is the longest that the text can be and still have the progress
  1055. // bar on the same line, based on the current window width
  1056. #ifdef ESI_PROGRESS_BAR
  1057. int legendTextMaxWidth =
  1058. m_rcCtlRect.right -
  1059. 2*m_Margin -
  1060. 2*m_EtchedLineOffset - m_ProgressBarLength;
  1061. #else
  1062. int legendTextMaxWidth =
  1063. m_rcCtlRect.right -
  1064. 2*m_Margin -
  1065. 2*m_EtchedLineOffset;
  1066. #endif
  1067. #ifdef ESI_PROGRESS_BAR
  1068. // check if we need to move the progress bar down
  1069. if (m_LegendTextWidth < legendTextMaxWidth){ // if true, all on 1 line
  1070. m_IsProgressBarMoved = FALSE;
  1071. // progress bar background (absolute coords)
  1072. rcProgressBarBG.right = m_rcCtlRect.right;
  1073. rcProgressBarBG.left = m_rcCtlRect.right - m_Margin - m_ProgressBarLength - m_EtchedLineOffset;
  1074. rcProgressBarBG.bottom = m_rcCtlRect.bottom;
  1075. rcProgressBarBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
  1076. // legend background (absolute coords)
  1077. rcLegendBG.left = m_rcCtlRect.left;
  1078. rcLegendBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
  1079. rcLegendBG.right = m_rcCtlRect.right - m_Margin - m_ProgressBarLength - m_EtchedLineOffset;
  1080. rcLegendBG.bottom = m_rcCtlRect.bottom;
  1081. // calculate the rectangle positions for the legend bitmaps
  1082. int currentLineLength = 0;
  1083. for (i=0; i<(SIMPLE_DISPLAY?4:7); i++) {
  1084. m_LegendData[i].rcBmp.top = 0;
  1085. m_LegendData[i].rcBmp.bottom = m_LegendData[i].rcBmp.top + y;
  1086. m_LegendData[i].rcBmp.left = currentLineLength;
  1087. m_LegendData[i].rcBmp.right = m_LegendData[i].rcBmp.left + x;
  1088. currentLineLength += m_LegendData[i].length;
  1089. }
  1090. }
  1091. else { // need to move progress bar down below text
  1092. m_IsProgressBarMoved = TRUE;
  1093. // progress bar background (absolute coords)
  1094. rcProgressBarBG.right = m_rcCtlRect.right;
  1095. rcProgressBarBG.left = m_rcCtlRect.left;
  1096. rcProgressBarBG.bottom = m_rcCtlRect.bottom;
  1097. rcProgressBarBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
  1098. #endif
  1099. int yOffset = 0; // use a Bitmap coordinate system first, stack from the top
  1100. int screenWidth = m_rcCtlRect.right - m_rcCtlRect.left - 2 * m_Margin;
  1101. // start the first legend entry off at the upper left
  1102. m_LegendData[0].rcBmp.top = 0;
  1103. m_LegendData[0].rcBmp.left = 0;
  1104. int currentLineLength = m_LegendData[0].length;
  1105. // loop thru the rest of the entries (note the loop starts at 1!)
  1106. // and determine if they will fit on the current line, or if
  1107. // we need to start another line
  1108. for (i=1; i<(SIMPLE_DISPLAY?4:7); i++) {
  1109. if (currentLineLength + m_LegendData[i].length > screenWidth){
  1110. // need to go to the next line
  1111. yOffset += m_FontHeight + m_LegendGraphicSpacer; // add height of bitmap and a spacer
  1112. m_LegendData[i].rcBmp.top = yOffset;
  1113. m_LegendData[i].rcBmp.left = 0;
  1114. // current length of current line is reset
  1115. currentLineLength = m_LegendData[i].length;
  1116. }
  1117. else { // it will fit on this line
  1118. m_LegendData[i].rcBmp.top = yOffset;
  1119. m_LegendData[i].rcBmp.left = currentLineLength;
  1120. currentLineLength += m_LegendData[i].length;
  1121. }
  1122. }
  1123. #ifdef ESI_PROGRESS_BAR
  1124. rcLegendBG.left = m_rcCtlRect.left;
  1125. rcLegendBG.right = m_rcCtlRect.right;
  1126. rcLegendBG.top = m_rcCtlRect.bottom -
  1127. (m_LegendHeight + 4*m_EtchedLineOffset + y + 2*m_BitmapVOffset + yOffset);
  1128. rcLegendBG.bottom = m_rcCtlRect.bottom -
  1129. (m_LegendHeight + 2*m_EtchedLineOffset);
  1130. }
  1131. #else
  1132. // legend background (absolute coords)
  1133. rcLegendBG.left = m_rcCtlRect.left;
  1134. rcLegendBG.right = m_rcCtlRect.right;
  1135. rcLegendBG.bottom = m_rcCtlRect.bottom;
  1136. rcLegendBG.top = m_rcCtlRect.bottom -
  1137. (2*m_EtchedLineOffset + y + 2*m_BitmapVOffset + yOffset);
  1138. #endif
  1139. }
  1140. //-------------------------------------------------------------------*
  1141. // function: CDfrgCtl::DrawSingleInstanceScreen
  1142. //
  1143. // returns: None
  1144. // note:
  1145. //-------------------------------------------------------------------*
  1146. BOOL CDfrgCtl::DrawSingleInstanceScreen(HDC OutputDC)
  1147. {
  1148. HANDLE hBitmap = ::CreateCompatibleBitmap(
  1149. OutputDC,
  1150. m_rcCtlRect.right - m_rcCtlRect.left,
  1151. m_rcCtlRect.bottom - m_rcCtlRect.top);
  1152. if (hBitmap == NULL)
  1153. return FALSE;
  1154. // Now we need a memory DC to copy old bitmap to new one.
  1155. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  1156. EF_ASSERT(WorkDC);
  1157. HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
  1158. // Paint the background of the legend
  1159. HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  1160. EF_ASSERT(hBrush);
  1161. ::FillRect(WorkDC, &m_rcCtlRect, hBrush);
  1162. ::DeleteObject(hBrush);
  1163. ::BitBlt(OutputDC, // screen DC
  1164. 0,
  1165. 0,
  1166. m_rcCtlRect.right-m_rcCtlRect.left,
  1167. m_rcCtlRect.bottom-m_rcCtlRect.top,
  1168. WorkDC,
  1169. 0, 0,
  1170. SRCCOPY);
  1171. HBITMAP hCriticalIcon = (HBITMAP)::LoadImage(
  1172. GetDfrgResHandle(),
  1173. MAKEINTRESOURCE(IDB_CRITICALICON_GREY),
  1174. IMAGE_BITMAP,
  1175. 0, 0,
  1176. LR_LOADTRANSPARENT|LR_LOADMAP3DCOLORS);
  1177. ::SelectObject(WorkDC, hCriticalIcon);
  1178. ::BitBlt(OutputDC, // screen DC
  1179. 10,
  1180. 10,
  1181. m_rcCtlRect.right-m_rcCtlRect.left,
  1182. m_rcCtlRect.bottom-m_rcCtlRect.top,
  1183. WorkDC,
  1184. 0, 0,
  1185. SRCCOPY);
  1186. // Cleanup the bitmap stuff.
  1187. ::SelectObject(WorkDC, hOld);
  1188. ::DeleteObject(hCriticalIcon);
  1189. ::DeleteObject(hBitmap);
  1190. ::DeleteDC(WorkDC);
  1191. return TRUE;
  1192. }
  1193. //-------------------------------------------------------------------*
  1194. // function: CDfrgCtl::DrawLegend
  1195. //
  1196. // returns: None
  1197. // note:
  1198. //-------------------------------------------------------------------*
  1199. BOOL CDfrgCtl::DrawLegend(HDC OutputDC)
  1200. {
  1201. int x = 0, y = 0;
  1202. m_pLegend->GetBmpSize(0, &x, &y);
  1203. // total legend background in local coordinates
  1204. RECT tmpLegendBGLocal = {0};
  1205. tmpLegendBGLocal.bottom = rcLegendBG.bottom - rcLegendBG.top;
  1206. tmpLegendBGLocal.right = rcLegendBG.right - rcLegendBG.left;
  1207. HANDLE hBitmap = ::CreateCompatibleBitmap(
  1208. OutputDC,
  1209. rcLegendBG.right - rcLegendBG.left,
  1210. rcLegendBG.bottom - rcLegendBG.top);
  1211. if (hBitmap == NULL)
  1212. return FALSE;
  1213. // Now we need a memory DC to copy old bitmap to new one.
  1214. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  1215. EF_ASSERT(WorkDC);
  1216. HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
  1217. // Paint the background of the legend
  1218. HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  1219. EF_ASSERT(hBrush);
  1220. ::FillRect(WorkDC, &tmpLegendBGLocal, hBrush);
  1221. ::DeleteObject(hBrush);
  1222. // select the font
  1223. ::SetBkColor(WorkDC, GetSysColor(COLOR_BTNFACE));
  1224. ::SetBkMode(WorkDC, OPAQUE);
  1225. if (m_IsOkToRun){
  1226. ::SetTextColor(WorkDC, GetSysColor(COLOR_BTNTEXT));
  1227. }
  1228. else {
  1229. ::SetTextColor(WorkDC, GetSysColor(COLOR_GRAYTEXT));
  1230. }
  1231. ::SelectObject(WorkDC, m_hFont);
  1232. // use for debugging
  1233. //::DrawEdge(WorkDC, &tmpLegendBGLocal, EDGE_RAISED, BF_RECT);
  1234. RECT rcBmp;
  1235. RECT rcLegend = tmpLegendBGLocal;
  1236. rcLegend.left += m_Margin;
  1237. rcLegend.top += m_EtchedLineOffset;
  1238. rcLegend.bottom -= m_EtchedLineOffset;
  1239. // Draw the legend at the bottom
  1240. for (int i=0; i<(SIMPLE_DISPLAY?4:7); i++) {
  1241. // rcBmp gets the bitmap position in absolute coordinates
  1242. rcBmp.top = rcLegend.top + m_BitmapVOffset + m_LegendData[i].rcBmp.top;
  1243. rcBmp.left = rcLegend.left + m_LegendData[i].rcBmp.left;
  1244. rcBmp.bottom = rcBmp.top + y;
  1245. rcBmp.right = rcBmp.left + x;
  1246. // draw bitmap in upper-left corner of rectangle
  1247. m_pLegend->DrawBmpInHDCTruncate(WorkDC, i, &rcBmp);
  1248. // draw the text 5 units to the right of the bitmap
  1249. ::TextOut(
  1250. WorkDC,
  1251. rcBmp.left + x + m_LegendGraphicSpacer,
  1252. rcBmp.top-0,
  1253. m_LegendData[i].text.GetBuffer(),
  1254. m_LegendData[i].text.GetLength());
  1255. }
  1256. // etched line on top of legend
  1257. RECT rcHorizontalDivider = tmpLegendBGLocal;
  1258. rcHorizontalDivider.left += m_Margin;
  1259. rcHorizontalDivider.right += 1; // small adjustment
  1260. // is the progress bar is on the bottom, adjust the line in from the margin
  1261. #ifdef ESI_PROGRESS_BAR
  1262. if (m_IsProgressBarMoved){
  1263. rcHorizontalDivider.right -= m_Margin;
  1264. }
  1265. #else
  1266. rcHorizontalDivider.right -= m_Margin;
  1267. #endif
  1268. // rectangle used as the horizontal divider line (top, and bottom if necessary)
  1269. ::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
  1270. ::BitBlt(OutputDC, // screen DC
  1271. rcLegendBG.left,
  1272. rcLegendBG.top,
  1273. rcLegendBG.right-rcLegendBG.left,
  1274. rcLegendBG.bottom-rcLegendBG.top,
  1275. WorkDC,
  1276. 0, 0,
  1277. SRCCOPY);
  1278. // Cleanup the bitmap stuff.
  1279. ::SelectObject(WorkDC, hOld);
  1280. ::DeleteObject(hBitmap);
  1281. ::DeleteDC(WorkDC);
  1282. return TRUE;
  1283. }
  1284. //-------------------------------------------------------------------*
  1285. // function: CDfrgCtl::DrawProgressBar
  1286. //
  1287. // returns: None
  1288. // note:
  1289. //-------------------------------------------------------------------*
  1290. #ifdef ESI_PROGRESS_BAR
  1291. BOOL CDfrgCtl::DrawProgressBar(HDC OutputDC)
  1292. {
  1293. UINT percentDone = 0;
  1294. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  1295. if (pVolume){
  1296. percentDone = pVolume->PercentDone();
  1297. }
  1298. // total progress background in local coordinates
  1299. RECT tmpProgressBarBGLocal = {0};
  1300. tmpProgressBarBGLocal.bottom = rcProgressBarBG.bottom - rcProgressBarBG.top;
  1301. tmpProgressBarBGLocal.right = rcProgressBarBG.right - rcProgressBarBG.left;
  1302. HANDLE hBitmap = ::CreateCompatibleBitmap(
  1303. OutputDC,
  1304. rcProgressBarBG.right - rcProgressBarBG.left,
  1305. rcProgressBarBG.bottom - rcProgressBarBG.top);
  1306. if (hBitmap == NULL)
  1307. return FALSE;
  1308. // Now we need a memory DC to copy old bitmap to new one.
  1309. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  1310. EF_ASSERT(WorkDC);
  1311. HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
  1312. // Paint the background of the legend
  1313. HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  1314. EF_ASSERT(hBrush);
  1315. ::FillRect(WorkDC, &tmpProgressBarBGLocal, hBrush);
  1316. ::DeleteObject(hBrush);
  1317. // use for debugging
  1318. //DrawEdge(WorkDC, &tmpProgressBarBGLocal, EDGE_RAISED, BF_RECT);
  1319. // find the actual outline of the progress bar
  1320. rcProgressBar.left = m_Margin;
  1321. rcProgressBar.top = m_EtchedLineOffset + m_ProgressBarOffset;
  1322. rcProgressBar.right = m_EtchedLineOffset + m_ProgressBarLength;
  1323. rcProgressBar.bottom = m_EtchedLineOffset + m_LegendHeight - m_ProgressBarOffset;
  1324. // etched line on top of legend
  1325. RECT rcHorizontalDivider = tmpProgressBarBGLocal;
  1326. rcHorizontalDivider.right -= m_Margin;
  1327. if (m_IsProgressBarMoved){
  1328. rcHorizontalDivider.left += m_Margin;
  1329. // rectangle used as the horizontal divider line (top, and bottom if necessary)
  1330. ::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
  1331. }
  1332. else{
  1333. ::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
  1334. // etched line to the left (if needed)
  1335. RECT rcVerticalDivider = tmpProgressBarBGLocal;
  1336. rcVerticalDivider.top = m_EtchedLineOffset + m_ProgressBarOffset;
  1337. rcVerticalDivider.bottom -= m_EtchedLineOffset + m_ProgressBarOffset;
  1338. // Draw the etched line to the left of the progress bar
  1339. ::DrawEdge(WorkDC, &rcVerticalDivider, EDGE_ETCHED, BF_LEFT);
  1340. }
  1341. ProgressBar(WorkDC,
  1342. &rcProgressBar,
  1343. m_hFont,
  1344. 4, // width
  1345. 2, // space
  1346. percentDone);
  1347. ::BitBlt(OutputDC, // screen DC
  1348. rcProgressBarBG.left,
  1349. rcProgressBarBG.top,
  1350. rcProgressBarBG.right-rcProgressBarBG.left,
  1351. rcProgressBarBG.bottom-rcProgressBarBG.top,
  1352. WorkDC,
  1353. 0, 0,
  1354. SRCCOPY);
  1355. // Cleanup the bitmap stuff.
  1356. ::SelectObject(WorkDC, hOld);
  1357. ::DeleteObject(hBitmap);
  1358. ::DeleteDC(WorkDC);
  1359. return TRUE;
  1360. }
  1361. #endif
  1362. //-------------------------------------------------------------------*
  1363. // function: CDfrgCtl::SizeButtons
  1364. //
  1365. // returns: None
  1366. // note:
  1367. //-------------------------------------------------------------------*
  1368. void CDfrgCtl::SizeButtons(void)
  1369. {
  1370. /////////////////////////////////////////
  1371. // The button coordinates are absolute!!!
  1372. /////////////////////////////////////////
  1373. // the area around the buttons needed to grey out the background
  1374. rcButtonBG.left = m_rcCtlRect.left;
  1375. rcButtonBG.top = rcLegendBG.top - m_ButtonTopBottomSpacer - m_ButtonHeight;
  1376. rcButtonBG.bottom = rcLegendBG.top;
  1377. rcButtonBG.right = m_rcCtlRect.right;
  1378. HDC OutputDC = GetDC();
  1379. EV_ASSERT(OutputDC);
  1380. HDC WorkDC = ::CreateCompatibleDC(OutputDC);
  1381. EV_ASSERT(WorkDC);
  1382. ::SelectObject(WorkDC, m_hFont);
  1383. TCHAR buttonText[200];
  1384. UINT adjustedButtonWidth;
  1385. const bigButtonSpacer = 20;
  1386. UINT adjustedButtonHeight = __max((UINT)(1.5 * m_FontHeight), m_ButtonHeight);
  1387. // Calculate the Analyze button position and size.
  1388. ::LoadString(GetDfrgResHandle(), IDS_BTN_ANALYZE, buttonText, 200);
  1389. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
  1390. rcAnalyzeButton.left = m_Margin;
  1391. rcAnalyzeButton.bottom = rcLegendBG.top - m_ButtonTopBottomSpacer;
  1392. rcAnalyzeButton.top = rcAnalyzeButton.bottom - adjustedButtonHeight;
  1393. rcAnalyzeButton.right = rcAnalyzeButton.left + adjustedButtonWidth;
  1394. // start off with all buttons the same as the analyze button
  1395. rcDefragButton =
  1396. rcPauseButton =
  1397. rcCancelButton =
  1398. rcReportButton = rcAnalyzeButton;
  1399. // Calculate the Defrag button position and size.
  1400. ::LoadString(GetDfrgResHandle(), IDS_BTN_DEFRAGMENT, buttonText, 200);
  1401. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
  1402. rcDefragButton.left = rcAnalyzeButton.right + m_ButtonSpacer;
  1403. rcDefragButton.right = rcDefragButton.left + adjustedButtonWidth;
  1404. // Calculate the Pause button position and size.
  1405. ::LoadString(GetDfrgResHandle(), IDS_BTN_PAUSE, buttonText, 200);
  1406. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
  1407. // check to see if the resume text is longer
  1408. ::LoadString(GetDfrgResHandle(), IDS_BTN_RESUME, buttonText, 200);
  1409. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), adjustedButtonWidth);
  1410. rcPauseButton.left = rcDefragButton.right + m_ButtonSpacer;
  1411. rcPauseButton.right = rcPauseButton.left + adjustedButtonWidth;
  1412. // Calculate the Cancel button position and size.
  1413. ::LoadString(GetDfrgResHandle(), IDS_BTN_STOP, buttonText, 200);
  1414. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
  1415. rcCancelButton.left = rcPauseButton.right + m_ButtonSpacer;
  1416. rcCancelButton.right = rcCancelButton.left + adjustedButtonWidth;
  1417. // Calculate the See Report button position and size.
  1418. ::LoadString(GetDfrgResHandle(), IDS_BTN_REPORT, buttonText, 200);
  1419. adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
  1420. rcReportButton.left = rcCancelButton.right + m_ButtonSpacer;
  1421. rcReportButton.right = rcReportButton.left + adjustedButtonWidth;
  1422. // Set the rectangles of the buttons
  1423. if (m_bHaveButtons) {
  1424. m_pAnalyzeButton->PositionButton(&rcAnalyzeButton);
  1425. m_pDefragButton->PositionButton(&rcDefragButton);
  1426. m_pPauseButton->PositionButton(&rcPauseButton);
  1427. m_pStopButton->PositionButton(&rcCancelButton);
  1428. m_pReportButton->PositionButton(&rcReportButton);
  1429. }
  1430. ::DeleteDC(WorkDC);
  1431. EH_ASSERT(ReleaseDC(OutputDC));
  1432. }
  1433. //-------------------------------------------------------------------*
  1434. // function: CDfrgCtl::SizeGraphicsWindow
  1435. //
  1436. // returns: None
  1437. // note:
  1438. //-------------------------------------------------------------------*
  1439. BOOL CDfrgCtl::SizeGraphicsWindow(void)
  1440. {
  1441. rcGraphicsBG.left = m_rcCtlRect.left;
  1442. rcGraphicsBG.right = m_rcCtlRect.right;
  1443. rcGraphicsBG.bottom = rcLegendBG.top - m_ButtonTopBottomSpacer - m_ButtonHeight;
  1444. rcGraphicsBG.top =
  1445. rcGraphicsBG.bottom -
  1446. m_ButtonTopBottomSpacer -
  1447. 2*m_GraphicWellHeight -
  1448. 2*m_GraphicWellSpacer;
  1449. // analyze graphics well
  1450. rcAnalyzeDisp.left = m_Margin+1;
  1451. rcAnalyzeDisp.top = m_GraphicWellSpacer;
  1452. rcAnalyzeDisp.bottom = rcAnalyzeDisp.top + m_GraphicWellHeight;
  1453. rcAnalyzeDisp.right = __max(rcGraphicsBG.right - m_Margin, rcReportButton.right);
  1454. // defrag graphics well
  1455. rcDefragDisp = rcAnalyzeDisp;
  1456. rcDefragDisp.top = rcAnalyzeDisp.bottom + m_GraphicWellSpacer;
  1457. rcDefragDisp.bottom = rcDefragDisp.top + m_GraphicWellHeight;
  1458. // Calculate the analyze display border.
  1459. rcAnalyzeBorder.top = rcAnalyzeDisp.top - 1;
  1460. rcAnalyzeBorder.left = rcAnalyzeDisp.left - 1;
  1461. rcAnalyzeBorder.right = rcAnalyzeDisp.right;
  1462. rcAnalyzeBorder.bottom = rcAnalyzeDisp.bottom;
  1463. // Calculate the defrag display border.
  1464. rcDefragBorder.top = rcDefragDisp.top - 1;
  1465. rcDefragBorder.left = rcDefragDisp.left - 1;
  1466. rcDefragBorder.right = rcDefragDisp.right;
  1467. rcDefragBorder.bottom = rcDefragDisp.bottom;
  1468. //Set output dimensions on the analyze display rectangle.
  1469. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  1470. if (pVolume == (CVolume *) NULL){
  1471. return FALSE;
  1472. }
  1473. //Set the dimensions.
  1474. pVolume->m_AnalyzeDisplay.SetOutputArea(rcAnalyzeBorder);
  1475. //Set the dimensions.
  1476. pVolume->m_DefragDisplay.SetOutputArea(rcDefragBorder);
  1477. //tell the engines what the line count is
  1478. SET_DISP_DATA DispData = {0};
  1479. DispData.AnalyzeLineCount = pVolume->m_AnalyzeDisplay.GetLineCount();
  1480. DispData.DefragLineCount = pVolume->m_DefragDisplay.GetLineCount();
  1481. DispData.bSendGraphicsUpdate = TRUE; // send graphics back immediately
  1482. DataIoClientSetData(ID_SETDISPDIMENSIONS,
  1483. (PTCHAR)&DispData,
  1484. sizeof(SET_DISP_DATA),
  1485. pVolume->m_pdataDefragEngine);
  1486. return TRUE;
  1487. }
  1488. //-------------------------------------------------------------------*
  1489. // function: CDfrgCtl::SetButtonState
  1490. //
  1491. // returns: None
  1492. // note:
  1493. //-------------------------------------------------------------------*
  1494. void CDfrgCtl::SetButtonState(void)
  1495. {
  1496. // sanity check to make sure the buttons are created
  1497. if (!m_bHaveButtons) {
  1498. return;
  1499. }
  1500. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  1501. if (pVolume == (CVolume *) NULL){
  1502. return;
  1503. }
  1504. // set the pause/resume text correctly
  1505. m_pPauseButton->LoadString(GetDfrgResHandle(), pVolume->Paused() ? IDS_BTN_RESUME : IDS_BTN_PAUSE);
  1506. if (m_VolumeList.Locked() || !m_IsOkToRun){
  1507. m_pAnalyzeButton->EnableButton(FALSE);
  1508. m_pDefragButton->EnableButton(FALSE);
  1509. m_pReportButton->EnableButton(FALSE);
  1510. m_pPauseButton->EnableButton(FALSE);
  1511. m_pStopButton->EnableButton(FALSE);
  1512. return;
  1513. }
  1514. if (pVolume->EngineState() == ENGINE_STATE_RUNNING){ // the selected vol is being analyzed/defragged
  1515. m_pAnalyzeButton->EnableButton(FALSE);
  1516. m_pDefragButton->EnableButton(FALSE);
  1517. m_pPauseButton->EnableButton(TRUE);
  1518. m_pStopButton->EnableButton(TRUE);
  1519. m_pReportButton->EnableButton(FALSE);
  1520. }
  1521. else {
  1522. m_pAnalyzeButton->EnableButton(TRUE);
  1523. m_pDefragButton->EnableButton(TRUE);
  1524. m_pPauseButton->EnableButton(FALSE);
  1525. m_pStopButton->EnableButton(FALSE);
  1526. m_pReportButton->EnableButton(pVolume->IsReportOKToDisplay());
  1527. }
  1528. }
  1529. //-------------------------------------------------------------------*
  1530. // function: CDfrgCtl::GetStringWidth
  1531. //
  1532. // returns: None
  1533. // note:
  1534. //-------------------------------------------------------------------*
  1535. UINT CDfrgCtl::GetStringWidth(PTCHAR stringBuf, HDC WorkDC)
  1536. {
  1537. if (!stringBuf){
  1538. return 0;
  1539. }
  1540. UINT iStringWidth = 0;
  1541. int iCharWidth = 0; //initialize for bugf 445627
  1542. for (UINT i=0; i<wcslen(stringBuf); i++){
  1543. ::GetCharWidth32(
  1544. WorkDC,
  1545. stringBuf[i],
  1546. stringBuf[i],
  1547. &iCharWidth);
  1548. iStringWidth += iCharWidth;
  1549. }
  1550. return iStringWidth;
  1551. }
  1552. //-------------------------------------------------------------------*
  1553. // function: CDfrgCtl::IsOnlyInstance
  1554. //
  1555. // returns: None
  1556. // note:
  1557. //-------------------------------------------------------------------*
  1558. BOOL CDfrgCtl::IsOnlyInstance()
  1559. {
  1560. BOOL fFirst = FALSE;
  1561. IDataObject* pData = NULL;
  1562. SECURITY_ATTRIBUTES saSecurityAttributes;
  1563. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  1564. if (CheckForAdminPrivs() == FALSE) {
  1565. return FALSE;
  1566. }
  1567. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  1568. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  1569. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  1570. saSecurityAttributes.bInheritHandle = FALSE;
  1571. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatSemaphore, FALSE)) {
  1572. return FALSE;
  1573. }
  1574. #ifdef ESI_MULTI_ALLOWED
  1575. return( TRUE );
  1576. #endif
  1577. if (CheckForAdminPrivs() == FALSE) {
  1578. return FALSE;
  1579. }
  1580. if (m_hIsOkToRunSemaphore == NULL){
  1581. m_hIsOkToRunSemaphore = CreateSemaphore(&saSecurityAttributes, 1, 1, IS_OK_TO_RUN_SEMAPHORE_NAME);
  1582. }
  1583. CleanupSecurityAttributes(&saSecurityAttributes);
  1584. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  1585. if (m_hIsOkToRunSemaphore){
  1586. // is the semaphore signaled?
  1587. DWORD retValue = WaitForSingleObject(m_hIsOkToRunSemaphore, 10);
  1588. // if so, this process is the only one, and the semaphore count is decremented to 0
  1589. if (retValue == WAIT_OBJECT_0){
  1590. return TRUE;
  1591. }
  1592. }
  1593. return FALSE;
  1594. }
  1595. //-------------------------------------------------------------------*
  1596. // function: CDfrgCtl::SendStatusChange
  1597. //
  1598. // returns: None
  1599. // note: Loops through all of the connection points and sends
  1600. // the status change message.
  1601. //-------------------------------------------------------------------*
  1602. void CDfrgCtl::SendStatusChange( LPCTSTR pszStatus )
  1603. {
  1604. BSTR bszStatus;
  1605. if (pszStatus){
  1606. bszStatus = SysAllocString( pszStatus );
  1607. }
  1608. else {
  1609. bszStatus = SysAllocString(_T(""));
  1610. }
  1611. Lock();
  1612. IUnknown** pp = m_vec.begin();
  1613. while (pp < m_vec.end())
  1614. {
  1615. if (*pp != NULL)
  1616. {
  1617. IDfrgEvents* pEvents = reinterpret_cast<IDfrgEvents*>( *pp );
  1618. pEvents->StatusChanged( bszStatus );
  1619. }
  1620. pp++;
  1621. }
  1622. Unlock();
  1623. SysFreeString( bszStatus );
  1624. }
  1625. //-------------------------------------------------------------------*
  1626. // function: CDfrgCtl::SendOKToRun
  1627. //
  1628. // returns: None
  1629. // note: Loops through all of the connection points and sends
  1630. // the new OKToRun property.
  1631. //-------------------------------------------------------------------*
  1632. void CDfrgCtl::SendOKToRun( BOOL bOK )
  1633. {
  1634. Lock();
  1635. IUnknown** pp = m_vec.begin();
  1636. while (pp < m_vec.end())
  1637. {
  1638. if (*pp != NULL)
  1639. {
  1640. IDfrgEvents* pEvents = reinterpret_cast<IDfrgEvents*>( *pp );
  1641. pEvents->IsOKToRun( bOK );
  1642. }
  1643. pp++;
  1644. }
  1645. Unlock();
  1646. }
  1647. //-------------------------------------------------------------------*
  1648. // function: CDfrgCtl::TranslateAccelerator
  1649. //
  1650. // returns: None
  1651. // note:
  1652. //-------------------------------------------------------------------*
  1653. STDMETHODIMP CDfrgCtl::TranslateAccelerator(LPMSG pMsg)
  1654. {
  1655. HRESULT hr = S_FALSE; // we didn't handle keypress
  1656. switch( pMsg->message )
  1657. {
  1658. case WM_KEYDOWN:
  1659. {
  1660. switch ( pMsg->wParam )
  1661. {
  1662. case VK_TAB:
  1663. {
  1664. //
  1665. // Check for the shift key.
  1666. //
  1667. Message(TEXT("CDfrgCtl got a tab key press"), -1, NULL);
  1668. if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 )
  1669. hr = PreviousTab();
  1670. else
  1671. hr = NextTab();
  1672. }
  1673. break;
  1674. case VK_SPACE:
  1675. Message(TEXT("CDfrgCtl got a spacebar key press"), -1, NULL);
  1676. break;
  1677. case VK_RETURN:
  1678. Message(TEXT("CDfrgCtl got an enter key press"), -1, NULL);
  1679. hr = HandleEnterKeyPress();
  1680. break;
  1681. case VK_F5:
  1682. m_ListView.GetDrivesToListView();
  1683. hr = S_OK; // we handled keypress
  1684. break;
  1685. }
  1686. }
  1687. break;
  1688. default:
  1689. break;
  1690. }
  1691. return( hr );
  1692. }
  1693. //-------------------------------------------------------------------*
  1694. // function: CDfrgCtl::PreviousTab
  1695. //
  1696. // returns: None
  1697. // note: Handle moving to the previous tab.
  1698. //-------------------------------------------------------------------*
  1699. HRESULT CDfrgCtl::PreviousTab()
  1700. {
  1701. HRESULT hr;
  1702. HWND hWndNext = NULL;
  1703. CTabEnumerator TabEnum(m_hWndCD, FALSE);
  1704. hWndNext = TabEnum.GetNextTabWindow();
  1705. if(hWndNext == NULL) //out of memory bug 445628
  1706. {
  1707. return(S_FALSE);
  1708. }
  1709. ::SetFocus(hWndNext);
  1710. if (hWndNext == m_ListView.m_hwndListView)
  1711. hr = S_FALSE; // we didn't handle keypress
  1712. else
  1713. hr = S_OK; // we handled keypress
  1714. return(hr);
  1715. }
  1716. //-------------------------------------------------------------------*
  1717. // function: CDfrgCtl::NextTab
  1718. //
  1719. // returns: None
  1720. // note: Handle moving to the next tab.
  1721. //-------------------------------------------------------------------*
  1722. HRESULT CDfrgCtl::NextTab()
  1723. {
  1724. HRESULT hr;
  1725. HWND hWndNext = NULL;
  1726. CTabEnumerator TabEnum(m_hWndCD, TRUE);
  1727. hWndNext = TabEnum.GetNextTabWindow();
  1728. if(hWndNext == NULL) //out of memory bug 445628
  1729. {
  1730. return(S_FALSE);
  1731. }
  1732. ::SetFocus(hWndNext);
  1733. if (hWndNext == m_ListView.m_hwndListView)
  1734. hr = S_FALSE; // we didn't handle keypress
  1735. else
  1736. hr = S_OK; // we handled keypress
  1737. return(hr);
  1738. }
  1739. //-------------------------------------------------------------------*
  1740. // function: CDfrgCtl::GetNextTabWindow
  1741. //
  1742. // returns: None
  1743. // note:
  1744. //-------------------------------------------------------------------*
  1745. HWND CTabEnumerator::GetNextTabWindow()
  1746. {
  1747. HWND hWndNext = NULL;
  1748. //
  1749. // Get the window with the current focus.
  1750. //
  1751. HWND hWndCurrent = GetFocus();
  1752. _ASSERTE( hWndCurrent );
  1753. //
  1754. // Enumerate our child windows. This should generate
  1755. // a list of child windows.
  1756. //
  1757. EnumChildWindows( m_hWndParent, TabEnumChildren, (LONG_PTR) this );
  1758. //
  1759. // Find the existing position of the focus window.
  1760. //
  1761. HWND* pFind = find( m_Children.begin(), m_Children.end(), hWndCurrent );
  1762. //
  1763. // Determine if we need to wrap around to the beginning.
  1764. //
  1765. if (m_fForward)
  1766. {
  1767. if (pFind == m_Children.end() - 1)
  1768. pFind = m_Children.begin();
  1769. else
  1770. pFind++;
  1771. }
  1772. else
  1773. {
  1774. if (pFind == m_Children.begin())
  1775. pFind = m_Children.end() - 1;
  1776. else
  1777. pFind--;
  1778. }
  1779. hWndNext = *pFind;
  1780. return(hWndNext);
  1781. }
  1782. //-------------------------------------------------------------------*
  1783. // function: TabEnumChildren
  1784. //
  1785. // returns: None
  1786. // note:
  1787. //-------------------------------------------------------------------*
  1788. BOOL CALLBACK TabEnumChildren( HWND hwnd, LPARAM lParam )
  1789. {
  1790. reinterpret_cast<CTabEnumerator*>( lParam )->AddChild( hwnd );
  1791. return( TRUE );
  1792. }
  1793. //-------------------------------------------------------------------*
  1794. // function: OnContextMenu
  1795. //
  1796. // returns: None
  1797. // note:
  1798. //-------------------------------------------------------------------*
  1799. HRESULT CDfrgCtl::OnContextMenu(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
  1800. {
  1801. //return( m_ListView.OnContextMenu( (HWND) wParam, LOWORD( lParam ), HIWORD( lParam ) ) );
  1802. HRESULT hr = E_NOTIMPL;
  1803. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  1804. if (pVolume == (CVolume *) NULL){
  1805. return hr;
  1806. }
  1807. if ( m_ListView.m_hwndListView == (HWND) wParam )
  1808. {
  1809. HMENU hMenu;
  1810. hMenu = ::CreatePopupMenu();
  1811. if ( hMenu != NULL )
  1812. {
  1813. // determine button availability
  1814. BOOL AnalDfrgOk = FALSE;
  1815. BOOL StopPauseOk = FALSE;
  1816. BOOL ReportOk = FALSE;
  1817. if (m_VolumeList.Locked() || !m_IsOkToRun) { // UI disabled
  1818. AnalDfrgOk = FALSE;
  1819. StopPauseOk = FALSE;
  1820. ReportOk = FALSE;
  1821. }
  1822. else if (pVolume->EngineState() == ENGINE_STATE_RUNNING) { // the selected vol is being analyzed/defragged
  1823. AnalDfrgOk = FALSE;
  1824. StopPauseOk = TRUE;
  1825. ReportOk = FALSE;
  1826. }
  1827. else {
  1828. AnalDfrgOk = TRUE;
  1829. StopPauseOk = FALSE;
  1830. ReportOk = pVolume->IsReportOKToDisplay();
  1831. }
  1832. TCHAR menuText[200];
  1833. UINT uFlags;
  1834. //
  1835. // Populate context menu.
  1836. //
  1837. // analyze
  1838. ::LoadString(GetDfrgResHandle(), IDS_ANALYZE, menuText, sizeof(menuText) / sizeof(TCHAR));
  1839. uFlags = MF_STRING | (AnalDfrgOk ? MF_ENABLED : MF_GRAYED);
  1840. ::AppendMenu(hMenu, uFlags, ID_ANALYZE, menuText);
  1841. // defrag
  1842. ::LoadString(GetDfrgResHandle(), IDS_DEFRAGMENT, menuText, sizeof(menuText) / sizeof(TCHAR));
  1843. uFlags = MF_STRING | (AnalDfrgOk ? MF_ENABLED : MF_GRAYED);
  1844. ::AppendMenu(hMenu, uFlags, ID_DEFRAG, menuText);
  1845. if (pVolume->Paused()){ // resume
  1846. ::LoadString(GetDfrgResHandle(), IDS_RESUME, menuText, sizeof(menuText) / sizeof(TCHAR));
  1847. uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
  1848. ::AppendMenu(hMenu, uFlags, ID_PAUSE, menuText);
  1849. }
  1850. else { // pause
  1851. ::LoadString(GetDfrgResHandle(), IDS_PAUSE, menuText, sizeof(menuText) / sizeof(TCHAR));
  1852. uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
  1853. ::AppendMenu(hMenu, uFlags, ID_PAUSE, menuText);
  1854. }
  1855. // stop
  1856. ::LoadString(GetDfrgResHandle(), IDS_STOP, menuText, sizeof(menuText) / sizeof(TCHAR));
  1857. uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
  1858. ::AppendMenu(hMenu, uFlags, ID_STOP, menuText);
  1859. // see report
  1860. ::LoadString(GetDfrgResHandle(), IDS_REPORT, menuText, sizeof(menuText) / sizeof(TCHAR));
  1861. uFlags = MF_STRING | (ReportOk ? MF_ENABLED : MF_GRAYED);
  1862. ::AppendMenu(hMenu, uFlags, ID_REPORT, menuText);
  1863. // separator
  1864. ::AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
  1865. // refresh
  1866. ::LoadString(GetDfrgResHandle(), IDS_REFRESH, menuText, sizeof(menuText) / sizeof(TCHAR));
  1867. ::AppendMenu(hMenu, MF_STRING | MF_ENABLED, ID_REFRESH, menuText);
  1868. // separator
  1869. ::AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
  1870. // help
  1871. ::LoadString(GetDfrgResHandle(), IDS_HELP, menuText, sizeof(menuText) / sizeof(TCHAR));
  1872. ::AppendMenu(hMenu, MF_STRING | MF_ENABLED, ID_HELP_CONTENTS, menuText);
  1873. //
  1874. // Display pop-up.
  1875. //
  1876. // get mouse coordinates
  1877. short xPos = LOWORD(lParam);
  1878. short yPos = HIWORD(lParam);
  1879. // get window screen location
  1880. RECT rect;
  1881. BOOL ok = ::GetWindowRect(m_ListView.m_hwndListView, &rect);
  1882. // if we got the window location and the mouse coords are negative,
  1883. // assume invoked from keyboard and locate menu in window
  1884. if (ok && (xPos < 0 || yPos < 0)) {
  1885. xPos = rect.left + 10;
  1886. yPos = rect.top + 10;
  1887. }
  1888. // map menu
  1889. TrackPopupMenu(hMenu,
  1890. TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  1891. xPos,
  1892. yPos,
  1893. 0,
  1894. m_hWndCD, //GetParent( m_hwndListView ),
  1895. NULL );
  1896. ::DestroyMenu(hMenu);
  1897. hr = S_OK;
  1898. }
  1899. }
  1900. return( hr );
  1901. }
  1902. STDMETHODIMP CDfrgCtl::get_Enabled(BOOL *pVal)
  1903. {
  1904. if (m_IsOkToRun)
  1905. Message(TEXT("CDfrgCtl::get_Enabled returning TRUE"), -1, NULL);
  1906. else
  1907. Message(TEXT("CDfrgCtl::get_Enabled returning FALSE"), -1, NULL);
  1908. *pVal = m_IsOkToRun;
  1909. return S_OK;
  1910. }
  1911. STDMETHODIMP CDfrgCtl::put_Enabled(BOOL newVal)
  1912. {
  1913. if (newVal)
  1914. Message(TEXT("CDfrgCtl::put_Enabled got TRUE"), -1, NULL);
  1915. else
  1916. Message(TEXT("CDfrgCtl::put_Enabled got FALSE"), -1, NULL);
  1917. return S_OK;
  1918. }
  1919. //-------------------------------------------------------------------*
  1920. // function: OnSetFocus
  1921. //
  1922. // returns: None
  1923. // note:
  1924. //-------------------------------------------------------------------*
  1925. LRESULT CDfrgCtl::OnSetFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1926. {
  1927. Message(TEXT("CDfrgCtl::OnSetFocus"), -1, NULL);
  1928. CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
  1929. if (m_bInPlaceActive && spSite)
  1930. {
  1931. spSite->OnFocus(TRUE);
  1932. m_ListView.SetFocus(); // list box gets focus first
  1933. }
  1934. return 0;
  1935. }
  1936. LRESULT CDfrgCtl::OnKillFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1937. {
  1938. Message(TEXT("CDfrgCtl::OnKillFocus"), -1, NULL);
  1939. CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
  1940. if (m_bInPlaceActive && spSite)
  1941. spSite->OnFocus(FALSE);
  1942. return 0;
  1943. }
  1944. //-------------------------------------------------------------------*
  1945. // function: HandleEnterKeyPress
  1946. //
  1947. // returns: S_OK: we handled keypress
  1948. // S_FALSE: we didn't handle keypress
  1949. // note:
  1950. //-------------------------------------------------------------------*
  1951. HRESULT CDfrgCtl::HandleEnterKeyPress()
  1952. {
  1953. HWND hWndCurrent = GetFocus(); // current focus window
  1954. HRESULT hr = S_FALSE;
  1955. if (hWndCurrent == m_pAnalyzeButton->GetWindowHandle())
  1956. {
  1957. put_Command(ID_ANALYZE);
  1958. hr = S_OK;
  1959. }
  1960. else if (hWndCurrent == m_pDefragButton->GetWindowHandle())
  1961. {
  1962. put_Command(ID_DEFRAG);
  1963. hr = S_OK;
  1964. }
  1965. else if (hWndCurrent == m_pPauseButton->GetWindowHandle())
  1966. {
  1967. put_Command(ID_PAUSE);
  1968. hr = S_OK;
  1969. }
  1970. else if (hWndCurrent == m_pStopButton->GetWindowHandle())
  1971. {
  1972. put_Command(ID_STOP);
  1973. hr = S_OK;
  1974. }
  1975. else if (hWndCurrent == m_pReportButton->GetWindowHandle())
  1976. {
  1977. // is the engine IDLE?
  1978. CVolume *pVolume = m_VolumeList.GetCurrentVolume();
  1979. if (pVolume)
  1980. {
  1981. if(pVolume->EngineState() == ENGINE_STATE_IDLE)
  1982. {
  1983. RaiseReportDialog(pVolume);
  1984. hr = S_OK;
  1985. ::SetFocus(m_pReportButton->GetWindowHandle());
  1986. }
  1987. }
  1988. }
  1989. return hr;
  1990. }