给程序加上漂亮的注释!!!

1. VC

插件下载:

http://files.cnblogs.com/aoyihuashao/12435_CommentWizard15.zip

插件使用方法,其实附件里有,这里也贴出来:

    
    
二.使用说明: 1 .拷贝CommentWizard.dll到VC的AddIns目录下( VC安装目录\Common\MSDev98\AddIns\) 2 .运行VC选择Tools --> Customize --> Add - ins and Macro Files 在Add - ins and macro里选中CommendWizard VC Add - in (注释精灵),若找不到 则浏览文件,然后Close,此时VC的界面里多了个Toolbar,上面有 五个按钮,注释精灵安装成功。 3 .五个按钮分别为 1 > 注释按钮,选中要注释的类( class )、结构体( struct )、枚举( enum )、联合体(union)、 接口( interface )、函数等声明,例如选中一行文字为 int Func( int nParam1, int nParam2) 后按下注释按钮则注释会自动的添加进去,并且会自动的帮你把函数名,参数,返回值给提取 出来,你只要写写功能就行了。注意一定要选中文本后再按按钮才会起作用。 2 > 设置按钮,会弹出设置对话框,让用户自己设置注释的格式在对话框里的参数设定里指定 作者的名字和公司,则在注释时会自动添加在注释类型里选中一个注释的类型,则进入风格 编辑,风格编辑中类似 % Author % 的为变量, 以下为各变量名代表的含义: % Time % 时间 % Author % 作者 % Company % 公司 % ClassName % 类名 % BaseClassName % 基类名 % StructName % 结构体名 % UnionName % 联合体名 % EnumName % 枚举体名 % Function % 函数名 % ReturnValue % 返回值类型 % FunctionParam % 参数列表 % MicroName % 宏名称 % CaretPos % 注释后光标所停的位置 % Interface % 接口名(如 interface A,DECLARE_INTERFACE(A) 等) % BaseInterface % 基接口名(如 interface A: public B ,DECLARE_INTERFACE(A) 等) % MethodName % 方法名(如 STDMETHOD(A)(),STDMETHOD_( int ,A)() 等) % ProjectName % 当前项目的名称 % CurrentFileName % 当前文件名 改变风格只需要编辑文件,同时要注意相应变量的位置,退出时自动保存 3 .在文件头加入注释,按下此按钮会在文件头加入注释,注释风格在设置对话框里设置。 4 .删除 / 反删除选定的文本,选中要注释掉的文本,按下按钮,则把代码注掉,但不真正删除。 再此选中被注释过的文本,按下按钮,则会把代码还原。 5 .About按钮,提示关于本软件的一些信息。

 插件设计说明:

设计目标:


1. 自动提取函数名称;
2. 自动提取函数功能注释(假设在头文件中);
3. 自动列出参数列表;
4.自动提取返回值;
5.自动填写作者及日期(作者名称可以设置)

例如:

//------------------------------------------------
// 名称:CDSAddIn::OnConnection
// 功能:
// 参数:[IApplication* pApp] ---
//       [VARIANT_BOOL bFirstTime] ---
//       [long dwCookie] ---
//       [VARIANT_BOOL* OnConnection] ---
// 返回:STDMETHODIMP ---
// 作者:麻军  2002-3-4
//------------------------------------------------
STDMETHODIMP CDSAddIn::OnConnection(IApplication* pApp, VARIANT_BOOL bFirstTime, long dwCookie, VARIANT_BOOL* OnConnection)


设计思想:

1. 使用IDSAddIn接口;
2. 设计CCmtBlock(COMMENT BLOCK)类维护注释中的各个字段,用来提供扩展灵活性。

实现:

//-----------------------------------------------------------------------------------------------------


// CmtBlock.h: interface for the CCmtBlock class.
//
//


#if !defined(AFX_CMTBLOCK_H__51B4002A_A935_4764_80B5_03103D5E716E__INCLUDED_)
#define AFX_CMTBLOCK_H__51B4002A_A935_4764_80B5_03103D5E716E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <vector>

