新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 用Visual C++干干净净地清除进程 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3980 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 用Visual C++干干净净地清除进程 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 用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、 添加代码,编译运行程序。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/9/13 10:53:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    三、程序代码

    //////////////////////////////////////////////////////
    #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" or "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;
    }

    //////////////////
    // 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(0x%08x)\n"),pid,pid);
       } else {
        fkp.KillProcess(pid, bZap);
       }
      } else if (!bQuiet) {
       tpf(_T("Error: Can't find process '%s'.\n"),it->c_str());
      }
     }
     return 0;
    }

    int help()
    {
     tpf(_T("kp: Kill process from command line.\n"));
     tpf(_T(" Copyright 2002 Paul DiLascia.\n\n"));
     tpf(_T(" kp [/nqz?] modname1 [modname2....]\n"));
     tpf(_T(" where modnameN is a module name; eg foo or foo.exe\n"));
     tpf(_T("\n"));
     tpf(_T(" /n(othing) don't kill, just show results\n"));
     tpf(_T(" /q(uiet) don't show errors\n"));
     tpf(_T(" /z(ap) force kill (ignore WM_QUERYENDSESSION)\n"));
     tpf(_T("\n"));
     return 0;
    }

      四、小结

      本实例通过介绍CfindKillProcess类探讨了在Windows2000下彻底消除进程的方法,虽然该程序只能在Windows2000环境下编译运行,但是该方法对Windows98下进程的控制也是有借鉴意义的。

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/9/13 10:53:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/26 15:02:23

    本主题贴数2,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    5,660.156ms