www.pudn.com > countingsrc.rar > CountingDlg.cpp


/************************************************************* 
* 源码统计器1.0版 
*  作者:魏镇江 
*  Email: xiaogi@sohu.com 
*  homepage: http://xiaogi.nease.net 
*  版权所有(C) 2004.1. 
**************************************************************/ 
// CountingDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "Counting.h" 
#include "CountingDlg.h" 
#include "FolderDialog.h" 
#include "HyperLink.h" 
 
#include "PropertyDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
#include "CreditStatic.h" 
 
///////////////////////////////////////////////////////////////////////////// 
// CAboutDlg dialog used for App About 
 
class CAboutDlg : public CDialog 
{ 
public: 
	CAboutDlg(); 
 
private: 
	UINT m_nCreditTimer; 
	UINT m_nIconTimer; 
	CCreditStatic m_static; 
 
// Dialog Data 
	//{{AFX_DATA(CAboutDlg) 
	enum { IDD = IDD_ABOUTBOX }; 
	CHyperLink	m_ctrlMyEmail; 
	CHyperLink	m_ctrlMyHomepage; 
	CStatic	m_ctlCount; 
	//}}AFX_DATA 
 
	// ClassWizard generated virtual function overrides 
	//{{AFX_VIRTUAL(CAboutDlg) 
	protected: 
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support 
	//}}AFX_VIRTUAL 
 
// Implementation 
protected: 
	//{{AFX_MSG(CAboutDlg) 
	afx_msg void OnTimer(UINT nIDEvent); 
	virtual BOOL OnInitDialog(); 
	//}}AFX_MSG 
	DECLARE_MESSAGE_MAP() 
}; 
 
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 
{ 
	//{{AFX_DATA_INIT(CAboutDlg) 
	//}}AFX_DATA_INIT 
	m_nIconTimer = NULL; 
	m_nCreditTimer = NULL; 
} 
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CAboutDlg) 
	DDX_Control(pDX, IDC_MYEMAIL, m_ctrlMyEmail); 
	DDX_Control(pDX, IDC_MYHOMEPAGE, m_ctrlMyHomepage); 
	DDX_Control(pDX, IDC_COUNTICON, m_ctlCount); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
	//{{AFX_MSG_MAP(CAboutDlg) 
	ON_WM_TIMER() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
char *pArrCredit = { 
"IDB_COUNT^|" 
"源码统计器1.1\t|" 
"版权所有(c) 2004.1.\r|" 
"软件设计者\t|魏镇江\r|" 
"E-mail: xiaogi@sohu.com\r||" 
"主页: http://xiaogi.nease.net\r||" 
"IDB_COUNT^|" 
 
"★ “源码统计器”使用说明 ★\t|" 
"最新更新下载:http://xiaogi.nease.net\r||" 
 
"软件说明:               \t||" 
 
"在工作中,我们经常碰到客户要求告之所写程\r|" 
"序的行数,包括代码行、注释行和空白行等。\r|" 
"本软件就是为了这一目的编写的,最先是用于\r|" 
"对我自己写的C/C++,VC++程序进行行数统计\r|" 
"。它可以准确地计算出源代码中的各种行数。\r|" 
"后来经过不断改进,增加了对VB, Java, ASP,\r|" 
"JSP和SQL等程序的源代码的统计,使得软件的\r|" 
"应用范围更加广泛。网络上也有不少类似统计\r|" 
"行数的软件,但到目前为止,我发现我的这个\r|" 
"源码统计器统计速度是最快的,而且相比较发\r|" 
"现更加准确,考虑到了源码中的许多特殊情况\r|" 
"(如引号之间有/*,或/*之后有//,或//之后\r|" 
"有/*等)。               \r||" 
 
"使用方法:               \t||" 
 
"在“文件名或文件类型”组合框中输入你需要\r|" 
"进行统计的文件类型(如:*.cpp;*.c;*.h),\r|" 
"扩展名之间用;,:分隔。你也可以直接输入需 \r|" 
"要统计的文件名(如:a.cpp;b.c;c.h),同样\r|" 
"的,文件名之间也用;,:分隔。点击下拉框可 \r|" 
"以选择软件缺省为你提供的几种文件类型,点\r|" 
"击右边的按钮可以选择需要进行统计文件(可\r|" 
"多选,并且软件自动将选中文件所在目录放入\r|" 
"“搜索文件夹”组合框中)。       \r||" 
 
"在“搜索文件夹”组合框中输入你需要进行统\r|" 
"计的文件所在的文件夹(如:d:\\study),点\r|" 
"击下拉框可以选择近几次选择的文件夹。如果\r|" 
"你手动输入的文件夹不在下拉框中,那软件在\r|" 
"统计开始后将自动加入。点击右边的按钮可以\r|" 
"选择文件夹。              \r||" 
 
"你可以选择统计时是否也需要统计子文件夹中\r|" 
"的相关文件。              \r||" 
 
"点击“统计”按钮开始,再次点击该按钮停止\r|" 
"统计。                 \r||" 
 
"若你需要保存统计结果,请点击“保存”按钮\r|" 
"。你可以选择以文本文件或csv文件两种格式 \r|" 
"保存。其中csv文件可被几乎所有的统计软件 \r|" 
"识别,包括微软Office系列的Excel.    \r||" 
 
"软件可稳定地运行于MS Windows系列操作系统\r|" 
"上。                  \r||" 
 
"作者声明:               \t||" 
 
"本软件为自由软件,源代码完全公开。你可以\r|" 
"来信索要并不受限制地利用,但务请保留作者\r|" 
"的版权信息。若你觉得本软件对你有帮助或你\r|" 
"需要将其中部分的代码用到自己的软件中,请\r|" 
"给作者来信告知。如果你对本软件有好的建议\r|" 
"或bug 发现,也请来信告知。       \r|" 
"我的Email:xiaogi@sohu.com       \r|" 
"个人主页:http://xiaogi.nease.net     \r||" 
 
"            xiaogi     \r|" 
"            2002年11月   \r|||" 
}; 
 
BOOL CAboutDlg::OnInitDialog()  
{ 
	CDialog::OnInitDialog(); 
	 
	// TODO: Add extra initialization here 
	m_ctrlMyEmail.SetURL("mailto:xiaogi@sohu.com"); 
	m_ctrlMyHomepage.SetURL("http://xiaogi.nease.net"); 
 
 
	m_static.SubclassDlgItem(IDC_DISPLAY_HELP,this); 
	m_static.SetCredits(pArrCredit,'|'); 
	m_static.SetColor(BACKGROUND_COLOR, RGB(0,0,255)); 
	m_static.SetTransparent(); 
	m_static.StartScrolling(); 
	m_nCreditTimer = SetTimer(ABOUT_CREDIT_TIMER,5000,NULL); 
    ASSERT(m_nCreditTimer != 0); 
 
	m_nIconTimer = SetTimer(ABOUT_ICON_TIMER, 200, NULL); 
    ASSERT(m_nIconTimer != 0); 
 
	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
/***************************************************************** 
	动态显示About对话框中的图标 
*****************************************************************/ 
 
void CAboutDlg::OnTimer(UINT nIDEvent)  
{ 
	// TODO: Add your message handler code here and/or call default 
	if(nIDEvent != (UINT)m_nIconTimer) 
		return; 
	static int big_icons[] = 
	{ IDI_BIG_ICON1, IDI_BIG_ICON2, IDI_BIG_ICON3, IDI_BIG_ICON4, 
	IDI_BIG_ICON5, IDI_BIG_ICON6, IDI_BIG_ICON7}; 
	 
	static long big_index = 0; 
 
	HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), 
		MAKEINTRESOURCE(big_icons[big_index++%7]), 
		IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);//SM_CXICON  
	m_ctlCount.SendMessage(STM_SETICON, (WPARAM)hIcon, 0); 
