首页 > 代码库 > Windows-进程-退出进程

Windows-进程-退出进程

终止进程的运行
1.主线程的进入点函数返回(最好使用这个方法)。
2.进程中的一个线程调用ExitProcess函数(应该避免使用这种方法)。
3.另一个进程中的线程调用TerminateProcess函数(应该避免使用这种方法)。
4.进程中的所有线程自行终止运行(这种情况几乎从未发生)。




主线程的进入点函数返回



始终都应该这样来设计应用程序,即只有当主线程的进入点函数返回时,它的进程才终止运行。这是保证所有线程资源能够得到正确清除的唯一办法。让主线程的进入点函数返回,可以确保下列操作的实现:


该线程创建的任何C++对象将能使用它们的析构函数正确地撤消。
操作系统将能正确地释放该线程的堆栈使用的内存。
系统将进程的退出代码(在进程的内核对象中维护)设置为进入点函数的返回值。
系统将进程内核对象的返回值递减1。


ExitProcess函数



主线程的进入点函数(WinMain、wWinMain、main或wmain)返回时,它将返回给C/C++运行期启动代码,它能正确地清除该进程使用的所有的C运行期资源。当C运行期资源被释放之后,C运行期启动代码就显式调用ExitProcess,并将进入点函数返回的值传递给它。这解释了为什么只需要主线程的进入点函数返回,就能够终止整个进程的运行。请注意,进程中运行的任何其他线程都随着进程而一道终止运行。


调用ExitProcess或ExitThread可使进程或线程在函数中就终止运行
可能会导致运行期库的C,C++资源没有得到释放,主线程也没有的到释放

#include <windows.h>
#include <stdio.h>

class CSomeObj
{
public:
	CSomeObj(int index)
	{
		m_index = index;
		printf("Constructor\r\n");
	}

	~CSomeObj()
	{
		printf("Destructor %d \r\n",m_index);
	}
public:
	int m_index;
};
CSomeObj g_GlobalObj(100);
int _tmain(int argc, _TCHAR* argv[])
{
	CSomeObj LocalObj(200);

	//This shouldn't be here
	ExitProcess(0);
	return 0;
}




TerminateProcess函数



BOOL TerminateProcess(HANDLE hProcess,UINT fuExitCode);
在任何线程中都能终止另一个进程或者自己本身的进程
只有当无法用另一种方法来迫使进程退出时,才应该使用TerminateProcess。终止运行的进程绝对得不到关于它将终止运行的任何通知,因为应用程序无法正确地清除,并且不能避免自己被撤消(除非通过正常的安全机制)。
这个有点像你的电脑死机蓝屏正在运行的程序的数据没有得到正确的保存
注意TerminateProcess函数是个异步运行的函数,你不知道它什么时间结束

#include <windows.h>
#include <stdio.h>
typedef DWORD(__stdcall *NtTerminateProcess)(HANDLE, UINT);
NtTerminateProcess fNtTerminateProcess = NULL;
BOOL ExitProc(HANDLE hProc)
{
	HINSTANCE hModule = LoadLibrary(_T("ntdll.dll")); //加载 ntdll.dll
	if (hModule != 0)
	{
		fNtTerminateProcess = (NtTerminateProcess)GetProcAddress(hModule, "NtTerminateProcess"); //加载外部DLL函数
		HANDLE hToken = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)hProc); //获得进程的最大权限
		if (hToken != 0)
		{
			if (fNtTerminateProcess(hToken, 1) == 0) //关闭程序
			{
				printf("End Proc:%d\n", (int)hProc);
				return TRUE;
			}
			else
			{
				return FALSE;
			}
		}
		return FALSE;
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));
	TCHAR szpath[] = TEXT("WORDPAD README.txt");
	TCHAR lpCommandLine[] = _T("C:\\Windows\\notepad.exe");
	// Start the child process. 
	if (!CreateProcess(NULL,   // No module name (use command line)
		lpCommandLine,        // Command line
		NULL,           // Process handle not inheritable
		NULL,           // Thread handle not inheritable
		FALSE,          // Set handle inheritance to FALSE
		0,              // No creation flags
		NULL,           // Use parent's environment block
		NULL,           // Use parent's starting directory 
		&si,            // Pointer to STARTUPINFO structure
		&pi)           // Pointer to PROCESS_INFORMATION structure
		)
	{
		printf("CreateProcess failed (%d)\n", GetLastError());
		return 0;
	}
