干干净净杀死进程

要杀掉某个程序的进程,能够输入下面的命令即可以杀死其运行实例:html

tskill 程序名      

可是我想在本身写的代码里实现tskill的功能该如何作呢?最安全的杀死进程的方法是向运行程序的主窗口发送WM_CLOSE消息。安全

HWND hwnd = // 得到主窗口
PostMessage(hwnd, WM_CLOSE, 0, 0);      

发送此消息后,一般应该等待直到进程确实终止:并发

HANDLE hp = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,pid);
WaitForSingleObject(hp, 5000); // 等待5秒      

当进程终止时,它发出状态信号,而且 WaitForSingleObject 返回WAIT_OBJECT_0。若是返回别的值,进程要么挂起了,要么仍然在进行处理。在这种状况下,杀死这个进程的惟一方法是用功能更强大的 TerminateProcess:工具

if (WaitForSingleObject(hp, 5000) != WAIT_OBJECT_0)
    TerminateProcess(hp,0);       

若是想干得漂亮一点,能够在关闭以前向主窗口发送一个WM_QUERYENDSESSION消息。当用户结束会话(log out)或者有人调用ExitWindows时,应用程序会收到这个消息。而后准备即未来临的死亡。此时通常都会弹出一个确认对话框,告诉世人:“我要完 蛋了,若是要保存修改的东西,如今是最佳时机,想保存吗?”有三种选择(Yes/No/Cancel)。此外,WM_QUERYENDSESSION甚至 能够拒绝死亡(按下"Cancel键"),若是是这样,生命将会延续。代码应该这样写:post

DWORD bOKToKill = FALSE;
SendMessageTimeout(hwnd, WM_QUERYENDSESSION, 0, 0,
    SMTO_ABORTIFHUNG|SMTO_NOTIMEOUTIFNOTHUNG, 100, &bOKToKill);
if (bOKToKill) {
  // 发送WM_CLOSE 并等待
}      

若是想要关闭的进程被挂起。使用SendMessageTimeout就很是重要,而不是用SendMessage。ui

SMTO_NOTIMEOUTIFNOTHUNG是一个只有Windows 2000 和Windows XP才有的标志。其意义是“若是线程没有挂起,不要超时。”换句话说就是:若是线程正在进行正常处理,那么永远等待,以便用户能看到对话框并决定作什么。 当用户最终作出决定后,SendMessageTimeout将带着相应的bOKToKill值返回。全部这些的前提是其它的应用程序运行正常而且 WM_QUERYENDSESSION也获得正常处理。 本文提供了一个小例子程序kp.exe,下面是关键代码:命令行

/////////////////////////////////////////////
kp.exe程序代码
////////////////////////////////////////////

#include "stdafx.h"
#include "EnumProc.h"

typedef list<string> CStringList;         // 使用STL,与MFC的相似
inline BOOL isswitch(TCHAR c) { return c==L''''''''/'''''''' || c==L''''''''-''''''''; }

int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CStringList cmdargs;             // 命令行参数 (要杀死的进程,能够多个)
    BOOL bDisplayOnly=FALSE;     // 不杀,只是显示
    BOOL bQuiet=FALSE;           // 禁止出错信息
    BOOL bZap=FALSE;            // 强行杀死

    // 解析命令行开关,开关顺序能够任意
    for (int i=1; i<argc; i++) {
        if (isswitch(argv[i][0])) {
            for (UINT j=1; j<strlen(argv[i]); j++) {
                switch(tolower(argv[i][j])) {
                case ''''''''?'''''''':    help();    return 0;
                case ''''''''n'''''''':    bDisplayOnly=TRUE; break;
                case ''''''''q'''''''':    bQuiet=TRUE;       break;
                case ''''''''z'''''''':    bZap=TRUE;         break;
                default:
                    return help();
                }
            }
        } else {
            cmdargs.push_back(argv[i]);     // 若是是非开关参数,添加到列表
        }
    }
    if (cmdargs.size()<=0)
        help();

    // 遍历参数(模块名),一个一个干掉
    CStringList::iterator it;
    for (it=cmdargs.begin(); it!=cmdargs.end(); it++) {
        CFindKillProcess fkp;
        DWORD pid = fkp.FindProcess(it->c_str());
        if (pid) {
            if (bDisplayOnly) {
                _tprintf(_T("Kill process %d(0x%08x)\n"),pid,pid);
            } else {
                fkp.KillProcess(pid, bZap);
            }
        } else if (!bQuiet) {
            _tprintf(_T("错误: 找不到进程 ''''''''%s''''''''.\n"),it->c_str());
        }
    }
    return 0;
}     