//	CDialog::OnTimer(nIDEvent); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CCountingDlg dialog 
 
CCountingDlg::CCountingDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CCountingDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CCountingDlg) 
	m_strFiles = _T(""); 
	m_bIncludeSubfolder = TRUE; 
	m_strComboExt = _T(""); 
	m_strComboFolder = _T(""); 
	m_strSize = _T(""); 
	m_strCommentLines = _T(""); 
	m_strBlankLines = _T(""); 
	m_strCodeLines = _T(""); 
	m_strTotalLines = _T(""); 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
	m_CountingStatus = STOP; 
	m_nTimer = NULL; 
	m_nSysTimer = NULL; 
	m_nStatMethod = 1; 
} 
 
CCountingDlg::~CCountingDlg() 
{ 
} 
 
void CCountingDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CCountingDlg) 
//	DDX_Control(pDX, IDC_SAVE, m_ctrlSave); 
	DDX_Control(pDX, IDC_COUNTINGICON, m_ctrlCountingIcon); 
	DDX_Control(pDX, IDC_SIZES, m_ctrlSize); 
	DDX_Control(pDX, IDC_RESULT, m_ctlResult); 
	DDX_Control(pDX, IDC_COMBO_FOLDER, m_ctlFolder); 
	DDX_Control(pDX, IDC_COMBO_EXTENSION, m_ctlExtension); 
	DDX_Text(pDX, IDC_FILES, m_strFiles); 
	DDX_Check(pDX, IDC_INCLUDE_SUBFOLDER, m_bIncludeSubfolder); 
	DDX_CBString(pDX, IDC_COMBO_EXTENSION, m_strComboExt); 
	DDX_CBString(pDX, IDC_COMBO_FOLDER, m_strComboFolder); 
	DDX_Text(pDX, IDC_SIZES, m_strSize); 
	DDX_Text(pDX, IDC_COMMENT, m_strCommentLines); 
	DDX_Text(pDX, IDC_BLANK, m_strBlankLines); 
	DDX_Text(pDX, IDC_CODE, m_strCodeLines); 
	DDX_Text(pDX, IDC_TOTAL, m_strTotalLines); 
	//}}AFX_DATA_MAP 
	DDX_Control(pDX, IDC_COUNT, m_btnCount); 
	DDX_Control(pDX, IDC_SAVE, m_btnSave); 
	DDX_Control(pDX, IDC_PROPERTY, m_btnProperty); 
	DDX_Control(pDX, IDC_ABOUT, m_btnAbout); 
	DDX_Control(pDX, IDC_QUIT, m_btnQuit); 
} 
 
BEGIN_MESSAGE_MAP(CCountingDlg, CDialog) 
	//{{AFX_MSG_MAP(CCountingDlg) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDC_SAVE, OnSave) 
	ON_BN_CLICKED(IDC_COUNT, OnCount) 
	ON_BN_CLICKED(IDC_BROWSE_FOLDER, OnBrowseFolder) 
	ON_BN_CLICKED(IDC_BROWSE_EXT, OnBrowseExt) 
	ON_WM_TIMER() 
	ON_BN_CLICKED(IDC_QUIT, OnQuit) 
	ON_BN_CLICKED(IDC_ABOUT, OnAbout) 
	ON_BN_CLICKED(IDC_PROPERTY, OnProperty) 
	//}}AFX_MSG_MAP 
//	ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnNeedText) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CCountingDlg message handlers 
 
