开发一个简易的任务监控程序
需求:时刻监控任务列表,如果需要一直启动的程序未开启,则开启
实现:
1、枚举当前已经启动的进程、获取进程的ID和名称
vector launchedProcess; HANDLE handle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//创建当前快照列表 PROCESSENTRY32* info=new PROCESSENTRY32;//创建进程信息变量,用于保存信息 info->dwSize=sizeof(PROCESSENTRY32);//设置块大小 int i=0; if(Process32First(handle,info))//开始枚举进程 { if(GetLastError()==ERROR_NO_MORE_FILES ) { AfxMessageBox(_T("No More Process")); } else { CString id,file; id.Format(L"%d",info->th32ProcessID);//获取当前进程ID file.Format(L"%s",info->szExeFile);//获取当前进程名 ////TRACE(L"ID:%s,Name:%s",id,file); launchedProcess.push_back(file); if(!isExistInList(id,file)) { m_list.InsertItem(i,id);//插入一个项目 m_list.SetItemData(i,info->th32ProcessID);//设置项目值 m_list.SetItemText(i,1,file);//设置名 i++; } while(Process32Next(handle,info)!=FALSE)//继续获取进程 { id.Format(L"%5d",info->th32ProcessID); file.Format(L"%s",info->szExeFile); launchedProcess.push_back(file); if(!isExistInList(id,file)) { m_list.InsertItem(i,id); m_list.SetItemData(i,info->th32ProcessID); m_list.SetItemText(i,1,file); i++; } } } } delete info;//参考博文中未添加 CloseHandle(handle);//关闭进程句柄
2、通过进程ID获取进程所对应的执行文件路径,需要实现逻辑设备名映射盘符的问题
HANDLE hProcess = NULL; BOOL bSuccess = FALSE; // 由于进程权限问题,有些进程是无法被OpenProcess的,如果将调用进程的权限 // 提到“调试”权限,则可能可以打开更多的进程 hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , FALSE, dwProcessId ); CString path(_T("")); do { if ( NULL == hProcess ) { // 打开句柄失败,比如进程为0的进程 break; } // 用于保存文件路径,扩大一位,是为了保证不会有溢出 TCHAR szPath[_MAX_PATH + 1] = {0}; // 模块句柄 HMODULE hMod = NULL; // 这个参数在这个函数中没用处,仅仅为了调用EnumProcessModules DWORD cbNeeded = 0; #if 0 // 【注】此种方法Win7-64bit cmd.exe获取不到路径(同时勾选dbgview、chrome、beyondcompare、cmd) // 获取路径 // 因为这个函数只是要获得进程的Exe路径,因为Exe路径正好在返回的数据的 // 第一位,则不用去关心cbNeeded,hMod里即是Exe文件的句柄. // If this function is called from a 32-bit application running on WOW64, // it can only enumerate the modules of a 32-bit process. // If the process is a 64-bit process, // this function fails and the last error code is ERROR_PARTIAL_COPY (299). if( FALSE == EnumProcessModules( hProcess, &hMod, sizeof( hMod ), &cbNeeded ) ) { break; } // 通过模块句柄,获取模块所在的文件路径,此处即为进程路径。 // 传的Size为_MAX_PATH,而不是_MAX_PATH+1,是因为保证不会存在溢出问题 if ( 0 == GetModuleFileNameEx( hProcess, hMod, szPath, _MAX_PATH ) ) { break; } #endif #if 1 TCHAR szWinPath[_MAX_PATH + 1] = {0}; //http://www.codeproject.com/Questions/282205/Get-Path-all-of-opened-Windows-WinAPI HINSTANCE hinstLib; typedef DWORD (WINAPI *FPGetProcessImageFileName)(HANDLE,LPTSTR,DWORD); FPGetProcessImageFileName fpGetProcessImageFileName = NULL; // Get a handle to the DLL module. GetWindowsDirectory(szWinPath,sizeof(szWinPath)); path.Format(L"%s\\SYSTEM32\\psapi.dll",szWinPath); ////TRACE(L"path:%s",(LPCTSTR)path); hinstLib = ::LoadLibrary((LPCTSTR)path); if (hinstLib != NULL) { #ifdef UNICODE #define GetProcessImageFileNameStr "GetProcessImageFileNameW" #else #define GetProcessImageFileNameStr "GetProcessImageFileNameA" #endif // !UNICODE //http://blog.163.com/danshiming@126/blog/static/109412748201141425648762/ CString strFunName = _T(GetProcessImageFileNameStr); CStringA strFunNameA(strFunName); fpGetProcessImageFileName = (FPGetProcessImageFileName) ::GetProcAddress(hinstLib, strFunNameA); // If the function address is valid, call the function. if (NULL != fpGetProcessImageFileName) { // if(!fpGetProcessImageFileName(hProcess, szPath, _MAX_PATH)) GetLastError(); } } else { AfxMessageBox(_T("psapi.dll not found")); } // Free the DLL when you are done. ::FreeLibrary(hinstLib); #endif #if 0 if(!GetProcessImageFileName(hProcess, szPath, _MAX_PATH)) { break; } #endif // 保存文件路径 path = szPath; // //TRACE(L"%s",(LPCTSTR)path); // 查找成功了 #if 1 CString deviceName(_T("")); int num=0;//第三次出现\的位置左边即为逻辑设备名 //"\Device\HarddiskVolume2\Windows\System32\cmd.exe" for(int i=0;i<path.GetLength();i++) { if(path.GetAt(i)=='\\') { num++; if(num == 3) { deviceName.Empty(); deviceName = path.Left(i); path = path.Right(path.GetLength()-i-1); ////TRACE(L"logicVolume:%s,path:%s",logicVolume,path); break; } } } //TRACE(L"deviceName---%s",deviceName); std::map<CString, CString>::iterator iterator1; std::map<CString, CString>::iterator Enditerator1 = m_mapDevicePath.end(); for(iterator1 = m_mapDevicePath.begin();iterator1 != Enditerator1; iterator1++) { //TRACE(L"iterator---%s",iterator1->first); CStringA left(iterator1->first); CStringA right(deviceName); //TRACE(L"left---%s",left); //TRACE(L"right---%s",right); if(!left.Compare(right)) { //TRACE("helloworld"); } if(!iterator1->first.Compare(deviceName)) { //TRACE(L"iterator===%s",iterator1->first); //TRACE(L"m_mapDevicePath---%s",m_mapDevicePath[deviceName]); deviceName = iterator1->second; break; } } //TRACE(L"deviceName---%s",deviceName); path = deviceName + path; TRACE(L"path---%s",path); cstrPath = path; path.Empty(); #endif /****** //两种由逻辑设备名映射盘符的解决链接 //http://bbs.csdn.net/topics/330144410 //IoVolumeDeviceToDosName()//需要ddk驱动神马的,超级麻烦,驱动用的 //vc6.0不支持,被迫迁移到vs8,一下超链接部分的代码可直接拷贝编译运行 //http://msdn.microsoft.com/en-us/library/cc542456(v=VS.85).aspx ******/ if(cstrPath.GetLength()) bSuccess = TRUE; } while( 0 ); // 释放句柄 if ( NULL != hProcess ) { CloseHandle( hProcess ); hProcess = NULL; }
3、开启进程
//http://blog.csdn.net/itjobtxq/article/details/6233455 SHELLEXECUTEINFO ShExecInfo = {0}; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; ShExecInfo.lpFile = m_daemonModulePath[i]; ShExecInfo.lpParameters =_T(""); ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess,100); launchedProcess.push_back(m_daemonModulePath[i]);
4、边边角角的需求:只启用一个实例;最小化时任务栏不显示,只在后台中运行;再点击exe的图标,激活后台进程显示主窗口
其中需求4的最后一个小需求在vs2008生成的执行文件里会失败
最终程序截图:
vc6.0 vs2008
工程和可执行文件下载:http://download.csdn.net/detail/lonelyrains/5705883