class CCmtBlock 
{
public:
 CCmtBlock();
 ~CCmtBlock();

private:
 CString m_szBegin;       // 注释首行(hard coded)
 CString m_szName;        // 函数名称(auto)
 CString m_szPurpose;     // 函数功能(auto)
 CString m_szParam;       // 函数参数列表(auto)
 CString m_szReturn;      // 函数返回(can change)
 CString m_szAuthor;      // 函数作者(auto)
 CString m_szEnd;         // 注释尾行(hard coded)
 CString m_szFuncDefine;  // 函数定义(自动获得)
// CString m_szBlock;       // 函数注释块
 std::vector< CString* > m_arrSort;  // 注释部分的排列顺序

private:
 void ExtractName();      // 提取名称
 void ExtractPurpose();   // 提取功能
 void ExtractParam();     // 提取参数列表
 void ExtractReturn();    // 提取返回类型
 void ComposeAuthorAndDate(); // 编辑作者和日期时间

public:
 void SetFunctionDefine( CString szFuncDefine );   // 设置函数定义(自动获得)
 CString ComposeComment();   // 编辑函数注释
 void SetPurpose( CString& szFuncPurpose ) {
  m_szPurpose = szFuncPurpose; }  // 设置函数头文件中的注释

};

#endif // !defined(AFX_CMTBLOCK_H__51B4002A_A935_4764_80B5_03103D5E716E__INCLUDED_)

//-----------------------------------------------------------------------------------------------------


// CmtBlock.cpp: implementation of the CCmtBlock class.
//
//

#include "stdafx.h"
#include "AutoComment.h"
#include "CmtBlock.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//

CCmtBlock::CCmtBlock()
{
 m_szBegin = _T("//------------------------------------------------\r\n");
 m_szEnd   = _T("//------------------------------------------------\r\n");

 m_arrSort.clear();
 m_arrSort.push_back( &m_szBegin );
 m_arrSort.push_back( &m_szName );
 m_arrSort.push_back( &m_szPurpose );
 m_arrSort.push_back( &m_szParam );
 m_arrSort.push_back( &m_szReturn );
 m_arrSort.push_back( &m_szAuthor );
 m_arrSort.push_back( &m_szEnd );
}

CCmtBlock::~CCmtBlock()
{
 m_arrSort.clear();
}

void CCmtBlock::ExtractName()
{
 int iPosSpace = m_szFuncDefine.FindOneOf(_T(" "));
 int iPosBracket = m_szFuncDefine.FindOneOf(_T("("));
 CString szName = m_szFuncDefine.Mid( iPosSpace, iPosBracket-iPosSpace );
 szName.TrimLeft();
 szName.TrimRight();
 m_szName = _T("// 名称:") + szName + _T("\r\n");
}

void CCmtBlock::ExtractPurpose()
{
 CString szTemp = m_szPurpose;
 m_szPurpose = _T("// 功能:") + szTemp + _T("\r\n");
}

void CCmtBlock::ExtractParam()
{
 // 得到参数表
 int iPosLeftBracket = m_szFuncDefine.FindOneOf(_T("("));
 int iPosRightBracket = m_szFuncDefine.ReverseFind(_T(')'));
 CString szParamTable = m_szFuncDefine.Mid( iPosLeftBracket+1, iPosRightBracket-iPosLeftBracket-1 );


 // 分解参数
 // 判断是否具有参数
 szParamTable.TrimLeft();
 szParamTable.TrimRight();
 if( szParamTable == _T("") )
 {
  // 没有参数
  m_szParam = _T("// 参数:无\r\n");
  return;
 }
 m_szParam = _T("// 参数:");
 int iPos1 = 0;
 int iPos2 = 0;
 CString szOneParam = _T("");
 CString szOneLine;
 int iLineCount = 0;
 szParamTable += _T(",");
 while( ( iPos2 = szParamTable.Find( _T(','), iPos1 ) ) != -1 )
 {
  iLineCount++;

  // 找到参数
  szOneParam = szParamTable.Mid( iPos1, iPos2-iPos1 );
  szOneParam.TrimLeft();
  szOneParam.TrimRight();
  if( iLineCount == 1 )
   szOneLine = _T("[") + szOneParam + _T("] --- ");
  else
   szOneLine = _T("//       [") + szOneParam + _T("] --- ");
  szOneLine += _T("\r\n");

  // 添加到函数列表上
  m_szParam += szOneLine;

  iPos1 = iPos2 + 1;
 }

// ::MessageBox( NULL, szParamTable, NULL, MB_OK );
}


