C/C++:Windows编程—创建进程、终止进程、枚举进程、枚举线程、枚举DLL

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_29542611/article/details/86567304

创建进程的2种方式

1. 创建进程最简单的方法

UINT WINAPI WinExec(
  _In_ LPCSTR lpCmdLine, // 指向可执行文件
  _In_ UINT   uCmdShow // 程序运行后的窗口状态
);

2. CreateProcess函数创建进程

通常情况下,创建一个进程会选择CreateProcess函数,该函数的参数非常多,功能强大,使用也更为灵活。

https://docs.microsoft.com/zh-cn/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa

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终止进程。

  1. 结束指定进程的示例代码
// 强制退出进程 
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;
}
  1. 结束进程所用的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);

猜你喜欢

转载自blog.csdn.net/qq_29542611/article/details/86567304