如何"干净地"终止 Win32 中的应用程序_VC技术_C语言教程
在理想环境中,某一进程可能会通过某种形式的进程间通信要求另一进程关闭。不过,如果你对希望其关闭的应用程序没有源代码级控制权,可能就没有办法做这样的选择。尽管没有哪种方法能保证“干净地”关闭 Win32 中的应用程序,但你可以采取一些步骤来确保应用程序使用最佳方法清除资源。
在 Win32 下,操作系统可保证在进程关闭时清除进程所拥有的资源。但是,这并不意味着进程本身将有机会对磁盘执行任何最后的信息刷新或通过远程连接执行任何最后的通信,也不意味着进程的 DLL 将有机会执行其 PROCESS_DETACH 代码。这就是通常最好避免在 Windows 95 和 Windows NT 下终止应用程序的原因。
如果你必须关闭进程,请按照下列步骤操作:
通过执行上述这些步骤,你便完全有可能干净地关闭应用程序(无需 IPC 或用户干预)。
上述步骤适用于 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。有关这方面的其它信息,请参见:“如何用 Win32 APIs 枚举应用程序窗口和进程”。
关闭 Windows NT 下的 16 位应用程序的首选和最直接的方法是关闭整个 NTVDM 进程。你可以通过执行前面所描述的步骤来完成此操作。你只需知道 NTVDM 的进程 ID 即可,参考“如何用 Win32 APIs 枚举应用程序窗口和进程”所讲的方法来查找 NTVDM 的进程 ID。此方法的缺点是它会关闭在该 VDM 中运行的所有 16 位应用程序。如果这不是你想要的结果,则需要采取其它方法。
如果你希望关闭 NTVDM 进程中的单个 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 都兼容。
//****************** // 头文件 TermApp.h //****************** #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 ); //********************* // 实现代码 TermApp.cpp //********************* #include "TermApp.h" #include <vdmdbg.h> typedef struct { DWORD dwID ; DWORD dwThread ; } TERMINFO ; // 声明回调枚举函数. BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ; BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam ) ; /*---------------------------------------------------------- ------ DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout ) 功能: 关闭 32-位进程(或 Windows 95 下的 16-位进程) 参数: dwPID 要关闭之进程的进程 ID. dwTimeout 进程关闭前等待的毫秒时间. 返回值: TA_FAILED —— 如果关闭失败. TA_SUCCESS_CLEAN —— 如果使用 WM_CLOSE 关闭了进程. TA_SUCCESS_KILL —— 如果使用 TerminateProcess() 关闭了进程. 返回值的定义参见头文件. ------------------------------------------------------------ ----*/ DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout ) { HANDLE hProc ; DWORD dwRet ; // 如果无法用 PROCESS_TERMINATE 权限打开进程,那么立即放弃。 hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,dwPID); if(hProc == NULL) { return TA_FAILED ; } // TerminateAppEnum() 将 WM_CLOSE 消息发到所有其进程ID 与你所提供的进程ID 匹配的窗口. EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ; // 等待处理,如果成功,OK。如果超时,则干掉它. 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 ) 功能: 关闭 Win16 应用程序. 参数: dwPID 16-位程序运行其中的 NTVDM 进程 ID. dwThread 16-位程序中执行线程的线程 ID. w16Task 应用程序的 16-位任务句柄. dwTimeout 任务关闭前等待的毫秒时间. 返回值: 如果成功, 返回 TA_SUCCESS_16 如果不成功, 返回 TA_FAILED. 返回值的定义参见该函数的头文件. 注意: 你可以通过 VDMEnumTaskWOW() 或 VDMEnumTaskWOWEx() 函数获得 Win16 和线程 ID. ------------------------------------------------------------ ----*/ DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread, WORD w16Task, DWORD dwTimeout ) { HINSTANCE hInstLib ; TERMINFO info ; // 你必须通过外部链接调用函数,以便代码在所有 Win32 平台上都兼容。 BOOL (WINAPI *lpfVDMTerminateTaskWOW)(DWORD dwProcessId,WORD htask) ; hInstLib = LoadLibraryA( "VDMDBG.DLL" ) ; if( hInstLib == NULL ) return TA_FAILED ; // 获得函数过程地址. lpfVDMTerminateTaskWOW = (BOOL (WINAPI *)(DWORD, WORD )) GetProcAddress( hInstLib, "VDMTerminateTaskWOW" ) ; if( lpfVDMTerminateTaskWOW == NULL ) { FreeLibrary( hInstLib ) ; return TA_FAILED ; } // 向所有匹配进程 ID 和线程的窗口发送 WM_CLOSE 消息. info.dwID = dwPID ; info.dwThread = dwThread ; EnumWindows((WNDENUMPROC)Terminate16AppEnum, (LPARAM) &info) ; // 等待. Sleep( dwTimeout ) ; // 然后终止. 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 ; }
Word教程网 | Excel教程网 | Dreamweaver教程网 | Fireworks教程网 | PPT教程网 | FLASH教程网 | PS教程网 |
HTML教程网 | DIV CSS教程网 | FLASH AS教程网 | ACCESS教程网 | SQL SERVER教程网 | C语言教程网 | JAVASCRIPT教程网 |
ASP教程网 | ASP.NET教程网 | CorelDraw教程网 |