void CCmtBlock::ExtractReturn()
{
 CString szRet = m_szFuncDefine.Mid( 0, m_szFuncDefine.FindOneOf( _T(" ") ) );
 m_szReturn = _T("// 返回:") + szRet + _T(" --- \r\n");
}


extern CString g_szAuthor;  // 作者名称


void CCmtBlock::ComposeAuthorAndDate()
{
 CString szAuthor = g_szAuthor;//_T("Author");

 COleDateTime& date = COleDateTime::GetCurrentTime();
 CString szDate = date.Format( VAR_DATEVALUEONLY );

 m_szAuthor = _T("// 作者:") + szAuthor + _T("  ") + szDate + _T("\r\n");
}


void CCmtBlock::SetFunctionDefine( CString szFuncDefine )
{
 m_szFuncDefine = szFuncDefine;
}

CString CCmtBlock::ComposeComment()
{
 ExtractName();      // 提取名称
 ExtractPurpose();   // 提取功能
 ExtractParam();     // 提取参数列表
 ExtractReturn();    // 提取返回类型
 ComposeAuthorAndDate(); // 编辑作者和日期时间

 CString szBlock = _T("");
 for( int i=0;i<m_arrSort.size();i++)
  szBlock += *m_arrSort[i];

 return szBlock;
}

//-----------------------------------------------------------------------------------------------------

AutoCommentCommandMethod 函数是ADDIN向导自动建立的那个函数

/
// CCommands methods


STDMETHODIMP CCommands::AutoCommentCommandMethod()
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 // TODO: Replace this with the actual code to execute this command
 //  Use m_pApplication to access the Developer Studio Application object,
 //  and VERIFY_OK to see error strings in DEBUG builds of your add-in
 //  (see stdafx.h)

// VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
// ::MessageBox(NULL, "AutoComment Command invoked.", "AutoComment", MB_OK | MB_ICONINFORMATION);
// VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

 // 得到当前文档
 CComPtr<IDispatch> pDispActDocument = NULL;
 m_pApplication->get_ActiveDocument( &pDispActDocument );
 if( !pDispActDocument )
  return E_FAIL;
 CComQIPtr< ITextDocument, &IID_ITextDocument > pDoc( pDispActDocument );

 // 得到选择对象
 CComPtr< IDispatch > pDispSelection;
 pDoc->get_Selection( &pDispSelection );
 if( !pDispSelection )
  return E_FAIL;
 CComQIPtr< ITextSelection, &IID_ITextSelection > pSelection( pDispSelection );

 // 得到函数定义(假设光标插在函数定义中)
 //    -- 寻找的标志是:头(NewLine),尾({)>> 将来实现
 // 选择函数定义的第一行
 CComBSTR bstrFuncDefine;
 pSelection->SelectLine();
 pSelection->get_Text( &bstrFuncDefine );

 // 将光标插入行的起始位置
 VARIANT var1,var2;
 VariantInit( &var1 );
 VariantInit( &var2 );
 pSelection->StartOfLine( var1, var2 );

 if( bstrFuncDefine.Length() == 0 )
  return E_FAIL;  // 不是函数定义
 USES_CONVERSION;
 CString szFuncDefine = W2A(bstrFuncDefine);
 m_CmtBlock.SetFunctionDefine( szFuncDefine );

 // 找到头文件中函数定义的注释
 CString& szFuncComm = FindFunctionPurposeInHeader( szFuncDefine );
 m_CmtBlock.SetPurpose( szFuncComm );

 // 构成函数注释字符串
 CString szBlock = m_CmtBlock.ComposeComment();
 BSTR bstrBlock;
 bstrBlock = A2W( szBlock );
 pSelection->put_Text( bstrBlock );

 return S_OK;
}

