www.pudn.com > DiskInfo.tgz > DiskListCtrl.cpp


// DiskListCtrl.cpp : implementation file 
// BY Yuheng Zhao 1999-1 
//  
// To optimize 
// Improve HitTestEx(..) 
// Save ClientRect 
 
#include "stdafx.h" 
#include "diskinfo.h" 
#include "DiskListCtrl.h" 
 
#include "Common/Useful.h" 
#include "Common/memDC.h" 
#include "Common/DrawEx.h" 
 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
int CDiskListCtrl::m_nSortCode; 
///////////////////////////////////////////////////////////////////////////// 
// CDiskListCtrl 
 
CDiskListCtrl::CDiskListCtrl() 
{ 
	m_nMouseInCode = 1000; //0-n buttons -1 - -6 title bar 
	m_nMouseDownCode = 1000; 
	m_bMouseDown = FALSE; 
	m_nSortCode = -100; 
 
	m_nNrThread = 0; 
} 
 
CDiskListCtrl::~CDiskListCtrl() 
{ 
	DeleteAll(); 
} 
 
 
BEGIN_MESSAGE_MAP(CDiskListCtrl, CWnd) 
//{{AFX_MSG_MAP(CDiskListCtrl) 
	ON_WM_PAINT() 
	ON_WM_ERASEBKGND() 
	ON_WM_SETCURSOR() 
	ON_WM_CREATE() 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_TIMER() 
	//}}AFX_MSG_MAP 
	ON_MESSAGE(WM_DISKLIST_UPDATE, OnItemUpdate) 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CDiskListCtrl message handlers 
 
BOOL CDiskListCtrl::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)  
{ 
	// TODO: Add your specialized code here and/or call the base class 
	static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); 
 
	return  CWnd::CreateEx(NULL, ///*WS_EX_CLIENTEDGE  WS_EX_STATICEDGE,  
		className, NULL, dwStyle,  
		rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 
		pParentWnd->GetSafeHwnd(), (HMENU) nID); 
} 
 
CDiskListCtrl::CItemInfo::CItemInfo(CDiskListCtrl* pCtrl) 
{ 
	m_pCtrl = pCtrl; 
	Reset(); 
} 
 
CDiskListCtrl::CItemInfo::~CItemInfo() 
{ 
	StopThread(); 
	 
} 
 
BOOL CDiskListCtrl::CItemInfo::Update() 
{ 
	BOOL bChanged = FALSE; 
	 
	m_nDriveType = ::GetDriveType((LPCTSTR)m_strDriveName); 
	 
	CString strTemp; 
	char driveName[32]; 
	char driveType[32]; 
	DWORD dwDword1, dwDword2, dwDword3; 
	if (::GetVolumeInformation( 
		m_strDriveName, 
		driveName, 32, &dwDword1, &dwDword2, &dwDword3, 
		driveType, 32)) 
	{ 
		if (!m_bAvailable) 
		{ 
			m_bAvailable = TRUE; 
			bChanged = TRUE; 
		} 
		 
		strTemp = driveName; 
		strTemp.MakeLower(); 
		strTemp = strTemp.Right(strTemp.GetLength()-1); 
		strTemp = CString(driveName).Left(1) + strTemp; 
		strTemp += " (" + m_strDriveName.Left(m_strDriveName.GetLength()-1) + ")"; 
		 
		if (strTemp != m_strTitle) 
		{ 
			m_strTitle = strTemp; 
			bChanged = TRUE; 
		} 
		 
		//Type 
		strTemp = driveType; 
		if (strTemp.CompareNoCase(_T("FAT")) == 0) 
			strTemp = _T("FAT16"); 
		if (strTemp != m_strPartitionType) 
		{ 
			m_strPartitionType = strTemp; 
			bChanged = TRUE; 
		} 
	}else 
	{ 
		if (m_nDriveType == DRIVE_REMOVABLE || m_nDriveType ==  
			DRIVE_REMOTE || m_nDriveType == DRIVE_CDROM) 
		{ 
			if (m_bAvailable != FALSE) 
			{ 
				m_bAvailable = FALSE; 
				bChanged = TRUE; 
			} 
		}else 
		{ 
		/* 
		LPVOID lpMsgBuf; 
		 
		  FormatMessage( 
		  FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
		  NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, 
		  SUBLANG_DEFAULT), // Default language 
		  (LPTSTR) &lpMsgBuf, 0, NULL );// Process any inserts in lpMsgBuf. 
		   
			CString strError(m_strDriveName + "..." + CString((LPCSTR)lpMsgBuf)); 
			CFunctionLog log(strError, 5); 
			//MessageBox( NULL, lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); 
			/// Free the buffer. 
			LocalFree( lpMsgBuf );*/ 
		}		 
	} 
	 
	 
	if (m_bAvailable) 
	{ 
		// Spaces 
		DWORD dwFreeSpaceLow; 
		DWORD dwFreeSpaceHigh; 
		DWORD dwTotalSpaceLow; 
		DWORD dwTotalSpaceHigh; 
		if (GetHDSpace(m_strDriveName, dwFreeSpaceLow, dwFreeSpaceHigh, 
			dwTotalSpaceLow, dwTotalSpaceHigh)) 
		{ 
			long double ldTotal = ((long double)dwTotalSpaceHigh)* 
				MAX_DWORD_VALUE + (long double)dwTotalSpaceLow; 
			long double ldFree = ((long double)dwFreeSpaceHigh) *  
				MAX_DWORD_VALUE + (long double)dwFreeSpaceLow; 
			 
			// Total 
			if (ldTotal != m_ldTotalSpace) 
			{ 
				m_ldTotalSpace = ldTotal; 
				bChanged = TRUE; 
			} 
			 
			// Free 
			if (ldFree != m_ldFreeSpace) 
			{ 
				m_ldFreeSpace = ldFree; 
				bChanged = TRUE; 
			} 
		} 
	} 
	 
	return bChanged; 
	 
} 
 
