分享
 
 
 

如何“干净地”终止 Win32 中的应用程序

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

如何“干净地”终止 Win32 中的应用程序察看这篇文章对应的产品

文章 ID

:

178893

最后更新日期

:

2004年11月25日

版本

:

2.2

本页内容

概要

更多信息

32 位进程(和 Windows 95 下的 16 位进程)

16 位问题(在 Windows NT 下)

示例代码

这篇文章中的信息适用于:

概要在理想环境中,某一进程可能会通过某种形式的进程间通信要求另一进程关闭。不过,如果您对希望其关闭的应用程序没有源代码级控制权,可能就无法选择这样做。尽管没有哪种方法保证可以“干净地”关闭 Win32 中的应用程序,但您可以采取一些步骤以确保应用程序使用最佳方法来清除资源。

返回页首

更多信息32 位进程(和 Windows 95 下的 16 位进程)在 Win32 下,操作系统可保证在进程关闭时清除进程所拥有的资源。但是,这并不意味着进程本身将有机会对磁盘执行任何最后的信息刷新或通过远程连接执行任何最后的通信,也不意味着进程的 DLL 将有机会执行其 PROCESS_DETACH 代码。这就是通常最好避免在 Windows 95 和 Windows NT 下终止应用程序的原因。

如果您必须关闭进程,请按照下列步骤操作: 1.

向您要关闭的进程所拥有的所有顶级窗口发送一条 WM_CLOSE 消息。许多 Windows 应用程序会通过关闭它自身来响应此消息。

注意:控制台应用程序对 WM_CLOSE 的响应取决于它是否安装了控制处理程序。

使用 EnumWindows() 找到目标窗口的句柄。在回调函数中,检查该窗口的进程 ID 是否与要关闭的进程相匹配。您可以通过调用 GetWindowThreadProcessId() 来执行此操作。确定匹配项后,使用 PostMessage() 或 SendMessageTimeout() 向该窗口发送 WM_CLOSE 消息。

2.

使用 WaitForSingleObject() 等待进程的句柄。确保您使用超时值等待,因为在很多情况下 WM_CLOSE 不会关闭应用程序。记住,应使超时值足够长(通过 WaitForSingleObject() 或 SendMessageTimeout()),以便用户可以响应为了响应 WM_CLOSE 消息而创建的任何对话框。

3.

如果返回值为 WAIT_OBJECT_0,则应用程序已干净地将它自身关闭。如果返回值为 WAIT_TIMEOUT,则必须使用 TerminateProcess() 关闭应用程序。

注意:如果您从 WaitForSingleObject() 得到的返回值不是 WAIT_OBJECT_0 或 WAIT_TIMEOUT,则应使用 GetLastError() 找出原因。

通过执行上述这些步骤,您就为应用程序提供了干净(无需 IPC 或用户干预)关闭的最佳机会。 16 位问题(在 Windows NT 下)上述步骤适用于 Windows 95 下的 16 位应用程序,而 Windows NT 下的 16 位应用程序与 Windows 95 下的 16 位应用程序的工作方式差别非常大。

在 Windows NT 下,所有 16 位应用程序都在虚拟 DOS 机 (VDM) 中运行。此 VDM 是作为 Windows NT 下的一个 Win32 进程 (NTVDM) 运行的。NTVDM 进程具有进程 ID。您可以通过 OpenProcess() 获取该进程的句柄,就像处理其他任何 Win32 进程一样。不过,在 VDM 中运行的 16 位应用程序都没有进程 ID,因此您无法从 OpenProcess() 获取进程句柄。VDM 中的每个 16 位应用程序都有一个 16 位任务句柄和一个 32 位执行线程。可通过调用函数 VDMEnumTaskWOWEx() 找到该任务句柄和线程 ID。有关其他信息,请参见以下 Microsoft 知识库文章: 175030 如何使用 Win32 API 来枚举应用程序

关闭 Windows NT 下的 16 位应用程序的首选和最直接的方法是关闭整个 NTVDM 进程。您可以通过执行前面概述的步骤来完成此操作。您只需知道 NTVDM 的进程 ID 即可(请参见前面引用的知识库文章175030 来查找 NTVDM 的进程 ID)。此方法的缺点是它会关闭在该 VDM 中运行的所有 16 位应用程序。如果这不是您想要的结果,则需要采取其他方法。

如果您希望关闭 NTVDM 进程中的单个 16 位应用程序,需要按照下列步骤操作: 1.

向该进程所拥有的以及与您要关闭的 16 位任务具有相同线程 ID 的所有顶级窗口发送一条 WM_CLOSE 消息。执行此操作最有效的方法是使用 EnumWindows()。在回调函数中,检查窗口的进程 ID 和线程 ID 是否与要关闭的 16 位任务相匹配。请记住,该进程 ID 将成为在其中运行 16 位应用程序的 NTVDM 的进程 ID。

2.

尽管您有线程 ID,但无法等待 16 位进程的终止。因此,您必须等待任意时间长度(以允许干净关闭),然后尝试关闭应用程序。如果应用程序已关闭,则此操作无效。如果应用程序尚未关闭,则它将终止应用程序。

3.

使用称为 VDMTerminateTaskWOW() 的函数终止应用程序,该函数可在 Vdmdbg.dll 中找到。它采用 VDM 的进程 ID 和 16 位任务的任务编号。

