windows-nt/Source/XPSP1/NT/base/fs/utils/dfrg/dfrgui/dfrgctl.cpp
2020-09-26 16:20:57 +08:00

2368 lines
72 KiB
C++

//=============================================================================*
// COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
//=============================================================================*
// File: DfrgCtl.cpp
//=============================================================================*
//#define ESI_MULTI_ALLOWED
#include "stdafx.h"
#define GLOBAL_DATAHOME
#ifndef SNAPIN
#ifndef NOWINDOWSH
#include <windows.h>
#endif
#endif
#include <commctrl.h>
#include <htmlhelp.h>
#include "adminprivs.h"
extern "C" {
#include "SysStruc.h"
}
#include "DfrgCmn.h"
#include "DfrgEngn.h"
#include "DiskDisp.h"
#include "DfrgUI.h"
#include "DfrgCtl.h"
#include "DataIo.h"
#include "DataIoCl.h"
#include "ListView.h"
#include "ErrMacro.h"
#include "ErrMsg.h"
#include "Graphix.h"
#include "DfrgRes.h"
#include "EsButton.h"
#include "DlgRpt.h"
#include "DfrgRes.h"
#include "GetDfrgRes.h"
#include "IntFuncs.h"
#include "VolList.h"
#include "VolCom.h"
#include "MIMessage.h"
#include "adminprivs.h"
#include <algorithm>
#include "secattr.h"
#define NUM_ACCELERATORS 5
#ifndef SM_REMOTESESSION
#define SM_REMOTESESSION 0x1000
#endif
#define MULTI_INSTANCE_TIMER 1000
#define PING_TIMER 3000
static const MI_TIMER_ID = 1;
static const LISTVIEW_TIMER_ID = 2;
static const PING_TIMER_ID = 3;
BOOL CALLBACK TabEnumChildren( HWND hwnd, LPARAM lParam );
//-------------------------------------------------------------------*
// function: CDfrgCtl::
//
// returns: None
// note:
//-------------------------------------------------------------------*
CDfrgCtl::CDfrgCtl() : m_VolumeList( this ), m_ListView ( this )
{
ATLTRACE( _T( "Creating defrag control.\n" ) );
m_bStart = TRUE;
m_bNeedMultiInstanceMessage = TRUE;
m_bNeedIllegalVolumeMessage = FALSE;
m_dwInstanceRegister = 0;
m_hIsOkToRunSemaphore = NULL;
// Determine if we're the first instance of the control running.
m_IsOkToRun = IsOnlyInstance();
if ( m_IsOkToRun )
{
//
// Register the dataio with the system.
//
m_dwInstanceRegister = InitializeDataIo( CLSID_DfrgCtlDataIo, REGCLS_MULTIPLEUSE );
}
m_LegendHeight = 34;
m_FontHeight = 0; // calculated later
m_LegendTextSpacer = 0; // calculated later
m_LegendTopSpace = 10;
m_EtchedLineOffset = 5;
#ifdef ESI_PROGRESS_BAR
m_ProgressBarOffset = 7; // offset top and bottom in legend window
m_ProgressBarLength = 121;
#endif
m_Margin = 14;
m_GraphicWellHeight = 40;
m_LegendGraphicSpacer = 5;
m_LegendTextWidth = 0; // calculated later
m_BitmapVOffset = 0; // calculated later
m_ButtonTopBottomSpacer = 14;
m_ButtonHeight = 26;
m_ButtonWidth = 84;
m_ButtonSpacer = 6;
m_GraphicWellSpacer = 40;
m_hFont = NULL;
m_bHaveButtons = FALSE;
m_pAnalyzeButton = (ESButton *) NULL;
m_pDefragButton = (ESButton *) NULL;
m_pPauseButton = (ESButton *) NULL;
m_pStopButton = (ESButton *) NULL;
m_pReportButton = (ESButton *) NULL;
m_pLegend = (CBmp *) NULL;
ZeroMemory(&rcLegendBG, sizeof(RECT));
ZeroMemory(&rcReportButton, sizeof(RECT));
// Initialize the legend.
INT_PTR iBmp[20];
if(SIMPLE_DISPLAY){
iBmp[0] = (INT_PTR)MAKEINTRESOURCE(IDB_FRAGMENTED_FILES);
iBmp[1] = (INT_PTR)MAKEINTRESOURCE(IDB_CONTIGUOUS_FILES);
iBmp[2] = (INT_PTR)MAKEINTRESOURCE(IDB_SYSTEM_FILES);
iBmp[3] = (INT_PTR)MAKEINTRESOURCE(IDB_FREE_SPACE);
m_pLegend = new CBmp(GetDfrgResHandle(), iBmp, 4);
EV_ASSERT(m_pLegend);
// load the strings into all the text strings
m_LegendData[0].text.LoadString(IDS_FRAGMENTED_FILES, GetDfrgResHandle());
m_LegendData[1].text.LoadString(IDS_CONTIGUOUS_FILES, GetDfrgResHandle());
m_LegendData[2].text.LoadString(IDS_SYSTEM_FILES, GetDfrgResHandle());
m_LegendData[3].text.LoadString(IDS_FREE_SPACE, GetDfrgResHandle());
}
else{
iBmp[0] = (INT_PTR)MAKEINTRESOURCE(IDB_SYSTEM_FILES);
iBmp[1] = (INT_PTR)MAKEINTRESOURCE(IDB_RESERVED_SPACE);
iBmp[2] = (INT_PTR)MAKEINTRESOURCE(IDB_PAGE_FILE);
iBmp[3] = (INT_PTR)MAKEINTRESOURCE(IDB_DIRECTORY_FILES);
iBmp[4] = (INT_PTR)MAKEINTRESOURCE(IDB_FRAGMENTED_FILES);
iBmp[5] = (INT_PTR)MAKEINTRESOURCE(IDB_CONTIGUOUS_FILES);
iBmp[6] = (INT_PTR)MAKEINTRESOURCE(IDB_FREE_SPACE);
m_pLegend = new CBmp(GetDfrgResHandle(), iBmp, 7);
EV_ASSERT(m_pLegend);
m_LegendData[0].text.LoadString(IDS_SYSTEM_FILES, GetDfrgResHandle());
m_LegendData[1].text.LoadString(IDS_RESERVED_SPACE, GetDfrgResHandle());
m_LegendData[2].text.LoadString(IDS_PAGE_FILE, GetDfrgResHandle());
m_LegendData[3].text.LoadString(IDS_DIRECTORY_FILES, GetDfrgResHandle());
m_LegendData[3].text.LoadString(IDS_FRAGMENTED_FILES, GetDfrgResHandle());
m_LegendData[3].text.LoadString(IDS_CONTIGUOUS_FILES, GetDfrgResHandle());
m_LegendData[3].text.LoadString(IDS_FREE_SPACE, GetDfrgResHandle());
}
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::~CDfrgCtl
//
// returns: None
// note:
//-------------------------------------------------------------------*
CDfrgCtl::~CDfrgCtl()
{
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume) {
pVolume->StoppedByUser(TRUE);
}
DestroyButtons();
if(m_pLegend){
delete m_pLegend;
}
::DeleteObject(m_hFont);
//
// Remove our instance handler.
//
if ( m_dwInstanceRegister )
CoRevokeClassObject( m_dwInstanceRegister );
if(m_hIsOkToRunSemaphore) {
if (m_IsOkToRun) {
// this would increment the count, and make the semaphore seem like
// is was available (signaled). Only do this if this is the running instance
ReleaseSemaphore(m_hIsOkToRunSemaphore, 1, NULL);
}
CloseHandle(m_hIsOkToRunSemaphore);
}
return;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnClose
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult){
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::InterfaceSupportsErrorInfo
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] = { &IID_IDfrgCtl,};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++) {
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnNotify
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
m_ListView.NotifyListView(lParam);
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnCommand
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
switch (LOWORD(wParam)) {
case ID_ANALYZE:
put_Command(ID_ANALYZE);
break;
case ID_DEFRAG:
put_Command(ID_DEFRAG);
break;
case ID_PAUSE:
put_Command(ID_PAUSE);
break;
case ID_STOP:
put_Command(ID_STOP);
break;
case ID_REFRESH:
put_Command(ID_REFRESH);
break;
case ID_HELP_CONTENTS:
put_Command(ID_HELP_CONTENTS);
break;
case ID_REPORT:
{
// is the engine IDLE?
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume){
if(pVolume->EngineState() == ENGINE_STATE_IDLE){
RaiseReportDialog(pVolume);
::SetFocus(m_pReportButton->GetWindowHandle());
}
}
}
break;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnSize
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
TCHAR msg[200];
_stprintf(msg, TEXT("CDfrgCtl::OnSize() lParam LO=%d, HI=%d"), LOWORD(lParam), HIWORD(lParam));
Message(msg, -1, NULL);
//Zero is passed in the first time this function is called. This puts incorrect data into
//the rectangles below for a fraction of a second. Probably harmless, but better safe than sorry.
if(!lParam) {
ZeroMemory(&m_rcCtlRect, sizeof(RECT));
return S_OK;
}
m_rcCtlRect.top = 0;
m_rcCtlRect.left = 0;
m_rcCtlRect.right = LOWORD(lParam);
m_rcCtlRect.bottom = HIWORD(lParam);
SizeWindow();
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SizeWindow
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::SizeWindow()
{
TCHAR msg[200];
_stprintf(msg, TEXT("CDfrgCtl::SizeWindow() m_bStart=%d"), m_bStart);
Message(msg, -1, NULL);
if( m_bStart) {
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
::SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof (ncm), &ncm, 0);
ncm.lfMenuFont.lfWeight = FW_NORMAL;
m_hFont = ::CreateFontIndirect(&ncm.lfMenuFont);
m_FontHeight = -ncm.lfMenuFont.lfHeight;
EH_ASSERT(m_hFont);
VString windowText(IDS_DK_TITLE, GetDfrgResHandle());
SetWindowText(windowText.GetBuffer());
CreateButtons();
// Initialize list view and graphix windows.
m_ListView.InitializeListView(&m_VolumeList, m_hWndCD, _Module.GetModuleInstance());
// Display the drives available in the listview.
m_ListView.GetDrivesToListView();
// get the first drive hilited (check command line)
m_ListView.SelectInitialListViewDrive(&m_bNeedIllegalVolumeMessage);
// Hide or show the listview
m_ListView.EnableWindow(m_IsOkToRun);
// get the buttons enabled/disables properly
SetButtonState();
//Set the multi-instance timer.
SetTimer(MI_TIMER_ID, MULTI_INSTANCE_TIMER, NULL);
//Set the list view timer.
SetTimer(LISTVIEW_TIMER_ID, m_VolumeList.GetRefreshInterval(), NULL);
//Set the ping timer.
SetTimer(PING_TIMER_ID, PING_TIMER, NULL);
m_bStart = FALSE;
}
// size the legend and progress bar
SizeLegend();
// Size the buttons
SizeButtons();
m_pAnalyzeButton->ShowButton(SW_SHOW);
m_pDefragButton->ShowButton(SW_SHOW);
m_pReportButton->ShowButton(SW_SHOW);
m_pPauseButton->ShowButton(SW_SHOW);
m_pStopButton->ShowButton(SW_SHOW);
::SetFocus(m_pAnalyzeButton->GetWindowHandle());
// Now size the graphics window.
SizeGraphicsWindow();
// size the list view (he gets the screen that is left over)
rcListView.bottom = rcGraphicsBG.top;
rcListView.top = 0;
rcListView.left = 0;
rcListView.right = m_rcCtlRect.right;
// Now size the listview
m_ListView.SizeListView(
rcListView.left,
rcListView.top,
rcListView.right - rcListView.left, // width
rcListView.bottom - rcListView.top); // height
Invalidate(FALSE);
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnEraseBkgnd
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::RefreshListViewRow
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::RefreshListViewRow(CVolume *pVolume)
{
// refresh this row of the list view
m_ListView.Update(pVolume);
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnPaint
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
PAINTSTRUCT paintStruct;
HDC OutputDC = BeginPaint(&paintStruct);
// Paint the various windows.
if (OutputDC){
DrawLegend(OutputDC);
#ifdef ESI_PROGRESS_BAR
DrawProgressBar(OutputDC);
#endif
PaintGraphicsWindow(OutputDC);
DrawButtons(OutputDC);
}
EndPaint(&paintStruct);
// display the multi-instance screen if needed
if (!m_IsOkToRun && m_bNeedMultiInstanceMessage){
m_bNeedMultiInstanceMessage = FALSE;
if (CheckForAdminPrivs() == FALSE) {
SetLastError(ESI_VOLLIST_ERR_NON_ADMIN);
VString title(IDS_DK_TITLE, GetDfrgResHandle());
VString msg(IDS_NEED_ADMIN_PRIVS, GetDfrgResHandle());
MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK|MB_ICONWARNING);
}
else if (!RaiseMIDialog(m_hWndCD)) {
ATLTRACE( _T( "MI Dialog failed\n" ) );
}
}
// display the illegal volume dialog if needed
if (m_bNeedIllegalVolumeMessage) {
// don't need to do it again
m_bNeedIllegalVolumeMessage = FALSE;
// warn user he can't defrag illegal volume
VString title(IDS_DK_TITLE, GetDfrgResHandle());
VString msg(IDS_VOLUME_TYPE_NOT_SUPPORTED, GetDfrgResHandle());
MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK | MB_ICONWARNING);
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::OnTimer
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnTimer(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
switch (wParam)
{
// This timer checks the multi-instance semaphore
case MI_TIMER_ID:
// if we are in a Terminal Server session, don't change anything
// if (GetSystemMetrics(SM_REMOTESESSION)){
// return S_OK;
//}
//
// Refresh whether or not we're the only instance.
//
if ( m_IsOkToRun == FALSE )
{
m_IsOkToRun = IsOnlyInstance();
if ( m_IsOkToRun == TRUE )
{
m_dwInstanceRegister = InitializeDataIo( CLSID_DfrgCtlDataIo, REGCLS_MULTIPLEUSE );
SetButtonState();
// Hide or show the listview
m_ListView.EnableWindow(m_IsOkToRun);
// Send OKToRun property change to advises.
SendOKToRun( TRUE );
Invalidate(TRUE);
}
}
KillTimer(MI_TIMER_ID);
SetTimer(MI_TIMER_ID, MULTI_INSTANCE_TIMER, NULL);
break;
// This timer refreshes the list view
case LISTVIEW_TIMER_ID:
KillTimer(LISTVIEW_TIMER_ID);
m_ListView.GetDrivesToListView();
SetTimer(LISTVIEW_TIMER_ID, m_VolumeList.GetRefreshInterval(), NULL);
break;
// This timer pings the engine
case PING_TIMER_ID:
{
KillTimer(PING_TIMER_ID);
CVolume *pVolume;
for (UINT ii = 0; ii < m_VolumeList.GetVolumeCount(); ii++)
{
pVolume = (CVolume *) m_VolumeList.GetVolumeAt(ii);
if (pVolume)
{
pVolume->PingEngine();
}
}
SetTimer(PING_TIMER_ID, PING_TIMER, NULL);
break;
}
default:
EE_ASSERT(FALSE);
break;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_EngineState
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_EngineState(short * pVal)
{
// sets pVal to current engine state
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume) {
*pVal = (short) pVolume->EngineState();
}
else {
*pVal = 0;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_IsEngineRunning
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_IsEngineRunning(BOOL *pVal)
{
// TRUE or FALSE whether current engine is running
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume) {
*pVal = (pVolume->EngineState() == ENGINE_STATE_RUNNING);
}
else {
*pVal = FALSE;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_IsOkToRun
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_IsOkToRun(BOOL *pVal)
{
*pVal = m_IsOkToRun;
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_IsEnginePaused
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_IsEnginePaused(BOOL *pVal)
{
// TRUE or FALSE whether current engine is paused
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume) {
*pVal = pVolume->Paused();
}
else {
*pVal = FALSE;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_IsDefragInProcess
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_IsDefragInProcess(BOOL *pVal)
{
// TRUE or FALSE whether any engine is running
*pVal = m_VolumeList.DefragInProcess();
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_IsVolListLocked
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_IsVolListLocked(BOOL *pVal)
{
// TRUE or FALSE if current volume is locked
*pVal = m_VolumeList.Locked();
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_ReportStatus
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_ReportStatus(BOOL * pVal)
{
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume) {
*pVal = pVolume->IsReportOKToDisplay();
}
else {
*pVal = FALSE;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::get_Command
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::get_Command(short * pVal)
{
// not used so far
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::put_Command
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::put_Command(short newVal)
{
// get a pointer to the current volume
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume == (CVolume *) NULL) {
return S_OK;
}
switch (newVal){
case ID_REFRESH:
// Display the drives available in the listview.
m_ListView.GetDrivesToListView();
Invalidate(TRUE);
break;
case ID_REPORT:
pVolume->ShowReport();
::SetFocus(m_pReportButton->GetWindowHandle());
break;
case ID_HELP_CONTENTS:
HtmlHelp(
m_hWndCD,
TEXT("defrag.chm::/defrag_overview.htm"),
HH_DISPLAY_TOPIC, //HH_TP_HELP_CONTEXTMENU,
NULL); //(DWORD)(LPVOID)myarray);
break;
case ID_STOP:
m_ListView.SetFocus(); // list box gets focus
pVolume->StopEngine();
break;
case ID_ABORT:
pVolume->AbortEngine();
break;
case ID_PAUSE:
pVolume->PauseEngine();
break;
case ID_CONTINUE:
if (!pVolume->ContinueEngine()){
if (GetLastError() == ESI_VOLLIST_ERR_MUST_RESTART){
VString msg(IDS_MUST_RESTART, GetDfrgResHandle());
VString title(IDS_DK_TITLE, GetDfrgResHandle());
MessageBox(msg.GetBuffer(), title.GetBuffer(), MB_OK|MB_ICONWARNING);
}
}
break;
case ID_ANALYZE:
m_ListView.SetFocus(); // list box gets focus
m_VolumeList.Locked(TRUE);
pVolume->Analyze();
m_VolumeList.Locked(FALSE);
break;
case ID_DEFRAG:
m_ListView.SetFocus(); // list box gets focus
m_VolumeList.Locked(TRUE);
pVolume->Defragment();
m_VolumeList.Locked(FALSE);
break;
default:
return S_OK;
}
SetButtonState();
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::CreateButtons
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::CreateButtons(void)
{
m_pAnalyzeButton = new ESButton(m_hWndCD, ID_ANALYZE, _Module.GetModuleInstance());
m_pDefragButton = new ESButton(m_hWndCD, ID_DEFRAG, _Module.GetModuleInstance());
m_pPauseButton = new ESButton(m_hWndCD, ID_PAUSE, _Module.GetModuleInstance());
m_pStopButton = new ESButton(m_hWndCD, ID_STOP, _Module.GetModuleInstance());
m_pReportButton = new ESButton(m_hWndCD, ID_REPORT, _Module.GetModuleInstance());
// if any buttons fail, abort the whole thing and mark have buttons false
if (m_pAnalyzeButton == NULL || m_pDefragButton == NULL || m_pPauseButton == NULL ||
m_pStopButton == NULL || m_pReportButton == NULL) {
Message(TEXT("CDfrgCtl::CreateButtons failed to alloc memory"), -1, NULL);
m_bHaveButtons = FALSE;
DestroyButtons();
return E_OUTOFMEMORY;
}
// if all ok, set up buttons
m_bHaveButtons = TRUE;
m_pAnalyzeButton->SetFont(m_hFont);
m_pAnalyzeButton->LoadString(GetDfrgResHandle(), IDS_BTN_ANALYZE);
m_pDefragButton->SetFont(m_hFont);
m_pDefragButton->LoadString(GetDfrgResHandle(), IDS_BTN_DEFRAGMENT);
m_pPauseButton->SetFont(m_hFont);
m_pPauseButton->LoadString(GetDfrgResHandle(), IDS_BTN_PAUSE);
m_pStopButton->SetFont(m_hFont);
m_pStopButton->LoadString(GetDfrgResHandle(), IDS_BTN_STOP);
m_pReportButton->SetFont(m_hFont);
m_pReportButton->LoadString(GetDfrgResHandle(), IDS_BTN_REPORT);
SetButtonState();
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::DestroyButtons
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::DestroyButtons(void)
{
if (m_pAnalyzeButton) {
delete m_pAnalyzeButton;
}
if (m_pDefragButton) {
delete m_pDefragButton;
}
if (m_pPauseButton) {
delete m_pPauseButton;
}
if (m_pStopButton) {
delete m_pStopButton;
}
if (m_pReportButton) {
delete m_pReportButton;
}
return S_OK;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::PaintClusterMap
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::PaintClusterMap(
IN BOOL bPartialRedraw,
HDC WorkDC
)
{
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume == (CVolume *) NULL) {
return FALSE;
}
/////////////////////////////////////////////////////////////////
// Status text written in the graphics wells
/////////////////////////////////////////////////////////////////
// make the text white in all color schemes
// SetTextColor(WorkDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
// SetBkMode(WorkDC, TRANSPARENT);
UINT defaultId;
if (pVolume->NoGraphicsMemory() ||
pVolume->m_AnalyzeDisplay.NoGraphicsMemory() ||
pVolume->m_DefragDisplay.NoGraphicsMemory()) {
defaultId = IDS_NO_GRAPHICS_MEMORY;
}
else {
defaultId = IDS_LABEL_RESIZING;
}
// get the label that appears in the graphics wells
VString defragLabel;
VString analyzeLabel;
VString statusLabel;
VString compactingLabel(IDS_COMPACTING_FILES, GetDfrgResHandle());
VString movingLabel(IDS_MOVING_FILES, GetDfrgResHandle());
analyzeLabel.Empty();
defragLabel.Empty();
statusLabel.Empty();
switch (pVolume->DefragState()){
case DEFRAG_STATE_ANALYZING:
case DEFRAG_STATE_REANALYZING:
analyzeLabel = pVolume->DisplayLabel();
analyzeLabel.AddChar(L' ');
analyzeLabel += pVolume->sDefragState();
statusLabel = analyzeLabel;
//acs bug #101862//
statusLabel += _T(" ");
statusLabel += pVolume->cPercentDone();
statusLabel += _T("%");
if (pVolume->PausedBySnapshot()) {
pVolume->m_AnalyzeDisplay.SetReadyToDraw(FALSE);
}
break;
case DEFRAG_STATE_ENGINE_DEAD:
analyzeLabel = pVolume->DisplayLabel();
analyzeLabel.AddChar(L' ');
analyzeLabel += pVolume->sDefragState();
statusLabel = analyzeLabel;
break;
case DEFRAG_STATE_DEFRAGMENTING:
analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
defragLabel = pVolume->DisplayLabel();
defragLabel.AddChar(L' ');
defragLabel += pVolume->sDefragState();
statusLabel += defragLabel;
//acs bug #101862//
UINT mmpass;
mmpass = pVolume->Pass();
if (pVolume->PausedBySnapshot()) {
pVolume->m_DefragDisplay.SetReadyToDraw(FALSE);
}
else {
if(mmpass == 2 || mmpass == 4 || mmpass == 6)
{
statusLabel += _T(" ");
statusLabel += pVolume->cPercentDone();
statusLabel += _T("%");
statusLabel += compactingLabel;
} else
{
statusLabel += _T(" ");
statusLabel += pVolume->cPercentDone();
statusLabel += _T("%");
statusLabel += movingLabel;
statusLabel += pVolume->m_fileName;
}
}
break;
case DEFRAG_STATE_BOOT_OPTIMIZING:
analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
defragLabel = pVolume->DisplayLabel();
defragLabel.AddChar(L' ');
defragLabel += pVolume->sDefragState();
statusLabel += defragLabel;
if (pVolume->PausedBySnapshot()) {
pVolume->m_DefragDisplay.SetReadyToDraw(FALSE);
}
else {
statusLabel += _T(" ");
statusLabel += pVolume->cPercentDone();
statusLabel += _T("%");
statusLabel += compactingLabel;
}
break;
case DEFRAG_STATE_ANALYZED:
analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
statusLabel = pVolume->DisplayLabel();
statusLabel.AddChar(L' ');
statusLabel += pVolume->sDefragState();
break;
case DEFRAG_STATE_DEFRAGMENTED:
analyzeLabel.LoadString(defaultId, GetDfrgResHandle());
defragLabel.LoadString(defaultId, GetDfrgResHandle());
statusLabel = pVolume->DisplayLabel();
statusLabel.AddChar(L' ');
statusLabel += pVolume->sDefragState();
break;
}
// override the others if the user pressed "Stop"
if (pVolume->StoppedByUser()){
analyzeLabel.Empty();
defragLabel.Empty();
statusLabel.Empty();
}
pVolume->m_AnalyzeDisplay.SetLabel(analyzeLabel.GetBuffer());
pVolume->m_DefragDisplay.SetLabel(defragLabel.GetBuffer());
// write the text into the graphic wells
// ::DrawText(WorkDC, analyzeLabel, analyzeLabel.GetLength(), &rcAnalyzeDisp, DT_CENTER);
// ::DrawText(WorkDC, defragLabel, defragLabel.GetLength(), &rcDefragDisp, DT_CENTER);
#ifndef ESI_PROGRESS_BAR
// add the progress bar percent to the status text
// Format: "left status well text"|"%percentdone"|"right status well text"
// we are not currently using the right well, but we could if we ever
// get an accurate progress bar percentage...
statusLabel += _T("|%");
statusLabel += pVolume->cPercentDone();
#endif
// send the status text to the lower-left status box
SendStatusChange(statusLabel.GetBuffer());
//Do the draw.
pVolume->m_AnalyzeDisplay.DrawLinesInHDC(WorkDC);
//Do the draw.
pVolume->m_DefragDisplay.DrawLinesInHDC(WorkDC);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::InvalidateProgressBar
//
// returns: None
// note:
//-------------------------------------------------------------------*
#ifdef ESI_PROGRESS_BAR
void CDfrgCtl::InvalidateProgressBar(void)
{
if (!InvalidateRect(&rcProgressBarBG, FALSE)){
Message(L"CDfrgCtl::InvalidateProgressBar()", GetLastError(), NULL);
}
}
#endif
//-------------------------------------------------------------------*
// function: CDfrgCtl::InvalidateGraphicsWindow
//
// returns: None
// note:
//-------------------------------------------------------------------*
void CDfrgCtl::InvalidateGraphicsWindow(void)
{
if(::IsWindow(m_hWnd))
{
if (!InvalidateRect(&rcGraphicsBG, FALSE))
{
Message(L"CDfrgCtl::InvalidateGraphicsWindow()", GetLastError(), NULL);
}
}
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::PaintGraphicsWindow
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::PaintGraphicsWindow(HDC OutputDC)
{
// total background in local coordinates
RECT tmpGraphicsBGLocal = {0};
tmpGraphicsBGLocal.bottom = rcGraphicsBG.bottom - rcGraphicsBG.top;
tmpGraphicsBGLocal.right = rcGraphicsBG.right - rcGraphicsBG.left;
HANDLE hBitmap = ::CreateCompatibleBitmap(
OutputDC,
rcGraphicsBG.right - rcGraphicsBG.left,
rcGraphicsBG.bottom - rcGraphicsBG.top);
if (hBitmap == NULL)
return 0;
// Now we need a memory DC to copy old bitmap to new one.
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EF_ASSERT(WorkDC);
HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
// Paint the background of the legend
HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
EF_ASSERT(hBrush);
::FillRect(WorkDC, &tmpGraphicsBGLocal, hBrush);
::DeleteObject(hBrush);
// edge below the list view is at the very top of this window
::DrawEdge(WorkDC, &tmpGraphicsBGLocal, EDGE_SUNKEN, BF_TOP);
/////////////////////////////////////////////////////////////////
// Draw the graphics wells
/////////////////////////////////////////////////////////////////
// Fill the dark gray analyze and defrag graphics area
// hBrush = ::CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
// EF_ASSERT(hBrush);
// ::FillRect(WorkDC, &rcAnalyzeDisp, hBrush);
// ::FillRect(WorkDC, &rcDefragDisp, hBrush);
// ::DeleteObject(hBrush);
// Draw the sunken box borders around the analyze and defragment graphics displays
// ::DrawBorderEx(WorkDC, rcAnalyzeBorder, SUNKEN_BOX);
// ::DrawBorderEx(WorkDC, rcDefragBorder, SUNKEN_BOX);
// Draw the text above the analyze and defrag displays
::SetBkColor(WorkDC, GetSysColor(COLOR_BTNFACE));
::SetBkMode(WorkDC, OPAQUE);
if (m_IsOkToRun){
::SetTextColor(WorkDC, GetSysColor(COLOR_BTNTEXT));
}
else {
::SetTextColor(WorkDC, GetSysColor(COLOR_GRAYTEXT));
}
::SelectObject(WorkDC, m_hFont);
// write the graphic wells' labels
VString textMsg;
textMsg.LoadString(IDS_LABEL_ANALYSIS_DISPLAY, GetDfrgResHandle());
UINT oldTxtAlignMode = ::SetTextAlign(WorkDC, TA_BOTTOM|TA_LEFT);
::TextOut(
WorkDC,
rcAnalyzeDisp.left-0,
rcAnalyzeDisp.top-6,
textMsg.GetBuffer(),
textMsg.GetLength());
textMsg.LoadString(IDS_LABEL_DEFRAG_DISPLAY, GetDfrgResHandle());
::TextOut(
WorkDC,
rcDefragDisp.left-1,
rcDefragDisp.top-6,
textMsg.GetBuffer(),
textMsg.GetLength());
::SetTextAlign(WorkDC, oldTxtAlignMode);
PaintClusterMap(FALSE, WorkDC);
::BitBlt(OutputDC, // screen DC
rcGraphicsBG.left,
rcGraphicsBG.top,
rcGraphicsBG.right-rcGraphicsBG.left,
rcGraphicsBG.bottom-rcGraphicsBG.top,
WorkDC,
0, 0,
SRCCOPY);
// Cleanup the bitmap stuff.
::SelectObject(WorkDC, hOld);
::DeleteObject(hBitmap);
::DeleteDC(WorkDC);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::DrawButtons
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::DrawButtons(HDC OutputDC)
{
// total background in local coordinates
RECT tmpButtonBGLocal = {0};
tmpButtonBGLocal.bottom = rcButtonBG.bottom - rcButtonBG.top;
tmpButtonBGLocal.right = rcButtonBG.right - rcButtonBG.left;
HANDLE hBitmap = ::CreateCompatibleBitmap(
OutputDC,
rcButtonBG.right - rcButtonBG.left,
rcButtonBG.bottom - rcButtonBG.top);
if (hBitmap == NULL)
return 0;
// Now we need a memory DC to copy old bitmap to new one.
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EF_ASSERT(WorkDC);
HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
// Paint the background of the buttons
HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
EF_ASSERT(hBrush);
::FillRect(WorkDC, &tmpButtonBGLocal, hBrush);
::DeleteObject(hBrush);
::BitBlt(OutputDC, // screen DC
rcButtonBG.left,
rcButtonBG.top,
rcButtonBG.right-rcButtonBG.left,
rcButtonBG.bottom-rcButtonBG.top,
WorkDC,
0, 0,
SRCCOPY);
// Cleanup the bitmap stuff.
::SelectObject(WorkDC, hOld);
::DeleteObject(hBitmap);
::DeleteDC(WorkDC);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SizeLegend
//
// returns: None
// note:
//-------------------------------------------------------------------*
void CDfrgCtl::SizeLegend()
{
int x = 0, y = 0, i;
// get the x and y size of the legend bitmap
// use the size of number 0 as representative of all bitmaps
// if they someday vary in size, put this call back into the loop
m_pLegend->GetBmpSize(0, &x, &y);
if (m_LegendTextWidth == 0) {
// calculate the width of the legend with all the
// entries on one line
HDC OutputDC = GetDC();
EV_ASSERT(OutputDC);
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EV_ASSERT(WorkDC);
::SelectObject(WorkDC, m_hFont);
// use the width of X to determine the spacer between legend entries
m_LegendTextSpacer = 3 * GetStringWidth(_T("X"), WorkDC);
m_LegendTextWidth = m_Margin;
UINT iStringWidth;
for (i=0; i < (SIMPLE_DISPLAY?4:7); i++) {
// calc the width of the legend string
iStringWidth = GetStringWidth(m_LegendData[i].text.GetBuffer(), WorkDC);
// save the string width
m_LegendData[i].length = x + iStringWidth + m_LegendTextSpacer;
// calculate the overall length
m_LegendTextWidth += m_LegendData[i].length; // add the space and the bitmap
}
// calculate the spacer between the top of the bitmaps and the legend rectangle
m_BitmapVOffset = (m_LegendHeight - y) / 2;
// subtract off the last spacers
m_LegendTextWidth -= x + m_LegendTextSpacer;
::DeleteDC(WorkDC);
EH_ASSERT(ReleaseDC(OutputDC)); // member function
}
// this is the longest that the text can be and still have the progress
// bar on the same line, based on the current window width
#ifdef ESI_PROGRESS_BAR
int legendTextMaxWidth =
m_rcCtlRect.right -
2*m_Margin -
2*m_EtchedLineOffset - m_ProgressBarLength;
#else
int legendTextMaxWidth =
m_rcCtlRect.right -
2*m_Margin -
2*m_EtchedLineOffset;
#endif
#ifdef ESI_PROGRESS_BAR
// check if we need to move the progress bar down
if (m_LegendTextWidth < legendTextMaxWidth){ // if true, all on 1 line
m_IsProgressBarMoved = FALSE;
// progress bar background (absolute coords)
rcProgressBarBG.right = m_rcCtlRect.right;
rcProgressBarBG.left = m_rcCtlRect.right - m_Margin - m_ProgressBarLength - m_EtchedLineOffset;
rcProgressBarBG.bottom = m_rcCtlRect.bottom;
rcProgressBarBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
// legend background (absolute coords)
rcLegendBG.left = m_rcCtlRect.left;
rcLegendBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
rcLegendBG.right = m_rcCtlRect.right - m_Margin - m_ProgressBarLength - m_EtchedLineOffset;
rcLegendBG.bottom = m_rcCtlRect.bottom;
// calculate the rectangle positions for the legend bitmaps
int currentLineLength = 0;
for (i=0; i<(SIMPLE_DISPLAY?4:7); i++) {
m_LegendData[i].rcBmp.top = 0;
m_LegendData[i].rcBmp.bottom = m_LegendData[i].rcBmp.top + y;
m_LegendData[i].rcBmp.left = currentLineLength;
m_LegendData[i].rcBmp.right = m_LegendData[i].rcBmp.left + x;
currentLineLength += m_LegendData[i].length;
}
}
else { // need to move progress bar down below text
m_IsProgressBarMoved = TRUE;
// progress bar background (absolute coords)
rcProgressBarBG.right = m_rcCtlRect.right;
rcProgressBarBG.left = m_rcCtlRect.left;
rcProgressBarBG.bottom = m_rcCtlRect.bottom;
rcProgressBarBG.top = m_rcCtlRect.bottom - 2*m_EtchedLineOffset - m_LegendHeight;
#endif
int yOffset = 0; // use a Bitmap coordinate system first, stack from the top
int screenWidth = m_rcCtlRect.right - m_rcCtlRect.left - 2 * m_Margin;
// start the first legend entry off at the upper left
m_LegendData[0].rcBmp.top = 0;
m_LegendData[0].rcBmp.left = 0;
int currentLineLength = m_LegendData[0].length;
// loop thru the rest of the entries (note the loop starts at 1!)
// and determine if they will fit on the current line, or if
// we need to start another line
for (i=1; i<(SIMPLE_DISPLAY?4:7); i++) {
if (currentLineLength + m_LegendData[i].length > screenWidth){
// need to go to the next line
yOffset += m_FontHeight + m_LegendGraphicSpacer; // add height of bitmap and a spacer
m_LegendData[i].rcBmp.top = yOffset;
m_LegendData[i].rcBmp.left = 0;
// current length of current line is reset
currentLineLength = m_LegendData[i].length;
}
else { // it will fit on this line
m_LegendData[i].rcBmp.top = yOffset;
m_LegendData[i].rcBmp.left = currentLineLength;
currentLineLength += m_LegendData[i].length;
}
}
#ifdef ESI_PROGRESS_BAR
rcLegendBG.left = m_rcCtlRect.left;
rcLegendBG.right = m_rcCtlRect.right;
rcLegendBG.top = m_rcCtlRect.bottom -
(m_LegendHeight + 4*m_EtchedLineOffset + y + 2*m_BitmapVOffset + yOffset);
rcLegendBG.bottom = m_rcCtlRect.bottom -
(m_LegendHeight + 2*m_EtchedLineOffset);
}
#else
// legend background (absolute coords)
rcLegendBG.left = m_rcCtlRect.left;
rcLegendBG.right = m_rcCtlRect.right;
rcLegendBG.bottom = m_rcCtlRect.bottom;
rcLegendBG.top = m_rcCtlRect.bottom -
(2*m_EtchedLineOffset + y + 2*m_BitmapVOffset + yOffset);
#endif
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::DrawSingleInstanceScreen
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::DrawSingleInstanceScreen(HDC OutputDC)
{
HANDLE hBitmap = ::CreateCompatibleBitmap(
OutputDC,
m_rcCtlRect.right - m_rcCtlRect.left,
m_rcCtlRect.bottom - m_rcCtlRect.top);
if (hBitmap == NULL)
return FALSE;
// Now we need a memory DC to copy old bitmap to new one.
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EF_ASSERT(WorkDC);
HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
// Paint the background of the legend
HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
EF_ASSERT(hBrush);
::FillRect(WorkDC, &m_rcCtlRect, hBrush);
::DeleteObject(hBrush);
::BitBlt(OutputDC, // screen DC
0,
0,
m_rcCtlRect.right-m_rcCtlRect.left,
m_rcCtlRect.bottom-m_rcCtlRect.top,
WorkDC,
0, 0,
SRCCOPY);
HBITMAP hCriticalIcon = (HBITMAP)::LoadImage(
GetDfrgResHandle(),
MAKEINTRESOURCE(IDB_CRITICALICON_GREY),
IMAGE_BITMAP,
0, 0,
LR_LOADTRANSPARENT|LR_LOADMAP3DCOLORS);
::SelectObject(WorkDC, hCriticalIcon);
::BitBlt(OutputDC, // screen DC
10,
10,
m_rcCtlRect.right-m_rcCtlRect.left,
m_rcCtlRect.bottom-m_rcCtlRect.top,
WorkDC,
0, 0,
SRCCOPY);
// Cleanup the bitmap stuff.
::SelectObject(WorkDC, hOld);
::DeleteObject(hCriticalIcon);
::DeleteObject(hBitmap);
::DeleteDC(WorkDC);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::DrawLegend
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::DrawLegend(HDC OutputDC)
{
int x = 0, y = 0;
m_pLegend->GetBmpSize(0, &x, &y);
// total legend background in local coordinates
RECT tmpLegendBGLocal = {0};
tmpLegendBGLocal.bottom = rcLegendBG.bottom - rcLegendBG.top;
tmpLegendBGLocal.right = rcLegendBG.right - rcLegendBG.left;
HANDLE hBitmap = ::CreateCompatibleBitmap(
OutputDC,
rcLegendBG.right - rcLegendBG.left,
rcLegendBG.bottom - rcLegendBG.top);
if (hBitmap == NULL)
return FALSE;
// Now we need a memory DC to copy old bitmap to new one.
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EF_ASSERT(WorkDC);
HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
// Paint the background of the legend
HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
EF_ASSERT(hBrush);
::FillRect(WorkDC, &tmpLegendBGLocal, hBrush);
::DeleteObject(hBrush);
// select the font
::SetBkColor(WorkDC, GetSysColor(COLOR_BTNFACE));
::SetBkMode(WorkDC, OPAQUE);
if (m_IsOkToRun){
::SetTextColor(WorkDC, GetSysColor(COLOR_BTNTEXT));
}
else {
::SetTextColor(WorkDC, GetSysColor(COLOR_GRAYTEXT));
}
::SelectObject(WorkDC, m_hFont);
// use for debugging
//::DrawEdge(WorkDC, &tmpLegendBGLocal, EDGE_RAISED, BF_RECT);
RECT rcBmp;
RECT rcLegend = tmpLegendBGLocal;
rcLegend.left += m_Margin;
rcLegend.top += m_EtchedLineOffset;
rcLegend.bottom -= m_EtchedLineOffset;
// Draw the legend at the bottom
for (int i=0; i<(SIMPLE_DISPLAY?4:7); i++) {
// rcBmp gets the bitmap position in absolute coordinates
rcBmp.top = rcLegend.top + m_BitmapVOffset + m_LegendData[i].rcBmp.top;
rcBmp.left = rcLegend.left + m_LegendData[i].rcBmp.left;
rcBmp.bottom = rcBmp.top + y;
rcBmp.right = rcBmp.left + x;
// draw bitmap in upper-left corner of rectangle
m_pLegend->DrawBmpInHDCTruncate(WorkDC, i, &rcBmp);
// draw the text 5 units to the right of the bitmap
::TextOut(
WorkDC,
rcBmp.left + x + m_LegendGraphicSpacer,
rcBmp.top-0,
m_LegendData[i].text.GetBuffer(),
m_LegendData[i].text.GetLength());
}
// etched line on top of legend
RECT rcHorizontalDivider = tmpLegendBGLocal;
rcHorizontalDivider.left += m_Margin;
rcHorizontalDivider.right += 1; // small adjustment
// is the progress bar is on the bottom, adjust the line in from the margin
#ifdef ESI_PROGRESS_BAR
if (m_IsProgressBarMoved){
rcHorizontalDivider.right -= m_Margin;
}
#else
rcHorizontalDivider.right -= m_Margin;
#endif
// rectangle used as the horizontal divider line (top, and bottom if necessary)
::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
::BitBlt(OutputDC, // screen DC
rcLegendBG.left,
rcLegendBG.top,
rcLegendBG.right-rcLegendBG.left,
rcLegendBG.bottom-rcLegendBG.top,
WorkDC,
0, 0,
SRCCOPY);
// Cleanup the bitmap stuff.
::SelectObject(WorkDC, hOld);
::DeleteObject(hBitmap);
::DeleteDC(WorkDC);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::DrawProgressBar
//
// returns: None
// note:
//-------------------------------------------------------------------*
#ifdef ESI_PROGRESS_BAR
BOOL CDfrgCtl::DrawProgressBar(HDC OutputDC)
{
UINT percentDone = 0;
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume){
percentDone = pVolume->PercentDone();
}
// total progress background in local coordinates
RECT tmpProgressBarBGLocal = {0};
tmpProgressBarBGLocal.bottom = rcProgressBarBG.bottom - rcProgressBarBG.top;
tmpProgressBarBGLocal.right = rcProgressBarBG.right - rcProgressBarBG.left;
HANDLE hBitmap = ::CreateCompatibleBitmap(
OutputDC,
rcProgressBarBG.right - rcProgressBarBG.left,
rcProgressBarBG.bottom - rcProgressBarBG.top);
if (hBitmap == NULL)
return FALSE;
// Now we need a memory DC to copy old bitmap to new one.
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EF_ASSERT(WorkDC);
HANDLE hOld = ::SelectObject(WorkDC, hBitmap);
// Paint the background of the legend
HBRUSH hBrush = ::CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
EF_ASSERT(hBrush);
::FillRect(WorkDC, &tmpProgressBarBGLocal, hBrush);
::DeleteObject(hBrush);
// use for debugging
//DrawEdge(WorkDC, &tmpProgressBarBGLocal, EDGE_RAISED, BF_RECT);
// find the actual outline of the progress bar
rcProgressBar.left = m_Margin;
rcProgressBar.top = m_EtchedLineOffset + m_ProgressBarOffset;
rcProgressBar.right = m_EtchedLineOffset + m_ProgressBarLength;
rcProgressBar.bottom = m_EtchedLineOffset + m_LegendHeight - m_ProgressBarOffset;
// etched line on top of legend
RECT rcHorizontalDivider = tmpProgressBarBGLocal;
rcHorizontalDivider.right -= m_Margin;
if (m_IsProgressBarMoved){
rcHorizontalDivider.left += m_Margin;
// rectangle used as the horizontal divider line (top, and bottom if necessary)
::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
}
else{
::DrawEdge(WorkDC, &rcHorizontalDivider, EDGE_ETCHED, BF_TOP);
// etched line to the left (if needed)
RECT rcVerticalDivider = tmpProgressBarBGLocal;
rcVerticalDivider.top = m_EtchedLineOffset + m_ProgressBarOffset;
rcVerticalDivider.bottom -= m_EtchedLineOffset + m_ProgressBarOffset;
// Draw the etched line to the left of the progress bar
::DrawEdge(WorkDC, &rcVerticalDivider, EDGE_ETCHED, BF_LEFT);
}
ProgressBar(WorkDC,
&rcProgressBar,
m_hFont,
4, // width
2, // space
percentDone);
::BitBlt(OutputDC, // screen DC
rcProgressBarBG.left,
rcProgressBarBG.top,
rcProgressBarBG.right-rcProgressBarBG.left,
rcProgressBarBG.bottom-rcProgressBarBG.top,
WorkDC,
0, 0,
SRCCOPY);
// Cleanup the bitmap stuff.
::SelectObject(WorkDC, hOld);
::DeleteObject(hBitmap);
::DeleteDC(WorkDC);
return TRUE;
}
#endif
//-------------------------------------------------------------------*
// function: CDfrgCtl::SizeButtons
//
// returns: None
// note:
//-------------------------------------------------------------------*
void CDfrgCtl::SizeButtons(void)
{
/////////////////////////////////////////
// The button coordinates are absolute!!!
/////////////////////////////////////////
// the area around the buttons needed to grey out the background
rcButtonBG.left = m_rcCtlRect.left;
rcButtonBG.top = rcLegendBG.top - m_ButtonTopBottomSpacer - m_ButtonHeight;
rcButtonBG.bottom = rcLegendBG.top;
rcButtonBG.right = m_rcCtlRect.right;
HDC OutputDC = GetDC();
EV_ASSERT(OutputDC);
HDC WorkDC = ::CreateCompatibleDC(OutputDC);
EV_ASSERT(WorkDC);
::SelectObject(WorkDC, m_hFont);
TCHAR buttonText[200];
UINT adjustedButtonWidth;
const bigButtonSpacer = 20;
UINT adjustedButtonHeight = __max((UINT)(1.5 * m_FontHeight), m_ButtonHeight);
// Calculate the Analyze button position and size.
::LoadString(GetDfrgResHandle(), IDS_BTN_ANALYZE, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
rcAnalyzeButton.left = m_Margin;
rcAnalyzeButton.bottom = rcLegendBG.top - m_ButtonTopBottomSpacer;
rcAnalyzeButton.top = rcAnalyzeButton.bottom - adjustedButtonHeight;
rcAnalyzeButton.right = rcAnalyzeButton.left + adjustedButtonWidth;
// start off with all buttons the same as the analyze button
rcDefragButton =
rcPauseButton =
rcCancelButton =
rcReportButton = rcAnalyzeButton;
// Calculate the Defrag button position and size.
::LoadString(GetDfrgResHandle(), IDS_BTN_DEFRAGMENT, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
rcDefragButton.left = rcAnalyzeButton.right + m_ButtonSpacer;
rcDefragButton.right = rcDefragButton.left + adjustedButtonWidth;
// Calculate the Pause button position and size.
::LoadString(GetDfrgResHandle(), IDS_BTN_PAUSE, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
// check to see if the resume text is longer
::LoadString(GetDfrgResHandle(), IDS_BTN_RESUME, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), adjustedButtonWidth);
rcPauseButton.left = rcDefragButton.right + m_ButtonSpacer;
rcPauseButton.right = rcPauseButton.left + adjustedButtonWidth;
// Calculate the Cancel button position and size.
::LoadString(GetDfrgResHandle(), IDS_BTN_STOP, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
rcCancelButton.left = rcPauseButton.right + m_ButtonSpacer;
rcCancelButton.right = rcCancelButton.left + adjustedButtonWidth;
// Calculate the See Report button position and size.
::LoadString(GetDfrgResHandle(), IDS_BTN_REPORT, buttonText, 200);
adjustedButtonWidth = __max(bigButtonSpacer + GetStringWidth(buttonText, WorkDC), m_ButtonWidth);
rcReportButton.left = rcCancelButton.right + m_ButtonSpacer;
rcReportButton.right = rcReportButton.left + adjustedButtonWidth;
// Set the rectangles of the buttons
if (m_bHaveButtons) {
m_pAnalyzeButton->PositionButton(&rcAnalyzeButton);
m_pDefragButton->PositionButton(&rcDefragButton);
m_pPauseButton->PositionButton(&rcPauseButton);
m_pStopButton->PositionButton(&rcCancelButton);
m_pReportButton->PositionButton(&rcReportButton);
}
::DeleteDC(WorkDC);
EH_ASSERT(ReleaseDC(OutputDC));
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SizeGraphicsWindow
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::SizeGraphicsWindow(void)
{
rcGraphicsBG.left = m_rcCtlRect.left;
rcGraphicsBG.right = m_rcCtlRect.right;
rcGraphicsBG.bottom = rcLegendBG.top - m_ButtonTopBottomSpacer - m_ButtonHeight;
rcGraphicsBG.top =
rcGraphicsBG.bottom -
m_ButtonTopBottomSpacer -
2*m_GraphicWellHeight -
2*m_GraphicWellSpacer;
// analyze graphics well
rcAnalyzeDisp.left = m_Margin+1;
rcAnalyzeDisp.top = m_GraphicWellSpacer;
rcAnalyzeDisp.bottom = rcAnalyzeDisp.top + m_GraphicWellHeight;
rcAnalyzeDisp.right = __max(rcGraphicsBG.right - m_Margin, rcReportButton.right);
// defrag graphics well
rcDefragDisp = rcAnalyzeDisp;
rcDefragDisp.top = rcAnalyzeDisp.bottom + m_GraphicWellSpacer;
rcDefragDisp.bottom = rcDefragDisp.top + m_GraphicWellHeight;
// Calculate the analyze display border.
rcAnalyzeBorder.top = rcAnalyzeDisp.top - 1;
rcAnalyzeBorder.left = rcAnalyzeDisp.left - 1;
rcAnalyzeBorder.right = rcAnalyzeDisp.right;
rcAnalyzeBorder.bottom = rcAnalyzeDisp.bottom;
// Calculate the defrag display border.
rcDefragBorder.top = rcDefragDisp.top - 1;
rcDefragBorder.left = rcDefragDisp.left - 1;
rcDefragBorder.right = rcDefragDisp.right;
rcDefragBorder.bottom = rcDefragDisp.bottom;
//Set output dimensions on the analyze display rectangle.
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume == (CVolume *) NULL){
return FALSE;
}
//Set the dimensions.
pVolume->m_AnalyzeDisplay.SetOutputArea(rcAnalyzeBorder);
//Set the dimensions.
pVolume->m_DefragDisplay.SetOutputArea(rcDefragBorder);
//tell the engines what the line count is
SET_DISP_DATA DispData = {0};
DispData.AnalyzeLineCount = pVolume->m_AnalyzeDisplay.GetLineCount();
DispData.DefragLineCount = pVolume->m_DefragDisplay.GetLineCount();
DispData.bSendGraphicsUpdate = TRUE; // send graphics back immediately
DataIoClientSetData(ID_SETDISPDIMENSIONS,
(PTCHAR)&DispData,
sizeof(SET_DISP_DATA),
pVolume->m_pdataDefragEngine);
return TRUE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SetButtonState
//
// returns: None
// note:
//-------------------------------------------------------------------*
void CDfrgCtl::SetButtonState(void)
{
// sanity check to make sure the buttons are created
if (!m_bHaveButtons) {
return;
}
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume == (CVolume *) NULL){
return;
}
// set the pause/resume text correctly
m_pPauseButton->LoadString(GetDfrgResHandle(), pVolume->Paused() ? IDS_BTN_RESUME : IDS_BTN_PAUSE);
if (m_VolumeList.Locked() || !m_IsOkToRun){
m_pAnalyzeButton->EnableButton(FALSE);
m_pDefragButton->EnableButton(FALSE);
m_pReportButton->EnableButton(FALSE);
m_pPauseButton->EnableButton(FALSE);
m_pStopButton->EnableButton(FALSE);
return;
}
if (pVolume->EngineState() == ENGINE_STATE_RUNNING){ // the selected vol is being analyzed/defragged
m_pAnalyzeButton->EnableButton(FALSE);
m_pDefragButton->EnableButton(FALSE);
m_pPauseButton->EnableButton(TRUE);
m_pStopButton->EnableButton(TRUE);
m_pReportButton->EnableButton(FALSE);
}
else {
m_pAnalyzeButton->EnableButton(TRUE);
m_pDefragButton->EnableButton(TRUE);
m_pPauseButton->EnableButton(FALSE);
m_pStopButton->EnableButton(FALSE);
m_pReportButton->EnableButton(pVolume->IsReportOKToDisplay());
}
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::GetStringWidth
//
// returns: None
// note:
//-------------------------------------------------------------------*
UINT CDfrgCtl::GetStringWidth(PTCHAR stringBuf, HDC WorkDC)
{
if (!stringBuf){
return 0;
}
UINT iStringWidth = 0;
int iCharWidth = 0; //initialize for bugf 445627
for (UINT i=0; i<wcslen(stringBuf); i++){
::GetCharWidth32(
WorkDC,
stringBuf[i],
stringBuf[i],
&iCharWidth);
iStringWidth += iCharWidth;
}
return iStringWidth;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::IsOnlyInstance
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CDfrgCtl::IsOnlyInstance()
{
BOOL fFirst = FALSE;
IDataObject* pData = NULL;
SECURITY_ATTRIBUTES saSecurityAttributes;
SECURITY_DESCRIPTOR sdSecurityDescriptor;
if (CheckForAdminPrivs() == FALSE) {
return FALSE;
}
ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
saSecurityAttributes.bInheritHandle = FALSE;
if (!ConstructSecurityAttributes(&saSecurityAttributes, esatSemaphore, FALSE)) {
return FALSE;
}
#ifdef ESI_MULTI_ALLOWED
return( TRUE );
#endif
if (CheckForAdminPrivs() == FALSE) {
return FALSE;
}
if (m_hIsOkToRunSemaphore == NULL){
m_hIsOkToRunSemaphore = CreateSemaphore(&saSecurityAttributes, 1, 1, IS_OK_TO_RUN_SEMAPHORE_NAME);
}
CleanupSecurityAttributes(&saSecurityAttributes);
ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
if (m_hIsOkToRunSemaphore){
// is the semaphore signaled?
DWORD retValue = WaitForSingleObject(m_hIsOkToRunSemaphore, 10);
// if so, this process is the only one, and the semaphore count is decremented to 0
if (retValue == WAIT_OBJECT_0){
return TRUE;
}
}
return FALSE;
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SendStatusChange
//
// returns: None
// note: Loops through all of the connection points and sends
// the status change message.
//-------------------------------------------------------------------*
void CDfrgCtl::SendStatusChange( LPCTSTR pszStatus )
{
BSTR bszStatus;
if (pszStatus){
bszStatus = SysAllocString( pszStatus );
}
else {
bszStatus = SysAllocString(_T(""));
}
Lock();
IUnknown** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
IDfrgEvents* pEvents = reinterpret_cast<IDfrgEvents*>( *pp );
pEvents->StatusChanged( bszStatus );
}
pp++;
}
Unlock();
SysFreeString( bszStatus );
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::SendOKToRun
//
// returns: None
// note: Loops through all of the connection points and sends
// the new OKToRun property.
//-------------------------------------------------------------------*
void CDfrgCtl::SendOKToRun( BOOL bOK )
{
Lock();
IUnknown** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
IDfrgEvents* pEvents = reinterpret_cast<IDfrgEvents*>( *pp );
pEvents->IsOKToRun( bOK );
}
pp++;
}
Unlock();
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::TranslateAccelerator
//
// returns: None
// note:
//-------------------------------------------------------------------*
STDMETHODIMP CDfrgCtl::TranslateAccelerator(LPMSG pMsg)
{
HRESULT hr = S_FALSE; // we didn't handle keypress
switch( pMsg->message )
{
case WM_KEYDOWN:
{
switch ( pMsg->wParam )
{
case VK_TAB:
{
//
// Check for the shift key.
//
Message(TEXT("CDfrgCtl got a tab key press"), -1, NULL);
if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 )
hr = PreviousTab();
else
hr = NextTab();
}
break;
case VK_SPACE:
Message(TEXT("CDfrgCtl got a spacebar key press"), -1, NULL);
break;
case VK_RETURN:
Message(TEXT("CDfrgCtl got an enter key press"), -1, NULL);
hr = HandleEnterKeyPress();
break;
case VK_F5:
m_ListView.GetDrivesToListView();
hr = S_OK; // we handled keypress
break;
}
}
break;
default:
break;
}
return( hr );
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::PreviousTab
//
// returns: None
// note: Handle moving to the previous tab.
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::PreviousTab()
{
HRESULT hr;
HWND hWndNext = NULL;
CTabEnumerator TabEnum(m_hWndCD, FALSE);
hWndNext = TabEnum.GetNextTabWindow();
if(hWndNext == NULL) //out of memory bug 445628
{
return(S_FALSE);
}
::SetFocus(hWndNext);
if (hWndNext == m_ListView.m_hwndListView)
hr = S_FALSE; // we didn't handle keypress
else
hr = S_OK; // we handled keypress
return(hr);
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::NextTab
//
// returns: None
// note: Handle moving to the next tab.
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::NextTab()
{
HRESULT hr;
HWND hWndNext = NULL;
CTabEnumerator TabEnum(m_hWndCD, TRUE);
hWndNext = TabEnum.GetNextTabWindow();
if(hWndNext == NULL) //out of memory bug 445628
{
return(S_FALSE);
}
::SetFocus(hWndNext);
if (hWndNext == m_ListView.m_hwndListView)
hr = S_FALSE; // we didn't handle keypress
else
hr = S_OK; // we handled keypress
return(hr);
}
//-------------------------------------------------------------------*
// function: CDfrgCtl::GetNextTabWindow
//
// returns: None
// note:
//-------------------------------------------------------------------*
HWND CTabEnumerator::GetNextTabWindow()
{
HWND hWndNext = NULL;
//
// Get the window with the current focus.
//
HWND hWndCurrent = GetFocus();
_ASSERTE( hWndCurrent );
//
// Enumerate our child windows. This should generate
// a list of child windows.
//
EnumChildWindows( m_hWndParent, TabEnumChildren, (LONG_PTR) this );
//
// Find the existing position of the focus window.
//
HWND* pFind = find( m_Children.begin(), m_Children.end(), hWndCurrent );
//
// Determine if we need to wrap around to the beginning.
//
if (m_fForward)
{
if (pFind == m_Children.end() - 1)
pFind = m_Children.begin();
else
pFind++;
}
else
{
if (pFind == m_Children.begin())
pFind = m_Children.end() - 1;
else
pFind--;
}
hWndNext = *pFind;
return(hWndNext);
}
//-------------------------------------------------------------------*
// function: TabEnumChildren
//
// returns: None
// note:
//-------------------------------------------------------------------*
BOOL CALLBACK TabEnumChildren( HWND hwnd, LPARAM lParam )
{
reinterpret_cast<CTabEnumerator*>( lParam )->AddChild( hwnd );
return( TRUE );
}
//-------------------------------------------------------------------*
// function: OnContextMenu
//
// returns: None
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::OnContextMenu(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult)
{
//return( m_ListView.OnContextMenu( (HWND) wParam, LOWORD( lParam ), HIWORD( lParam ) ) );
HRESULT hr = E_NOTIMPL;
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume == (CVolume *) NULL){
return hr;
}
if ( m_ListView.m_hwndListView == (HWND) wParam )
{
HMENU hMenu;
hMenu = ::CreatePopupMenu();
if ( hMenu != NULL )
{
// determine button availability
BOOL AnalDfrgOk = FALSE;
BOOL StopPauseOk = FALSE;
BOOL ReportOk = FALSE;
if (m_VolumeList.Locked() || !m_IsOkToRun) { // UI disabled
AnalDfrgOk = FALSE;
StopPauseOk = FALSE;
ReportOk = FALSE;
}
else if (pVolume->EngineState() == ENGINE_STATE_RUNNING) { // the selected vol is being analyzed/defragged
AnalDfrgOk = FALSE;
StopPauseOk = TRUE;
ReportOk = FALSE;
}
else {
AnalDfrgOk = TRUE;
StopPauseOk = FALSE;
ReportOk = pVolume->IsReportOKToDisplay();
}
TCHAR menuText[200];
UINT uFlags;
//
// Populate context menu.
//
// analyze
::LoadString(GetDfrgResHandle(), IDS_ANALYZE, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (AnalDfrgOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_ANALYZE, menuText);
// defrag
::LoadString(GetDfrgResHandle(), IDS_DEFRAGMENT, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (AnalDfrgOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_DEFRAG, menuText);
if (pVolume->Paused()){ // resume
::LoadString(GetDfrgResHandle(), IDS_RESUME, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_PAUSE, menuText);
}
else { // pause
::LoadString(GetDfrgResHandle(), IDS_PAUSE, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_PAUSE, menuText);
}
// stop
::LoadString(GetDfrgResHandle(), IDS_STOP, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (StopPauseOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_STOP, menuText);
// see report
::LoadString(GetDfrgResHandle(), IDS_REPORT, menuText, sizeof(menuText) / sizeof(TCHAR));
uFlags = MF_STRING | (ReportOk ? MF_ENABLED : MF_GRAYED);
::AppendMenu(hMenu, uFlags, ID_REPORT, menuText);
// separator
::AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
// refresh
::LoadString(GetDfrgResHandle(), IDS_REFRESH, menuText, sizeof(menuText) / sizeof(TCHAR));
::AppendMenu(hMenu, MF_STRING | MF_ENABLED, ID_REFRESH, menuText);
// separator
::AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
// help
::LoadString(GetDfrgResHandle(), IDS_HELP, menuText, sizeof(menuText) / sizeof(TCHAR));
::AppendMenu(hMenu, MF_STRING | MF_ENABLED, ID_HELP_CONTENTS, menuText);
//
// Display pop-up.
//
// get mouse coordinates
short xPos = LOWORD(lParam);
short yPos = HIWORD(lParam);
// get window screen location
RECT rect;
BOOL ok = ::GetWindowRect(m_ListView.m_hwndListView, &rect);
// if we got the window location and the mouse coords are negative,
// assume invoked from keyboard and locate menu in window
if (ok && (xPos < 0 || yPos < 0)) {
xPos = rect.left + 10;
yPos = rect.top + 10;
}
// map menu
TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
xPos,
yPos,
0,
m_hWndCD, //GetParent( m_hwndListView ),
NULL );
::DestroyMenu(hMenu);
hr = S_OK;
}
}
return( hr );
}
STDMETHODIMP CDfrgCtl::get_Enabled(BOOL *pVal)
{
if (m_IsOkToRun)
Message(TEXT("CDfrgCtl::get_Enabled returning TRUE"), -1, NULL);
else
Message(TEXT("CDfrgCtl::get_Enabled returning FALSE"), -1, NULL);
*pVal = m_IsOkToRun;
return S_OK;
}
STDMETHODIMP CDfrgCtl::put_Enabled(BOOL newVal)
{
if (newVal)
Message(TEXT("CDfrgCtl::put_Enabled got TRUE"), -1, NULL);
else
Message(TEXT("CDfrgCtl::put_Enabled got FALSE"), -1, NULL);
return S_OK;
}
//-------------------------------------------------------------------*
// function: OnSetFocus
//
// returns: None
// note:
//-------------------------------------------------------------------*
LRESULT CDfrgCtl::OnSetFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
Message(TEXT("CDfrgCtl::OnSetFocus"), -1, NULL);
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
if (m_bInPlaceActive && spSite)
{
spSite->OnFocus(TRUE);
m_ListView.SetFocus(); // list box gets focus first
}
return 0;
}
LRESULT CDfrgCtl::OnKillFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
Message(TEXT("CDfrgCtl::OnKillFocus"), -1, NULL);
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
if (m_bInPlaceActive && spSite)
spSite->OnFocus(FALSE);
return 0;
}
//-------------------------------------------------------------------*
// function: HandleEnterKeyPress
//
// returns: S_OK: we handled keypress
// S_FALSE: we didn't handle keypress
// note:
//-------------------------------------------------------------------*
HRESULT CDfrgCtl::HandleEnterKeyPress()
{
HWND hWndCurrent = GetFocus(); // current focus window
HRESULT hr = S_FALSE;
if (hWndCurrent == m_pAnalyzeButton->GetWindowHandle())
{
put_Command(ID_ANALYZE);
hr = S_OK;
}
else if (hWndCurrent == m_pDefragButton->GetWindowHandle())
{
put_Command(ID_DEFRAG);
hr = S_OK;
}
else if (hWndCurrent == m_pPauseButton->GetWindowHandle())
{
put_Command(ID_PAUSE);
hr = S_OK;
}
else if (hWndCurrent == m_pStopButton->GetWindowHandle())
{
put_Command(ID_STOP);
hr = S_OK;
}
else if (hWndCurrent == m_pReportButton->GetWindowHandle())
{
// is the engine IDLE?
CVolume *pVolume = m_VolumeList.GetCurrentVolume();
if (pVolume)
{
if(pVolume->EngineState() == ENGINE_STATE_IDLE)
{
RaiseReportDialog(pVolume);
hr = S_OK;
::SetFocus(m_pReportButton->GetWindowHandle());
}
}
}
return hr;
}