BOOL CDiskListCtrl::AddDrive(const CString &str) 
{ 
	CItemInfo* pItem = new CItemInfo(this); 
	pItem->m_strDriveName = str; 
 
	try  
	{ 
		m_arrayDrive.Add(pItem); 
		return TRUE; 
	} 
	catch (CMemoryException* e) 
	{ 
		CString strTemp, strMes; 
		strTemp.LoadString(IDS_ERR_OUTOFMEM); 
		strMes.Format(strTemp, 2012); 
		AfxMessageBox(strMes); 
 
		if (pItem !=NULL)  
			delete pItem; 
		e->Delete(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
BOOL CDiskListCtrl::AddFolder(const CString &str) 
{ 
	CItemInfo* pItem = new CItemInfo(this); 
	pItem->m_strDriveName = str; 
	if (str.Right(1)!="\\") 
		pItem->m_strDriveName += "\\";	 
 
	try  
	{ 
		m_arrayFolder.Add(pItem); 
		return TRUE; 
	} 
	catch (CMemoryException* e) 
	{ 
		CString strTemp, strMes; 
		strTemp.LoadString(IDS_ERR_OUTOFMEM); 
		strMes.Format(strTemp, 2012); 
		AfxMessageBox(strMes); 
 
		if (pItem !=NULL)  
			delete pItem; 
		e->Delete(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
void CDiskListCtrl::CItemInfo::Reset() 
{ 
	m_bAvailable = FALSE; 
	m_nDriveType = -1; 
	m_strDriveName = _T(""); 
	m_strTitle = _T(""); 
	m_strPartitionType = _T(""); 
 
	m_nFileCount = -1; 
	m_nFolderCount = 0; 
	m_ldTotalSpace = 0;	// Numbers of files in folder mode 
	m_ldFreeSpace = 0;	// Numbers of folders in folder mode 
 
	m_pThread = NULL; 
	m_nThreadCode = 1; 
} 
 
void CDiskListCtrl::DeleteAll() 
{ 
	int nCount = m_arrayDrive.GetSize(); 
	 
	for (int i = 0; i < nCount; i++) 
		delete m_arrayDrive.GetAt(i); 
 
	m_arrayDrive.RemoveAll(); 
 
	EmptyFolderArray(); 
} 
 
void CDiskListCtrl::OnPaint()  
{ 
	CPaintDC dc(this); // device context for painting 
 
	CRect rcClient; 
	GetClientRect(&rcClient); 
	CRect rcItem; 
 
	COLORREF colorFace = GetSysColor(COLOR_BTNFACE); 
	COLORREF colorShadow = GetSysColor(COLOR_3DSHADOW); 
	COLORREF colorLight = GetSysColor(COLOR_3DHILIGHT); 
 
	CMemDC dcMem(&dc); 
 
 
	BOOL bUseBmp = FALSE; 
	if (m_bEnableBackground) 
	{ 
		// Check system color >16 bit 
		bUseBmp = TRUE; //Update later 
	} 
 
	CFont* pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT)); 
	CString strText; 
	//CFont* pOldFont = dcMem.SelectObject(&m_fontTitle); 
	CFont* pOldFont = dcMem.SelectObject(pFont); 
	COLORREF oldTextColor = dcMem.SetTextColor(RGB(0,0,0)); 
	int oldBkMod = dcMem.SetBkMode(TRANSPARENT); 
 
	int nDriveSize = GetDriveSize(); 
	int nFolderSize = GetFolderSize(); 
	if (nDriveSize != 0) 
	{ 
		// Title  
		GetItemRect(rcClient, rcItem, -1, -1); 
		dcMem.FillSolidRect(rcItem, colorFace); 
		 
		// Paint title Text 
		for (int i=1; i<7;i++) 
		{ 
			GetItemRect(rcClient, rcItem, -1, i); 
			 
			switch (i) 
			{ 
			case 1: 
				strText.LoadString(IDS_TITLE); 
				//rectText.left -= 20; 
				break; 
			case 2: 
				strText.LoadString(IDS_TYPE); 
				break; 
			case 3: 
				strText.LoadString(IDS_TOTAL); 
				break; 
			case 4: 
				strText.LoadString(IDS_USAGE);			 
				break; 
			case 5: 
				strText.LoadString(IDS_USED); 
				break; 
			case 6: 
				strText.LoadString(IDS_FREE); 
				break; 
			} 
			 
			if (i == -m_nMouseInCode && (m_nMouseDownCode>=1000 || m_nMouseDownCode == m_nMouseInCode)) 
				dcMem.SetTextColor(RGB(0,0,128)); 
			 
			dcMem.DrawText(strText, rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE); 
			 
			if (i == -m_nMouseInCode && (m_nMouseDownCode>=1000 || m_nMouseDownCode == m_nMouseInCode)) 
			{ 
				dcMem.SetTextColor(RGB(0,0,0)); 
				if (m_bMouseDown) 
					dcMem.Draw3dRect(rcItem, colorShadow, colorLight); 
				else 
					dcMem.Draw3dRect(rcItem, colorLight, colorShadow); 
			} 
		}	 
	} 
 
	// Drive Buttons 
	GetItemRect(rcClient, rcItem, -2, -1); 
	if (bUseBmp && !m_bmpDriveBack.IsEmpty()) 
		m_bmpDriveBack.FillDIB(&dcMem, rcItem); 
	else 
		dcMem.FillSolidRect(rcItem, colorLight); 
 
	GetItemRect(rcClient, rcItem, -2, 6); 
	if (bUseBmp && !m_bmpFreeBack.IsEmpty()) 
		m_bmpFreeBack.FillDIB(&dcMem, rcItem); 
	else 
		dcMem.FillSolidRect(rcItem, colorFace); 
 
	//GetItemRect(rcClient, rcItem, -3, 6); 
	//dcMem.FillSolidRect(rcItem, colorFace); 
 
	// Folder buttons 
	GetItemRect(rcClient, rcItem, -4, -1); 
	if (bUseBmp && !m_bmpFolderBack.IsEmpty()) 
		m_bmpFolderBack.FillDIB(&dcMem, rcItem); 
	else 
		dcMem.FillSolidRect(rcItem, colorLight); 
 
	// High light 
	if (m_nMouseInCode>=0 && m_nMouseInCode<1000 && 
		(m_nMouseDownCode>=1000 || m_nMouseDownCode == m_nMouseInCode)) 
	{ 
		GetItemRect(rcClient, rcItem, m_nMouseInCode, -1); 
		if (m_bMouseDown) 
		{ 
			if (bUseBmp && !m_bmpPressedBack.IsEmpty()) 
				m_bmpPressedBack.FillDIB(&dcMem, rcItem); 
			else 
				dcMem.FillSolidRect(rcItem, colorFace); 
			 
			dcMem.Draw3dRect(rcItem, colorShadow, colorLight); 
		}else 
		{ 
			if (bUseBmp && !m_bmpHighBack.IsEmpty()) 
				m_bmpHighBack.FillDIB(&dcMem, rcItem); 
			else 
				dcMem.FillSolidRect(rcItem, colorFace); 
			 
			dcMem.Draw3dRect(rcItem, colorLight, colorShadow); 
		} 
	} 
 
	// Border 
	GetItemRect(rcClient, rcItem, -5, -1); 
	dcMem.Draw3dRect(rcItem, colorShadow, colorLight); 
 
	// Total info Button 
	if (nDriveSize != 0) 
	{ 
		GetItemRect(rcClient, rcItem, -3, -1); 
		rcItem.InflateRect(1,0); 
		if (nFolderSize == 0) 
			rcItem.bottom ++; 
		if (bUseBmp && !m_bmpTotalBack.IsEmpty()) 
			m_bmpTotalBack.FillDIB(&dcMem, rcItem); 
		else 
			dcMem.FillSolidRect(rcItem, colorFace); 
		rcItem.DeflateRect(2,0); 
		if (nFolderSize != 0) 
			dcMem.DrawEdge(rcItem, BDR_RAISEDINNER, BF_BOTTOM|BF_TOP); 
		else 
			dcMem.DrawEdge(rcItem, BDR_RAISEDINNER, BF_TOP); 
	} 
 
	 
 
	for (int i = 0; i < nDriveSize; i++) 
		DrawDrive(&dcMem, rcClient, i); 
 
	for (i = 0; i < nFolderSize; i++) 
		DrawFolder(&dcMem, rcClient, i); 
 
	//pFont = CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FONT)); 
	//dcMem.SelectObject(pFont); 
	dcMem.SetTextColor(RGB(0,0,128)); 
 
	if (nDriveSize != 0) 
		DrawTotalItem(&dcMem, rcClient); 
 
	dcMem.SelectObject(pOldFont);		 
	dcMem.SetTextColor(oldTextColor); 
	dcMem.SetBkMode(oldBkMod); 
} 
 
BOOL CDiskListCtrl::OnEraseBkgnd(CDC* pDC)  
{ 
	return TRUE; 
} 
 
void CDiskListCtrl::GetItemRect(const CRect &rcClient,  
								CRect &rc, int nType, int nPos) 
{ 
	// nType -1 = titlebar 
	// nType -2 = All Drivebuttons 
	// nType -3 = total info button 
	// nType -4 = All folderbuttons 
	// nType -5 = Border rect 
	// nType 0- = for button number 
 
	CRect rcC(rcClient); 
	rcC.DeflateRect(1,1,1,1); 
	rc = rcC; 
	int nDriveSize = GetDriveSize(); 
 
	int nHeight = GetItemHeight(rcClient); 
	int nTitleHeight = GetItemHeight(rcClient, TRUE); 
 
	switch (nType) 
	{ 
	case -1: 
		rc.top = 0; 
		rc.bottom = nTitleHeight; 
		rc.left -= 1; 
		rc.right += 1; 
		break; 
	case -2: 
		rc.top = nTitleHeight + 1; // Plus border 
		rc.bottom = rc.top + nHeight*nDriveSize; 
		break; 
	case -3: 
		rc.top = nTitleHeight + 1 + nHeight*nDriveSize; // Plus border 
		rc.bottom = rc.top + nHeight; 
 
		rc.left -= 1; 
		rc.right += 1; 
		break; 
	case -4: 
		rc.top = nTitleHeight + 1 + nHeight*(nDriveSize+(nDriveSize!=0)); // Plus border 
		rc.bottom = rc.top + nHeight*GetFolderSize(); 
		break; 
	case -5: 
		rc.top = nTitleHeight; 
		rc.bottom = rcC.bottom+1; 
		rc.left -= 1; 
		rc.right += 1; 
		break; 
	default: 
		if (nType>=100) // Folders 
			rc.top = nTitleHeight + 1 + nHeight*((nType-100)+(nDriveSize!=0)+nDriveSize); 
		else 
			rc.top = nTitleHeight + 1 + nHeight*nType; 
 
		rc.bottom = rc.top + nHeight;		 
	} 
	 
	 
	if (nPos == -1) 
		return; 
	// nPos -1 = Max Width 
	// nPos 0-n = for every column 
 
	// nPos in percent 
	// 4 20 11 15 15,6 15,6 18,8 
	// 0 <= nCode <= 6 
 
	// Drive item rects 
	if (nType<100) 
	{ 
		double dWidth[7] = {0.04, 0.242, 0.11, 0.156, 0.14, 0.156, 0.156}; 
	 
		double dOff = 0; 
		int nTotal = rcC.Width(); 
		for (int i=0; i -1; i--) 
	{ 
		if (!m_arrayItem.GetAt(i)->m_bIsDrive) 
			nCount --; 
	} 
	 
	return nCount;*/ 
} 
 
int CDiskListCtrl::GetFolderSize() 
{ 
	return m_arrayFolder.GetSize(); 
	/* 
	for (int i = nCount-1; i > -1; i--) 
	{ 
		if (m_arrayItem.GetAt(i)->m_bIsDrive) 
			nCount --; 
	} 
	 
	return nCount;*/ 
} 
 
BOOL CDiskListCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)  
{ 
	SetCursor(LoadCursor(NULL, IDC_ARROW)); 
 
	return TRUE; 
} 
 
void CDiskListCtrl::DrawTotalItem(CDC *pDC, const CRect& rcClient) 
{ 
	int nCount; 
	long double ldTotal, ldFree; 
	GetTotalUsage(nCount, ldTotal, ldFree); 
 
	CRect rcItem; 
	// Draw Total info 
	GetItemRect(rcClient, rcItem, -3, 1); 
	CString str, str1; 
	str1.LoadString(IDS_TOTAL_DRIVES); 
	str.Format(str1, nCount); 
	pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);	 
	 
	GetItemRect(rcClient, rcItem, -3, 3); 
	FormatByteSize(ldTotal, str); 
	pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
	 
	long double ldUsed = ldTotal - ldFree; 
	GetItemRect(rcClient, rcItem, -3, 4); 
	rcItem.DeflateRect(0, 2); 
	str.Format("%.0f%%", (ldTotal==0)?0:(ldUsed/ldTotal)*100); 
	DrawPercentBar(pDC, rcItem, (ldTotal==0)?0:ldUsed/ldTotal,  
		str, GetFont()); 
	 
	GetItemRect(rcClient, rcItem, -3, 5); 
	FormatByteSize(ldUsed, str); 
	pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
	 
	GetItemRect(rcClient, rcItem, -3, 6); 
	FormatByteSize(ldFree, str); 
	pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
} 
 
void CDiskListCtrl::DrawFolder(CDC *pDC, const CRect& rcClient, int nItem) 
{ 
	CRect rcItem; 
	CItemInfo* pItem = m_arrayFolder.GetAt(nItem); 
	CString str, strTemp; 
 
	// Image 
	GetItemRect(rcClient, rcItem, nItem+100, 0); 
	rcItem.left += (rcItem.Width() - 16) / 2; 
	rcItem.top += (rcItem.Height() - 16) / 2; 
	if (pItem->m_pThread) 
		m_imgTypeList.Draw(pDC, 7, rcItem.TopLeft(), ILD_NORMAL); 
	else 
		m_imgTypeList.Draw(pDC, 6, rcItem.TopLeft(), ILD_NORMAL); 
 
	GetItemRect(rcClient, rcItem, nItem+100, 1); 
	rcItem.left += 2; 
	rcItem.right -= 2; 
	::DrawTextEx (pDC->m_hDC, 
                pItem->m_strDriveName.GetBuffer (0), 
                pItem->m_strDriveName.GetLength(), 
                &rcItem, 
                DT_SINGLELINE | DT_VCENTER | DT_LEFT | DT_PATH_ELLIPSIS, 
                NULL); 
	 
	if (pItem->GetFinished()) 
	{ 
		GetItemRect(rcClient, rcItem, nItem+100, 2); 
		rcItem.left += 2; 
		strTemp.LoadString(IDS_COUNT_FOLDER); 
		str.Format(strTemp, pItem->m_nFolderCount); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_LEFT); 
		 
		GetItemRect(rcClient, rcItem, nItem+100, 3); 
		rcItem.left += 2; 
		strTemp.LoadString(IDS_COUNT_FILE); 
		str.Format(strTemp, pItem->m_nFileCount); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_LEFT); 
		 
		GetItemRect(rcClient, rcItem, nItem+100, 4); 
		rcItem.left += 2; 
		FormatByteSize(pItem->m_ldTotalSpace, str); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_LEFT); 
	}else 
	{ 
		GetItemRect(rcClient, rcItem, nItem+100, 2); 
		rcItem.left += 2; 
		str.LoadString(IDS_ABORTED); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_LEFT); 
	} 
 
	// Alert indicator 
	GetItemRect(rcClient, rcItem, nItem+100, 5); 
	rcItem.left += 2; 
	rcItem.top += (rcItem.Height() - 16) / 2; 
	double dMb = pItem->m_ldTotalSpace / (1024*1024); 
	int nMode = ( dMb> m_dRedAlert)? 2 :  
				((dMb > m_dYellowAlert)? 1 : 0); 
 
	for (int i=0; i<3; i++) 
	{ 
		m_imgTypeList.Draw(pDC, 8 + ((nMode==i && (pItem->GetFinished()))?i+1:0), rcItem.TopLeft(), ILD_NORMAL); 
		rcItem.left += 16; 
	} 
 
} 
 
