如何結束 「 完全 」 在 Win32 應用程式

文章翻譯 文章翻譯
文章編號: 178893 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

結論

在完美的世界您的處理程序可能要求透過某種形式的到關機的處理序間通訊的另一個處理序。不過,如果您沒有您想要關閉應用程式的來源層級的控制項再您可能沒有這個選項。雖然沒有保證的全新方法,可以關閉在 Win32 應用程式有您可以採取確保應用程式的清除資源使用最佳的方法的步驟。

其他相關資訊

32 位元處理序 (和 16 位元處理程序在 Windows 95 下)

在 Win32,作業系統承諾清除它關機時,由處理程序所擁有的資源。這並不,但是,表示程序本身已經有機會執行磁碟透過遠端連線的任何最終通訊的資訊的任何最終排清也意思,處理序的 DLL 的將有機會執行其 PROCESS_DETACH 程式碼。這就是為什麼最好通常以避免終止受 Windows 95 與 Windows NT 應用程式。

如果您絕對必須關機處理程序,請依照下列步驟執行:
  1. 將一個 WM_CLOSE 張貼到您想要關閉處理序所擁有的全部 Top-Level 視窗。許多 Windows 應用程式由正在關閉回應這個訊息。

    注意: WM_CLOSE A 主控台應用程式的回應取決於是否它已安裝控制處理常式。

    使用 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 的傳回值的 getting3,使用 GetLastError() 來判斷原因。
請依照下列步驟執行,您讓應用程式最佳的可能機會關機俐落地 (除了從 IPC 或使用者介入情況下)。

(在 Windows NT) 下的 [16 位元] 問題

上述步驟 16 位元應用程式在 Windows 95 下工作,但是,Windows NT 16 位元應用程式運作完全不同。

在 Windows NT 下所有的 16 位元應用程式在虛擬 DOS 機器 (VDM) 中執行。這個 VDM 以 Win32 程序 (NTVDM) 在 Windows NT 下執行。NTVDM 程序有處理序 ID。就跟您可以與任何其他 Win32 處理序的方式一樣,您可以取得 OpenProcess(),透過處理序的控制代碼。 不過,沒有任何 [VDM 中執行的 16 位元應用程式有一個處理程序] 識別碼,因此您無法取得處理序控制代碼從 OpenProcess()。每個 16 位元應用程式中一個 VDM 有 16 位元工作控制碼和執行的 32 位元執行緒。透過呼叫函式 VDMEnumTaskWOWEx() 找不到控制代碼和執行緒 ID。如需詳細資訊請參閱 「 Microsoft 知識庫 」 中下列文:
175030列舉在 Win32 的應用程式的方式
當關閉 Windows NT] 下的 16 位元應用程式時您第一個,也是最直接選項是關閉整個 NTVDM 處理序。您可以只要遵循上述步驟。您只需要知道 NTVDM 程序的處理序 ID (請參閱 [KB 文章 175030 引用上面來尋找一個 NTVDM 處理序 ID)。這種方法的缺點是它會關閉所有執行中該 VDM 的 16 位元應用程式。如果這不是您的目標,您就需要採取另一種方法。

如果想關閉單一的 16 位元應用程式,在 NTVDM 程序中以下是您需採取的步驟:
  1. 將一個 WM_CLOSE 張貼到所有 Top-Level 視窗由在程序所擁有和有您要關閉的 16 位元工作跟相同主控執行緒識別碼。若要這麼做最有效方法是使用 EnumWindows()。 在您的回呼函式檢查視窗的處理序識別碼,而且執行緒 ID 是否符合您要關閉的 16 位元工作。請記住處理序 ID 要將 NTVDM 程序執行 16 位元應用程式的處理序 ID。
  2. 雖然您執行緒識別碼會者不能等待的 16 位元處理序終止。如此一來您必須等待的時間 (以容許一個乾淨關機),將任意長度,然後再嘗試仍要關閉應用程式。如果應用程式已經有關機,然後這將會做執行任何動作。如果它尚未關閉,它將會結束這個應用程式。
  3. 終止應用程式使用稱為可在 [Vdmdbg.dll 中找到的 VDMTerminateTaskWOW() 函式。花在 VDM 和 16 位元工作的工作數目的處理序 ID。
這種方法可讓您關閉單一的 16 位元應用程式在 Windows NT VDM 內。不過,16 位元 Windows 不是非常擅於清除已經終止任務的資源,且兩者都不是執行中 [VDM WOWExec。如果您要尋找最簡單的可能方式來終止在 Windows NT 為 16 位元應用程式,您應該考慮終止整個 VDM 程序。注意: 如果您啟動 16 位元應用程式,您可能稍後終止,然後使用 [CREATE_SEPARATE_WOW_VDM CreateProcess()。

範例程式碼

程式碼範例會實作上述使用下列兩個功能的 16 位元和 32 位元應用程式的技術: TerminateApp() 和 Terminate16App()。TerminateApp() 會使用 32 位元處理序識別碼和逾時 (以毫秒為單位))。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 ;
   }
				

屬性

文章編號: 178893 - 上次校閱: 2004年7月13日 - 版次: 2.4
這篇文章中的資訊適用於:
  • Microsoft Win32 Application Programming Interface?應用於:
    • Microsoft Windows 95
    • Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows XP
關鍵字:?
kbmt kbhowto kbkernbase kbthread KB178893 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:178893
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com