J'écris une application (C ++) qui utilise une seule boîte de dialogue.
Après avoir configuré une pompe et un gestionnaire de messages, j'ai commencé à me demander comment j'aurais proposé de propager des exceptions C ++ à mon code d'origine (c.-à-d. Le code qui appelle Voici un exemple de squelette de ce que je veux dire: p> Comme vous pouvez le constater, ma question fondée est simple; Quel serait un moyen élégant de propager ces sortes d'erreurs au code original "appel"? strong> p> J'ai pensé à utiliser des messages personnalisés et à déplacer le Peut-être que je regarde cette situation tout faux. Comment vous EM> cautionnez généralement quand quelque chose de fatal (c'est-à-dire une acquisition d'une ressource critique échoue, et il n'y a aucune chance de récupération) lorsque vous êtes dans le gestionnaire de messages? P> p > créatedialogparam code>, par exemple).
winmain code> va gérer "exception 2" et "3", mais pas < / forte> "exception 1". p>
jette code> code> -statifs sur la pompe à message (dans
runapp () code>), mais je ne sais pas comment cela fonctionnerait encore car j'ai relativement peu d'expérience avec Windows en général. P>
4 Réponses :
Je resterais à l'écart de l'enregistrement des messages de fenêtre personnalisés à des fins de manutention d'erreur. Je veux dire que cette approche fonctionnera bien, mais il n'ya pas vraiment de besoin. P>
Au fait, votre gestionnaire de capture ci-dessus devrait prendre toutes les 3 exceptions. Votre procédure de dialogue s'exécute sur le même thread qui appelle créée. Créer une boîte de dialogue sans faille ne produit pas de fil de travail. La boîte de dialogue sans faille reçoit toujours ses messages via votre boucle GetMessage / Traduire / Dispatch. Il y a un cadre de pile là-bas, ce qui signifie que lorsque vous lancez, il devrait vous détendre tout le chemin de sortie à votre vainqueur ESSAY / CATCH. P>
n'est-ce pas le comportement que vous voyez? p>
C'est incroyablement bizarre, je n'ai pas pourquoi, mais après avoir redémarré vs, je reçois le comportement souhaité (c'est-à-dire que le gestionnaire de capture est invoqué maintenant). J'aurai besoin d'enquêter sur ce qui s'est passé plus loin. Merci de me faire vérifier!
@ssayq je ne suis pas sûr de cela. Lorsque vous appelez la fonction Winapi, vous ne savez pas ce qu'il fait en interne. Il ne doit pas nécessairement être prêt à gérer correctement les exceptions C ++ car la mise en œuvre des exceptions C ++ est interne au compilateur tandis que la mise en œuvre de WinapI est courante. Donc, si une fonction Winapi fait quelque chose de plus compliqué (comme allouer des ressources intérieures pour quelque chose), cela ne va pas bien avec des exceptions (car elle ne libérera pas ces ressources). Les exceptions AFAIK ne doivent pas être propagées hors des rappels Winapi (comme la fenêtre / la procédure de dialogue) et dans de nombreux cas même entre les modules.
En bref, je n'utilise jamais jamais des exceptions. Il existe cependant plusieurs approches pour signaler toutes les erreurs, qui utilisent toutes la journalisation de manière ou formulaire d'une manière ou d'une forme.
Approche 1. Utilisez la sortieDebuggstring ().
C'est bon parce que seule une personne atteinte de débogueur remarquera réellement quelque chose que, dans toute la réalité, ne devrait pas échouer.
Il existe évidemment de nombreux inconvénients à une personne qui tente d'utiliser une manipulation des exceptions cependant p>
Approche 2. Utilisez MessageBox.
Ce n'est pas bien meilleur que l'approche 1, mais il permet aux non de développeurs de voir une erreur. P>
approche 3. Utilisez un enregistreur d'erreur.
Plutôt que d'utiliser "lancer" pour être attrapé plus tard, puis "enregistré", vous pouvez ajouter la journalisation au moment de l'échec et utiliser les codes de retour Win32 standard pour quitter l'application: P>
if(msg == WM_INITDIALOG) //Or some other message { /* Load some critical resource(s) here. For instnace: const HANDLE someResource = LoadImage(...); if(someResource == NULL) { LogError("Cannot find resource 'foo'); } */ return TRUE; }
Les rappels Afaik Winapi (comme la fenêtre / la boîte de dialogue / les procédures de thread) ne doivent pas propager des exceptions. En effet, Winapi Internals (qui appelez le rappel) ne sont pas prêts à gérer des exceptions. Ils ne peuvent pas être préparés car la mise en œuvre des exceptions est spécifique au compilateur tandis que le code dans Winapi DLLS est corrigé, de sorte qu'il ne peut pas gérer toutes les implémentations de propagation des exceptions possibles. P>
Dans certains cas simples (en particulier lorsque vous compilez avec Visual Studio), vous pouvez observer que des exceptions sont propagées, comme cela semblerait juste. C'est cependant une coïncidence. Et même si votre application n'empêche pas que vous n'êtes pas sûr, vous n'êtes pas sûr que les fonctions Winapi appelées entre entre ne pas attribuer de ressources qu'ils n'ont pas publié en raison d'une exception, elles n'étaient pas préparées. P>
Une couche supplémentaire de complexité est ajoutée en ne connaissant pas la source du rappel (en général - pour certains messages qu'il peut être déduit). Les messages géré par votre procédure de dialogue passent par la boucle de message si et uniquement s'ils ont été affichés dans votre boîte de dialogue. S'ils ont été envoyés, ils ignorent la boucle et sont exécutés directement. De plus, si un message est envoyé, vous ne savez pas qui envoie le message - est-ce que vous? Ou peut-être que Windows? Ou une autre fenêtre d'un autre processus essayant de faire quelque chose? (Cependant, cela serait risqué.) Vous ne savez pas si le site d'appel est préparé pour une exception. P>
Un moyen de contour de contournement est offert par Boost.Exception . La bibliothèque permet d'en quelque sorte stocker l'exception capturée et l'utilisation (en particulier Rethow). De cette façon, vous pouvez envelopper votre procédure de dialogue dans un EDIT: Etant donné que C ++ 11 Les fonctionnalités de Boost.Exception pour stocker un objet d'exception fait partie du STD. Vous pouvez utiliser Cependant, certains problèmes restent toujours. Vous devez toujours récupérer d'une certaine manière et retourner une certaine valeur (pour les messages nécessitant une valeur de retour). Et vous devriez décider quoi faire avec l'exception stockée. Comment y accéder? Qui va le faire? Que fera-t-elle / elle avec elle? P>
En cas de lancer {...} catch (...) {...} code> où dans l'attrape, vous capturez l'exception et stockez-la pour cette dernière utilisation. < / p>
std :: exception_ptr code> pour cela. P>
wm_initdialog code> Vous pouvez passer des paramètres arbitraires à la procédure de dialogue avec ce message (Utiliser le formulaire approprié de la fonction de création de la boîte de dialogue), ce qui pourrait être un pointeur de structure qui conservera l'exception stockée ( si seulement). Ensuite, vous pourriez enquêter sur cette structure pour voir si l'initialisation de la boîte de dialogue a échoué et comment. Cela ne peut toutefois pas être appliqué simplement à n'importe quel message. P>
voir http: //www.boost. org / doc / libs / liber / libs / exception / doc / tutorial_exception_ptr.html . P>