void CDiskListCtrl::DrawDrive(CDC *pDC, const CRect& rcClient, int nItem) 
{ 
	CRect rcItem; 
	CItemInfo* pItem = m_arrayDrive.GetAt(nItem); 
 
	// Image 
	GetItemRect(rcClient, rcItem, nItem, 0); 
	rcItem.left += (rcItem.Width() - 16) / 2; 
	rcItem.top += (rcItem.Height() - 16) / 2; 
 
	switch (pItem->m_nDriveType) 
	{ 
	case DRIVE_REMOVABLE: 
		m_imgTypeList.Draw(pDC, 0, rcItem.TopLeft(), ILD_NORMAL); 
		break; 
		 
	case DRIVE_FIXED: 
		m_imgTypeList.Draw(pDC, 1, rcItem.TopLeft(), ILD_NORMAL); 
		break; 
		 
	case DRIVE_REMOTE: 
		if (pItem->m_bAvailable) 
			m_imgTypeList.Draw(pDC, 3, rcItem.TopLeft(), ILD_NORMAL); 
		else 
			m_imgTypeList.Draw(pDC, 4, rcItem.TopLeft(), ILD_NORMAL); 
		break; 
		 
		 
	case DRIVE_CDROM: 
		m_imgTypeList.Draw(pDC, 2, rcItem.TopLeft(), ILD_NORMAL); 
		break; 
		 
	case DRIVE_RAMDISK: 
		m_imgTypeList.Draw(pDC, 5, rcItem.TopLeft(), ILD_NORMAL); 
		break; 
	} 
 
	CString str, strText; 
								 
	if (pItem->m_bAvailable) 
	{	 
		// Draw Title 
		GetItemRect(rcClient, rcItem, nItem, 1); 
		pDC->DrawText(pItem->m_strTitle, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
		 
		//Draw Type 
		GetItemRect(rcClient, rcItem, nItem, 2); 
		pDC->DrawText(pItem->m_strPartitionType, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
		 
		// Total 
		GetItemRect(rcClient, rcItem, nItem, 3); 
		//rcItem.right-=10; 
		FormatByteSize(pItem->m_ldTotalSpace, str); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
		 
		 
		long double ldUsed = pItem->m_ldTotalSpace - pItem->m_ldFreeSpace; 
		// Draw Usage 
		GetItemRect(rcClient, rcItem, nItem, 4); 
		rcItem.DeflateRect(0, 2); 
		str.Format("%.0f%%", pItem->GetUsage() * 100); 
		DrawPercentBar(pDC, rcItem, pItem->GetUsage(),  
			str, GetFont()); 
		 
		// Used 
		GetItemRect(rcClient, rcItem, nItem, 5); 
		FormatByteSize(ldUsed, str); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
		 
		// Free in bold font 
		GetItemRect(rcClient, rcItem, nItem, 6); 
		FormatByteSize(pItem->m_ldFreeSpace, str); 
		pDC->DrawText(str, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
	}else 
	{ 
		if (pItem->m_nDriveType == DRIVE_CDROM || 
			pItem->m_nDriveType == DRIVE_REMOVABLE ) 
			str.LoadString(IDS_NODISK); 
		else 
			str.LoadString(IDS_NOTAVAILABLE); 
		 
		strText.Format(str, pItem->m_strDriveName); 
		GetItemRect(rcClient, rcItem, nItem, -1); 
		pDC->DrawText(strText, rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER); 
	} 
} 
 
void CDiskListCtrl::Update(BOOL bFolders) 
{ 
	int nCount = m_arrayDrive.GetSize(); 
	BOOL bUpdate = FALSE; 
	CItemInfo* pItem; 
 
	for (int i = 0; i < nCount; i++) 
	{ 
		pItem = m_arrayDrive.GetAt(i); 
			if (pItem->Update()) 
				bUpdate = TRUE; 
	} 
	 
	if (bFolders) 
	{ 
		nCount = m_arrayFolder.GetSize(); 
		 
		for (i = 0; i < nCount; i++) 
		{ 
			pItem = m_arrayFolder.GetAt(i); 
			pItem->UpdateFolder(i+100); 
		} 
	} 
 
	if (bUpdate) 
		InvalidateRect(NULL, FALSE); 
} 
 
int CDiskListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
	InitCtrl(); 
	 
	return 0; 
} 
 
void CDiskListCtrl::InitCtrl() 
{ 
	// Delete all 
	if (!m_bmpDriveBack.IsEmpty()) m_bmpDriveBack.DestroyBitmap(); 
	if (!m_bmpFreeBack.IsEmpty()) m_bmpFreeBack.DestroyBitmap(); 
	if (!m_bmpTotalBack.IsEmpty()) m_bmpTotalBack.DestroyBitmap(); 
	if (!m_bmpFolderBack.IsEmpty()) m_bmpFolderBack.DestroyBitmap(); 
	if (!m_bmpHighBack.IsEmpty()) m_bmpHighBack.DestroyBitmap(); 
	if (!m_bmpPressedBack.IsEmpty()) m_bmpPressedBack.DestroyBitmap(); 
 
	if (m_fontTitle.m_hObject) 
		m_fontTitle.DeleteObject(); 
 
	if (m_imgTypeList.m_hImageList) 
		m_imgTypeList.DeleteImageList(); 
	 
	m_fontTitle.CreateFont(16, 0,0,0,FW_NORMAL, 0,0,0, 
		DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, 
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); 
 
	HINSTANCE hIns = AfxGetResourceHandle(); 
	AfxSetResourceHandle(AfxGetInstanceHandle()); 
	m_imgTypeList.Create(IDB_TYPE_LIST_SMALL, 16, 0, RGB(255,0,255)); 
	AfxSetResourceHandle(hIns); 
 
	CWinApp* app = AfxGetApp(); 
	CString strPath = GetHomeDirectory(); 
 
	m_bEnableBackground = app->GetProfileInt("Settings", "EnableBackground",   1); 
	CString strBmpDrive = app->GetProfileString("Settings", "BmpDrive",   strPath+"images\\Drive.bmp"); 
	CString strBmpFolder = app->GetProfileString("Settings", "BmpFolder",   strPath+"images\\Folder.bmp"); 
	CString strBmpFree = app->GetProfileString("Settings", "BmpFree",   strPath+"images\\Free.bmp"); 
	CString strBmpHigh = app->GetProfileString("Settings", "BmpHigh",   strPath+"images\\High.bmp"); 
	CString strBmpPressed = app->GetProfileString("Settings", "BmpPressed",   strPath+"images\\Pressed.bmp"); 
	CString strBmpTotal = app->GetProfileString("Settings", "BmpTotal",   strPath+"images\\Total.bmp"); 
 
 
	if (m_bEnableBackground) 
	{ 
		m_bmpDriveBack.Load(strBmpDrive); 
		m_bmpFreeBack.Load(strBmpFree); 
		m_bmpTotalBack.Load(strBmpTotal); 
		m_bmpFolderBack.Load(strBmpFolder); 
		m_bmpHighBack.Load(strBmpHigh); 
		m_bmpPressedBack.Load(strBmpPressed); 
	} 
 
	InvalidateRect(NULL, FALSE); 
} 
 
void CDiskListCtrl::GetTotalUsage(int& nCount, long double &ldTotal, long double &ldFree) 
{ 
	int nSize = m_arrayDrive.GetSize(); 
	ldTotal = 0; 
	ldFree = 0; 
	nCount = 0; 
	 
	for (int i = 0; i < nSize; i++) 
	{ 
		CItemInfo* pItem = m_arrayDrive.GetAt(i); 
		if (pItem->m_bAvailable) 
		{ 
			nCount ++; 
			ldTotal += pItem->m_ldTotalSpace; 
			ldFree += pItem->m_ldFreeSpace; 
		} 
	} 
} 
 
void CDiskListCtrl::OnMouseMove(UINT nFlags, CPoint point)  
{ 
	if (GetActiveWindow() == NULL || GetOwner() == NULL) 
		return; 
 
	int nOldCode = m_nMouseInCode; 
 
	int nCode = HitTestEx(point); 
 
	if (nFlags & MK_LBUTTON) 
		m_bMouseDown = TRUE; 
	else 
	{ 
		m_bMouseDown = FALSE; 
		m_nMouseDownCode = 1000; 
	} 
 
	if (m_nMouseInCode != nCode) 
	{ 
		int nOld = m_nMouseInCode; 
		m_nMouseInCode = nCode; 
		RedrawItem(nOld); 
		RedrawItem(m_nMouseInCode); 
 
		KillTimer(5); 
		SetTimer(5,10,NULL); 
	} 
 
	 
 
	CWnd::OnMouseMove(nFlags, point); 
} 
 
void CDiskListCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	if (m_nMouseInCode<1000) 
	{ 
		int n = HitTestEx(point); 
		VERIFY(m_nMouseInCode == n); 
		m_nMouseDownCode = n; 
 
		if (!m_bMouseDown) 
			m_bMouseDown = TRUE; 
 
		RedrawItem(m_nMouseInCode); 
 
/* 
		CRect rcClient, rcItem; 
		GetClientRect(&rcClient); 
		GetItemRect(rcClient, rcItem, n, -1); 
		CString str; 
		str.Format("%d,%d, %d, %d", rcItem.left, rcItem.top, rcItem.right, rcItem.bottom); 
 
		MessageBox(str); 
*/ 
	} 
	 
	CWnd::OnLButtonDown(nFlags, point); 
} 
 
void CDiskListCtrl::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	if (m_nMouseInCode<1000 && m_nMouseDownCode== m_nMouseInCode) 
	{ 
		int n = HitTestEx(point); 
		 
		if (m_bMouseDown) 
		{ 
			if (m_nMouseInCode == n) 
			{ 
				m_bMouseDown = FALSE; 
				m_nMouseDownCode = 1000; 
				RedrawItem(m_nMouseInCode); 
 
				if (m_nMouseInCode < 0) // Sort 
					SortItems(-m_nMouseInCode); 
				else 
				{ 
					if (m_nMouseInCode>=100) 
						GetOwner()->SendMessage(WM_DISKLIST_NOTIFY, NULL,  
							(LPARAM)m_arrayFolder.GetAt(m_nMouseInCode-100)); 
					else 
						GetOwner()->SendMessage(WM_DISKLIST_NOTIFY, NULL,  
							(LPARAM)m_arrayDrive.GetAt(m_nMouseInCode)); 
				} 
				 
				/* 
				CRect rcClient, rcItem; 
				GetClientRect(&rcClient); 
				if (n>=0) 
					GetItemRect(rcClient, rcItem, n, -1); 
				else 
					GetItemRect(rcClient, rcItem, -1, -n); 
				CString str; 
				str.Format("Item %d : %d,%d, %d, %d", m_nMouseInCode, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom); 
				 
				MessageBox(str);*/ 
			}else 
			{ 
				int nOld = m_nMouseInCode; 
				m_bMouseDown = FALSE; 
				m_nMouseInCode = 1000; 
				m_nMouseDownCode = 1000; 
				RedrawItem(nOld); 
			} 
		} 
	}else 
	{ 
		m_bMouseDown = FALSE; 
		m_nMouseDownCode = 1000; 
		RedrawItem(m_nMouseInCode); 
	} 
	 
	CWnd::OnLButtonUp(nFlags, point); 
} 
 
