Question

Je sais que je dois utiliser setconsolehandler() si je veux gérer les événements de fermeture de la console.

Je ne sais pas comment bloquer le CTRL_CLOSE_EVENT. J'ai essayé de retourner faux / vrai si elle attrape cet événement, mais sans succès

Voici ce que j'ai jusqu'à présent (merci 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);

Aussi est-il possible de lancer un nouveau thread pour surveiller si la console est ferme et bloc fermer si le thread principal est au milieu de faire quelque chose?

Était-ce utile?

La solution

La documentation SetConsoleCtrlHandler() dit:

  

Le système génère CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, et des signaux de CTRL_SHUTDOWN_EVENT lorsque l'utilisateur ferme la console, se déconnecte ou arrête le système de sorte que le processus a la possibilité de nettoyer avant la terminaison.

Cela implique que, contrairement à lors de la manipulation CTRL + C ou CTRL + événements BREAK, votre processus ne soit pas la possibilité d'annuler la fermeture, la fermeture de session, ou l'arrêt.

Autres conseils

En fait, vous pouvez bloquer (je reproduis ce sous Windows XP au moins). Par exemple, si dans votre gestionnaire vous avez un sans fin en boucle avec un sommeil, cela arrêtera ce processus de mettre fin à jamais (ou au moins pendant une longue période, ou jusqu'à ce que l'utilisateur tue le processus par le gestionnaire de tâches).

Si vous avez vraiment besoin de commencer un fil, vous pouvez utiliser une condition d'attente (AutoResetEvent en C #) et commencez votre fil (si un nouveau thread est probablement pas nécessaire dans la plupart des cas), puis notifier à l'état d'attente lorsque votre fil est fini. Cependant, cela ne importe quel nettoyage dans le gestionnaire suffirait dans la plupart des cas.

Si dans le pire des cas, vous avez attendu pour toujours, le processus continue de fonctionner et vous serez en mesure de le voir lorsque vous vous reconnectez (au moins sous Windows XP). Cependant, cela provoque le bureau pour faire une pause pendant environ 20 secondes avant de passer à la déconnexion écran (alors qu'il attend pour votre applicaiton pour quitter), puis fait une pause à nouveau le journal sur l'écran (je suppose alors qu'il tente pendant un certain temps 2) . Bien sûr, je déconseille fortement d'attendre pour toujours; pour toute substance courir de temps vous devriez vraiment mettre cela dans un service.

J'ai trouvé un possible « pirater » qui pourrait empêcher l'application de la fermeture, tout en continuant d'obéir parfaitement à la demande de fermeture de la console. En particulier, cela est approprié, je pense, pour les applications de GUI qui ont créé une console comme un « extra ». De la documentation MSDN, au point où le gestionnaire est appelé Ctrl nouveau thread est créé dans le processus d'appeler le gestionnaire. Ma solution est donc de tuer le fil envahisseur assaillante avant que le gestionnaire par défaut peut appeler ExitProcess. Dans le sous-programme de gestionnaire (code C ++):

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

EDIT: Il semble que cela ne provoque des problèmes, à attendre, je suppose. Un appel ultérieur à AllocConsole () est suspendu indéfiniment, alors je soupçonne que la sortie du fil ne prématurément à nettoyer correctement.

EDIT 2:

Pour préciser ci-dessus, j'ai trouvé aucun problème direct avec la poursuite pour exécuter le programme. Mais gardez à l'esprit que nous avons avec force terminé un fil qui KERNEL32 a créé, de sorte que toutes les ressources à l'intérieur kernel32 pourrait être dans un état indéterminé. Cela pourrait causer des problèmes imprévus lorsque le programme continue à fonctionner.

La plupart du temps, je pense, ces problèmes seront liés à l'API Console. Comme mentionné précédemment, AllocConsole ne fonctionne pas à partir de ce moment-là (il se bloque l'application), de sorte que le programme ne peut pas ouvrir une nouvelle console. Il est fort possible que d'autres fonctions de la console échouera aussi. En fait, tout ce que vous faites à partir de ce moment-là que de quelque façon que (directement ou indirectement) remet en kernel32 est soumis à un comportement non défini, mais je pense que dans la pratique il n'y aura pas de problèmes en dehors des fonctions de la console.

Ma conclusion est que vous devriez éviter cette méthode, si possible, mais si la résiliation prématurée est pire, cela peut être considéré comme un travail autour d'urgence, à utiliser avec parcimonie et avec soin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top