分类: C/C++
2008-03-17 14:05:21


二、实现原理
三、实现过程
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 作用:获取源文件的代码行数
// 参数: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;
}
HRESULT Initialize(LPCITEMIDLIST pidlFolder,LPDATAOBJECT lpdobj, HKEY hkeyProgID );我们将在这个函数里进行必要的初始化动作,例如保存文件名的完整路径,保存注册表的键值等。
// 在视窗的状态栏上显示命令说明,这里值得注意的是,我们需要对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()的实现,其他请看源代码。 //////////////////////////////////////////////////////////////////////////////////////////////////////////
// 作用:执行快捷菜单命令
// 参数:1. pici:包含命令信息的结构体
HRESULT CCountLines::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
BOOL bEx = FALSE;
BOOL bUnicode = FALSE;?
if (pici->cbSize = sizeof(CMINVOKECOMMANDINFOEX))
{
bEx = TRUE;
if ((pici->fMask & CMIC_MASK_UNICODE))
{
bUnicode = TRUE;
}
}
// lpVerb参数有两种标识:如高位字非0,则为命令字串,否则低位提供了快捷菜单的偏移值。
if (!bUnicode && HIWORD(pici->lpVerb))
{
if(StrCmpIA(pici->lpVerb, "Stat."))
{
return E_FAIL;
}
}
else if (bUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) pici)->lpVerbW))
{
if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW, L"Stat."))
{
return E_FAIL;
}
}
else if (LOWORD(pici->lpVerb) != IDM_SRC_COUNT)
{
return E_FAIL;
}
else
{
assert(0 == HIWORD(pici->lpVerb));
int lines = 0;
TCHAR szTitle[MAX_PATH] = {0};
TCHAR szMsg[MAX_PATH] = {0};
TCHAR szFormat[MAX_PATH] = {0};
memset(szMsg, 0, MAX_PATH);
//保存当前光标并重设为等待形状
HCURSOR hOldCursor = GetCursor();??
HCURSOR hNewCursor = LoadCursor(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDC_COUNT_WAIT));
assert(hNewCursor);
SetCursor(hNewCursor);?
TCHAR szTemp[MAX_PATH] = {0};
LoadString(_Module.GetModuleInstance(), IDS_TOTAL_LINES, szFormat, MAX_PATH);
if (SUCCEEDED(GetFolderLines((BSTR *)&m_pszPath, &lines)))
{
wsprintf(szMsg, szFormat, (LPTSTR)m_pszPath, lines);
}
// 恢复默认光标形状
SetCursor(hOldCursor);
// 显示统计代码信息
LoadString(_Module.GetModuleInstance(), IDS_TITLE, szTitle, MAX_PATH);
MessageBox(pici->hwnd, szMsg, szTitle, MB_OK | MB_ICONINFORMATION);
}
return S_OK;
}
四、其它 
HKEY_CLASSES_ROOT\Directory\Shellex\ContextMenuHandlers\下新建一项,命名为SrcCount,它的默认键值是组件的GUID,这里为:
{548773BA-874E-4C02-9DC7-B7A096772C7D} 现在在资源管理器里对文件夹按快捷菜单,看到了吗,多出一菜单项了:源代码统计…,当我们单击该项时即可进行代码统计。
五、参考资料