int CDiskListCtrl::HitTestEx(CPoint pt) 
{ 
	int nCount = m_arrayDrive.GetSize(); 
 
	CRect rcClient, rcItem; 
	GetClientRect(&rcClient); 
	int nHeight; 
 
	if (nCount>0) 
	{ 
		GetItemRect(rcClient, rcItem, 0, -1); 
		nHeight = rcItem.Height(); 
		rcItem.bottom += nHeight*(nCount-1); 
		if (rcItem.PtInRect(pt)) 
			return (pt.y - rcItem.top) / nHeight;		 
	} 
 
	//Check Folders 
	nCount = m_arrayFolder.GetSize(); 
	if (nCount>0) 
	{ 
		GetItemRect(rcClient, rcItem, 100, -1); 
		nHeight = rcItem.Height(); 
		rcItem.bottom += nHeight*(nCount-1); 
		if (rcItem.PtInRect(pt)) 
			return ((pt.y - rcItem.top) / nHeight)+100;		 
	} 
/* 
	for (int i=0; i=100) // Folders 
			rc.top = nTitleHeight + 1 + nHeight*((nType-100)+(nDriveSize!=0)+nDriveSize); 
		else 
			rc.top = nTitleHeight + 1 + nHeight*nType; 
 
		rc.bottom = rc.top + nHeight;		 
	} 
	 
	 
	if (nPos == -1) 
		return; 
	// nPos -1 = Max Width 
	// nPos 0-n = for every column 
 
	// nPos in percent 
	// 4 20 11 15 15,6 15,6 18,8 
	// 0 <= nCode <= 6 
 
	// Drive item rects 
	if (nType<100) 
	{ 
		double dWidth[7] = {0.04, 0.242, 0.11, 0.156, 0.14, 0.156, 0.156}; 
	 
		double dOff = 0; 
		int nTotal = rcC.Width(); 
		for (int i=0; i=0) 
	{ 
		GetItemRect(rcClient, rcItem, i, -1); 
		//rcItem.bottom +=2; 
		InvalidateRect(rcItem, FALSE); 
		return; 
	} 
 
	// Check Title bar 
	GetItemRect(rcClient, rcItem, -1, -i); 
	InvalidateRect(rcItem, FALSE); 
} 
 
void CDiskListCtrl::OnTimer(UINT nIDEvent)  
{ 
	if (m_nMouseInCode < 1000) 
	{ 
		CPoint pt; 
		if (!GetCursorPos(&pt)) 
			return; 
		ScreenToClient(&pt); 
		 
		CRect rcClient; 
		GetClientRect(&rcClient); 
 
		if (!rcClient.PtInRect(pt)) 
		{ 
			KillTimer(5); 
 
			int nOld = m_nMouseInCode; 
			m_nMouseInCode = 1000; 
			//m_bMouseDown = FALSE; 
			//m_nMouseDownCode = 1000; 
 
			RedrawItem(nOld); 
		} 
	}	 
	CWnd::OnTimer(nIDEvent); 
} 
 
void CDiskListCtrl::SortItems(int n) 
{ 
	int nSize = m_arrayDrive.GetSize(); 
	if (nSize>0) 
	{ 
		if (m_nSortCode == n) 
			m_nSortCode = -n; 
		else 
			m_nSortCode = n; 
 
		qsort((void*)(m_arrayDrive.GetData()),  
				((size_t)nSize),  
				sizeof(m_arrayDrive.GetAt(0)), 
				CompareItemSize); 
 
		InvalidateRect(NULL, FALSE); 
	} 
} 
 
 
int CDiskListCtrl::CompareItemSize(const void* f1, const void* f2) 
{ 
	CItemInfo* pItem1 = *(CItemInfo**)f1; 
	CItemInfo* pItem2 = *(CItemInfo**)f2; 
 
	if (!pItem2->m_bAvailable && abs(m_nSortCode)!=1) 
		return -1; 
	else if (!pItem1->m_bAvailable && abs(m_nSortCode)!=1) 
		return 1; 
 
	switch (m_nSortCode) 
	{ 
	case 1: 
		return (long)pItem1->m_strDriveName.CompareNoCase(pItem2->m_strDriveName);		 
	case 2: 
		return (long)pItem1->m_strPartitionType.CompareNoCase(pItem2->m_strPartitionType); 
	case 3: // Total 
		return (int)(pItem1->m_ldTotalSpace/1048576 - pItem2->m_ldTotalSpace/1048576); 
	case 4: //Usage 
		return (long)((pItem1->GetUsage() - pItem2->GetUsage())*100); 
	case 5: // Used 
		return (long)((pItem1->m_ldTotalSpace - pItem1->m_ldFreeSpace - pItem2->m_ldTotalSpace 
			+ pItem2->m_ldFreeSpace)/1048576); 
	case 6: // Free 
		return (long)((pItem1->m_ldFreeSpace - pItem2->m_ldFreeSpace)/1048576); 
 
	case -1: 
		return (long)pItem2->m_strDriveName.CompareNoCase(pItem1->m_strDriveName);		 
	case -2: 
		return (long)pItem2->m_strPartitionType.CompareNoCase(pItem1->m_strPartitionType); 
	case -3: // Total 
		return (long)(pItem2->m_ldTotalSpace/1048576 - pItem1->m_ldTotalSpace/1048576); 
	case -4: //Usage 
		return (long)((pItem2->GetUsage() - pItem1->GetUsage())*100); 
	case -5: // Used 
		return (long)((pItem2->m_ldTotalSpace - pItem2->m_ldFreeSpace - pItem1->m_ldTotalSpace 
			+ pItem1->m_ldFreeSpace)/1048576); 
	case -6: // Free 
		return (long)((pItem2->m_ldFreeSpace - pItem1->m_ldFreeSpace)/1048576); 
	} 
 
	return 0; 
} 
 
int CDiskListCtrl::GetSize() 
{ 
	return m_arrayDrive.GetSize() + m_arrayFolder.GetSize(); 
} 
 
double CDiskListCtrl::CItemInfo::GetUsage() 
{ 
	return (m_ldTotalSpace==0)?0:((m_ldTotalSpace-m_ldFreeSpace)/m_ldTotalSpace); 
} 
 
void CDiskListCtrl::CItemInfo::UpdateFolder(int nItemCode) 
{ 
	if (m_pThread) 
		return; 
 
	m_nFileCount = 0; 
	m_nFolderCount = 0; 
	m_ldTotalSpace = 0;	// Numbers of files in folder mode 
 
	 // Create a process to update folder info 
	THREADPARAMS* pThreadParams = new THREADPARAMS; 
 
	strcpy(pThreadParams->charPath, m_strDriveName); 
	pThreadParams->nItemCode = nItemCode; 
 
	pThreadParams->pnThreadCode = &m_nThreadCode; 
	pThreadParams->pnFileCount = &m_nFileCount; 
	pThreadParams->pnFolderCount = &m_nFolderCount; 
	pThreadParams->pldTotalSpace = &m_ldTotalSpace; 
	pThreadParams->lParam = (LPARAM)m_pCtrl; 
 
	m_pThread = AfxBeginThread(ThreadFunc, pThreadParams, THREAD_PRIORITY_BELOW_NORMAL); 
		 
	//.... 
} 
 
UINT CDiskListCtrl::CItemInfo::ThreadFunc(LPVOID pParam) 
{ 
	THREADPARAMS* pThreadParams = (THREADPARAMS*)pParam; 
/* 
	CString strPath = pThreadParams->strPath; 
	int nItemCode = pThreadParams->nItemCode; 
 
	int* pnThreadCode = pThreadParams->pnThreadCode; 
	int* pnFileCount = pThreadParams->pnFileCount; 
	int* pnFolderCount = pThreadParams->pnFolderCount; 
	long double* pldTotalSpace = pThreadParams->pldTotalSpace; 
	CDiskListCtrl* pCtrl = (CDiskListCtrl*)pThreadParams->lParam; 
*/ 
	((CDiskListCtrl*)pThreadParams->lParam)->OnStartUpdate(pThreadParams->nItemCode); 
 
	UpdateDir(pThreadParams); 
 
	((CDiskListCtrl*)pThreadParams->lParam)->PostMessage(WM_DISKLIST_UPDATE, NULL, 
				LPARAM(pThreadParams->nItemCode)); 
	((CDiskListCtrl*)pThreadParams->lParam)->OnFinishedUpdate(pThreadParams->nItemCode); 
	 
	delete pThreadParams; 
 
	return 0; 
} 
 