此方法允许您关闭 Windows NT 下 VDM 中的单个 16 位应用程序。不过,16 位 Windows 以及 VDM 中运行的 WOWExec 都不能有效地清除已终止任务的资源。如果您要寻找最有可能干净地终止 Windows NT 下的 16 位应用程序的方法,应考虑终止整个 VDM 进程。注意:如果您要启动以后可能会终止的 16 位应用程序,请将 CREATE_SEPARATE_WOW_VDM 与 CreateProcess() 结合使用。 示例代码下面的示例代码使用以下两个函数实现上述用于 16 位和 32 位应用程序的方法:TerminateApp() 和 Terminate16App()。TerminateApp() 采用一个 32 位进程 ID 和一个超时值(以毫秒为单位)。Terminate16App()。这两个函数都使用 DLL 函数的显式链接,以便它们的二进制文件与 Windows NT 和 Windows 95 都兼容。 //******************

//Header

//******************

#include <windows.h>

#define TA_FAILED 0

#define TA_SUCCESS_CLEAN 1

#define TA_SUCCESS_KILL 2

#define TA_SUCCESS_16 3

DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout ) ;

DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,

WORD w16Task, DWORD dwTimeout );

//******************

//Source

//******************

#include "TermApp.h"

#include <vdmdbg.h>

typedef struct

{

DWORD dwID ;

DWORD dwThread ;

} TERMINFO ;

// Declare Callback Enum Functions.

BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;

BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam ) ;

/*----------------------------------------------------------------

DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )

Purpose:

Shut down a 32-Bit Process (or 16-bit process under Windows 95)

Parameters:

dwPID

Process ID of the process to shut down.

dwTimeout

Wait time in milliseconds before shutting down the process.

Return Value:

TA_FAILED - If the shutdown failed.

TA_SUCCESS_CLEAN - If the process was shutdown using WM_CLOSE.

TA_SUCCESS_KILL - if the process was shut down with

TerminateProcess().

NOTE: See header for these defines.

----------------------------------------------------------------*/

DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )

{

HANDLE hProc ;

DWORD dwRet ;

// If we can't open the process with PROCESS_TERMINATE rights,

// then we give up immediately.

hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,

dwPID);

if(hProc == NULL)

{

return TA_FAILED ;

}

// TerminateAppEnum() posts WM_CLOSE to all windows whose PID

// matches your process's.

EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;

// Wait on the handle. If it signals, great. If it times out,

// then you kill it.

if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)

dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);

else

dwRet = TA_SUCCESS_CLEAN ;

CloseHandle(hProc) ;

return dwRet ;

}

/*----------------------------------------------------------------

DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,

WORD w16Task, DWORD dwTimeout )

Purpose:

Shut down a Win16 APP.

Parameters:

dwPID

Process ID of the NTVDM in which the 16-bit application is

running.

dwThread

Thread ID of the thread of execution for the 16-bit

application.

w16Task

16-bit task handle for the application.

dwTimeout

Wait time in milliseconds before shutting down the task.

Return Value:

If successful, returns TA_SUCCESS_16

If unsuccessful, returns TA_FAILED.

NOTE: These values are defined in the header for this

function.

NOTE:

You can get the Win16 task and thread ID through the

VDMEnumTaskWOW() or the VDMEnumTaskWOWEx() functions.

----------------------------------------------------------------*/

DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,

WORD w16Task, DWORD dwTimeout )

{

HINSTANCE hInstLib ;

TERMINFO info ;

// You will be calling the functions through explicit linking

// so that this code will be binary compatible across

// Win32 platforms.

BOOL (WINAPI *lpfVDMTerminateTaskWOW)(DWORD dwProcessId,

WORD htask) ;

hInstLib = LoadLibraryA( "VDMDBG.DLL" ) ;

if( hInstLib == NULL )

return TA_FAILED ;

// Get procedure addresses.

lpfVDMTerminateTaskWOW = (BOOL (WINAPI *)(DWORD, WORD ))

GetProcAddress( hInstLib, "VDMTerminateTaskWOW" ) ;

if( lpfVDMTerminateTaskWOW == NULL )

{

FreeLibrary( hInstLib ) ;

return TA_FAILED ;

}

// Post a WM_CLOSE to all windows that match the ID and the

// thread.

info.dwID = dwPID ;

info.dwThread = dwThread ;

EnumWindows((WNDENUMPROC)Terminate16AppEnum, (LPARAM) &info) ;

// Wait.

Sleep( dwTimeout ) ;

// Then terminate.

lpfVDMTerminateTaskWOW(dwPID, w16Task) ;

FreeLibrary( hInstLib ) ;

return TA_SUCCESS_16 ;

}

BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )

{

DWORD dwID ;

GetWindowThreadProcessId(hwnd, &dwID) ;

if(dwID == (DWORD)lParam)

{

PostMessage(hwnd, WM_CLOSE, 0, 0) ;

}

return TRUE ;

}

BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam )

{

DWORD dwID ;

DWORD dwThread ;

TERMINFO *termInfo ;

termInfo = (TERMINFO *)lParam ;

dwThread = GetWindowThreadProcessId(hwnd, &dwID) ;

if(dwID == termInfo->dwID && termInfo->dwThread == dwThread )

{

PostMessage(hwnd, WM_CLOSE, 0, 0) ;

}

return TRUE ;

}

返回页首

这篇文章中的信息适用于:•

Microsoft Win32 Application Programming Interface (API)当用于

Microsoft Windows 95 Service Pack 1

Microsoft Windows NT 4.0 Service Pack 7

Microsoft Windows 2000 Standard Edition

Microsoft Windows XP Standard Edition

返回页首

关键字:

kbhowto kbkernbase kbthread KB178893

返回页首

Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有