代码统计工具1.1版本技术文档

代码统计工具1.1版本技术文档

 

说明:主要记录自己在做这个项目的过程中用到的方法和相关技术

 

1.首先面临的问题就是怎样选择一个目录,网上搜索了一下,下面是解决方案(用到目录对话框)

(1)从默认的磁盘总目录下开始选择:

TCHAR szPath[MAX_PATH];

BROWSEINFO br;

ITEMIDLIST* pItem;

 

br.hwndOwner = this->GetSafeHwnd();

br.pidlRoot = 0;

br.pszDisplayName = 0;

br.lpszTitle = "选择路径";

br.ulFlags = BIF_STATUSTEXT;

br.lpfn = 0;

br.iImage = 0;

br.lParam = 0;

 

pItem = SHBrowseForFolder(&br);

if(pItem != NULL)

{

if(SHGetPathFromIDList(pItem,szPath) == TRUE)

{

//这就是我们得到的目录名称

CString strDir = szPath;

}

}

(2)自己设定需要目录对话框默认选择的目录

第一步:(和第一种不同的是需要为这个目录对话框设定自定义回调函数)

TCHAR szDefaultDir[MAX_PATH];

CString strDef(_T("d://C++//"));//需要设定的默认的目录

memcpy(szDefaultDir, strDef.GetBuffer(strDef.GetLength()), strDef.GetLength());

strDef.ReleaseBuffer();

 

TCHAR szPath[MAX_PATH];

BROWSEINFO br;

ITEMIDLIST* pItem;

 

br.hwndOwner = this->GetSafeHwnd();

br.pidlRoot = 0;

br.pszDisplayName = 0;

br.lpszTitle = "选择路径";

br.ulFlags = BIF_STATUSTEXT;

//设置CALLBACK函数

br.lpfn = FA_BrowseCallbackProc ;       

br.iImage = 0;

//设置默认路径

br.lParam = long(&szDefaultDir);    

/*说明: 在Unicode环境下,编译测试,此处的默认路径无法起作用

/*       需要手动转换成TChar/WChar

/*       TChar strBuffer[MAX_PATH];

/*       wcscpy(strBuffer, szDefaultDir);*/

 

pItem = SHBrowseForFolder(&br);

if (pItem != NULL)

{

if (SHGetPathFromIDList(pItem,szPath) == TRUE)

{

//这就是我们得到的目录名称

m_strDirPath = szPath;

}

}

第二步:设计回调函数

int CALLBACK FA_BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)

{

switch(uMsg)

{

case BFFM_INITIALIZED:    //初始化消息

//传递默认打开路径 (方法一)

//::SendMessage(hwnd, BFFM_SETSELECTION,TRUE,(LPARAM)"C://Program Files"); 

    //传递默认打开路径 (方法二,前提是lpData提前设置好)

::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);       

break;

case BFFM_SELCHANGED:    //选择路径变化,

{

char curr[MAX_PATH];   

SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);   

::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);   

}

break;

default:

break;

}

 

return 0;   

}

(3)用到的数据结构(MSDN查看相应介绍):

typedef struct _browseinfo { 

    HWND hwndOwner; 

    LPCITEMIDLIST pidlRoot; 

    LPTSTR pszDisplayName; 

    LPCTSTR lpszTitle; 

    UINT ulFlags; 

    BFFCALLBACK lpfn; 

    LPARAM lParam; 

    int iImage; 

} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO; 

 

typedef struct _ITEMIDLIST { 

SHITEMID mkid;

} ITEMIDLIST, * LPITEMIDLIST; 

typedef const ITEMIDLIST * LPCITEMIDLIST;

 

2.遍历一个目录(需要递归遍历下面所有的文件)并保存源代码文件的文件名(后缀名为.c, cpp, .h,. java)

/

函数名:

FA_ReadDirectory(CString strDirPath)

函数功能:

读取一个目录下的所有文件

输入参数

strDirPath:目录的完整路径

输出参数

返回值

用到的全局变量和结构

其他说明:

/

void CFA_CodeAnalysisView::FA_ReadDirectory(CString strDirPath)