这个程序的功能与tskill相似,用它也能够杀死进程。为了加强代码的可重用性,将实现细节都封装在一个叫CFindKillProcess的类中,包 括查找和杀死进程,详情请参见EnumProc.h和EnumProc.cpp文件。文件中还有另外两个可重用类,一个是 CProcessIterator,另外一个是CWindowIterator。这在之前的文章中有过详细描述。线程

///////////////////////////////////////////////////////////////
EnumProc.h和EnumProc.cpp
//////////////////////////////////////////////////////////////
EnumProc.h 


//////////////////////////////////////////////////////////////////////////////////////////////
// 下面是CFindKillProcess的定义和实现,这是一个小巧工具类,专门用来经过某个进程的名字查找并杀死它。
//
class CFindKillProcess {
public:
    CFindKillProcess();
    ~CFindKillProcess();
    DWORD FindProcess(LPCTSTR lpModname, BOOL bAddExe=TRUE);
    BOOL  KillProcess(DWORD pid, BOOL bZap);
};

EnumProc.cpp 

#include "stdafx.h"
#include "EnumProc.h"

……
//实现CProcessIterator
…….
//实现CWindowIterator

////////////////////////////////////////////////////////////////
// 实现CFindKillProcess - 用模块名查找并杀死进程。
//
CFindKillProcess::CFindKillProcess()
{
}

CFindKillProcess::~CFindKillProcess()
{
}

//////////////////
// 搜索与参数匹配的模块名,模块名能够是foo或者foo.exe
//
DWORD CFindKillProcess::FindProcess(LPCTSTR modname, BOOL bAddExe)
{
    CProcessIterator itp;
    for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
        TCHAR name[_MAX_PATH];
        CProcessModuleIterator itm(pid);
        HMODULE hModule = itm.First(); // .EXE
        if (hModule) {
            GetModuleBaseName(itm.GetProcessHandle(),
                hModule, name, _MAX_PATH);

            string sModName = modname;
            if (strcmpi(sModName.c_str(),name)==0)
                return pid;
            sModName += ".exe";
            if (bAddExe && strcmpi(sModName.c_str(),name)==0)
                return pid;
        }
    }
    return 0;
}

//////////////////
// 干净地杀死进程:关闭窗口后等待。
// bZap=TRUE :强行杀死
//
BOOL CFindKillProcess::KillProcess(DWORD pid, BOOL bZap)
{
    CMainWindowIterator itw(pid);
    for (HWND hwnd=itw.First(); hwnd; hwnd=itw.Next()) {
        DWORD bOKToKill = FALSE;
        SendMessageTimeout(hwnd, WM_QUERYENDSESSION, 0, 0,
            SMTO_ABORTIFHUNG|SMTO_NOTIMEOUTIFNOTHUNG, 100, &bOKToKill);
        if (!bOKToKill)
            return FALSE;  // 不肯意死亡,取消行动
        PostMessage(hwnd, WM_CLOSE, 0, 0);
    }

    // 我已经关闭了所有主窗口,如今等待进程死亡。 
    BOOL bKilled = TRUE;
    HANDLE hp=OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,pid);
    if (hp) {
        if (WaitForSingleObject(hp, 5000) != WAIT_OBJECT_0) {
            if (bZap) { // 不肯死,那不行,你必须死
                TerminateProcess(hp,0);
            } else {
                bKilled = FALSE;
            }
        }
        CloseHandle(hp);
    }
    return bKilled;
}
CFindKillProcess的使用方法以下:

CFindKillProcess fkp;
DWORD pid = fkp.FindProcess("outlook.exe");
fkp.KillProcess(pid);

FindKillProcess用 CProcessIterator 和 CProcessModuleIterator类来枚举全部进程,查找第一个与名字匹配的模块(即启动进程的exe文件):htm

CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
  CProcessModuleIterator itm(pid);
  HMODULE hModule = itm.First(); // .EXE
  if (/* 模块名 =  正在查找的模块名*/) {
    return pid;
  }
}     

FindProcess查找foo或者foo.exe。若是找到这个进程,它返回此进程的ID,而后你将它传给 CFindKillProcess::KillProcess。KillProcess封装了关闭窗口以及终止逻辑。它利用 CMainWindowIterator来枚举进程的主窗口,并发送WM_CLOSE到每个窗口,而后等待进程死亡。它有一个布尔型参数用来指示当应用程序不肯意死亡时是否执行TerminateProcess。详细细节请参见下载的代码。blog

转载于:https://www.cnblogs.com/rogee/archive/2011/03/31/2000497.html