精品主页 | 软件下载 | 系统下载 | 精品导航| 精彩图片 | 转帖工具 | 版主申请 | 影视下载

查看完整版本: 用Visual C 干干净净地清除进程

mxh1998 2008-3-26 22:49

用Visual C 干干净净地清除进程

  


                   很多朋友们可能经常会碰到这样一个问题,想对某些进行操作时,发现这些文件正在被其它程序使用


,处于打开状态,而且是被独占打开,这时是没法对文件进行操作的。因此,要想操作这些文件,必须将


打开这些文件的进程清除掉。那么如何干净地清除进程呢?其实,在Windows2000操作系统版本中有一个


工具程序叫tskill.exe,用它就可以清除掉某个程序的进程,在输入"tskill 程序名"后就可以清除其运


行实例。但是如何要在代码里实现tskill的功能该如何做呢?针对这一问题,本实例介绍了在


Windows2000下实现的方法。


  一、实现方法


  在Visual C  编程中,最安全的杀死进程的方法是向运行程序的主窗口发送WM_CLOSE消息,其实现代


码如下:


HWND hwnd =this.m_hWnd; // 获得主窗口

PostMessage(hwnd, WM_CLOSE, 0, 0);


  发送此消息后,通常应该等待直到进程确实终止,当进程终止时,它发出状态信号,并且


WaitForSingleObject 返回WAIT_OBJECT_0。如果返回别的值,进程要么挂起了,要么仍然在进行处理。


在这种情况下,杀死这个进程的唯一方法是用功能更强大的API函数:TerminateProcess()。如果想干


得漂亮一点,可以在关闭之前向主窗口发送一个WM_QUERYENDSESSION消息,当用户结束会话(log out)


或者调用ExitWindows()函数时,应用程序会收到这个消息,然后准备退出进程,此时一般都会弹出一


个确认对话框,告诉用户:"程序要推出了,如果要保存修改的东西,现在是最佳时机,想保存吗?"有三


种选择(Yes/No/Cancel)。此外,发送WM_QUERYENDSESSION消息可以拒绝推出进程(按下"Cancel键")


,如果是这样,进程将会延续。


  如果想要关闭的进程被挂起,使用SendMessageTimeout()函数就非常重要,而不是用SendMessage


()函数,其参数SMTO_NOTIMEOUTIFNOTHUNG是一个只有Windows 2000 和Windows XP才有的标志。其意义


是"如果线程没有挂起,不要超时",换句话说就是如果线程正在进行正常处理,那么永远等待,以便用户


能看到对话框并决定做什么,当用户最终做出决定后,SendMessageTimeout()将带着相应的bOKToKill


值返回。


  本例为了增强代码的可重用性,将实现细节都封装在一个叫CFindKillProcess的类中,包括查找和杀


死进程,详情请参见EnumProc.h和EnumProc.cpp文件。文件中还有另外两个可重用类,一个是


CProcessIterator,另一个是CWindowIterator。这在实例《获取进程的主窗口以及创建进程的程序名》


中有过详细的叙述。


  CfindKillProcess类的成员函数FindProcess()查找某个进程序,如果找到这个进程,它返回此进


程的ID,然后将此ID传给CFindKillProcess::KillProcess()函数,KillProcess()函数封装了关闭窗


