首先是读取进程,其中的PROCESSENTRY32是用来存放快照进程信息的一个结构体。(存放进程信息和调用成员输出进程信息)用来Process32First指向第一个进程信息,并将进程信息抽取到PROCESSENTRY32中。用Process32Next指向下一条进程信息。故可以用while循环不停的获取进程id以及进程名并存放到info中,然后跟注册表一样用字符串拼接起来,返回到过程处理函数并显示到编辑框内。
CString ReadProcess()
{
HANDLE handle;
CString res = TEXT("进程ID 进程名\r\n");
//调用CreatToolhelp32Snapshot来获取快照,用THREADENTRY32来获取线程信息等 就会用到'tlHelp32.h'头文件
handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 *info = new PROCESSENTRY32;
info->dwSize = sizeof(PROCESSENTRY32);
Process32First(handle, info);
while (Process32Next(handle, info) != FALSE)
{
DWORD PID = info->th32ProcessID; //获取进程ID
wchar_t *ExeName = info->szExeFile; //获取进程的EXE名(注意不是全路径)
CString temp;
temp.Format(TEXT("%d"), PID);
res += temp;
res += TEXT(" ");
res += ExeName;
res += TEXT("\r\n");
PROCESSENTRY32 *copyInfo = new PROCESSENTRY32; //将造成内存泄漏
copyInfo = info;
ProResult.push_back(copyInfo); //进程结构体PROCESSENTRY32存入vector
}
return res;
}
接着是创建进程,其中的STARTUPINFO结构是用于指定新进程的主窗口特性,cb成员是该结构的字节数。
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; //存放每个对象的与进程相关的句柄
HANDLE hThread; //返回的线程句柄。
DWORD dwProcessId; //用来存放进程ID号
DWORD dwThreadId; //用来存放线程ID号
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
PROCESS_INFORMATION结构在调用Createprocess函数后,系统会自动地对该结构进行填充。内部如上所示。一目了然,由于是系统自动填充,所以我们可以不用深究,如果感兴趣可以自己百度了解一下。
pszFilePath是全局函数,与读取文件时调用的是同一个函数OpenDlg,该函数通过打开一个对话框选择exe文件来获取文件路径并赋值给pszFilePath,以此来创建进程,CreateProcess函数的第二个参数是一个命令参数(大概这个意思),比如打开浏览器进程,第二个参数传入一个包含网址的字符串,可以在打开浏览器的时候自动打开该网站,具体可以自己了解一下。
void CreatePro()
{
STARTUPINFO stStartUpInfo;
memset(&stStartUpInfo, 0, sizeof(stStartUpInfo));
stStartUpInfo.cb = sizeof(stStartUpInfo);
PROCESS_INFORMATION stProcessInfo;
memset(&stProcessInfo, 0, sizeof(stProcessInfo));
bool bRet = CreateProcess(
pszFilePath,
NULL,
NULL,
NULL,
false,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&stStartUpInfo,
&stProcessInfo);
if (bRet)
{
//等待3s后关闭进程
WaitForSingleObject(stProcessInfo.hProcess, 3000L);
CloseHandle(stProcessInfo.hProcess);
CloseHandle(stProcessInfo.hThread);
stProcessInfo.hProcess = NULL;
stProcessInfo.hThread = NULL;
stProcessInfo.dwProcessId = 0;
stProcessInfo.dwThreadId = 0;
}
else
{
//如果创建进程失败,查看错误码
DWORD dwErrCode = GetLastError();
printf_s("ErrCode : %d\n", dwErrCode);
}
}
最后是结束进程,通过输入读取进程时获取的pid来结束进程,但是用TerminateProcess结束进程好像不是很安全,会导致资源没有正确释放,但这里不多探索,毕竟只是练手,点到为止。
函数过程也比较好理解,先获取用户输入的数字并判空,然后用wchar_t字符串接收,接着转换为DWORD类型,通过PID获取进程句柄,然后通过句柄来销毁进程,相当简单,这里不过多赘述。
void EndPro(HWND hwnd, HWND h)
{
DWORD nID;
HANDLE hPro;
DWORD n = GetWindowTextLength(hwnd);
if (n == 0)
{
MessageBox(h, TEXT("请输入一个数字"), TEXT("提示"), MB_OK);
return;
}
wchar_t* temp = new wchar_t[n + 1];
GetWindowText(hwnd, temp, n + 1);
CString t = temp;
nID = _tcstoul(t, NULL, 10);
//获得进程 ID,后通过进程 ID 获得进程句柄
hPro = OpenProcess(PROCESS_ALL_ACCESS,FALSE,nID);
if (TerminateProcess(hPro, 0) != 0)
{
MessageBox(h, TEXT("销毁成功"), TEXT("提示"), MB_OK);
return;
}
else
{
MessageBox(h, TEXT("销毁失败"), TEXT("提示"), MB_OK);
return;
}
}
到这里win32编程的练手项目就结束了,总而言之不算难,基本就是调用api进行处理,难得主要是要用正确的类型和大小来接收结果,特别是诸如LPSTR,LPSCSTR,LPCSWSTR,LPWSTR,长得挺像,但含义却不一样,一开始接触有点头大,毕竟只看了一点入门视频(小甲鱼)的就开始写demo,许多类型都是第一次见,断断续续摸了两个多星期才完结,实际上每天用来写的时间也就两三个小时,出个bug就要改好久,在家效率果然低,但也算是有收获,起码知道了一些关于注册表以及进程的知识,也不是很多,肯定还要继续深入的了解。
第一次写博客有点生疏,感觉不够细节,主要还是自己太懒,以后会更加注重这方面,博客也会持续更新。