创建进程的2种方式
1. 创建进程最简单的方法
UINT WINAPI WinExec(
_In_ LPCSTR lpCmdLine, // 指向可执行文件
_In_ UINT uCmdShow // 程序运行后的窗口状态
);
2. CreateProcess函数创建进程
通常情况下,创建一个进程会选择CreateProcess函数,该函数的参数非常多,功能强大,使用也更为灵活。
BOOL CreateProcessA(
LPCSTR lpApplicationName, // 应用程序名
LPSTR lpCommandLine, // 命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全属性
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性
BOOL bInheritHandles, // 当前进程中的可继承句柄是否被新进程继承
DWORD dwCreationFlags, // 新进程的优先级以及其他创建标志
// DEBUG_PROCESS,DEBUG_ONLY_THIS_PROCESS,CREATE_SUSPENDED ResumeThread() 进行恢复
LPVOID lpEnvironment, // 新进程的环境变量 通常这里指定为NULL
LPCSTR lpCurrentDirectory, // 指定新进程使用的当前目录
LPSTARTUPINFOA lpStartupInfo, // 新进程的启动信息,指向STARTUPINFO结构体
LPPROCESS_INFORMATION lpProcessInformation //用于返回新进程和主线程的相关信息,指向PROCESS_INFORMATION结构体
);
typedef struct _STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;
// 该结构体在使用前,需要对cb进行赋值,用户保存结构体的大小
// 如果要对新进程的输入输出重定向的话,会用到该结构体的更多成员
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/ns-processthreadsapi-process_information
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
// 该结构体用于返回 新创建进程的句柄和进程ID,进程主线程的句柄和主线程ID,进程创建后 这2个句柄需要关闭
示例代码
#include <windows.h>
#include <stdio.h>
#define EXEC_FILE "c:\\windows\\system32\\notepad.exe"
int main()
{
// 必须初始化
STARTUPINFOA sInfo = {0};
sInfo.cb = sizeof(sInfo);
PROCESS_INFORMATION pInfo = {0};
BOOL ret = CreateProcessA(EXEC_FILE,NULL,NULL,NULL,FALSE,
NULL,NULL,NULL,&sInfo,&pInfo);
if(!ret){
printf("创建进程失败");
} else
{
printf("创建进程成功");
}
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
return 0;
}
终止进程
进程正常退出时,会调用ExitProcess函数,调用SendMessage函数发送WM_CLOSE消息到目标窗口的方法,这种方法通常也会让程序正常结束而退出。本节 介绍 强制结束指定进程。使用OpenProcess获取进程句柄,然后TerminateProcess终止进程。
- 结束指定进程的示例代码
// 强制退出进程
int ExitProcess()
{
HWND hWnd = FindWindow(NULL,"无标题 - 记事本");
if( hWnd == NULL )
{
printf("FindWindow 失败");
return -1;
}
DWORD pid = 0;
GetWindowThreadProcessId(hWnd,&pid);
if( pid == 0)
{
printf("GetWindowThreadProcessId 失败");
return -1;
}
HANDLE hNote = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
if( hNote == NULL )
{
printf("OpenProcess 失败");
return -1;
}
BOOL ret = TerminateProcess(hNote,-1);
if( ret )
{
printf("成功退出");
}else
{
printf("TerminateProcess 失败");
return -1;
}
return 0;
}
- 结束进程所用的API函数说明
FindWindow() // 查找窗口
// 获取进程ID函数
DWORD WINAPI GetWindowThreadProcessId(
In HWND hWnd, // 窗口句柄
Out_opt LPDWORD lpdwProcessId // 进程ID,传出参数
);// 获取进程句柄,error return NULL
HANDLE WINAPI OpenProcess(
In DWORD dwDesiredAccess, // 打开进程的访问权限 PROCESS_ALL_ACCESS
In BOOL bInheritHandle, // 是否可继承
In DWORD dwProcessId // 进程ID
);// 结束进程
BOOL WINAPI TerminateProcess(
In HANDLE hProcess,
In UINT uExitCode
);
进程、线程及DLL枚举API介绍
无论是枚举进程还是枚举进程中的DLL文件,方法都是相同的,都是通过创建指定的相关快照,再通过循环逐条获取快照的内容。类似的枚举线程、枚举堆都是相同的方法,差别只是在创建快照时的参数不同,逐条获取快照的内容时的API函数不同而已。
枚举进程的API函数:CreateToolhelp32Snapshot()、Process32First()、Process32Next()。
枚举线程的API函数:CreateToolhelp32Snapshot()、Thread32First()、Thread32Next()。
枚举进程的DLL文件:CreateToolhelp32Snapshot()、Module32First()、Module32Next()。
// err,return INVALID_HANDLE_VALUE
HANDLE WINAPI CreateToolhelp32Snapshot(
// 建立系统快照的类型:TH32CS_SNAPMODULE,TH32CS_SNAPPROCESS,TH32CS_SNAPTHREAD
_In_ DWORD dwFlags,
// 如果枚举的是进程或者系统中的线程 该参数为NULL,如果是进程的DLL 那么该参数是进程ID
_In_ DWORD th32ProcessID
);
// err,return FALSE
BOOL WINAPI Process32First(
_In_ HANDLE hSnapshot,
_Inout_ LPPROCESSENTRY32 lppe // 输入输出
);
typedef struct tagPROCESSENTRY32 {
DWORD dwSize; // 该成员必须赋值,为结构体的大小
DWORD cntUsage;
DWORD th32ProcessID; // 进程ID
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID; // 父进程ID
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH]; // 可执行文件的文件名
} PROCESSENTRY32, *PPROCESSENTRY32;
BOOL WINAPI Process32Next(
_In_ HANDLE hSnapshot,
_Out_ LPPROCESSENTRY32 lppe // 传出参数
);
// 枚举进程中加载的DLL 和枚举系统中的线程都和上2个函数类似,所不同的是 XXX32First() 和 XXX32Next() 第二个参数指向的结构体不同
// DLL 指向的结构体
typedef struct tagMODULEENTRY32 {
DWORD dwSize;
DWORD th32ModuleID;
DWORD th32ProcessID;
DWORD GlblcntUsage;
DWORD ProccntUsage;
BYTE *modBaseAddr;
DWORD modBaseSize;
HMODULE hModule;
TCHAR szModule[MAX_MODULE_NAME32 + 1];
TCHAR szExePath[MAX_PATH];
} MODULEENTRY32, *PMODULEENTRY32;
// 线程 指向的结构体
typedef struct tagTHREADENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ThreadID;
DWORD th32OwnerProcessID;
LONG tpBasePri;
LONG tpDeltaPri;
DWORD dwFlags;
} THREADENTRY32, *PTHREADENTRY32;
枚举进程
HANDLE snapHandele = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);
if( INVALID_HANDLE_VALUE == snapHandele)
{
qDebug() << "CreateToolhelp32Snapshot error" ;
return;
}
PROCESSENTRY32 entry = {0};
entry.dwSize = sizeof(entry);// 长度必须赋值
BOOL ret = Process32First(snapHandele,&entry);
int i = 0;
while (ret) {
QString exeFile = QString::fromWCharArray(entry.szExeFile);
ui->processTab->insertRow(i);
ui->processTab->setItem(i,0,new QTableWidgetItem(exeFile));
ui->processTab->setItem(i,1,new QTableWidgetItem(QString("%1").arg(entry.th32ProcessID)));
i++;
ret = Process32Next(snapHandele,&entry);
}
CloseHandle(snapHandele);
枚举线程
下面是停止进程,实际上就是停止进程的所有线程,就用到了 枚举线程
HANDLE snapHandele = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);
if( INVALID_HANDLE_VALUE == snapHandele)
{
qDebug() << "CreateToolhelp32Snapshot error" ;
return;
}
THREADENTRY32 entry = {0};
entry.dwSize = sizeof(entry);
BOOL ret = Thread32First(snapHandele,&entry);
while( ret )
{
if( entry.th32OwnerProcessID == pid)
{
HANDLE tHandle = OpenThread(THREAD_ALL_ACCESS,FALSE,entry.th32ThreadID);
if( tHandle == NULL)
{
qDebug() << "OpenThread error,threadId = " << entry.th32ThreadID;
}
else
{
DWORD ret = SuspendThread(tHandle);
if( ret == -1)
{
qDebug() << "SuspendThread error";
}else
{
qDebug() << "SuspendThread success";
}
CloseHandle(tHandle);
}
}
ret = Thread32Next(snapHandele,&entry);
}
CloseHandle(snapHandele);
枚举DLL
HANDLE snapHandele = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE ,pid);
if( INVALID_HANDLE_VALUE == snapHandele)
{
qDebug() << "CreateToolhelp32Snapshot error" ;
return;
}
MODULEENTRY32 entry = {0};
entry.dwSize = sizeof(entry);// 长度必须赋值
BOOL ret = Module32First(snapHandele,&entry);
int i = 0;
while (ret) {
QString dllFile = QString::fromWCharArray(entry.szModule);
QString dllPath = QString::fromWCharArray(entry.szExePath);
ui->dllTab->insertRow(i);
ui->dllTab->setItem(i,0,new QTableWidgetItem(dllFile));
ui->dllTab->setItem(i,1,new QTableWidgetItem(QString("%1").arg(dllPath)));
i++;
ret = Module32Next(snapHandele,&entry);
}
CloseHandle(snapHandele);