Como terminar um aplicativo "Corretamente" no Win32

Traduções deste artigo Traduções deste artigo
ID do artigo: 178893 - Exibir os produtos aos quais esse artigo se aplica.
Expandir tudo | Recolher tudo

Neste artigo

Sumário

Em um mundo perfeito, seu processo pode solicitar outro processo, por meio de alguma forma de comunicação entre processos para desligar. No entanto, se você não tiver o controle de origem-nível do aplicativo que você deseja desligar, em seguida, você talvez não tenha essa opção. Embora não haja nenhuma maneira "limpa" garantida encerrar um aplicativo no Win32, há etapas que você pode tomar para garantir que o aplicativo usa o melhor método para limpeza de recursos.

Mais Informações

Processos de 32 bits (e processos de 16 bits no Windows 95)

Em Win32, o sistema operacional promete limpar recursos pertencentes a um processo quando ele é desligado. Isso não, no entanto, significa que o próprio processo teve a oportunidade de fazer qualquer liberações finais das informações de disco, qualquer comunicação final em uma conexão remota, nem significa que o processo DLL terá a oportunidade para executar seu código PROCESS_DETACH. É por isso que ele é geralmente preferível para evitar encerrar um aplicativo em Windows 95 e Windows NT.

Se é absolutamente necessário desligar um processo, execute estas etapas:
  1. Poste um WM_CLOSE para todas as janelas superior pertencentes ao processo que você deseja desligar. Muitos aplicativos Windows respondem a esta mensagem sendo encerrado.

    Observação : resposta de um aplicativo console para WM_CLOSE depende se ou não instalou um manipulador de controle.

    Use EnumWindows() para localizar as alças para as janelas de destino. Na sua função de retorno de chamada, verificar se as janelas identificação do processo corresponde ao processo que você deseja desligar. Você pode fazer isso chamando GetWindowThreadProcessId(). Depois de estabelecida uma correspondência, use PostMessage() ou SendMessageTimeout() para postar a mensagem WM_CLOSE para a janela.
  2. Use WaitForSingleObject() para aguardar o identificador do processo. Verifique se que você esperar com um valor de tempo limite, porque há muitas situações em que o WM_CLOSE não desligará o aplicativo. Lembre-se fazer com que o tempo limite de tempo suficiente (com WaitForSingleObject() ou com SendMessageTimeout()) para que um usuário pode responder a qualquer caixa de diálogo de caixas que foram criados em resposta à mensagem WM_CLOSE.
  3. Se o valor de retorno for WAIT_OBJECT_0, em seguida, o aplicativo fechado próprio corretamente. Se o valor de retorno for WAIT_TIMEOUT, em seguida, você deverá usar TerminateProcess() para desligar o aplicativo.

    Observação : se você estiver getting3 um retorno de valor de WaitForSingleObject() outros, em seguida, WAIT_OBJECT_0 ou WAIT_TIMEOUT, use GetLastError() para determinar a causa.
Seguindo essas etapas, você dê ao aplicativo a chance melhor possível para desligar corretamente (além de IPC ou intervenção do usuário).

O problema de 16 bits (no Windows NT)

Precedente as etapas de trabalho para aplicativos de 16 bits no Windows 95, no entanto, aplicativos de Windows NT 16 bits funcionam muito diferentemente.

No Windows NT, todos os aplicativos de 16 bits executados em uma máquina virtual DOS (VDM). Este VDM é executado como um processo do Win32 (NTVDM) no Windows NT. O processo NTVDM tem uma identificação do processo. Você pode obter um identificador para o processo por meio de OpenProcess(), exatamente como faria com qualquer outro processo do Win32. No entanto, nenhum dos aplicativos de 16 bits em execução no VDM tem uma identificação de processo e, portanto, você não pode obter um identificador de processo do OpenProcess(). Cada aplicativo de 16 bits em uma VDM tem um identificador de tarefa de 16 bits e um segmento de 32 bits de execução. A identificação de thread e identificador pode ser encontrada por meio de uma chamada para a função VDMEnumTaskWOWEx(). Para obter informações adicionais, consulte o seguinte artigo na Base de dados de Conhecimento da Microsoft:
175030Como enumerar aplicativos no Win32
Sua opção primeira e mais simples, quando desligar um aplicativo de 16 bits no Windows NT é desligar todo o processo NTVDM. Você pode fazer isso seguindo as etapas descritas acima. Você só precisará saber a identificação do processo do processo NTVDM (consulte o KB artigo 175030 citado acima para localizar a identificação do processo de um NTVDM). A desvantagem dessa abordagem é que ele fecha todos os aplicativos de 16 bits que estão sendo executados em que VDM. Se este não é seu objetivo, você precisará outra abordagem.

Se você desejar encerrar um único aplicativo de 16 bits dentro de um processo NTVDM, a seguir estão as etapas que você precisa levar:
  1. Poste um WM_CLOSE para todas as janelas superior que pertencem ao processo e que tiverem a mesma identificação de thread proprietário como a tarefa de 16 bits que deseja desligar. A maneira mais eficiente para fazer isso é usando EnumWindows(). Na sua função de retorno de chamada, verifique se a janela identificação do processo e thread ID corresponde a tarefa de 16 bits que deseja desligar. Lembre-se de que a identificação do processo será a identificação do processo do processo NTVDM na qual o aplicativo de 16 bits está sendo executado.
  2. Embora você tenha uma identificação de thread, você não tem como para aguardar a finalização do processo de 16 bits. Como resultado, você deve aguardar um período arbitrário de tempo (para permitir que desligar um limpa) e, em seguida, tenta encerrar o aplicativo assim mesmo. Se o aplicativo já tem desligar, em seguida, isso não fará nada. Se ainda não desligar, ele terminará o aplicativo.
  3. Encerrar o aplicativo usando uma função chamada VDMTerminateTaskWOW(), que pode ser encontrado no Vdmdbg.dll. Leva o ID de processo do VDM e o número de tarefas da tarefa de 16 bits.
Essa abordagem permite que você desligar um único aplicativo 16 bits dentro de uma VDM no Windows NT. No entanto, Windows de 16 bits não é muito bom em Limpeza de recursos de uma tarefa terminada e nenhuma é WOWExec em execução no VDM. Se você estiver procurando a abordagem possível cleanest para encerrar um aplicativo de 16 bits no Windows NT, você deve considerar encerrando todo o processo VDM. Observação: Se você estiver iniciando um aplicativo de 16 bits que você pode terminar mais tarde, em seguida, use o CREATE_SEPARATE_WOW_VDM com CreateProcess().

Código de exemplo

O código de exemplo implementa as técnicas descritas acima para aplicativos de 16 e 32 bits usam duas funções a seguir: TerminateApp() e Terminate16App(). TerminateApp() leva uma identificação de processo de 32 bits e um tempo limite (em milissegundos). Terminate16App(). Ambas as funções usam vinculando explícita a funções DLL para que elas fiquem binário compatível entre Windows NT e 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 ;
   }
				

Propriedades

ID do artigo: 178893 - Última revisão: terça-feira, 13 de julho de 2004 - Revisão: 2.4
A informação contida neste artigo aplica-se a:
  • Interface de Programação de Aplicativos do Microsoft Win32 nas seguintes plataformas
    • Microsoft Windows 95
    • Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows XP
Palavras-chave: 
kbmt kbhowto kbkernbase kbthread KB178893 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 178893

Submeter comentários

 

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