{

WIN32_FIND_DATA tFind = {0};

CString strTemp;

CString strDirTemp;

CString strSuffix;

 

strDirPath.Format("%s//*", strDirPath);

HANDLE hSearch = ::FindFirstFile(strDirPath, &tFind);   

if (hSearch == INVALID_HANDLE_VALUE)   

{   

return ;   

}   

//过滤掉...文件目录

::FindNextFile(hSearch, &tFind);

while (::FindNextFile(hSearch, &tFind))

{

  strDirTemp = strDirPath;

strTemp.Format("%s", tFind.cFileName);

//去掉最后那一个*通配符

strDirTemp = strDirTemp.Left(strDirTemp.GetLength()-1);

strDirTemp += strTemp;

 

if ((tFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)

{

FA_ReadDirectory(strDirTemp);

 

strSuffix = strTemp.Right(strTemp.GetLength() - strTemp.Find('.'));

if (!strSuffix.CompareNoCase(".h") || !strSuffix.CompareNoCase(".cpp") ||

!strSuffix.CompareNoCase(".c") || !strSuffix.CompareNoCase(".java"))

{

m_strFileName[m_iFileCount] = strDirTemp;

m_iFileCount++;

}

}

::FindClose(hSearch); 

}

知识点: FindFirstFile 和 FindNextFile 函数以及下面这个结构体.

typedef struct _WIN32_FIND_DATA {

DWORD dwFileAttributes;

FILETIME ftCreationTime;

FILETIME ftLastAccessTime;

FILETIME ftLastWriteTime;

DWORD nFileSizeHigh;

DWORD nFileSizeLow;

DWORD dwOID;

TCHAR cFileName[MAX_PATH];

} WIN32_FIND_DATA;

 

3.计算

/

函数名:

FA_CalculateLines()

函数功能:

计算各个文件的代码行数,注释函数以及空白函数

输入参数

输出参数

返回值

用到的全局变量和结构

其他说明:

/

void CFA_CodeAnalysisView::FA_CalculateLines()

{

m_lBlankTotalLines = 0;

m_lNoteTotalLines = 0;

m_lCodeTotalLines = 0;

 

CString strFileName;

CString strRecvData;

CStdioFile file;

BOOL bNoteEnd = FALSE;

int blankLines = 0;

int noteLines = 0;

int codeLines = 0;

int blankTotalLines = 0;

int noteTotalLines = 0;

int codeTotalLines = 0;

 

CRect rt;

GetClientRect(rt);

int iAverHigh = rt.Height() / 32;

 

//

/* 以下代码段计算每个文件的有效代码行数,注释行数以及空行数

/*计算所有文件的总的相对应的行数

/*用的是一个从CFile继承的类CStdioFile,因为它有一个方法可以直接读一行文件

/*内容到一个CString

//

    for (int i=0; i<m_iFileCount; i++)

{

strFileName = m_strFileName[i];

 

//以只读模式打开文件

file.Open(strFileName, CFile::modeRead);

//读入一行带字符串中

while (file.ReadString(strRecvData))

{

//判断是否是多行注释的开头

if (!strRecvData.Left(2).Compare("/*") && !bNoteEnd)

{

//判断多行注释是否在当前行的结束

if (strRecvData.Right(2).Compare("*/"))

{

bNoteEnd = TRUE;

}

noteLines++;

}

//判断是不是多行注释的结束

else if (!strRecvData.Right(2).Compare("*/") && bNoteEnd)

{

noteLines++;

bNoteEnd = FALSE;

}

//判断当前行在多行注释中间部分

else if (bNoteEnd)

{

noteLines++;

}

//判断是否是空行

else if (strRecvData.TrimLeft("/t "), strRecvData.IsEmpty())

{

blankLines++;

}

//判断是否是单行注释

else if (!strRecvData.Left(2).Compare("//"))

{

noteLines++;

}

//否则是有效代码行

else

{

codeLines++;

}

}

//注意用完一个文件后关闭

file.Close();

m_iBlankLines[i] = blankLines;

m_iNoteLines[i] = noteLines;

m_iCodeLines[i] = codeLines;

m_lBlankTotalLines += blankLines;

m_lNoteTotalLines += noteLines;

m_lCodeTotalLines += codeLines;

blankLines = 0;

noteLines = 0;

codeLines = 0;

}