CString CCommands::FindFunctionPurposeInHeader( CString& szDefine )
{
 CString szRet;
 // 得到当前文档
 CComPtr<IDispatch> pDispActDocument = NULL;
 m_pApplication->get_ActiveDocument( &pDispActDocument );
 if( !pDispActDocument )
  return "";
 CComQIPtr< ITextDocument, &IID_ITextDocument > pDoc( pDispActDocument );
 if( !pDoc )
  return "";

 // 得到函数名称
 CString szFuncName;
 int iPosSpace = szDefine.FindOneOf(_T(":"));
 int iPosBracket = szDefine.FindOneOf(_T("("));
 szFuncName = szDefine.Mid( iPosSpace+2, iPosBracket-iPosSpace-2 );
 szFuncName.TrimLeft();
 szFuncName.TrimRight();

 // 打开对应的.h文件
 CComBSTR bstrFullName;
 pDoc->get_FullName( &bstrFullName );
 CString szFullName( bstrFullName );
 szFullName.MakeLower();
 CString szExt = szFullName.Right( 3 );
 if( szExt != "cpp" )   // 不是.cpp
  return "";
 szFullName.TrimRight( "cpp" );
 szFullName += "h";  // 转换成.h

 CStdioFile file;
 if( !file.Open( szFullName, CFile::modeRead ) )
  return "";
 CString szLine;
 CString szPurpose;
 int pos;
 while( file.ReadString( szLine ) )
 {
  // 检查每一行是否有函数名称
  if( (pos=szLine.Find( szFuncName )) != -1 )
  {
   // 检查szFuncName的前后字符是否为空格and'('
   // 构造一个字符串在szFuncName的前后个加一个字符
   CString szTemp = szLine.Mid( pos-1, szFuncName.GetLength()+2 );
   if( szTemp.Left(1) != " " ||
    ( szTemp.Right(1) != " " && szTemp.Right(1) != "(" ) )
    szRet = "";
   else
   {
    // 找到函数声明
    // 查看当前行的末尾有没有注释
    int posSplash = 0;
    if( ( posSplash = szLine.ReverseFind( '/' ) ) != -1 )
     szRet = szLine.Right( szLine.GetLength() - posSplash - 1 );
    else
    {
     // 查看下一行有没有注释
     if( file.ReadString( szLine ) )
     {
      szLine.TrimLeft();
      szLine.TrimRight();
      if( szLine.Left(1) == "/" )
      {
       // 有注释
       szLine.TrimLeft("//");
       szRet = szLine;
      }
      else
       szRet = "";
     }
     else
      szRet = "";
    }
   }
  }
 }
 file.Close();

 szRet.TrimRight();
 szRet.TrimLeft();
 return szRet;
}

//-----------------------------------------------------------------------------------------------


// 在CDSAddIn::OnConnection函数中改写以下代码,注意:CParamDlg 类是一个输入作者名称的对话框类

 if (bFirstTime == VARIANT_TRUE)
 {
  VERIFY_OK(pApplication->
   AddCommandBarButton(dsGlyph, bszCmdName, m_dwCookie));
  // 第一次使用让用户输入姓名
  CParamDlg dlgParam;
  if( dlgParam.DoModal() == IDOK )
  {
   g_szAuthor = dlgParam.m_szAuthor;
   // 存入注册表
   ::WriteProfileString("DSAddIn_AutoComment","Author",g_szAuthor);
  }
 }
 else
 {
  char szAuthor[255];
  ::GetProfileString("DSAddIn_AutoComment","Author","Author",szAuthor,sizeof(szAuthor));
  g_szAuthor = CString(szAuthor);
 }

//-------------------------------------------------------------------------------------------------




