分类: 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}现在在资源管理器里对文件夹按快捷菜单,看到了吗,多出一菜单项了:源代码统计…,当我们单击该项时即可进行代码统计。