BOOL CCountingDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Add "About..." menu item to system menu. 
 
	// IDM_ABOUTBOX must be in the system command range. 
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
	ASSERT(IDM_ABOUTBOX < 0xF000); 
 
	CMenu* pSysMenu = GetSystemMenu(FALSE); 
	if (pSysMenu != NULL) 
	{ 
		CString strAboutMenu; 
		strAboutMenu.LoadString(IDS_ABOUTBOX); 
		if (!strAboutMenu.IsEmpty()) 
		{ 
			pSysMenu->AppendMenu(MF_SEPARATOR); 
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
		} 
	} 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	HICON hIcon = AfxGetApp()->LoadIcon(IDI_SMALLICON); 
	SetIcon(hIcon, FALSE);		// Set small icon 
 
	m_structExtention.arrayType.Add("cpp"); //0 
	m_structExtention.arrayType.Add("c");	//1 
	m_structExtention.arrayType.Add("h");	//2 
	m_structExtention.arrayType.Add("txt");	//3 
	m_structExtention.arrayType.Add("wri");	//4 
	m_structExtention.arrayType.Add("tli");	//5 
	m_structExtention.arrayType.Add("tlh");	//6 
	m_structExtention.arrayType.Add("rc");	//7 
	m_structExtention.arrayType.Add("dsw");	//8 
	m_structExtention.arrayType.Add("hpj");	//9 
	m_structExtention.arrayType.Add("htm");	//10 
	m_structExtention.arrayType.Add("html");//11 
	m_structExtention.arrayType.Add("cxx");	//12 
	m_structExtention.arrayType.Add("hpp");	//13 
	m_structExtention.arrayType.Add("def");	//14 
	m_structExtention.arrayType.Add("java");//15 
	m_structExtention.arrayType.Add("frm");	//16 
	m_structExtention.arrayType.Add("bas");	//17 
	m_structExtention.arrayType.Add("ctl");	//18 
	m_structExtention.arrayType.Add("cls");	//19 
	m_structExtention.arrayType.Add("asp");	//20 
	m_structExtention.arrayType.Add("jsp");	//21 
	m_structExtention.arrayType.Add("sql");	//22 
	m_structExtention.arrayType.Add("pl");	//23 
	m_structExtention.arrayType.Add("sh");	//24 
	m_structExtention.arrayType.Add("*");	//25 
 
	m_structExtention.nType[0] = TYPE_CPP; 
	m_structExtention.nType[1] = TYPE_C; 
	m_structExtention.nType[2] = TYPE_H; 
	m_structExtention.nType[3] = TYPE_TXT; 
	m_structExtention.nType[4] = TYPE_WRI; 
	m_structExtention.nType[5] = TYPE_H; 
	m_structExtention.nType[6] = TYPE_H; 
	m_structExtention.nType[7] = TYPE_RC; 
	m_structExtention.nType[8] = TYPE_DSW; 
	m_structExtention.nType[9] = TYPE_HPJ; 
	m_structExtention.nType[10] = TYPE_HTM; 
	m_structExtention.nType[11] = TYPE_HTM; 
	m_structExtention.nType[12] = TYPE_CPP; 
	m_structExtention.nType[13] = TYPE_H; 
	m_structExtention.nType[14] = TYPE_OTH; 
	m_structExtention.nType[15] = TYPE_JAVA; 
	m_structExtention.nType[16] = TYPE_VB; 
	m_structExtention.nType[17] = TYPE_VB; 
	m_structExtention.nType[18] = TYPE_VB; 
	m_structExtention.nType[19] = TYPE_VB; 
	m_structExtention.nType[20] = TYPE_ASP; 
	m_structExtention.nType[21] = TYPE_JSP; 
	m_structExtention.nType[22] = TYPE_SQL; 
	m_structExtention.nType[23] = TYPE_PERL; 
	m_structExtention.nType[24] = TYPE_SHELL; 
	m_structExtention.nType[25] = TYPE_OTH; 
 
	//设置按钮图标等 
	m_btnCount.SetIcon(IDI_COUNT); 
	m_btnCount.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30); 
	m_btnCount.SetRounded(TRUE); 
	m_btnCount.SetSound(MAKEINTRESOURCE(IDR_WAVEHOVER), ::GetModuleHandle(NULL)); 
	m_btnCount.SetBtnCursor(IDC_HAND); 
 
	m_btnSave.SetIcon(IDI_SAVE); 
	m_btnSave.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30); 
	m_btnSave.SetRounded(TRUE); 
	m_btnSave.SetSound(MAKEINTRESOURCE(IDR_WAVEHOVER), ::GetModuleHandle(NULL)); 
	m_btnSave.SetBtnCursor(IDC_HAND); 
 
	m_btnProperty.SetIcon(IDI_PROP); 
	m_btnProperty.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30); 
	m_btnProperty.SetRounded(TRUE); 
	m_btnProperty.SetSound(MAKEINTRESOURCE(IDR_WAVEHOVER), ::GetModuleHandle(NULL)); 
	m_btnProperty.SetBtnCursor(IDC_HAND); 
 
	m_btnAbout.SetIcon(IDI_ABOUT); 
	m_btnAbout.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30); 
	m_btnAbout.SetRounded(TRUE); 
	m_btnAbout.SetSound(MAKEINTRESOURCE(IDR_WAVEHOVER), ::GetModuleHandle(NULL)); 
	m_btnAbout.SetBtnCursor(IDC_HAND); 
 
	m_btnQuit.SetIcon(IDI_QUIT); 
	m_btnQuit.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30); 
	m_btnQuit.SetRounded(TRUE); 
	m_btnQuit.SetSound(MAKEINTRESOURCE(IDR_WAVEHOVER), ::GetModuleHandle(NULL)); 
	m_btnQuit.SetBtnCursor(IDC_HAND); 
 
	//文件夹选择框设置MRU 
	m_ctlFolder.SetMRURegKey ( _T("Combobox MRU folder") ); 
	m_ctlFolder.SetMRUValueFormat ( _T("String #%d") ); 
 
	m_ctlFolder.SetAutoRefreshAfterAdd ( TRUE ); 
	m_ctlFolder.SetAutoSaveAfterAdd ( TRUE ); 
 
	m_ctlFolder.LoadMRU(); 
	m_ctlFolder.RefreshCtrl(); 
 
	//设置ListCtrl属性 
	DWORD oldStyle = m_ctlResult.GetExtendedStyle(); 
	m_ctlResult.SetExtendedStyle(oldStyle |LVS_EX_FULLROWSELECT|LVS_EX_TRACKSELECT|LVS_EX_UNDERLINEHOT|LVS_EX_GRIDLINES); 
 
	CString str; 
	str.LoadString(IDS_FILENAME); 
	m_ctlResult.InsertColumn(0,  str, LVCFMT_LEFT, 120, -1); 
	str.LoadString(IDS_PATHNAME); 
	m_ctlResult.InsertColumn(1,  str, LVCFMT_LEFT, 120, -1); 
	str.LoadString(IDS_TOTALLINE); 
	m_ctlResult.InsertColumn(2,  str, LVCFMT_RIGHT, 70, -1); 
	str.LoadString(IDS_CODELINE); 
	m_ctlResult.InsertColumn(3,  str, LVCFMT_RIGHT, 70, -1); 
	str.LoadString(IDS_COMMENTLINE); 
	m_ctlResult.InsertColumn(4,  str, LVCFMT_RIGHT, 70, -1); 
	str.LoadString(IDS_BLANKLINE); 
	m_ctlResult.InsertColumn(5,  str, LVCFMT_RIGHT, 70, -1); 
	str.LoadString(IDS_FILETYPE); 
	m_ctlResult.InsertColumn(6,  str, LVCFMT_LEFT, 120, -1); 
 
	//获取log文件路径 
	char pathname[_MAX_PATH]; 
	char drive[_MAX_DRIVE]; //由于读取动态鼠标时还要用,所以改成成员变量 
	char dir[_MAX_DIR]; 
	char fname[_MAX_FNAME]; 
	char ext[_MAX_EXT]; 
 
	GetModuleFileName(NULL, pathname, _MAX_PATH);//可执行文件所在目录 
	_splitpath(pathname, drive, dir, fname, ext); 
	_makepath(pathname, drive, dir, "log", "txt"); 
 
	m_strLogFile = pathname; 
 
	m_nSysTimer = SetTimer(SYS_TIMER, 200, NULL);//左上角图标动画 
 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CCountingDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
	if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
	{ 
		CAboutDlg dlgAbout; 
		dlgAbout.DoModal(); 
	} 
	else 
	{ 
		CDialog::OnSysCommand(nID, lParam); 
	} 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CCountingDlg::OnPaint()  
{ 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CCountingDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
/*********************************************************** 
* 当按下ESC键时,确认是否退出 
***********************************************************/ 
void CCountingDlg::OnCancel()  
{ 
	// TODO: Add extra cleanup here 
	CString str1, str2; 
	str1.LoadString(IDS_TOQUIT); 
	str2.LoadString(IDS_MESSAGE); 
	if(MessageBox(str1, str2, MB_YESNO)==IDNO) 
	{ 
		return ; 
	} 
	CDialog::OnCancel(); 
} 
 
/*********************************************************** 
* 将统计保存为文本文件和csv文件 
***********************************************************/ 
void CCountingDlg::OnSave()  
{ 
	// TODO: Add your control notification handler code here 
	if(0==m_ctlResult.GetItemCount()) 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_UNSTARTED); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
		return; 
	} 
 
	if(m_CountingStatus == COUNTING) 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_WAITING); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
		return; 
	} 
 
	CFileDialog dlgFile( 
		FALSE, _T("*.txt"), NULL, 
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
		NULL, this); 
	dlgFile.m_ofn.lStructSize = sizeof(OPENFILENAME); 
	dlgFile.m_ofn.lpstrFilter = "文本文件(*.txt)\0*.txt\0Excel 文件(*.xls)\0*.xls\0CSV 文件(*.csv)\0*.csv\0\0"; 
	dlgFile.m_ofn.lpstrTitle = "选择保存统计结果的文件"; 
	if (dlgFile.DoModal() == IDCANCEL) 
		return ; 
 
	CString sPath = dlgFile.GetPathName(); 
	CString sExt = dlgFile.GetFileExt(); 
	sExt.MakeLower(); 
 
	if(sExt == "txt") 
		SaveAsTextFile((LPCTSTR)sPath); 
	else if(sExt == "csv") 
		SaveAsCSVFile((LPCTSTR)sPath); 
	else if(sExt == "xls") 
		SaveAsExcelFile((LPCTSTR)sPath); 
	else 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_WRONGTYPE); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
	} 
 
	CString str1, str2; 
	str1.LoadString(IDS_SAVEOVER); 
	str2.Format("%s:%s", str1, sPath); 
	GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str2); 
} 
 