//	ExitProcess(0);
	//ExitThread(0);
	ExitProc(pi.hProcess);
	//CloseHandle(pi.hProcess);
	//CloseHandle(pi.hThread);
	return 0;
}


进程终止运行时出现的情况

基本上不会发生
当进程终止运行时,下列操作将启动运行:


1)进程中剩余的所有线程全部终止运行。
2)进程指定的所有用户对象和GDI对象均被释放,所有内核对象均被关闭(如果没有其他进程打开它们的句柄,那么这些内核对象将被撤消。但是,如果其他进程打开了它们的句柄,内核对象将不会撤消)。
3)进程的退出代码将从STILL_ACTIVE改为传递给ExitProcess或TerminateProcess的代码。
4)进程内核对象的状态变成收到通知的状态(关于传送通知的详细说明,参见第9章)。系统中的其他线程可以挂起,直到进程终止运行。
5)进程内核对象的使用计数递减1。

BOOL GetExitCodeProcess(HANDLE hProcess,PDWORD pdwExitCode);
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>

int _tmain(int argc, _TCHAR* argv[])
{

	TCHAR  lpCommandLine[] = TEXT("NOTEPAD");
	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(pi));

	SECURITY_ATTRIBUTES ps;
	ps.bInheritHandle = FALSE;
	ps.nLength = sizeof(ps);
	ps.lpSecurityDescriptor = NULL;
	if (!CreateProcess(NULL,
		lpCommandLine,
		&ps,
		NULL,
		FALSE,
		NULL,
		NULL,
		NULL,
		&si,
		&pi
		))
	{
		printf("CreateProcess failed (%d)\n", GetLastError());
		return 0;
	}
	else
	{
		DWORD dwExitCode = NULL;
			//Close the thread handle as soon as
			//it is no longer needed!
			

			//Suspend our execution until
			//the child has terminated.
			WaitForSingleObject(pi.hProcess, INFINITE);

			//The child process terminated;
			//get its exit code.
			if (!GetExitCodeProcess(pi.hProcess,
				&dwExitCode))
			{
				_tprintf(_T("GetExitCodeProcess false"));
				printf("exitcode failed (%d)\n", GetLastError());
			}
			else
			{
	    printf("exitcode is  %s", dwExitCode);

			}
		
			//Close the process handle as soon as
			//it is no longer needed.
			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);
		}
	
	return 0;
}


该函数查看进程的内核对象(由hProcess参数来标识),取出内核对象的数据结构中用于标识进程的退出代码的成员。该退出代码的值在pdwExitCode参数指向的DWORD中返回。


枚举系统进程

// EnumProcess.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <Psapi.h>

void PrintProcessNameAndID(DWORD processID)
{
	TCHAR szProcessName[MAX_PATH] = _T("<unknown>");
	//进程ID 打开进程
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
		FALSE, processID);

	if (NULL != hProcess)
	{
		HMODULE hMod;
		DWORD cbNeeded;

		if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
			&cbNeeded))
		{
			GetModuleBaseName(hProcess, hMod, szProcessName,
				sizeof(szProcessName) / sizeof(TCHAR));
		}
	}
	_tprintf(_T("(PID: %-4u)\t%20s\n"), processID, szProcessName);
	CloseHandle(hProcess);
}

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD aProcesses[1024], cbNeeded, cProcesses;
	unsigned int i;
	//枚举进程的ID
	if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
		return 0;
	cProcesses = cbNeeded / sizeof(DWORD);
	for (i = 0; i < cProcesses; i++)
	if (aProcesses[i] != 0)
		PrintProcessNameAndID(aProcesses[i]);
	_tsystem(_T("PAUSE"));
	return 0;
}






Windows-进程-退出进程