口以及终止逻辑,它利用CmainWindowIterator类对象来枚举进程的主窗口(可能不止一个,见"如何获取


某个进程的主窗口以及创建进程的程序名?"),并发送WM_CLOSE到每一个窗口,然后等待进程死亡。它


有一个布尔型参数用来指示当应用程序进程不愿意退出时是否执行TerminateProcess()函数。详细细节


请参见下载的代码。


  二、编程步骤


  1、 启动Visual C  6.0,生成一个控制台应用程序,将该程序命名为"kp";


  2、 在程序代码中添加CfindKillProcess、CProcessIterator类的定义;


  3、 添加代码,编译运行程序。


  


                  


三、程序代码


//////////////////////////////////////////////////////

#pragma once

//////////////////

// Process iterator -- iterator over all system processes

// Always skips the first (IDLE) process with PID=0.

class CProcessIterator {

 protected:

  DWORD* m_pids; // array of procssor IDs

  DWORD m_count; // size of array

  DWORD m_current; // next array item


 public:

  CProcessIterator();

  ~CProcessIterator();

  DWORD First();

  DWORD Next() {

   return m_pids && m_current < m_count ? m_pids[m_current  ] : 0;

  }

  DWORD GetCount() {

   return m_count;

  }

};


//////////////////

// Handy class to facilitate finding and killing a process by name.

class CFindKillProcess {

 public:

  CFindKillProcess();

  ~CFindKillProcess();

  DWORD FindProcess(LPCTSTR lpModname, BOOL bAddExe=TRUE);

  BOOL KillProcess(DWORD pid, BOOL bZap);

};


////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "EnumProc.h"

// CProcessIterator - Iterates all processes

CProcessIterator::CProcessIterator()

{

 m_pids = NULL;

}


CProcessIterator::~CProcessIterator()

{

 delete [] m_pids;

}


//////////////////

// Get first process: Call EnumProcesses to init array. Return first one.

DWORD CProcessIterator::First()

{

 m_current = (DWORD)-1;

 m_count = 0;

 DWORD nalloc = 1024;

 do {

  delete [] m_pids;

  m_pids = new DWORD [nalloc];

  if (EnumProcesses(m_pids, nalloc*sizeof(DWORD), &m_count)) {

   m_count /= sizeof(DWORD);

   m_current = 1; // skip IDLE process

  }

 } while (nalloc <= m_count);

 return Next();

}


////////////////////////////////////////////////////////////////

// CFindKillProcess - to find/kill a process by module name.

//

CFindKillProcess::CFindKillProcess()

{}


CFindKillProcess::~CFindKillProcess()

{}


//////////////////

// Search for process whose module name matches parameter.

// Finds "foo[/img]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;

}


//////////////////

// Kill a process cleanly: Close main windows and wait.

// bZap=TRUE to force kill.

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; // window doesn't want to die: abort

  PostMessage(hwnd, WM_CLOSE, 0, 0);

 }

 // I've closed the main windows; now wait for process to die.

 BOOL bKilled = TRUE;

 HANDLE hp=OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,pid);

 if (hp) {

  if (WaitForSingleObject(hp, 5000) != WAIT_OBJECT_0) {

   if (bZap) { // didn't die: force kill it if zap requested

    TerminateProcess(hp,0);

   } else {

    bKilled = FALSE;

   }

  }

  CloseHandle(hp);

 }

 return bKilled;

}


//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "EnumProc.h"

#define tpf _tprintf // to save typing

typedef list<string> CStringList; // like MFC, but with STL

// pre-declare functions

int help();

// check for switch: / or -

inline BOOL isswitch(TCHAR c) { return c==L'/' || c==L'-'; }


int main(int argc, TCHAR* argv[], TCHAR* envp[])

{

 CStringList cmdargs; // command-line args (processes to kill)

 BOOL bDisplayOnly=FALSE; // don't kill, just show results

 BOOL bQuiet=FALSE; // suppress error messages

 BOOL bZap=FALSE; // force-kill process

 // Parse command line. Switches can come in any order.

 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]); // got a non-switch arg: add to list

  }

 }

 if (cmdargs.size()<=0)

  help();

 // Now iterate args (module names), killing each one

 CStringList::iterator it;

 for (it=cmdargs.begin(); it!=cmdargs.end(); it  ) {

  CFindKillProcess fkp;

  DWORD pid = fkp.FindProcess(it->c_str());

  if (pid) {

   if (bDisplayOnly) {

    tpf(_T("Kill process %d(0xx)"),pid,pid);

   } else {

    fkp.KillProcess(pid, bZap);

   }

  } else if (!bQuiet) {

   tpf(_T("Error: Can't find process '%s'."),it->c_str());

  }

 }

 return 0;

}


int help()

{

 tpf(_T("kp: Kill process from command line."));

 tpf(_T([/img] tpf(_T([/img] tpf(_T([/img] tpf(_T(""));

 tpf(_T([/img] tpf(_T([/img] tpf(_T([/img] tpf(_T(""));

 return 0;

}


  四、小结


  本实例通过介绍CfindKillProcess类探讨了在Windows2000下彻底消除进程的方法,虽然该程序只能


在Windows2000环境下编译运行,但是该方法对Windows98下进程的控制也是有借鉴意义的。
页: [1]
查看完整版本: 用Visual C 干干净净地清除进程