/******************************************************* 
点击“统计”按钮,开始统计 
********************************************************/ 
void CCountingDlg::OnCount()  
{ 
	// TODO: Add your control notification handler code here 
	if(m_CountingStatus == COUNTING) 
	{ 
		m_CountingStatus = STOP; 
		return; 
	} 
	UpdateData(TRUE); 
 
	if(m_strComboExt.Find(_T("**")) != -1||m_strComboFolder.Find(_T("**")) != -1) 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_INVALIDFILE); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
		return; 
	} 
 
	if(m_strComboExt.IsEmpty()) 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_INPUT_FILE); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
		return; 
	} 
 
	if(m_strComboFolder.IsEmpty()) 
	{ 
		CString str1, str2; 
		str1.LoadString(IDS_COUNTING_PATH); 
		str2.LoadString(IDS_MESSAGE); 
		MessageBox(str1, str2); 
		return; 
	} 
 
	if(m_ctlFolder.FindStringExact(-1, m_strComboFolder)==CB_ERR) 
	{ 
		m_ctlFolder.AddToMRU((LPCTSTR)m_strComboFolder); 
	} 
 
	m_btnCount.SetIcon(IDI_COUNTSTOP); 
	CString str; 
	str.LoadString(IDS_STOP); 
	m_btnCount.SetWindowText(str); 
	 
	m_imageList.DeleteImageList(); 
	m_imageList.Create(16, 16, ILC_MASK|ILC_COLORDDB, 1, 100); 
	m_ctlResult.SetImageList(&m_imageList, LVSIL_SMALL); 
 
	m_ctlResult.DeleteAllItems(); 
	m_nItemCountSet = 1000; 
	m_ctlResult.SetItemCount(m_nItemCountSet); 
 
	char strCurrentDirectory[_MAX_PATH]; 
	GetCurrentDirectory(_MAX_PATH, strCurrentDirectory); 
	m_strCurrentDir = strCurrentDirectory; //保存当前路径以便线程结束后恢复 
 
	SetCurrentDirectory(m_strComboFolder);//set directory to count 
 
	m_nTotalLines = 0;//initialize 
	m_nCodeLines = 0; 
	m_nCommentLines = 0; 
	m_nBlankLines = 0; 
	m_nFiles = 0; 
	m_nSize = 0; 
 
	m_nTimer = SetTimer(COUNTING_TIMER, 200, NULL); 
	m_CountingStatus = COUNTING; 
 
	HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_BIG_ICON2), 
		IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);//SM_CXICON  
	m_ctrlCountingIcon.SendMessage(STM_SETICON, (WPARAM)hIcon, 0); 
 
	char buf[_MAX_PATH]; 
	GetCurrentDirectory(_MAX_PATH, buf); 
	//开始线程 
	CWinThread* pThread = AfxBeginThread(CountThread, this); 
} 
 
/******************************************************************* 
* Extract one extension from strExtension, and assign it to strOneOfExt 
* for example: strExtension = "*.cpp;*.c;*.h" 
*	then,	1st time: strOneOfExt = "*.cpp",  
*			2nd time: strOneOfExt = "*.c", 
*			3rd time: strOneOfExt = "*.h", 
*	return: TRUE: extracted successfully 
*			FALSE: strExtension is empty.  
*********************************************************************/ 
BOOL CCountingDlg::ExtractExtension(CString & strOneOfExt, CString & strExtension) 
{ 
	strExtension.TrimLeft(); 
 
	if(strExtension.IsEmpty()) 
		return FALSE; 
 
	int nLength = strExtension.GetLength(); 
 
	int nFirst = strExtension.FindOneOf(";,:"); 
	if(nFirst == -1) //there may be only one extension in strExtsion 
		nFirst = nLength; 
	strOneOfExt = strExtension.Left(nFirst); 
 
	if(nFirst == nLength) 
		strExtension.Empty(); 
	else 
		strExtension = strExtension.Right(nLength-1-nFirst);//rest 
 
	strOneOfExt.TrimLeft();//trim whitespace 
	strOneOfExt.TrimRight(); 
 
	return TRUE; 
} 
 
/******************************************************************* 
* find file type according to its extension 
* for example: strExtension = "xiaogi.c" 
*	return: TYPE_C 
*********************************************************************/ 
int CCountingDlg::FindFileType(CString strFile) 
{ 
	int nLast = strFile.ReverseFind('.'); 
	CString extNoDot = strFile.Right(strFile.GetLength()-nLast-1); 
 
	for(int i=0; im_strComboFolder[pThis->m_strComboFolder.GetLength()-1]=='\\') 
		strPath = pThis->m_strComboFolder + "*.*"; 
	else 
		strPath = pThis->m_strComboFolder + "\\*.*"; 
 
	do{ 
		bWorking = finder.FindFile(strPath); 
		while(bWorking  && pThis->m_CountingStatus==COUNTING) 
		{ 
			bWorking = finder.FindNextFile(); 
			CString strFilePath = finder.GetFilePath(); 
			if(finder.IsDots()) 
				continue; 
 
			if(finder.IsDirectory()) 
			{ 
				if(pThis->m_bIncludeSubfolder) 
					listPaths.AddHead(strFilePath); 
				continue; 
			} 
			else 
			{ 
				if(pThis->IsSearchingFor(strFilePath)) 
				{ 
					CString str1, str2; 
					str1.LoadString(IDS_COUNTINGFILE); 
					str2.Format("%s:%s", str1, strFilePath); 
					pThis->GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str2); 
 
					int nType; 
					nType = pThis->FindFileType(strFilePath); 
					if(nType == -1) 
						nType = TYPE_OTH; 
 
					int nLines=0; 
					int nCodeLines=0; 
					int nCommentLines=0; 
					int nBlankLines=0; 
					int nLength=0; 
 
					switch(nType) 
					{ 
					case TYPE_C: 
					case TYPE_CPP: 
					case TYPE_H: 
					case TYPE_JAVA: 
						nLines = pThis->GetCppFileLines((LPCTSTR)strFilePath, &nLength, &nCodeLines, &nCommentLines, &nBlankLines); 
						break; 
					case TYPE_VB: 
					case TYPE_ASP: 
						nLines = pThis->GetVBFileLines((LPCTSTR)strFilePath, &nLength, &nCodeLines, &nCommentLines, &nBlankLines); 
						break; 
					case TYPE_SQL: 
//						nLines = pThis->GetSqlFileLines((LPCTSTR)strFilePath, &nLength, &nCodeLines, &nCommentLines, &nBlankLines); 
						break; 
					case TYPE_JSP: 
						//AfxMessageBox("jsp文件目前还不提供统计"); 
						break; 
					case TYPE_PERL: 
					case TYPE_SHELL: 
						nLines = pThis->GetPerlFileLines((LPCTSTR)strFilePath, &nLength, &nCodeLines, &nCommentLines, &nBlankLines); 
						break; 
					default: 
						nLines = pThis->GetTxtFileLines((LPCTSTR)strFilePath, &nLength, &nCodeLines, &nCommentLines, &nBlankLines); 
						break; 
					} 
 
					//下行在1.0以后的版本中删掉,nCodeLines由函数计算 
//					nCodeLines = nLines - nCommentLines - nBlankLines; 
 
					int pos=strFilePath.ReverseFind('\\'); 
 
					if(pThis->m_nFiles > pThis->m_nItemCountSet) 
						pThis->m_nItemCountSet += 1000; 
					pThis->m_ctlResult.SetItemCount(pThis->m_nItemCountSet); 
 
					SHFILEINFO sfi; 
					if (::SHGetFileInfo (strFilePath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO),SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_TYPENAME |SHGFI_ICON|SHGFI_SMALLICON )) 
					{	 
						CString str; 
						pThis->m_imageList.Add(sfi.hIcon); 
						pThis->m_ctlResult.InsertItem(pThis->m_nFiles,sfi.szDisplayName,pThis->m_nFiles); 
 
     					pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 1, strFilePath.Mid(0,pos)); 
						str.Format("%d", nLines); 
    					pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 2, str); 
						str.Format("%d", nCodeLines); 
    					pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 3, str); 
						str.Format("%d", nCommentLines); 
    					pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 4, str); 
						str.Format("%d", nBlankLines); 
    					pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 5, str); 
						pThis->m_ctlResult.SetItemText(pThis->m_nFiles, 6, sfi.szTypeName); 
					} 
 
					pThis->m_ctlResult.Update(pThis->m_nFiles); 
 
					pThis->m_nFiles++; 
					pThis->m_nSize += nLength; 
					pThis->m_nTotalLines += nLines; 
					pThis->m_nCodeLines += nCodeLines; 
					pThis->m_nCommentLines += nCommentLines; 
					pThis->m_nBlankLines += nBlankLines; 
 
					pThis->UpdateResult(); 
				} 
			} 
		} 
		if(listPaths.IsEmpty()) 
			break; 
 
		strFolder = listPaths.RemoveHead(); 
		strPath = strFolder + "\\*.*"; 
		finder.Close(); 
	}while(pThis->m_CountingStatus==COUNTING); 
 
	if(pThis->m_nTimer!=NULL) 
	{ 
		pThis->KillTimer(pThis->m_nTimer); 
		pThis->m_nTimer = NULL; 
	} 
 
	CString str1; 
	if(pThis->m_CountingStatus==STOP) 
		str1.LoadString(IDS_ABORT); //用户强行终止 
	else 
		str1.LoadString(IDS_COUNTINGSTOP); 
	pThis->GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str1); 
 
	pThis->m_CountingStatus = STOP; 
 
	pThis->m_btnCount.SetIcon(IDI_COUNT); 
	CString str; 
	str.LoadString(IDS_COUNT); 
	pThis->m_btnCount.SetWindowText(str); 
 
	HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_BIG_ICON1), 
		IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);//SM_CXICON  
	pThis->m_ctrlCountingIcon.SendMessage(STM_SETICON, (WPARAM)hIcon, 0); 
 
	return 0; 
} 
 