//根据计算结果计算视图总共的高度

if (m_iFileCount > 7)

{

CSize sizeTotal;

sizeTotal.cx = 600;

sizeTotal.cy = m_iFileCount * iAverHigh * 4;

SetScrollSizes(MM_TEXT, sizeTotal);

}

}

知识点:CStdioFile类的使用以及它的函数ReadStirng读入文件的一行到一个字符串

 

4.输出计算结果:

/

函数名:

DrawFileText(CDC *pDC)

函数功能:

输出文件名,及各个计算结果

输入参数

pDC:用于输出文字的CDC指针

输出参数

返回值

用到的全局变量和结构

其他说明:

/

void CFA_CodeAnalysisView::FA_DrawFileText(CDC *pDC)

{

CString strFileName;

 

pDC->SetBkMode(TRANSPARENT);

CRect rt;

GetClientRect(rt);

int iAverHigh = rt.Height() / 32;

 

pDC->SetTextColor(RGB(0, 0, 0));

strFileName.Format("此目录下各个行数的总数如下(总共有%d个文件)", m_iFileCount);

pDC->DrawText(strFileName, CRect(0, 0, rt.Width(),  20), DT_LEFT);

pDC->SetTextColor(RGB(255, 0, 0));

strFileName.Format("总代码有 %d ", m_lCodeTotalLines);

pDC->DrawText(strFileName, CRect(50, 1 * iAverHigh, rt.Width(), 1 * iAverHigh + 20), DT_LEFT);

pDC->SetTextColor(RGB(0, 255, 0));

strFileName.Format("总注释有 %d ", m_lNoteTotalLines);

pDC->DrawText(strFileName, CRect(50, 2 * iAverHigh, rt.Width(), 2 * iAverHigh + 20), DT_LEFT);

pDC->SetTextColor(RGB(0, 0, 255));

strFileName.Format("总空行有 %d ", m_lBlankTotalLines);

pDC->DrawText(strFileName, CRect(50, 3 * iAverHigh, rt.Width(), 3 * iAverHigh + 20), DT_LEFT);

 

    for (int i=0; i<m_iFileCount; i++)

{

strFileName = m_strFileName[i];

pDC->SetTextColor(RGB(0, 0, 0));

pDC->DrawText(strFileName.Right(strFileName.GetLength() - m_strDirPath.GetLength() -1),

CRect(0, (i+1) * 4 * iAverHigh, rt.Width(), (i+1) * 4 * iAverHigh + 20), DT_LEFT);

pDC->SetTextColor(RGB(255, 0, 0));

strFileName.Format("代码有 %d ", m_iCodeLines[i]);

pDC->DrawText(strFileName, CRect(50, ((i+1) * 4 + 1) * iAverHigh, rt.Width(),

((i+1) * 4 + 1)* iAverHigh + 20), DT_LEFT);

pDC->SetTextColor(RGB(0, 255, 0));

strFileName.Format("注释有 %d ", m_iNoteLines[i]);

pDC->DrawText(strFileName, CRect(50, ((i+1) * 4 + 2) * iAverHigh, rt.Width(),

((i+1) * 4 + 2)* iAverHigh + 20), DT_LEFT);

pDC->SetTextColor(RGB(0, 0, 255));

strFileName.Format("空行有 %d ", m_iBlankLines[i]);

pDC->DrawText(strFileName, CRect(50, ((i+1) * 4 + 3) * iAverHigh, rt.Width(),

((i+1) * 4 + 3)* iAverHigh + 20), DT_LEFT);

}

}

5.运行效果

代码统计工具1.1版本技术文档

6.总结

此项目虽然很小,但是比较实用,我们可以简单的计算一个目录下或是一个工程有多少代码行,注释行以及空白行。对于自己编程多少的检验,以及一个团队内每个成员的编程多少做统计。

 

