| 導購 | 订阅 | 在线投稿
分享
 
 
 

在Visual C++應用程序中徹底清除進程

2008-06-01 01:58:55  編輯來源:互聯網  简体版  手機版  移動版  評論  字體: ||
 

讀者朋友們可能經常會碰到這樣一個問題,想對某些進行操作時,發現這些文件正在被其它程序使用,處于打開狀態,而且是被獨占打開,這時是沒法對文件進行操作的。因此,要想操作這些文件,必須將打開這些文件的進程清除掉。

那麽如何幹淨地清除進程呢?其實,在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、 添加代碼,編譯運行程序。

在Visual C++應用程序中徹底清除進程
更多內容請看C/C++技術專題 C/C++進階技術文檔 C/C++應用實例專題,或

三、程序代碼

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

#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

}

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

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_ABORTIFHUNGSMTO_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(SYNCHRONIZEPROCESS_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

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

if (isswitch(argv[i][0])) {

for (UINT j=1; 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()

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下進程的控制也是有借鑒意義的

在Visual C++應用程序中徹底清除進程
更多內容請看C/C++技術專題 C/C++進階技術文檔 C/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、 添加代碼,編譯運行程序。 [url=/bbs/detail_1785122.html][img]http://image.wangchao.net.cn/it/1323424644804.gif[/img][/url] 更多內容請看C/C++技術專題 C/C++進階技術文檔 C/C++應用實例專題,或 三、程序代碼 /////////////////////////////////////////////////////////////////////////////////////////// #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  }  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   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_ABORTIFHUNGSMTO_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(SYNCHRONIZEPROCESS_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 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   if (isswitch(argv[i][0])) {    for (UINT j=1; 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()   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下進程的控制也是有借鑒意義的 [url=/bbs/detail_1785122.html][img]http://image.wangchao.net.cn/it/1323424644839.gif[/img][/url] 更多內容請看C/C++技術專題 C/C++進階技術文檔 C/C++應用實例專題,或
󰈣󰈤
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有