//////////////////////////////////////////////////////////// 
//modify a path with file name to without file name 
// such as:  
//   modify:  d:\\temp\\countingdlg.cpp 
//        to:   d:\\temp 
// 
//////////////////////////////////////////////////////////// 
CString CCountingDlg::GetPurePath(CString strPath) 
{ 
	int nLast = strPath.ReverseFind('\\'); 
	return strPath.Left(nLast); 
} 
 
/****************************************************************** 
*  往一字符串strText中追加空格,使其长度达到num 
*  bAtEnd : TRUE表示在字符串后面追加空格 
*			  FALSE表示在字符串前面追加空格 
*    若strText的长度本来就大于num,则将最后三个字符改为... 
*******************************************************************/ 
CString CCountingDlg::TextAppendSpace(CString strText, int num, BOOL bAtEnd) 
{ 
	CString str; 
	if(strText.GetLength()>=num) 
	{ 
		str = strText.Left(num-3); 
		str += "..."; 
	} 
	else 
	{ 
		str = strText; 
		for(int i=strText.GetLength(); i=nLength2) 
				return TRUE; 
 
			while(i=nLength1) 
				return FALSE; 
 
			continue; 
		} 
		if(inputFile[j]=='?') 
		{ 
			continue; 
		} 
		if(inputFile[j]==strFile[i]) 
		{ 
			continue; 
		} 
		else 
			return FALSE; 
	} 
 
	if(i==nLength1&&j==nLength2) 
		return TRUE; 
	else 
		return FALSE; 
} 
 
/***************************************************************** 
	统计开始后动态显示图标,表示统计进行中 
*****************************************************************/ 
 
void CCountingDlg::OnTimer(UINT nIDEvent)  
{ 
	// TODO: Add your message handler code here and/or call default 
	if(nIDEvent == (UINT)m_nSysTimer) 
	{//左上角动态图标 
		static int icons[] = 
		{ IDI_ICON1, IDI_ICON2, IDI_ICON3, IDI_ICON4, IDI_ICON5, IDI_ICON6,  
		IDI_ICON7, IDI_ICON8, IDI_ICON9, IDI_ICON10, IDI_ICON10}; 
		 
		static long index = 0; 
 
		index = ++index%10; 
 
		HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(icons[index]), 
			IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);//SM_CXICON  
		HICON hPrevIcon = (HICON)AfxGetMainWnd()->SendMessage(WM_SETICON,ICON_SMALL,(LPARAM)hIcon); 
 
		return; 
	} 
	if(nIDEvent != (UINT)m_nTimer) 
		return; 
 
	static int icons[] = 
	{ IDI_BIG_ICON1, IDI_BIG_ICON2, IDI_BIG_ICON3, IDI_BIG_ICON4, IDI_BIG_ICON5, IDI_BIG_ICON6,  
	IDI_BIG_ICON7}; 
	 
	static long index = 0; 
 
	HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(icons[index++%7]), 
		IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);//SM_CXICON  
	m_ctrlCountingIcon.SendMessage(STM_SETICON, (WPARAM)hIcon, 0); 
} 
 
 
/***************************************************************** 
	确定是否退出 
*****************************************************************/ 
void CCountingDlg::OnQuit()  
{ 
	// TODO: Add your control notification handler code here 
	CString str1, str2; 
	str1.LoadString(IDS_TOQUIT); 
	str2.LoadString(IDS_MESSAGE); 
	if(MessageBox(str1, str2, MB_YESNO)==IDNO) 
	{ 
		return ; 
	} 
	CDialog::OnCancel(); 
} 
 