void CDiskListCtrl::CItemInfo::UpdateDir(THREADPARAMS* pThreadParams) 
{ 
	HANDLE hFind; 
    WIN32_FIND_DATA fd; 
 
	char charCmp[MAX_PATH], charPath[MAX_PATH]; 
	strcpy(charPath, pThreadParams->charPath); 
	strcpy(charCmp, charPath); 
	strcat(charCmp, "*.*");	 
 
    if ((hFind = ::FindFirstFile ((LPCTSTR) charCmp, &fd)) == 
        INVALID_HANDLE_VALUE)  
	{ 
        return; 
    } 
 
    do { 
		if (*(pThreadParams->pnThreadCode) == -1) 
			break; 
 
		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  
		{ 
			strcpy(charCmp, (LPCTSTR) &fd.cFileName); 
 
			if ((strcmp(charCmp, ".")!=0) && (strcmp(charCmp, "..")!=0))  
			{ 
				(*(pThreadParams->pnFolderCount)) ++; 
				strcat(pThreadParams->charPath, charCmp); 
				strcat(pThreadParams->charPath, "\\"); 
				UpdateDir(pThreadParams); 
				strcpy(pThreadParams->charPath, charPath); 
            } 
        }else 
		{ 
			(*(pThreadParams->pnFileCount)) ++; 
			(*(pThreadParams->pldTotalSpace)) += fd.nFileSizeLow; 
		} 
 
		if (*(pThreadParams->pnThreadCode) == -1) 
			break; 
		if (((*(pThreadParams->pnFileCount))+(*(pThreadParams->pnFileCount))) % 299 == 0) 
		{ 
			((CDiskListCtrl*)pThreadParams->lParam)->PostMessage(WM_DISKLIST_UPDATE, NULL, 
				LPARAM(pThreadParams->nItemCode)); 
		//((CDiskListCtrl*)pThreadParams->lParam)->RedrawItem(pThreadParams->nItemCode); 
			Sleep(1); 
		}else 
			Sleep(0); 
    } while (::FindNextFile (hFind, &fd)); 
     
	::FindClose (hFind); 
} 
 
