2008-11-26 3 views
8

Comment obtenez-vous le nom et/ou la description d'une SEH exception sans avoir à coder en dur les chaînes dans votre application?Comment obtenir le nom/la description d'une exception?

J'ai essayé d'utiliser FormatMessage(), mais il tronque le message parfois, même si vous spécifiez d'ignorer les inserts:

__asm { // raise access violation 
    xor eax, eax 
    mov eax, [eax] 
} 

Déclenche une exception avec le code 0xC0000005 (EXCEPTION_ACCESS_VIOLATION).

char msg[256]; 
FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, 
    GetModuleHandleA("ntdll.dll"), 0xC0000005, 
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
    msg, sizeof(msg), NULL); 

Remplit msg avec la chaîne tronquée: "The instruction at 0x".

+0

Wow, cela semble vraiment cassé. Cela fonctionne pour divers messages, mais je ne peux pas le faire fonctionner pour STATUS_ACCESS_VIOLATION pour la vie de moi. – Charlie

+0

Je suis un peu rouillé maintenant mais avez-vous essayé FORMAT_MESSAGE_FROM_SYSTEM? – morechilli

+0

morechilli: Oui, je l'ai déjà essayé, mais ça ne change pas le résultat. – Sascha

Répondre

2

codes d'exception structurés sont définis par des nombres NTSTATUS. Bien que quelqu'un de MS suggests en utilisant FormatMessage() pour convertir les nombres NTSTATUS en chaînes, je ne le ferais pas. Le drapeau FORMAT_MESSAGE_FROM_SYSTEM est utilisé pour convertir le résultat de GetLastError() en une chaîne, donc cela n'a aucun sens ici. L'utilisation du flag FORMAT_MESSAGE_FROM_HMODULE avec ntdll.dll conduira à des résultats incorrects pour certains codes. Par exemple, pour EXCEPTION_ACCESS_VIOLATION vous obtiendrez The instruction at 0x, ce qui n'est pas très instructif :).

Quand vous regardez les chaînes qui sont stockées dans ntdll.dll il devient évident que beaucoup d'entre eux sont censés être utilisés avec la fonction printf(), pas avec le FormatMessage(). Par exemple, la chaîne pour EXCEPTION_ACCESS_VIOLATION est:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0 est traité par FormatMessage() comme la séquence d'échappement qui signifie terminaison de message, pas un insert. Les insertions sont% 1 à% 99. C'est pourquoi le drapeau FORMAT_MESSAGE_IGNORE_INSERTS ne fait aucune différence.

Vous pouvez charger la chaîne de ntdll.dll et le transmettre à vprintf mais vous devrez préparer des arguments exactement comme les Précise de chaîne (par exemple pour EXCEPTION_ACCESS_VIOLATION il est unsigned long, unsigned long, char*). Et cette approche a un inconvénient majeur: tout changement dans le nombre, l'ordre ou la taille des arguments dans ntdll.dll peut casser votre code.

Il est donc plus sûr et plus facile de coder les chaînes dans votre propre code. Je trouve dangereux d'utiliser des cordes préparées par quelqu'un d'autre sans coordination avec moi :) et de plus pour d'autres fonctions. Ceci est juste une possibilité de plus pour un dysfonctionnement.

+0

C'est tellement cassé, mais il est trop tard pour changer. – davidbak

+0

@davidbak Qu'est-ce qui est cassé? – 4LegsDrivenCat

+1

Qu'ils avaient toutes les chances au départ (quand NT a été créé) de créer ces chaînes de journalisation des événements (formatage de style% 1) et de les remplacer par des chaînes au format printf. Et puis ils n'ont jamais fourni de substitut. Il doit y avoir des centaines de programmes - sinon des milliers - qui ont un code spécial pour formater les AV à des fins de journalisation. – davidbak

Questions connexes