用Shell扩展实现源代码统计程序
2006-07-20 11:39:12 来源:WEB开发网核心提示: 三、实现过程1.新建一个VC工程,选定ATL COM AppWizard类型,用Shell扩展实现源代码统计程序(2),工程起名为SrcCount,进入下一步; 2.选择服务类型为DLL(默认选项)即可,在此可以实现具体的功能,HRESULT InvokeCommand( LPCMINVO
三、实现过程
- 1.新建一个VC工程,选定ATL COM AppWizard类型,工程起名为SrcCount,进入下一步;
- 2.选择服务类型为DLL(默认选项)即可,这里不需要MFC支持(若加入MFC支持的话,编写代码时会方便些,但程序失去ATL短小精悍的特点了,熊掌与鱼不可兼得:)),进入下一步;
- 3.现在会显示工程的配置信息,我们按确定按钮后就建立一个ATL COM组件了。
- 4.我们现在加入一个组件对象,在工程的快捷菜单上选择New ATL Object…,在随后的对话框中的种类中选择Simple Object,单击下一步,在“Short Name”中填写CountLines,Attributes属性页中按默认选项,单击确定按钮。我们可以在VC的工作区里看到已添加一个接口ICountLines。
- 5.为该接口添加方法,在接口的快捷菜单上按右键,选择Add method…,方法名为GetFileLines,它的参数分别为:[in]BSTR *pFilePath, [out]int *lines。它的作用是统计源代码文件的行数。下面是代码的主要实现部分:
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 作用:获取源文件的代码行数
// 参数:1. pFilePath :输入参数,指定源文件的路径;
// 2. lines:输出参数,获得源文件的代码行数。
STDMETHODIMP CCountLines::GetFileLines(BSTR *pFilePath, int *lines)
{
// 存放代码的总行数
int totalLine = 0; ?
// 打开文件
HANDLE hFile = CreateFile((TCHAR *)pFilePath, ?
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ((HANDLE)-1 == hFile)
{
*lines = -1;
return S_FALSE;
}
// 开辟缓冲区存放文件内容
DWORD dwFileSize = GetFileSize(hFile, NULL);
BYTE *lpBuffer = new BYTE[dwFileSize];
memset(lpBuffer, 0, dwFileSize); ?
DWORD dwRead = 0;
BOOL bReadFile = ReadFile(hFile, lpBuffer, dwFileSize, &dwRead, NULL);
assert(bReadFile && dwRead == dwFileSize); ?
// 我们这里仅用一个简单的统计规则,即以换行符(‘\n’)为一行代码结束的标记
for (unsigned i = 0; i < dwFileSize; i++)
{
if (lpBuffer[i] == ''\n'')
{
totalLine++;
}
}
// 释放缓冲区
delete []lpBuffer;
CloseHandle(hFile);
// 保存代码行数
*lines = totalLine + 1; ?
return S_OK;
} - 6.继续添加方法GetFolderLines,它将根据递归算法对文件夹里的每个文件进行代码统计,这里就不具体写出了,请参看源代码。
- 7.在CCountLines的基类中添加IShellExtInit、IContextMenu。
- 8.当浏览器explorer.exe加载我们的程序段时,将调用IShellExtInit 接口初始化菜单,然后调用接口IContexMenu处理右键菜单,所以我们将在DLL组件中暴露以上接口。这只需要在BEGIN_COM_MAP()与END_COM_MAP()宏中加入接口即可。
- 9.Windows窗口初始化快捷菜单时调用IShellExtInit接口的Initialize ()方法,函数原型如下:
HRESULT Initialize(LPCITEMIDLIST pidlFolder,LPDATAOBJECT lpdobj, HKEY hkeyProgID );
我们将在这个函数里进行必要的初始化动作,例如保存文件名的完整路径,保存注册表的键值等。 - 10.浏览器调用IContexMenu接口进行命令的解释执行,这是我们进行源代码统计的主要部分,我们将调用以上的算法对所选定的文件夹按照约定的规则进行代码统计。这个接口主要有以下三个方法需要实现:
// 在视窗的状态栏上显示命令说明,这里值得注意的是,我们需要对ASCII码和UNICODE码进行处理,
// 以适应不同系统。
HRESULT GetCommandString(
UINT idCmd,
UINT uFlags,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax
);
// 执行菜单明命令,在此可以实现具体的功能。
HRESULT InvokeCommand(
LPCMINVOKECOMMANDINFO pici
);
// 在这里增加快捷菜单
HRESULT QueryContextMenu(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
);
这里仅举例 InvokeCommand()的实现,其他请看源代码。
更多精彩
赞助商链接