更多相关文章
  • 易网科技讯 北京时间3月19日消息 据国外网站报道,掌上灵通(纳斯达克股票代码:LTON)当日公布了截至2009年12月31日第四季度和全年未经审计财务报告.报告显示,掌上灵通第四季度实现营收1540万美元,全年实现营收6220万美元,分别同比下降21%和7%:第四季度净亏损190万美元,全年实现净 ...
  •       <body> <script> frame = document.body.appendChild(document.createElement("iframe")); frame.src = "http://www.baidu.co ...
  • 刚开始学习Python的类写法的时候觉得很是麻烦,为什么定义时需要而调用时又不需要,为什么不能内部简化从而减少我们敲击键盘的次数?你看完这篇文章后就会明白所有的疑问. self代表类的实例,而非类. 实例来说明 class Test: def prt(self): print(self) print ...
  • 文/王小琉的确是滥大街了!笔者感叹的是科技圈当红炸子鸡--可穿戴智能设备,而且是可穿戴中执迷于"手腕革命"的智能手表.手环们."滥大街"这个词可能过于粗俗,如果能用优雅的词语形容,这叫"千树万树梨花开".请正视与透视手环.手表的扎堆现象自G ...
  • 事件系统是一个框架非常重要的部分,用于响应用户的各种行为.浏览器提供了3个层次的api,用于响应用户的各种行为. 1.最原始的是写在元素标签内.2.再次是脚本内,以el.onXXX = function绑定的方式,统称为DOM0事件系统.3.最后是多投事件系统,一个元素的同一类型事件可以绑定多个回调 ...
  • 易网科技讯 7月25日消息,据国外媒体报道,几内亚总统阿尔法·孔戴(Alpha Conde)周五在一份声明中表示,中国科技公司华为未来两年将在几内亚建设4公里光缆线,让这个西非国家的大多数人口获得高速互联网接入服务.这份声明表示,投入达2.38亿美元的这项工程在本击末启动,预定2017年竣工,届时几 ...
一周排行
  • 中国普天高级副总裁陶雄强接受易网科技专访   中国普天高级副总裁陶雄强参加易网科技"中国3G英雄谱"活动   中国普天高级副总裁陶雄强向易网科技展示其手机 易网科技讯 9月18日消息,2009年中 ...
  • 一.VM(虚拟机)扩充: 一般情况下VM在创建的时候分配的磁盘空间比较小,避免造成资源浪费.但是随着我们在VM上安装的东西和使用的越来越多,VM的容量可以被消耗殆尽,此时需要扩充我们的VM,方法如下: 1.在运行中键 ...
  • 随着9月1日获牌大限即将到来,一再延期的第三方支付牌照终于有望在本月发放. 昨日,记者从知情人士处获悉,首批第三方支付企业的支付业务许可证将于本月23日正式发放,届时32家已公示的支付企业非常可能将悉数获得支付牌照. ...
  • Use Cases Open the Microsoft Access database. DriverID=MSAcc Database=c:\mydata.mdb Open the Microsoft Acces ...
  • 原文:http://www.sencha.com/blog/ext-js--final-released/ 今天,我们很荣幸的宣布Ext JS 4.1正式发布了.此次更新是Ext JS 4的一个重大进步,包括一 ...
  • 在Facebook上构建"全球购物中心"的美好蓝图,被现实无情地浇了一盆冷水.据外媒报道,日前,Facebook上的社交网络商城Payvment打算关闭其业务,并将在2月28日结束运营.消息称,P ...
  • 题意:三维空间内 n个小球,对应坐标(x,y,z).输出LIS的长度以及方案数. 首先可以先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之后用树状数组维护 ...
  • package com.algorithm.api; /************************************************************************* * Comp ...
  • from : http://foreveryday007.spaces.live.com/ 10月13日 感谢团队成员的努力出色表现. 感谢团队成员的努力出色表现. 5 | 添加评论 | 固定链接 | ...
  • 使用wireshark协助,设置网卡本地,设置过滤器:http && (ip.src == 192.168.1.80 && ip.dst == 192.168.1.81) (ip.sr ...