วิธีการจบการแอพลิเคชัน "Cleanly" ใน Win32

ข้อมูลสำคัญ: บทความนี้แปลโดยซอฟต์แวร์การแปลด้วยคอมพิวเตอร์ของ Microsoft แทนที่จะเป็นนักแปลที่เป็นบุคคล Microsoft มีบทความที่แปลโดยนักแปลและบทความที่แปลด้วยคอมพิวเตอร์ เพื่อให้คุณสามารถเข้าถึงบทความทั้งหมดในฐานความรู้ของเรา ในภาษาของคุณเอง อย่างไรก็ตาม บทความที่แปลด้วยคอมพิวเตอร์นั้นอาจมีข้อบกพร่อง โดยอาจมีข้อผิดพลาดในคำศัพท์ รูปแบบการใช้ภาษาและไวยากรณ์ เช่นเดียวกับกรณีที่ชาวต่างชาติพูดผิดเมื่อพูดภาษาของคุณ Microsoft ไม่มีส่วนรับผิดชอบต่อความคลาดเคลื่อน ความผิดพลาดหรือความเสียหายที่เกิดจากการแปลเนื้อหาผิดพลาด หรือการใช้บทแปลของลูกค้า และ Microsoft มีการปรับปรุงซอฟต์แวร์การแปลด้วยคอมพิวเตอร์อยู่เป็นประจำ

ต่อไปนี้เป็นฉบับภาษาอังกฤษของบทความนี้:178893
สรุป
ในโลกที่สมบูรณ์แบบ กระบวนการของคุณสามารถขอการดำเนินการอื่น โดยบางรูปแบบของการสื่อสาร inter-process การปิดระบบ อย่างไรก็ตาม ถ้าคุณไม่มีตัวควบคุมระดับของแหล่งที่มาของแอพลิเคชันที่คุณต้องการปิด จากนั้นคุณอาจไม่มีตัวเลือกนี้ แม้ว่าไม่มีวิธี "ใหม่ทั้งหมด" รับประกันการปิดโปรแกรมประยุกต์ใน Win32 ไม่มีขั้นตอนที่คุณสามารถใช้เพื่อให้แน่ใจว่า โปรแกรมประยุกต์ใช้วิธีการที่ดีที่สุดสำหรับการล้างค่าทรัพยากร
ข้อมูลเพิ่มเติม

กระบวนการแบบ 32 บิต (และกระบวนการ 16 บิตภายใต้ Windows 95)

ภายใต้ Win32, promises ระบบปฏิบัติการที่จะล้างข้อมูลทรัพยากรที่เป็นเจ้าของกระบวนการเมื่อปิดระบบ ความหมายซึ่งไม่ อย่างไรก็ตาม ว่า กระบวนการตัวเองที่มีโอกาสที่จะดำเนินการใด ๆ flushes ขั้นสุดท้ายของข้อมูลไปยังดิสก์ สื่อสารใด ๆ ขั้นสุดท้ายที่ผ่านการเชื่อมต่อระยะไกล และไม่ได้หมาย ที่กระบวนการของ DLL จะมีโอกาสที่จะเรียกใช้โค้ด PROCESS_DETACH ของตนเอง นี้คือสาเหตุที่เป็น preferable โดยทั่วไปเพื่อหลีกเลี่ยงการหยุดโปรแกรมประยุกต์ภายใต้ Windows 95 และ Windows NT

