Pergunta

Eu sei que eu tenho que usar setconsolehandler() se eu quiser gerenciar eventos de fechamento console.

Eu não sei como bloquear o CTRL_CLOSE_EVENT. Eu tentei retornar false / true se ele pega esse evento, mas sem sucesso

Aqui está o que eu tenho até agora (obrigado Anton Gogolev!)

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

public enum CtrlTypes{
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{ 
    if(ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
        return false;// I have tried true and false and viceversa with the return   
                     // true/false but I cant seem to get it right.
    return true;
}


//and then I use this to call it
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

Também é possível executar uma nova thread para monitorar se o console está fechando e bloquear que perto se o thread principal está no meio de fazer algo?

Foi útil?

Solução

A documentação para SetConsoleCtrlHandler() diz:

O sistema gera CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT e sinais CTRL_SHUTDOWN_EVENT quando o usuário fecha o console, faz logoff ou desliga o sistema para que o processo tenha uma oportunidade para limpar antes da terminação.

Isto implica que ao contrário de quando manipulação de eventos CTRL + C ou CTRL + BREAK, o processo não terá a oportunidade de cancelar o fechamento, logoff ou desligamento.

Outras dicas

Na verdade, você pode bloqueá-lo (I reproduziram isso no Windows XP, pelo menos). Por exemplo, se no seu manipulador você tem um loop while infinitas com um sono, isso vai parar este processo de terminar para sempre (ou pelo menos por um longo tempo, ou até que o usuário mata o processo através do gerenciador de tarefas).

Se você realmente necessário para iniciar uma discussão, você poderia usar uma condição de espera (AutoResetEvent em C #) e começar seu segmento (embora um novo segmento, provavelmente, não é necessária na maioria dos casos), em seguida, notificar a condição de espera quando o segmento é acabado. No entanto, apenas fazendo qualquer limpeza no manipulador seria suficiente na maioria dos casos.

Se, no pior caso que você fez esperar para sempre, o processo continuará a ser executado e você vai ser capaz de vê-lo quando voltar a iniciar sessão (pelo menos no Windows XP). No entanto, isso faz com que o ambiente de trabalho para fazer uma pausa por cerca de 20 segundos antes de ir para a trave tela (enquanto aguarda o seu applicaiton para sair) e, em seguida, faz uma pausa novamente no log out tela (suponho enquanto ele tenta uma 2ª vez) . Claro, eu recomendo fortemente contra esperando para sempre; para qualquer material de longa duração você deve realmente colocar isso em um serviço.

Eu encontrei um possível 'truque' que poderia impedir a aplicação de fechamento, enquanto ainda perfeitamente obedecer o pedido do console perto. Particularmente, este é adequado, penso eu, para aplicações GUI que criaram um console como um 'extra'. A partir da documentação MSDN, no ponto onde o Ctrl Handler é chamado de novo segmento é criado no processo de chamar o manipulador. Minha solução, então, é para matar o fio invadindo agredir antes de o manipulador padrão pode chamar ExitProcess. Na rotina de tratamento (código em C ++):

// Detach Console:
FreeConsole();
// Prevent closing:
ExitThread(0);
return TRUE; // Not reached

EDIT: Parece que este causar alguns problemas, como se espera suponho. A chamada subsequente para AllocConsole () trava indefinidamente, então eu suspeito que sair o fio falhar prematuramente para limpar corretamente.

EDIT 2:

Para esclarecer acima, eu não encontrou problemas diretos de continuar a executar o programa. Mas tenha em mente que temos forçosamente terminado um segmento que kernel32 criou, portanto, quaisquer recursos dentro kernel32 poderia estar em um estado indeterminado. Isso pode causar problemas imprevistos quando o programa continua a funcionar.

Na maior parte, eu acho, esses problemas serão relacionados com a API Console. Como mencionado, AllocConsole falhar ao trabalho a partir deste ponto (ele vai travar a aplicação), para que o programa não pode abrir um novo console. É muito possível que outras funções do console irá falhar também. Basicamente, qualquer coisa que você faz a partir desse momento que de alguma forma (direta ou indiretamente) chamadas em kernel32 está sujeita a um comportamento indefinido, mas eu suspeito que, na prática, não haverá quaisquer problemas fora das funções do console.

A minha conclusão é que você deve evitar este método, se possível, mas se término prematuro é pior, então isso pode ser pensado como uma emergência de trabalho-around, para ser usado com moderação e com cuidado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top