/********************************************************* 
	统计c++文件 
*********************************************************/ 
int CCountingDlg::GetCppFileLines(LPCTSTR strFileName, int* pnLength, int *pnCodeLines, int* pnCommentLines, int* pnBlankLines) 
{ 
	//there are two methods to count lines in files, by CStdioFile or CFile 
	*pnLength = 0; 
	*pnCodeLines = 0; 
	*pnCommentLines = 0; 
	*pnBlankLines = 0; 
 
	CStdioFile file; 
	if(file.Open(strFileName, CFile::modeRead)==FALSE) 
		return 0; 
 
	int nLines = 0; 
	int nCodeLines = 0; 
	int nCommentLines = 0; 
	int nBlankLines = 0; 
 
	BOOL bCommentSet = FALSE; //注释行统计标识 有"/*"时TRUE, "*/"时FALSE 
	BOOL bQuatoSet = FALSE;   //字符串统计标识 首次一行有奇数个"时TRUE, 下一行有奇数个"时FALSE 
 
	int nLength = file.GetLength(); 
	*pnLength = nLength; 
 
	CString bufRead; 
 
	int nLineCommentBegin = 0; 
	while(file.ReadString(bufRead)!=FALSE) 
	{ 
		BOOL bStatedComment = FALSE;//本行作为注释行是否已统计过 
		BOOL bStatedCode = FALSE;   //本行作为代码行是否已统计过 
 
		nLines++; 
 
		bufRead.TrimLeft(); //先将文件头的空格或制表符去掉 
 
		if(bufRead.GetLength()==0) //为空白行 
		{ 
			nBlankLines++; 
			continue; 
		} 
 
		if(bCommentSet && bufRead.Find("*/")==-1) 
		{ 
			nCommentLines++; 
			continue; 
		} 
 
		if(bufRead.Find("//")==-1 && bufRead.Find("/*")==-1 && bufRead.Find("*/")==-1) 
		{//如果本行根本就无注释符,则要不是注释符,要不是代码行 
			if(bCommentSet) 
			{ 
				nCommentLines++; continue; 
			} 
			else 
			{ 
				if(bufRead.Find('"')==-1) 
				{ 
					nCodeLines++; continue; 
				} 
			} 
		} 
 
		if(bufRead.Find("//")==0 && !bCommentSet && !bQuatoSet) 
		{ 
			nCommentLines++; 
			continue; 
		} 
 
		BOOL bDoubleSplashFound = FALSE; 
		BOOL bSplashStarFound = FALSE; 
		for(int i=0; i=2 && (nEndComment == (bufRead.GetLength()-2)) && bCommentSet) 
		//至少有两个字符				*/在该行的最后							前面有/* 
		{ 
			bCommentSet = FALSE; 
			nCommentLines ++;   
		} 
		else if(nEndComment != -1 && bCommentSet)// */不在该行最后,则需要继续判断 
		{ 
			bCommentSet = FALSE; 
			if(nLineCommentBegin == nLines) // /* */ on the same line 
				nCommentLines++; 
			CString strRight = bufRead.Right(bufRead.GetLength()-nEndComment-2); 
			if(strRight.Find("//")!=-1) //it is very strange!  such as  "code */ (code or blank) // code" 
			{ 
				strRight.TrimLeft(); 
				if(strRight.Find("//")==0) 
					nCommentLines++; 
			} 
			else if(nLineCommentBegin != nLines && strRight.GetLength()==0) 
				nCommentLines++; 
		} 
 
		if(bCommentSet) 
			nCommentLines++; 
 
		if(IsOdd(HowManyCharsInString(bufRead, "\"", bCommentSet))&&!bCommentSet) 
		{ 
//			if(bQuatoSet) 
//			{//本行继续前一行的字符串 
//				BOOL bCommentBegin = FALSE; 
//				for(int i=0; i=2 && (nEndComment == (bufRead.GetLength()-2)) && bCommentSet) 
		//至少有两个字符				*/在该行的最后							前面有/* 
		{ 
			bCommentSet = FALSE; 
			nCommentLines ++;   
		} 
		else if(nEndComment != -1 && bCommentSet)// */不在该行最后,则需要继续判断 
		{ 
			bCommentSet = FALSE; 
			if(nLineCommentBegin == nLines) // /* */ on the same line 
				nCommentLines++; 
			bufRead = bufRead.Right(bufRead.GetLength()-nEndComment-2); 
			if(bufRead.Find("//")!=-1) //it is very strange!  such as  "code */ (code or blank) // code" 
			{ 
				bufRead.TrimLeft(); 
				if(bufRead.Find("//")==0) 
					nCommentLines++; 
			} 
			else if(nLineCommentBegin != nLines && bufRead.GetLength()==0) 
				nCommentLines++; 
		} 
 
		if(bCommentSet) 
			nCommentLines++; 
	} 
 
	*pnCommentLines = nCommentLines; 
	*pnBlankLines = nBlankLines; 
 
	file.Close(); 
 
	return nLines; 
 
	//下述代码不是使用CStdioFile,有错误 
 
/*	CFile file; 
 
	file.Open(strFileName, CFile::modeRead); 
 
	int nLines = 0; 
	int nCodeLines = 0; 
	int nCommentLines = 0; 
	int nBlankLines = 0; 
 
	BOOL bLastSplash = FALSE; 
	BOOL bDoubleSplash = FALSE; 
	BOOL bLastStar = FALSE; 
	BOOL bCommentCount = FALSE; 
	BOOL bBlankCount = TRUE; 
 
	int nLength = file.GetLength(); 
	m_nSize += nLength; 
	*pnLength = nLength; 
 
	char buf[255]; 
	int nRead = 0; 
	while(nLength>0) 
	{ 
		nRead = file.Read(buf, 250); 
		 
		if(buf[0] == '*' && bLastSplash) 
		{ 
			bLastSplash = FALSE; 
			bCommentCount = TRUE; 
		} 
 
		if(buf[0] == '/' && bLastSplash && !bCommentCount && bBlankCount && !bDoubleSplash) 
		{ 
			bLastSplash = FALSE; 
			bDoubleSplash = TRUE; 
		} 
 
		if(buf[0] == '/' && bLastStar) 
		{ 
			bLastStar = FALSE; 
			bCommentCount = FALSE; 
			nCommentLines++; 
		} 
 
		for(int i=0; i=2 && (nEndComment == bufRead.GetLength()-2)) 
		{ 
			bCommentSet = FALSE; 
			nCommentLines ++;   
		} 
		else if(nEndComment != -1) 
		{ 
			bCommentSet = FALSE; 
			if(bufRead.Find("--")!=-1) //it is very strange!  such as  " */   -- " 
			{ 
				CString sTemp = bufRead.Right(bufRead.GetLength()-nEndComment-3); 
				sTemp.TrimLeft(); 
				if(sTemp.Find("--")==0) 
					nCommentLines++; 
			} 
		} 
 
		if(bCommentSet) 
			nCommentLines++; 
	} 
 
	*pnCommentLines = nCommentLines; 
	*pnBlankLines = nBlankLines; 
 
	file.Close(); 
 
	return nLines; 
} 
 
int CCountingDlg::GetVBFileLines(LPCTSTR strFileName, int *pnLength, int *pnCodeLines, int *pnCommentLines, int *pnBlankLines) 
{ 
	*pnLength = 0; 
	*pnCommentLines = 0; 
	*pnBlankLines = 0; 
 
	CStdioFile file; 
	if(file.Open(strFileName, CFile::modeRead)==FALSE) 
		return 0; 
 
	int nLines = 0; 
	int nCodeLines = 0; 
	int nCommentLines = 0; 
	int nBlankLines = 0; 
 
	int nLength = file.GetLength(); 
	m_nSize += nLength; 
	*pnLength = nLength; 
 
	CString bufRead; 
 
	while(file.ReadString(bufRead)!=FALSE) 
	{ 
		nLines++; 
 
		bufRead.TrimLeft(); 
 
		if(bufRead.GetLength()==0) 
		{ 
			nBlankLines++; 
			continue; 
		} 
 
		if(bufRead.Find("'")==0) 
		{ 
			nCommentLines++; 
			continue; 
		} 
 
		if(bufRead.Find("'")!=-1) 
		{ 
			if(m_nStatMethod==0) 
				nCodeLines++; 
			else if(m_nStatMethod==1) 
			{ 
				nCodeLines++; 
				nCommentLines++; 
			} 
			else if(m_nStatMethod==2) 
			{ 
				nCommentLines++; 
			} 
			continue; 
		} 
		else 
			nCodeLines++; 
	} 
 
	*pnCodeLines = nCodeLines; 
	*pnCommentLines = nCommentLines; 
	*pnBlankLines = nBlankLines; 
 
	file.Close(); 
 
	return nLines; 
} 
 
int CCountingDlg::GetPerlFileLines(LPCTSTR strFileName, int *pnLength, int *pnCodeLines, int *pnCommentLines, int *pnBlankLines) 
{ 
	*pnLength = 0; 
	*pnCommentLines = 0; 
	*pnBlankLines = 0; 
 
	CStdioFile file; 
	if(file.Open(strFileName, CFile::modeRead)==FALSE) 
		return 0; 
 
	int nLines = 0; 
	int nCodeLines = 0; 
	int nCommentLines = 0; 
	int nBlankLines = 0; 
 
	int nLength = file.GetLength(); 
	m_nSize += nLength; 
	*pnLength = nLength; 
 
	CString bufRead; 
 
	while(file.ReadString(bufRead)!=FALSE) 
	{ 
		nLines++; 
 
		bufRead.TrimLeft(); 
 
		if(bufRead.GetLength()==0) 
		{ 
			nBlankLines++; 
			continue; 
		} 
 
		if(bufRead.Find("#")==0) 
		{ 
			nCommentLines++; 
			continue; 
		} 
 
		if(bufRead.Find("#")!=-1) 
		{ 
			if(m_nStatMethod==0) 
				nCodeLines++; 
			else if(m_nStatMethod==1) 
			{ 
				nCodeLines++; 
				nCommentLines++; 
			} 
			else if(m_nStatMethod==2) 
			{ 
				nCommentLines++; 
			} 
			continue; 
		} 
		else 
			nCodeLines++; 
	} 
 
	*pnCodeLines = nCodeLines; 
	*pnCommentLines = nCommentLines; 
	*pnBlankLines = nBlankLines; 
 
	file.Close(); 
 
	return nLines; 
} 
 