void CDiskListCtrl::OnStopAll() 
{ 
	int nCount = m_arrayFolder.GetSize(); 
	 
	for (int i = 0; i < nCount; i++) 
		m_arrayFolder.GetAt(i)->StopThread(); 
} 
 
void CDiskListCtrl::OnPause() 
{ 
 
} 
 
void CDiskListCtrl::OnFinishedUpdate(int n) 
{ 
	CItemInfo* pItem = m_arrayFolder.GetAt(n-100); 
	pItem ->m_nThreadCode = 1; 
	pItem ->m_pThread = NULL; 
 
	m_nNrThread --; 
 
	RedrawItem(n); 
} 
 
void CDiskListCtrl::OnStartUpdate(int n) 
{ 
	m_nNrThread ++; 
} 
 
void CDiskListCtrl::CItemInfo::StopThread() 
{ 
	if (m_pThread) 
	{ 
		m_nThreadCode = -1; 
		HANDLE hThread = m_pThread->m_hThread; 
		::WaitForSingleObject(hThread, INFINITE); 
		m_pThread = NULL; 
		m_nFileCount = -1; 
	} 
} 
 
inline BOOL CDiskListCtrl::CItemInfo::GetFinished() 
{ 
	return m_nFileCount!=-1; 
} 
 
void CDiskListCtrl::UpdateAbortedFolders() 
{ 
	int nCount = m_arrayFolder.GetSize(); 
 
	CItemInfo* pItem; 
	for (int i = 0; i < nCount; i++) 
	{ 
		pItem = m_arrayFolder.GetAt(i); 
		if (!pItem->GetFinished()) 
			pItem->UpdateFolder(i+100); 
	} 
} 
 
void CDiskListCtrl::OnItemUpdate(WPARAM wParam, LPARAM lParam) 
{ 
	RedrawItem((int)lParam);	 
} 
 
 
void CDiskListCtrl::EmptyFolderArray() 
{ 
	int nCount = m_arrayFolder.GetSize(); 
	 
	for (int i = 0; i < nCount; i++) 
		delete m_arrayFolder.GetAt(i); 
 
	m_arrayFolder.RemoveAll(); 
}