ถ้าคุณจริง ๆ ต้องปิดกระบวนการ ทำตามขั้นตอนเหล่านี้:
  1. การลงรายการบัญชีแบบ WM_CLOSE หน้าต่าง Top-Level ทั้งหมดที่เป็นเจ้าของกระบวนการที่คุณต้องการปิดระบบ โปรแกรมประยุกต์ Windows หลายโปรแกรมตอบสนองต่อข้อความนี้ โดยการปิดระบบ

    หมายเหตุ:: การตอบสนองของโปรแกรมประยุกต์การคอนโซลการ WM_CLOSE ขึ้นอยู่กับว่าหรือไม่ได้มีการติดตั้งตัวจัดการตัวควบคุม

    ใช้ EnumWindows() เพื่อค้นหาการจัดการหน้าต่างเป้าหมายของคุณ ในฟังก์ชันการเรียกกลับของคุณ ตรวจสอบเพื่อดูถ้าของหน้าต่างรหัสประมวลผลตรงกับกระบวนการที่คุณต้องการปิดระบบ คุณสามารถทำได้ โดยเรียก GetWindowThreadProcessId() เมื่อคุณได้สำเร็จคู่ที่ตรงกัน ใช้ PostMessage() หรือ SendMessageTimeout() เพื่อลงรายการบัญชีข้อความ WM_CLOSE หน้าต่าง
  2. ใช้ WaitForSingleObject() รอสำหรับหมายเลขอ้างอิงของกระบวนการ ตรวจสอบว่า คุณรอ มีค่าหมดเวลา เนื่องจากมีสถานการณ์มากซึ่ง WM_CLOSE จะไม่ปิดโปรแกรมประยุกต์ ไม่ลืมที่จะทำการหมดเวลานานพอ (อาจ มี WaitForSingleObject() หรือ SendMessageTimeout()) เพื่อให้ผู้ใช้สามารถตอบสนองต่อการโต้ตอบใด ๆ กล่องที่ได้สร้างขึ้นในการตอบสนองกับข้อความ WM_CLOSE
  3. If the return value is WAIT_OBJECT_0, then the application closed itself down cleanly. If the return value is WAIT_TIMEOUT, then you must use TerminateProcess() to shutdown the application.

    หมายเหตุ:: If you are getting3 a return value from WaitForSingleObject() other then WAIT_OBJECT_0 or WAIT_TIMEOUT, use GetLastError() to determine the cause.
By following these steps, you give the application the best possible chanceto shutdown cleanly (aside from IPC or user-intervention).

The 16-Bit Issue (under Windows NT)

The preceding steps work for 16-bit applications under Windows 95, however,Windows NT 16-bit applications work very differently.

Under Windows NT, all 16-bit applications run in a virtual DOS machine(VDM). This VDM runs as a Win32 process (NTVDM) under Windows NT. The NTVDMprocess has a process ID. You can obtain a handle to the process throughOpenProcess(), just like you can with any other Win32 process.Nevertheless, none of the 16-bit applications running in the VDM have aprocess ID, and therefore you cannot get a Process Handle fromOpenProcess(). Each 16-bit application in a VDM has a 16-bit Task Handleand a 32-bit thread of execution. The handle and thread ID can be foundthrough a call to the function VDMEnumTaskWOWEx(). For additionalinformation, please see the following article in the Microsoft KnowledgeBase:
175030How To Enumerate Applications in Win32
Your first, and most straightforward, option when shutting down a 16-bitapplication under Windows NT is to shut down the entire NTVDM process. Youcan do this by following the steps outlined above. You only need to knowthe process ID of the NTVDM process (see the KB article175030cited aboveto find the process ID of an NTVDM). The downside of this approach is thatit closes all 16-bit applications that are running in that VDM. If this isnot your goal, then you need to take another approach.

If you wish to shut down a single 16-bit application within a NTVDMprocess, following are the steps you need to take:
  1. Post a WM_CLOSE to all Top-Level windows that are owned by the process, and that have the same owning thread ID as the 16-bit task you want to shut down. The most effective way to do this is by using EnumWindows(). In your callback function, check to see if the window's process ID and thread ID matches the 16-bit task you want to shut down. Remember that the process ID is going to be the process ID of the NTVDM process in which the 16-bit application is running.
  2. Although you have a thread ID, you have no way to wait on the termination of the 16-bit process. As a result, you must wait for an arbitrary length of time (to allow a clean shut down), and then try to shut the application down anyway. If the application has already shut down, then this will do nothing. If it hasn't shut down, then it will terminate the application.
  3. Terminate the application using a function called VDMTerminateTaskWOW(), which can be found in the Vdmdbg.dll. It takes the process ID of the VDM and the task number of the 16-bit task.
This approach allows you to shut down a single 16-bit application within aVDM under Windows NT. However, 16-bit Windows is not very good at cleaningup resources of a terminated task, and neither is the WOWExec running inthe VDM. If you are looking for the cleanest possible approach toterminating a 16-bit application under Windows NT, you should considerterminating the entire VDM process. NOTE: If you are starting a 16-bitapplication that you may terminate later, then use theCREATE_SEPARATE_WOW_VDM with CreateProcess().

ตัวอย่างรหัส

The sample code implements the techniques described above for 16-bit and 32-bit applications using the following two functions: TerminateApp() andTerminate16App(). TerminateApp() takes a 32-bit process ID and a timeout(in miliseconds). Terminate16App(). Both functions use explicit linking toDLL functions so that they will be binary compatible across Windows NT andWindows 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 ;   }				
Kill Exit Terminate Program Application Process Task

คำเตือน: บทความนี้ได้รับการแปลโดยอัตโนมัติ