需求:时刻监控任务列表,如果需要一直启动的程序未开启,则开启
实现:
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
/******
//两种由逻辑设备名映射盘符的解决链接
//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、开启进程
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