2. C#


介绍:
    GhostDoc是Visual Studio的一个免费插件,可以帮助开发人员编写XML格式的注释文档。
    C#中XML格式的文档注释好处多多:Visual Studio会在很多地方显示这些注释内容(例如,编辑器的工具提示或对象浏览器),还有一些工具(比如NDoc或微软的文档工具Sandcastle)也可以利用这些注释生成具有良好外观的帮助文件。这些都让XML格式的注释看上去很美——但很不幸,你首先得编写大量简单、乏味的注释。
GhostDoc可以做什么?    
    GhostDoc为Visual Studio中的C#代码编辑器安装了一个新的命令。在编辑源文件时,只需将光标置于要添加文档的方法或属性内部,然后通过热键(默认为Ctrl+Shift+D)或右键菜单中的Document this菜单项调用命令,GhostDoc就会插入一段XML格式的注释。你也许会想到在方法或属性前面键入"///"时的类似效果,但是后者只能创建一段空的注释构造,而GhostDoc则能够生成大部分实用的注释。
    如果你的类成员是用于实现接口或重写基类的成员,GhostDoc会使用既存的文档,不论这些接口或基类来自何处。这样你就可以重用大量的微软编写的文档——是否想起了在实现IEumerable接口时,需要考虑如何为GetEnumerator()方法添加注释。
    如果没有既存的文档可用,GhostDoc会试着”猜测”如何为你生成注释。这主意初看起来也许有点奇怪,不过在特定条件下(后面会提到)GhostDoc做的很不错。有时候它”猜测”的结果会不太准确,甚至有些搞笑,但平均下来,修改这些生成的文档还是要比完全手工去写省了不少时间。
    GhostDoc事实上并”不懂”英语,那为何它生成的文档却常常令人相当满意?其中的基本原理颇为简单,GhostDoc假定你的代码遵从 微软类库开发人员设计规范
<!--[if !supportLists]--><!--[endif]-->
  1. 你的代码使用Pascal或Camel命名法为由多个单词组成的标识符命名
  2. 你的方法名通常以动词开头
  3. 你在标识符中不使用缩写
<!--[if !supportLists]--><!--[endif]--><!--[if !supportLists]--><!--[endif]-->

        如果你能够遵从这些规则(比如,使用ClearCache()而不是Clrcch()),同时使用一些自解释的标识符名称,那么GhostDoc就能派上用场了,它把标识符分割为几个单词,将它们组合来生成注释,也许并不完美,却给你一个良好文档的开始。
        文本的生成使用可定制的规则和模板,除了内置的规则,还可以定义新的自定义规则来扩展或替换既有的规则(为你的自定义规则提供更高的优先级或禁用内置规则)。
        上面提到过,GhostDoc并”不懂”英语,但它会尝试使用某种机制来提高生成注释的质量:

    <!--[if !supportLists]--><!--[endif]-->
    1. 动词的处理机制(GhostDoc假定方法名的首个单词为动词):Add->Adds,Do->Does,Specify->Specifies;
    2. "Of the"排序组织机制:ColumnWidth -> Width of the column.
    3. 一些特殊形容词的特殊合并机制:例如,MaximumColumnWidth->”Maximum width of the column”而不是”Width of the maximum column”
    4. 对首字母缩写组成的常量的自动检测,并通过一个列表来处理其它的一些首字母缩写术语
    5. 使用一个单词列表,以决定何时不使用”the”:AddItem -> Adds the item, BuildFromScratch -> Builds from scratch
    <!--[if !supportLists]--><!--[endif]--><!--[if !supportLists]--><!--[endif]--><!--[if !supportLists]--><!--[if !supportLists]--><!--[endif]-->
      下面是应用GhostDoc的一些例子:
      • 0
        点赞
      • 0
        收藏
        觉得还不错? 一键收藏
      • 0
        评论

      “相关推荐”对你有帮助么?

      • 非常没帮助
      • 没帮助
      • 一般
      • 有帮助
      • 非常有帮助
      提交
      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值