需求:時刻監控工作清單,如果需要一直啟動的程式未開啟,則開啟
實現:
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);//擷取當前進程IDfile.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 1TCHAR szWinPath[_MAX_PATH + 1] = {0};//http://www.codeproject.com/Questions/282205/Get-Path-all-of-opened-Windows-WinAPIHINSTANCE 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 0if(!GetProcessImageFileName(hProcess, szPath, _MAX_PATH)) { break; }#endif// 儲存檔案路徑 path = szPath;// //TRACE(L"%s",(LPCTSTR)path);// 尋找成功了 #if 1CString 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/6233455SHELLEXECUTEINFO 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