int CCountingDlg::GetTxtFileLines(LPCTSTR strFileName, int *pnLength, int *pnCodeLines, int *pnCommentLines, int *pnBlankLines) 
{ 
	*pnLength = 0; 
	*pnCommentLines = 0; 
	*pnBlankLines = 0; 
 
	CStdioFile file; 
	if(file.Open(strFileName, CFile::modeRead)==FALSE) 
		return 0; 
 
	int nLines = 0; 
	int nCommentLines = 0; 
	int nBlankLines = 0; 
 
	int nLength = file.GetLength(); 
	m_nSize += nLength; 
	*pnLength = nLength; 
 
	CString bufRead; 
 
	while(file.ReadString(bufRead)!=FALSE) 
	{ 
		nLines++; 
 
		bufRead.TrimLeft(); 
 
		if(bufRead.GetLength()==0) 
		{ 
			nBlankLines++; 
			continue; 
		} 
	} 
 
	*pnCommentLines = nCommentLines; 
	*pnBlankLines = nBlankLines; 
 
	file.Close(); 
 
	return nLines; 
} 
 
 
/********************************************************************* 
*  Save as Text file, in which every column has its own width 
*	input: filename: the save file name 
*	output: void		 
**********************************************************************/ 
void CCountingDlg::SaveAsTextFile(LPCTSTR filename) 
{ 
	CFile file(filename, CFile::modeCreate|CFile::modeWrite); 
	CString strText; 
 
#define COLUMN1_WIDTH	20 
#define COLUMN2_WIDTH	30 
#define COLUMN3_WIDTH	15 
#define COLUMN4_WIDTH	15 
#define COLUMN5_WIDTH	15 
#define COLUMN6_WIDTH	15 
#define COLUMN7_WIDTH	30 
 
	strText.LoadString(IDS_FILENAME); 
	strText = TextAppendSpace(strText, COLUMN1_WIDTH, TRUE); 
	file.Write(strText, strText.GetLength());//write file name 
	strText.LoadString(IDS_PATHNAME); 
	strText = TextAppendSpace(strText, COLUMN2_WIDTH, TRUE); 
	file.Write(strText, strText.GetLength());//write path name 
	strText.LoadString(IDS_TOTALLINE); 
	strText = TextAppendSpace(strText, COLUMN3_WIDTH, FALSE); 
	file.Write(strText, strText.GetLength()); 
	strText.LoadString(IDS_CODELINE); 
	strText = TextAppendSpace(strText, COLUMN4_WIDTH, FALSE); 
	file.Write(strText, strText.GetLength()); 
	strText.LoadString(IDS_COMMENTLINE); 
	strText = TextAppendSpace(strText, COLUMN5_WIDTH, FALSE); 
	file.Write(strText, strText.GetLength()); 
	strText.LoadString(IDS_BLANKLINE); 
	strText = TextAppendSpace(strText, COLUMN6_WIDTH, FALSE); 
	file.Write(strText, strText.GetLength()); 
	file.Write("  ", 2); 
	strText.LoadString(IDS_FILETYPE); 
	strText = TextAppendSpace(strText, COLUMN7_WIDTH, TRUE); 
	file.Write(strText, strText.GetLength()); 
	file.Write("\r\n", 2); 
 
	for(int i=0; i1024) 
	{ 
		fSize /= 1024.; 
		strUnit = "KB"; 
		if(fSize>1024) 
		{ 
			fSize /= 1024.; 
			strUnit = "MB"; 
		} 
	} 
 
	str1.LoadString(IDS_TOTALSIZE); 
	str2.Format("%s: %2.2f%s", str1, fSize, strUnit); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\r\n", 2); 
 
	str1.LoadString(IDS_TOTALLINE); 
	str2.Format("%s: %d (100%%)", str1, m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\r\n", 2); 
 
	str1.LoadString(IDS_CODELINE); 
	str2.Format("%s: %d (%.1f%%)", str1, m_nCodeLines, 100.*m_nCodeLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\r\n", 2); 
 
	str1.LoadString(IDS_COMMENTLINE); 
	str2.Format("%s: %d (%.1f%%)", str1, m_nCommentLines, 100.*m_nCommentLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\r\n", 2); 
 
	str1.LoadString(IDS_BLANKLINE); 
	str2.Format("%s: %d (%2.1f%%)", str1, m_nBlankLines, 100.*m_nBlankLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\r\n", 2); 
 
	str1.LoadString(IDS_SAVEOVER); 
	GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str1); 
} 
 
/********************************************************************* 
*  Save as csv file which can be analysed by Excel conveniently 
*	input: filename: the save file name 
*	output: void		 
**********************************************************************/ 
void CCountingDlg::SaveAsCSVFile(LPCTSTR filename) 
{ 
	CStdioFile file(filename, CFile::modeCreate|CFile::modeWrite); 
	CString strText; 
 
	CString str1, str2, str3, str4, str5, str6, str7; 
	str1.LoadString(IDS_FILENAME); 
	str2.LoadString(IDS_PATHNAME); 
	str3.LoadString(IDS_TOTALLINE); 
	str4.LoadString(IDS_CODELINE); 
	str5.LoadString(IDS_COMMENTLINE); 
	str6.LoadString(IDS_BLANKLINE); 
	str7.LoadString(IDS_FILETYPE); 
	strText.Format("%s,%s,%s,%s,%s,%s,%s\n", str1, str2, str3, str4, str5, str6, str7); 
	file.WriteString(strText); 
 
	for(int i=0; i1024) 
	{ 
		fSize /= 1024.; 
		strUnit = "KB"; 
		if(fSize>1024) 
		{ 
			fSize /= 1024.; 
			strUnit = "MB"; 
		} 
	} 
 
	str1.LoadString(IDS_TOTALSIZE); 
	str2.Format("%s,%2.2f%s", str1, fSize, strUnit); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\n", 1); 
 
	str1.LoadString(IDS_TOTALLINE); 
	str2.Format("%s,%d (100%%)", str1, m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\n", 1); 
 
	str1.LoadString(IDS_CODELINE); 
	str2.Format("%s,%d (%2.1f%%)", str1, m_nCodeLines, 100.*m_nCodeLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\n", 1); 
 
	str1.LoadString(IDS_COMMENTLINE); 
	str2.Format("%s,%d (%2.1f%%)", str1, m_nCommentLines, 100.*m_nCommentLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\n", 1); 
 
	str1.LoadString(IDS_BLANKLINE); 
	str2.Format("%s,%d (%2.1f%%)", str1, m_nBlankLines, 100.*m_nBlankLines/m_nTotalLines); 
	file.Write(str2, str2.GetLength()); 
	file.Write("\n", 1); 
 
	str1.LoadString(IDS_SAVEOVER); 
	GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str1); 
} 
 
/********************************************************************* 
*  Save as Excel file 参考徐景周代码 
 
///////////////////////////////////////////////////////////////////////////// 
//名称:OnWriteexcel 
//功能:创建并写入数据到Excel文件中 
//作者:徐景周(jingzhou_xu@163.net) 
//组织:未来工作室(Future Studio) 
//日期:2002.9.1 
///////////////////////////////////////////////////////////////////////////// 
 
*	input: filename: the save file name 
*	output: void		 
**********************************************************************/ 
void CCountingDlg::SaveAsExcelFile(LPCTSTR filename) 
{ 
	CDatabase database; 
	CString sDriver = "MICROSOFT EXCEL DRIVER (*.XLS)"; // Excel安装驱动 
	CString sSql; 
     
	//获取主程序所在路径,存在sPath中 
//	GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH); 
//	sPath.ReleaseBuffer (); 
	 
	TRY 
	{ 
		// 创建进行存取的字符串 
		sSql.Format("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s", 
			sDriver, filename, filename); 
		 
		// 创建数据库 (既Excel表格文件) 
		if( database.OpenEx(sSql, CDatabase::noOdbcDialog) ) 
		{ 
			// 创建表结构(姓名、年龄) 
			sSql = "CREATE TABLE 统计结果 (文件名 TEXT, 所在文件夹 TEXT, 总行数 NUMBER, 代码行 NUMBER, 注释行 NUMBER, 空白行 NUMBER, 类型 TEXT)"; 
			database.ExecuteSQL(sSql); 
			 
			for(int i=0; i1024) 
			{ 
				fSize /= 1024.; 
				strUnit = "KB"; 
				if(fSize>1024) 
				{ 
					fSize /= 1024.; 
					strUnit = "MB"; 
				} 
			} 
			sSql.Format("INSERT INTO 统计结果 (文件名, 所在文件夹) VALUES ('总大小', '%.2f%s')", fSize, strUnit); 
			database.ExecuteSQL(sSql); 
 
			sSql.Format("INSERT INTO 统计结果 (文件名, 所在文件夹) VALUES ('总行数', '%d(100%%)')", m_nTotalLines); 
			database.ExecuteSQL(sSql); 
 
			sSql.Format("INSERT INTO 统计结果 (文件名, 所在文件夹) VALUES ('代码行', '%d(%2.1f%%)')", m_nCodeLines, 100.*m_nCodeLines/m_nTotalLines); 
			database.ExecuteSQL(sSql); 
 
			sSql.Format("INSERT INTO 统计结果 (文件名, 所在文件夹) VALUES ('注释行', '%d(%2.1f%%)')", m_nCommentLines, 100.*m_nCommentLines/m_nTotalLines); 
			database.ExecuteSQL(sSql); 
 
			sSql.Format("INSERT INTO 统计结果 (文件名, 所在文件夹) VALUES ('空白行', '%d(%2.1f%%)')", m_nBlankLines, 100.*m_nBlankLines/m_nTotalLines); 
			database.ExecuteSQL(sSql); 
		}       
		 
		// 关闭数据库 
		database.Close(); 
		 
		AfxMessageBox("Excel文件保存成功!"); 
	} 
	CATCH_ALL(e) 
	{ 
		TRACE1("Excel驱动没有安装: %s",sDriver); 
	} 
	END_CATCH_ALL; 
 
	CString str; 
	str.LoadString(IDS_SAVEOVER); 
	GetDlgItem(IDC_PATH_COUNTING)->SetWindowText(str); 
} 
 
 
/********************************************************************* 
*  Show the About dialogbox 
**********************************************************************/ 
void CCountingDlg::OnAbout()  
{ 
	// TODO: Add your control notification handler code here 
	CAboutDlg dlgAbout; 
	dlgAbout.DoModal(); 
} 
 
/********************************************************************* 
*  Update counting result frequently 
*	the result including: total files, total size,  
*			total lines, code lines, comment lines, blank lines 
**********************************************************************/ 
void CCountingDlg::UpdateResult() 
{ 
	char sTemp[64]=" "; 
 
	//show the number of files 
	sprintf(sTemp, "%d", m_nFiles); 
	GetDlgItem(IDC_FILES)->SetWindowText(sTemp); 
 
	//show the total size 
	CString strUnit = ""; 
	float fSize = (float)m_nSize; 
	if(fSize>1024) 
	{ 
		fSize /= 1024; 
		strUnit = "KB"; 
		if(fSize>1024) 
		{ 
			fSize /= 1024; 
			strUnit = "MB"; 
		} 
	} 
	sprintf(sTemp, "%.2f%s", fSize, strUnit); 
	GetDlgItem(IDC_SIZES)->SetWindowText(sTemp); 
 
	//show total lines 
	sprintf(sTemp, "%d", m_nTotalLines); 
	GetDlgItem(IDC_TOTALLINES)->SetWindowText(sTemp); 
 
	//show code lines 
	if(m_nTotalLines!=0) 
		sprintf(sTemp, "%d(%2.1f%%)", m_nCodeLines, m_nCodeLines*100./m_nTotalLines); 
	else 
		sprintf(sTemp, "0(0%%)"); 
	GetDlgItem(IDC_CODELINES)->SetWindowText(sTemp); 
 
	//show comment lines 
	if(m_nTotalLines!=0) 
		sprintf(sTemp, "%d(%2.1f%%)", m_nCommentLines, m_nCommentLines*100./m_nTotalLines); 
	else 
		sprintf(sTemp, "0(0%%)"); 
	GetDlgItem(IDC_COMMENTLINES)->SetWindowText(sTemp); 
 
	//show blank lines 
	if(m_nTotalLines!=0) 
		sprintf(sTemp, "%d(%2.1f%%)", m_nBlankLines, m_nBlankLines*100./m_nTotalLines); 
	else 
		sprintf(sTemp, "0(0%%)"); 
	GetDlgItem(IDC_BLANKLINES)->SetWindowText(sTemp); 
} 
 
void CCountingDlg::OnProperty()  
{ 
	// TODO: Add your control notification handler code here 
	CPropertyDlg dlg; 
 
	dlg.m_nStatMethod = m_nStatMethod; 
	dlg.m_strLogFile = m_strLogFile; 
 
	if(dlg.DoModal()==IDOK) 
	{ 
		m_nStatMethod = dlg.m_nStatMethod; 
		m_strLogFile = dlg.m_strLogFile; 
	}	 
} 
 
int CCountingDlg::HowManyCharsInString(CString str, CString chars, BOOL bCommentSet) 
{ 
	str.TrimLeft(); 
	int nCount=0; 
	//要考虑/*/的情形 
//	if(str.Find("/*/")!=-1) 
//	{ 
//		CString strLeft = str.Left(str.Find("/*/")); 
//		if(strLeft.Find("*/")==-1 && chars == "/*" && bCommentSet) 
//			nCount--; 
//		if(strLeft.Find("/*/")==-1 && chars == "*/" && !bCommentSet) 
//			nCount--; 
//	} 
 
	while(str.Find(chars)!=-1) 
	{ 
		nCount++; 
		str = str.Right(str.GetLength()-str.Find(chars)-chars.GetLength()); 
	} 
	 
	return max(nCount, 0); 
} 
 
BOOL CCountingDlg::IsOdd(int nQuatos) 
{ 
	if(nQuatos%2==0)return FALSE; 
 
	return TRUE; 
} 
 
BOOL CCountingDlg::DestroyWindow()  
{ 
	// TODO: Add your specialized code here and/or call the base class 
	if(m_nSysTimer!=NULL) 
	{ 
		KillTimer(m_nSysTimer); 
		m_nSysTimer = NULL; 
	} 
	return CDialog::DestroyWindow(); 
}